Commit Graph

5971 Commits

Author SHA1 Message Date
Justin M. Keyes
dab5fab948 Merge #41114 from epithet/default-ruler-as-expression 2026-08-04 06:51:34 -04:00
Justin M. Keyes
8589447159 feat(detach): opt-in to "server keeps running" #41133
Problem:
By default, `nvim` does not survive if its host terminal dies. This is
inconvenient if you want to use Nvim as a "session manager" (like tmux).

Solution:
Let users opt-in to the "survive" behavior via `:detach!` (bang "!").
This marks the current UI as "detachable", so the server will not
self-exit if the UI channel closes.
2026-08-04 06:20:16 -04:00
Sébastien Hoffmann
ca07e505f9 refactor(ruler)!: replace C implementation with 'rulerformat' expression
Problem:
The default 'ruler' is implemented in C instead of the 'statusline' DSL.

Solution:
Replace the C implementation with a default 'rulerformat' expression.
This is a continuation of #1248 and #33036.

Advantages:
- configuration is more discoverable, the default being a useful example
- users and plugins can augment the default
- code reuse and less C code to maintain
- ui2: due to the use of an item group with `minwid`, it can expand
  instead of truncating when the content gets too long, which is
  particularly useful for locales with long translations of Top/Bot/All

Implementation details:
As is the case for 'statusline', when trying to set 'rulerformat' to an
empty string, the default expression is restored instead, mimicking how
previously the default C implementation would have been activated.
Just like before, `:set rulerformat=` and `:set rulerformat&` have the
same effect, and the ruler is disabled with `:set noruler`.

The default expression uses an item group with `%=`, unlike the fallback
in the previous default statusline `%-14.(%l,%c%V%) %P`, because the
total width and how it is configured is immediately clear without
documentation, it is a more useful pattern in general that works when
both sides have flexible width, and it also works for vim, which is
useful for configuration sharing/reuse.

A truncation marker `%<` is added at the end to mimic how at small
screen widths, the scroll percentage would disappear first, so that the
cursor position can remain fully visible.

BREAKING CHANGES:
- `&rulerformat` can no longer be set to an empty string
- ui2: the default ruler is no longer of fixed width, but can expand
- at very small screen widths (< 36 columns)
  - ui2: it will no longer try to shrink white-space before truncating
  - it truncates gradually from the right, whereas previously, the
    scroll percentage would disappear all at once
- l10n can no longer add a space after the comma between line and column
  (this was only done for one language: Ukrainian)
2026-08-04 12:12:23 +02:00
bfredl
0abc9ccc19 Merge pull request #40772 from Rawan10101/wasm-browser
feat(wasm-emcc): add browser support for Neovim
2026-08-04 12:11:17 +02:00
Barrett Ruth
a29297ac53 docs(api): buffer columns are byte indices #41137 2026-08-04 05:19:54 -04:00
Sébastien Hoffmann
259e6fa9cc fix(ruler)!: consistent width in last line and statusline
Problem: Traditionally, the ruler in the last line is one cell shorter
than in the statusline, leaving the last cell of the screen blank.
According to code comments, this is in order to prevent unwanted
scrolling on "some" (unspecified, but presumably ancient) terminals.
Berkeley vi is more specific in its `vs_modeline` function: dumb
terminals with hardware scroll, SunOS 4.1.1 and Ultrix 4.2 curses.
(n)curses still has a similar limitation in `(w)addstr`, but apparently
only for historical reasons.

Maintaining the different widths leads to awkward inconsistencies when
the ruler is configured with 'rulerformat', except for the special case
where it contains a top-level `%=`. Shifting the ruler in the last line
to the left would be a solution, but the empty cell at the end doesn't
seem to be relevant anymore.

Solution: extend the ruler in the last line all the way to the right
edge of the screen, just like in the statusline. The exact same amount
of place will be available to the rest of the UI as before.

BREAKING CHANGE:
- the default ruler width is now 18 cells
- the last cell of the screen is no longer empty

Closes #41076
2026-08-04 06:36:58 +02:00
Barrett Ruth
886a270e7f refactor(zip)!: address entries with zip:// paths
Problem:
`zipfile://{archive}::{entry}` is ambiguous: `::` is legal in both an
archive path and an entry path, so the separator cannot be identified.
Splitting at the last `::` reads archives correctly but breaks entries
that contain it, and the plugin then emits buffer names it cannot read
back.

Solution:
Address entries as `zip://{archive}/{entry}`, joining the two paths.
Resolve the split by walking components: the first one that is a regular
file is the archive, because a regular file cannot have children on disk.
Entry paths may then contain any character, and no escaping is needed.

zipPlugin.vim keeps its own scheme, so the Java ftplugin emits whichever
form matches the active plugin until the legacy package is removed.
2026-08-03 15:22:25 -05:00
Barrett Ruth
d03b4cfb7a feat(zip): checkhealth and encrypted entries
Problem:
There is no health check. Encrypted entries cannot be read at all, since
Info-ZIP takes a password only from a terminal and `-P` would expose it
in the process arguments.

Solution:
Add `:checkhealth nvim.zip`, reporting the backend and which
implementation is handling archives. Prompt for the password on a pty,
extracting to a file so the entry's bytes stay off the terminal. Report
Info-ZIP's exit code rather than inferring a cause, so an archive using
AES is not reported as a failed decryption.
2026-08-03 11:53:20 -05:00
rawan10101
5079787993 docs: mention wasm32-emscripten build target in news.txt 2026-08-03 15:40:16 +03:00
Ro
3b85a689ab docs(api): rpc examples #41077 2026-08-02 08:19:29 -04:00
Justin M. Keyes
98d767cd53 docs: func/expr options, misc #41102 2026-08-01 17:48:32 -04:00
AlexCodesApps
b11f1b1f76 feat(vim.fs): abspath({cwd, plain}) #40597
Adds optional parameters to `vim.fs.abspath`:
1. `cwd` to specify directory akin to `--relative-from` in `realpath(1)`.
2. `plain` disables expansion of tilde (~) in paths.
2026-08-01 09:09:21 -04:00
Justin M. Keyes
3e01dcddbe refactor(options): memory management
Problem:
Numerous callers have to manually check optval ownership (i.e. whether,
and how, to release) via `is_callback_option`, `option_is_global_local`,
etc. This is fragile, hard to use correctly; and if we introduce another
optval variant in the future, we'll have to redo all of these careful
checks and boilerplate again.

Solution:
Provide a unified system and use it everywhere:

    optval_free_owned
    optval_is_owned
    optval_own
2026-07-31 21:50:04 +02:00
Justin M. Keyes
726d1a92d2 feat(options): lua closure/function options
Problem:
Cannot assign Lua functions/closures to "func" ('completefunc',
'tagfun', …) or "expr" ('foldexpr', 'indentexpr', …) options.

Solution:
- Store "func"/"expr" options as `Callback` instead of string.
- Delete oceans of copy-pasted code.
- BREAKING: LuaRef returned via RPC/Vimscript is now represented as
  `"<Lua N: file:line>"` (like what `:map` shows) instead of `nil`.
- Note: `man.vim` still uses `v:lua` string, bc it's a vimscript ftplugin.

Helped-by: Lewis Russell <lewis6991@gmail.com>
2026-07-31 21:50:04 +02:00
Justin M. Keyes
917232b508 Merge #40953 from barrettruth/feat/zip-extract
feat(zip): extract archive entries
2026-07-31 15:45:14 -04:00
Justin M. Keyes
6cdab150bc docs: misc #41063 2026-07-30 15:09:19 -04:00
Barrett Ruth
c1a65ff353 docs(tui): kitty keyboard protocol flags #41056
Nvim has sent CSI > 3 u since 4fb3b57a19, but tui.txt still documented
CSI > 1 u.
2026-07-30 05:50:39 -04:00
zeertzjq
a85cce90e3 vim-patch:partial:b4ae16c: runtime(doc): clarify 'laststatus' effect (#41052)
fixes: vim/vim#20875

b4ae16ca3e

Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-07-30 00:11:46 +00:00
Barrett Ruth
36204b4323 feat(zip): extract archive members 2026-07-29 14:32:37 -05:00
Barrett Ruth
e29af9c32f refactor(zip)!: builtin zip.lua plugin #40846
Problem:
The bundled `zip` plugin is implemented in Vimscript, making it harder to
maintain and build on with Nvim's Lua runtime infrastructure.

Solution:
Add an opt-out `zip.lua` browser backed by `nvim.dir`, and disable the legacy
Vimscript implementation by moving it to `pack/dist/opt/zip/`. Load it with
`:packadd zip`.
2026-07-29 12:54:43 -04:00
flatplum
7b34bca2a6 docs(health): avoid warnings for dynamic filetypes #41036
Problem:
Dynamic filetypes defined by `vim.filetype.add` may show health warnings.

Solution:
Document a way to suppress these harmless warnings.
2026-07-29 09:03:53 -04:00
glepnir
916a6e9546 fix(eval): complete_info() equal, preselect, commit_chars #41022
Problem:  complete_info() does not report "equal", "preselect" or "commit_chars".

Solution: Report them for the items that set them.
2026-07-28 07:24:58 -04:00
Olivia Kinnear
5226e26e99 feat(pos): vim.pos.cursor() without args returns curwin pos #40975 2026-07-28 07:21:45 -04:00
Barrett Ruth
93f427f603 docs(dir): buffer state discarded by 'bufhidden' #41014 2026-07-28 06:12:01 -04:00
Barrett Ruth
e3c5974adf feat(dir): open cwd with 1- #40948 2026-07-27 18:30:54 -04:00
Justin M. Keyes
fbcb7a056c feat(exmode): "1q:", :exmode #41010
Problem:
Want `gQ` for _le multicursor_.

Solution:
- Don't use `gQ` for exmode.
- Introduce `:exmode`.
- Introduce `[count]q:` as an alias to `:exmode`.
2026-07-27 11:12:47 -04:00
Justin M. Keyes
80cd482577 fix(lua): vim.regex():match_str abort in Luv callback #41008 2026-07-27 11:01:54 +00:00
Justin M. Keyes
359459dec6 refactor(exmode): Ex-mode as cmdwin + Lua #40991
Problem:
POSIX-compatible Ex-mode requires special-cases all over the codebase to
match various quirks that don't actually matter to users.
- The main utility of *interactive* Ex-mode is its REPL behavior, and
  that can be achieved with `cmdwin`, which also gains extra UX
  benefits.
- The main utility of *non-interactive* `nvim -es` is for shell
  scripting, where Ex-mode quirks are mostly unhelpful (e.g. the
  "Entering Ex mode" message).

Solution:
- Reimplement *interactive* Ex-mode as a "persistent, insert-mode
  cmdwin" in Lua.
  - "nvim -e/-E" is simply an alias to "gQ".
- Reframe *non-interactive* Ex-mode (`nvim -es`) as "script mode".
  - Drop POSIX Ex-mode quirks.

Improvements:
- "nvim -V1 -es" output ends with a final newline!
- "nvim -V1 -es" no longer shows the "Entering Ex mode" msg. (This was
  pointless noise, unwanted for scripting purposes.)
- stdin is no longer typeahead. Scripts (":lua io.read()") can read
  stdin as data.
- Empty line is a no-op: a stray blank line no longer moves the cursor
  (deviates from POSIX ex "+1"), no longer exits 1 at EOF (E501).

Preserved behavior:
- cursor starts at "$"
- mode()=="cv" (for non-interactive)
- multiline commands (:append/:function/heredoc pull continuation lines)
- bare-range print
- :print=>stdout
- -V1=>stderr
- CRLF input
- continue-after-error and exit codes

Dropped (regressed) POSIX behavior (non-interactive):
- Event loop only ticks while/between commands, not while blocked
  waiting for a stdin line.
- ":g/pat/visual...Q"
- input()/getchar()/":s/x/y/c" no longer consume stdin lines as
  answers: Nvim stops at end-of-input, skipping the rest of the script,
  exit 0. Use ":lua io.read()" instead.
  - If users care about this they should use interactive Ex-mode (`gQ`).
- ":@r" stops at end of the register instead of continuing to read
  cmdline input from stdin.
2026-07-27 06:25:21 -04:00
Justin M. Keyes
6539bd6602 Merge #40910 from barrettruth/fix/dir-literal-env-paths 2026-07-26 06:11:01 -04:00
zeertzjq
43b666cb27 vim-patch:770eb7d: runtime(doc): clarify expandcmd() and "~" behaviour
fixes: vim/vim#20793

770eb7db17

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
2026-07-26 09:01:32 +08:00
zeertzjq
a7bab6121b vim-patch:e2d3e78: runtime(doc): remove incorrect note about spellcapcheck and the first word
'spellcapcheck' checks the first word in the file for a capital like any
sentence start: capcol is seeded to 0 for line 1 in spell_check_sblock().

This has been the case since the feature was added in v7.0100, so the note
that it "doesn't work for the first word in the file" is incorrect.

related: f9184a1d3151b5b727fec86c2ac0946c9c68df4d (code change)
related: 0d9c26dd8333aae4b20015f13fe2e8e1f07037bd (initial doc patch,
         just a few minutes later)
related: vim/vim#20715

e2d3e7818b

Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-07-26 09:00:30 +08:00
Barrett Ruth
ac4e5460b1 feat(vim.fs): dir(opts.normalize) 2026-07-25 18:02:55 -05:00
Barrett Ruth
22d44ef875 fix(api): add lhs option for keymap deletion 2026-07-25 10:36:56 -07:00
Justin M. Keyes
715d8887ec docs: misc #40847
Co-authored-by: Barrett Ruth <br@barrettruth.com>
Co-authored-by: Nathan Zeng <nathan.j.zeng@gmail.com>
2026-07-25 12:47:51 -04:00
Barrett Ruth
4975a186f2 fix(dir): :browse edit opens dir browser #40930
Problem: `:browse edit` (and variants) without an argument fails instead
of opening a browser.

Solution: Dispatch to dir.lua using the cwd as the implied directory.
Replace the inherited GUI-only documentation with the supported
behavior. Support vsplit, split, tabedit variants.
2026-07-25 06:56:52 -04:00
zeertzjq
63c84e4c1a vim-patch:9.2.0848: tagfunc "cmd" with a generic Ex command corrupts the tag entry (#40951)
Problem:  When a tagfunc returns a "cmd" that is neither a line number nor
          a search pattern, the tag entry is corrupted: the "kind" field is
          lost and taglist() returns a mangled "cmd".
Solution: Accept any Ex command in "cmd" as in a tags file, terminate a
          generic command with a bar so the trailing fields are preserved,
          and reject a value that cannot be stored in a tag line with E987
          (Hirohito Higashi).

fixes:   vim/vim#20781
related: vim/vim#20790
closes:  vim/vim#20828

86adef19fc

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Mao-Yining <mao.yining@outlook.com>
2026-07-25 07:07:22 +08:00
zeertzjq
db41e4c74f vim-patch:0c1a214: runtime(doc): Fix truncated sentence in :h map()
fixes: vim/vim#20725

0c1a214497

Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-07-25 06:32:03 +08:00
Justin M. Keyes
f8cfd7f06a feat(options): schema, "dict" options, messages
Problem:
Options parsing is still painful for dict-style options.

Solution:
schema-maxxing => better `opt:get()` (will be the basis for `vim.o()`),
unified (and more-detailed) err msgs.

- Drop bespoke structure-builder in `_core/options.lua`.
- Define `schema` for all non-primitive options (except 'guicursor' and
  statusline-style options); generate reified keysets `OptKeyDict`).
  - Generate 'fillchars' => `fcs_tab`, 'listchars' => `lcs_tab`.
- `nvim_set_option_value`:
  - Return the improved structures. Also from `vim.opt.x:get()`.
  - Eliminate api <=> lua roundtrip, centralize option structure
    handling.
- Improve/unify errors.
  - Bump ERR_BUFLEN 80 → 256 so the "one of" list isn't truncated.
- Eliminate old 'diffopt' order-dependence (`iwhiteall` before `iwhite`)

Error samples:

    Typed-key path (opt_strings_check → diffopt/mousescroll/breakindentopt):
    E474: Unknown item 'foo'
    E474: 'context' requires a number
    E474: 'ver' number is out of range
    E474: 'algorithm' must be one of: myers, minimal, patience, histogram
    E474: 'filler' does not take a value

Related:

- #31084
- #34661
- #31820
- #14739
- #20107
- fix #18875
  - :get() returns `{ sbr = true, shift = '3' }` (reified-keyset) instead of `{'sbr', 'shift:3'}`
  - Setting via table now works too. `object_as_optval_for` `is_map` now recognizes struct options.
- fix #30296
  - instead of `E474: Invalid argument`, errors now look like:
    ```
    E474: Invalid value 'x', expected one of: single, double: ambiwidth=x
    E474: Unknown item 'foo': diffopt=foo
    E474: 'context' requires a number: diffopt=context:x
    ```

simplify `win_float_parse_option` from #26799.
2026-07-24 13:05:20 +02:00
glepnir
f95bd73935 feat(float): 'previewpopup' option #26799
Problem:
The preview-window (:pedit, etc.) always uses a split, but it would be
useful as a floatwin (or "popup").

Solution:
Support Vim's 'previewpopup' option.
2026-07-23 17:27:14 -04:00
zeertzjq
b81c60c3fa vim-patch:9.2.0830: the completion menu is not used on terminals without colors (#40917)
Problem:  When the terminal reports no colors ("t_Co" is 0 or 1) the
          insert mode completion popup menu is not shown at all, while
          the command line completion popup menu ('wildoptions' contains
          "pum") is shown.  In 'wildmenu' completion the current match
          cannot be told apart from the other matches (Maxim Kim)
Solution: Show the insert mode completion popup menu regardless of the
          number of colors and add "term" attributes to the default
          highlighting of Pmenu, PmenuSel and PmenuThumb.  The wildmenu
          is drawn with the attributes of the status line, which is
          reversed, and on most terminals the standout mode is the same
          as the reverse mode, thus use the underline mode for the
          default highlighting of WildMenu (Hirohito Higashi).

fixes:  vim/vim#20800
closes: vim/vim#20803

52485e0d24

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 07:40:11 +00:00
Barrett Ruth
fe6c1cb4bd fix(treesitter): queries for bundled diff parser #40866 2026-07-22 12:03:34 -04:00
PinkLea
a56b74bde3 feat(lua): Iter:count() #40831 2026-07-20 09:53:06 -04:00
Rocco Vaccone
01c4d37959 fix(lsp): preview window converted to normal window is auto-closed (#40770)
Problem:
A floating preview window (hover, signature help) converted to a normal
window (e.g. with CTRL-W_H or nvim_win_set_config()) is still closed by
the open_floating_preview() autocommands, and a later preview may focus
or close it as if it were still a float.

Solution:
When the preview window is no longer floating, remove its auto-close
autocommands and stop tracking it as the buffer's floating preview.

Closes #36659
2026-07-19 17:16:56 -07:00
Justin M. Keyes
d1b3a9924d feat(api): mark nvim_create_autocmd as api-fast #40836
Problem:
nvim_create_autocmd() isn't |api-fast|, so modules that create autocmds
(e.g. vim.treesitter.query) can't be require()d in a fast event context.

Solution:
Mark it |api-fast|. Compile autocmd patterns with RE_NOBREAK so
aucmd_next() won't os_breakcheck() mid-iteration, where a fast
nvim_create_autocmd() could realloc the autocmds vector and dangle the
caller's AutoPat/AutoCmd.

RE_NOBREAK is low-risk because:
- aucmd_next()'s loop checks CTRL-C: `(for (… i < apc->ausize && !got_int; …)`.
- `line_breakcheck()` (`autocmd.c:1912`) runs once per matched autocmd.
- Each autocmd _execution_ runs through `do_cmdline`, which has its own
  breakchecks.

However this does admit risk of a pathological case:
a catastrophic-backtracking glob matched against a very long `User`
event-pattern.

Co-authored-by: Riley Bruins <ribru17@hotmail.com>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
2026-07-19 11:38:14 -04:00
Justin M. Keyes
239125b8c8 feat(eval): declare more "fast" functions #40834 2026-07-19 10:03:53 -04:00
Justin M. Keyes
6f5fae3f8c fix(lua): vim.keycode cleanup #40817 2026-07-18 14:31:36 -04:00
altermo
a2dfa195b2 feat(lua): vim.keycode() gets structured parse result #38636
Problems:
1. Can't get individual parts of a key-chord separately: modifiers, key.
2. Can't separate a key-combo into individual key-chords.

Solution:
Enhance `vim.keycode()` to optionally return a structured parse result
as a list of key-chords:
- `key_raw` the key-chord (problem 2)
- `mod` the modifiers of `key_raw` (problem 1)
- `key_orig` the key part of the key-chord, only here if differing from `key`
  (this doesn't solve any of the above mentioned problems, but it may provide
  useful and it's (in terms of code) free)
- `key` a normalized version of `key_orig` (solving problem 1), example(the
  first is `key_orig` and second is `key`): `lt` and `<`, `Bar` and `|` (in
  `<C-Bar>`)
2026-07-18 12:20:41 -04:00
Justin M. Keyes
446b9d8c55 docs: misc, remove some old help tags #40214
- Remove old help tags: they add noise to cmdline completion.

Co-authored-by: acehinnnqru <acehinnnqru@gmail.com>
Co-authored-by: KangaZero <samuelyongw@gmail.com>
Co-authored-by: Simone Ragusa <hi@interrato.dev>
Co-authored-by: Chinmay Dalal <~chinmay/public-inbox@lists.sr.ht>
Co-authored-by: coyaSONG <66289470+coyaSONG@users.noreply.github.com>
Co-authored-by: Olivia Kinnear <git@superatomic.dev>
2026-07-18 04:29:51 -04:00
Barrett Ruth
12e8db3847 fix(restart): distinguish v:exitreason for :restart! #40801 2026-07-18 04:07:14 -04:00
glepnir
9fae7234f6 feat(completion): support completionList.applyKind #40769
Problem: values from completionList.itemDefaults always replace the
item's own commitCharacters and data. Since 3.18 a server can ask for
them to be merged instead.

Solution: Handle CompletionList.applyKind and advertise applyKindSupport.
Drop itemDefaults once folded into the items: get_items() runs twice on
the same result and a Merge isn't idempotent.

https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#completionItemApplyKinds
2026-07-17 21:07:01 -04:00