Problem: Cannot set 'path' option via modeline (zeertzjq, after v9.2.0435)
Solution: Revert the part that disallows setting 'path' via modeline.
closes: vim/vim#2013788fb739918
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: [security]: Backticks enclosed shell commands in the 'path'
option value are executed during completion (q1uf3ng).
Solution: Skip path entries containing backticks, add P_SECURE to 'path'
option, so that it cannot be set from a modeline (for symmetry with
the 'cdpath' option)
Github Advisory:
https://github.com/vim/vim/security/advisories/GHSA-hwg5-3cxw-wvvg
Supported by AI.
190cb3c2b9
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: Completion with i_CTRL-X_CTRL-V doesn't use dict from cmdline
"customlist" completion.
Solution: Include abbr/kind/menu/info in the completion items
(zeertzjq).
closes: vim/vim#201392bfddbea47
Problem:
When using `vim.list.unique` or `vim.list.bisect`, if the `key` function is
complex, it can degrade performance, because it is invoked on every comparison
Solution:
The `key` interface convention is designed specifically to address this issue;
performance can be improved by memoizing its results.
Also added the shorthand use of the field name string as the key.
Problem:
Nested workspace capabilities like workspace.fileOperations.didCreate and
workspace.textDocumentContent are not handled consistently for dynamic and
static registration provider lookup.
Solution:
Generate explicit registration-provider mappings from the LSP metadata and use
them when registering and querying capabilities. Add coverage for dynamic and
static nested workspace registrations.
Problem:
With 'incsearch' enabled, the window can scroll while typing a
search pattern, but WinScrolled is not triggered until the next user
action in Normal mode. The event is effectively skipped for every
scroll that happens while the search prompt is still open.
Solution:
Call may_trigger_win_scrolled_resized() after update_screen()
in may_do_incsearch_highlighting() and finish_incsearch_highlighting().
Problem:
`EBUSY` during cleanup:
Windows CI can intermittently fail `pack_spec.lua` with `EBUSY` while removing
`site/pack/core/opt/plugindirs`.
This can happen because:
- the test Nvim session may still be alive when `after_each()` removes the pack
directory
- Windows does not allow removing a directory while another process still has an
open handle below it
- startup-time `vim.pack.add()` performs a real `git clone`, so process and file
handle release timing can vary on slower runners
Startup timeout:
The startup tests can also fail before cleanup because they wait for `_G.done`
with a fixed timeout. That timeout includes the time needed for startup to run
`vim.pack.add()` and finish the local clone.
Solution:
Close before cleanup:
Capture the pack, lockfile, and log paths while the test Nvim session is still
available, then call `n.check_close()` before removing the pack directory.
Extend Windows startup wait:
Increase the `_G.done` retry budget only on Windows so startup-time
`vim.pack.add()` has more time to finish on slower CI runners.
Problem:
The `nvim_get_chan_info()` terminal channel test used `shell-test INTERACT` to verify that `jobstop()` reports an unhandled `SIGHUP` as exit code `129`.
`INTERACT` reads from stdin with `fgets()`, so closing the PTY could race with `SIGHUP` delivery. If `fgets()` observed EOF first, `shell-test` exited normally with code `0`, causing intermittent failures on slower sanitizer builds.
Solution:
Add a `shell-test HOLD` mode that prints a readiness prompt and then waits without reading stdin. Use it for the `SIGHUP` assertion so PTY EOF cannot make the helper exit normally before the signal path is observed.
Problem: Test_termdebug_tbreak(), Test_termdebug_basic(), and
Test_termdebug_toggle_break() use synchronous assert_equal()
to check breakpoint signs immediately after sending commands
to gdb. On slow CI (ASAN, ARM64, macOS) gdb may not have
processed the response yet, causing the sign to be missing.
Solution: Wrap the three assertions in WaitForAssert() to poll until
the signs are placed, matching the pattern already used by
the other assertions in the same tests (Jesse Rosenstock).
closes: vim/vim#2013320a124a6e0
Co-authored-by: Jesse Rosenstock <jmr@google.com>
Co-authored-by: Gemini
Problem: termdebug: Need a few more user commands
Solution: Add the :RunOrContinue and the :ToggleBreak user commands
(bennyyip)
closes: vim/vim#18283c975d62473
Co-authored-by: bennyyip <yebenmy@gmail.com>
Problem: Info popup isn't removed when selecting an item that doesn't
have "info" in cmdline completion, which is inconsistent with
Insert mode behavior.
Solution: Set pum_call_update_screen in cmdline mode (zeertzjq).
closes: vim/vim#201283bfffcc290
Nvim already behaves correctly. Add a screen test as there are none.
Problem:
`gx` relies on `exepath` to get the fullpath of `cmd.exe`,
and that path must use `\`; otherwise, luv's spawn will fail.
Solution:
Revert `slash_adjust` in `exepath`, so that it still respects 'shellslash'
Problem:
This test would sometimes fail to match lines starting with `.` (indicating throttling) due to a race condition, likely because throttling completed before the test could properly assert.
Solution:
I 6x'd the amount of test data we were pushing into `nvim` in an attempt to trigger throttling consistently.
I don't _love_ this solution as it is still non-deterministic and might not hold up over time.
A good solution would be: create a deterministic way to pause neovim in a functional test, assert on the temporarily throttle state, then unpause neovim. However, it's likely this is not possible today and will take too much effort.
Before test time (30000 lines): ~0.40sec/run
After test time (150000 lines): ~1.7sec/run
This increases test runtime, but if it removes flakes I think it's worth it.
Problem: customlist completion cannot supply pum metadata
Solution: Allow each item returned by a customlist function to be
either a string or a Dict with keys "word", "abbr", "kind",
"menu" and "info" (Yasuhiro Matsumoto).
closes: vim/vim#201005c700152ae
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Problem: When an error line in a file passed to :cfile / :cgetfile is
longer than IOSIZE, qf_parse_file_pfx() copies the tail
into the fixed-size IObuff with STRMOVE(), overflowing the heap buffer.
The same code path can also loop indefinitely because
qf_parse_file_pfx() always returns QF_MULTISCAN when a
tail is present, and qf_init_ext() unconditionally goes
to "restofline" without bounding the tail length (Nabih).
Solution: Remove the STRMOVE() into IObuff. In the QF_MULTISCAN
branch, alias linebuf into the tail directly and update
linelen, requiring strict progress (new length less than
the previous length) before retrying; otherwise ignore
the line.
closes: vim/vim#20126
Supported by AI
77677c33de
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem:
`get_node_text()` returned inconsistent results between buffer and
string sources when a node's range ends at `end_col == 0` (i.e. the node
ends with a newline). The buffer path dropped the trailing newline; the
string path included it correctly.
Solution:
Append `'\n'` in `buf_range_get_text()` when `end_col == 0` and
`start_row ~= end_row`. The `start_row ~= end_row` guard excludes
zero-width nodes at column 0, which should return `""`.
Remove the workaround in the `#trim!` directive that manually
compensated for the missing newline.
Strip whitespace in `resolve_lang()` so injection language nodes ending
at `end_col == 0` (e.g. `">lua\n"`) still resolve correctly.
Problem: tests: Test_shortmess_F3() is flaky on MS-Windows
Solution: Increase the sleep to 3s (Yasuhiro Matsumoto)
On MS-Windows time_differs() treats mtime as unchanged unless st_mtime
differs by more than 1 second, so a 2-second sleep can fall short when
the two writes straddle a second boundary. Bump the non-nanotime sleep
to 3 seconds.
closes: vim/vim#201172219c89013
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Problem: tests: flaky screendump Test_smoothscroll_incsearch()
Solution: Replace screendump test by WaitForAssert()
(Yasuhiro Matsumoto)
VerifyScreenDump fails consistently on the macos-15-intel CI runner.
Replace the dump comparisons with assertions that verify the actual
invariant under test: that the visible buffer view stays unchanged
across the four incremental-search keystrokes (i.e. skipcol is not
reset). Drop the now-unused dump files.
closes: vim/vim#20118e25933014c
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Problem:
The fallback that tokenizes `eap->arg` by unescaped whitespace (when the
parser doesn't pre-split via `EX_EXPAND` etc.) lives in `nlua_do_ucmd`,
so only user-command callbacks got `eap.fargs`. Builtin commands routed
through `nlua_call_excmd` have to re-parse the args themselves
(e.g. `M.ex_lsp`).
Solution:
- Move the tokenization into `nlua_push_eap` so every Lua handler sees
`eap.fargs`. Keep only the `EX_NOSPC` override in `nlua_do_ucmd` (the
`nargs=1`/`?` case which is genuinely user-command-specific).
- Drop the re-parse in `M.ex_lsp`.
Problem: With $d='[dir]', `:e $d/file.txt` opens the wrong file,
`:e $d/<Tab>` fails to complete, and `glob('$d/*')` returns
nothing. Wildcard characters inside expanded environment
variables get picked up by globbing again.
Solution: Turn the 4th parameter of expand_env_esc() from a bool into a
string of characters to escape in each expanded value. Callers
that pass the result to wildcard expansion should include
PATH_ESC_WILDCARDS in addition to " \t" (glepnir).
closes: vim/vim#2005320e98ff1cc
Problem:
LSP clients previously did not handle dynamic registration for off-spec methods
Solution:
Update the client logic to assume support for dynamic registration when
the method is unknown. Adjust the registration provider fallback and
enhance tests to verify correct behaviour for unknown methods and their
registration options. This improves compatibility with servers using
custom dynamic registrations.
AI-assisted: OpenCode
Problem:
The argument to `:help` is normalized to fit the general tag format.
I.e. i^U-default, iCTRL-U-default and i_CTRL_U-default should all point
to the i_CTRL_U-default tag. Our normalization adds an underscore around
the CTRL keycode, e.g. iCTRL-GCTRL-J becomes i_CTRL-G_CTRL-J. That's not
necessary if the following part starts with a dash, like the case of
iCTRL-U-default.
Solution:
Do not insert an underscore if the following character is a dash/minus
(-).
Problem:
After 55ceb31, z= and tselect don't work if `vim.ui.select` is an async
provider (especially terminal buffers).
Solution:
Drop the `vim.wait()` approach, use an async approach.
fix#39506
Problem:
followup to 55ceb314ca#39478
`:oldfiles` and swapfile `:recover` do not delegate to `vim.ui.select`.
Solution:
- Delegate to `vim.ui.select`.
- Fix a long-standing `recover_names` bug where `concat_fnames(dir_name,
files[i], true)` produced malformed `<dir>//<dir>/<file>` paths (also
fixes `swapfilelist()`).
Problem: SPACE_IN_FILENAME is defined on most platforms but not on Unix.
As a result, set_context_for_wildcard_arg() on Unix always resets the
completion pattern at white space for Ex commands that take a
single file argument.
Solution: Drop the SPACE_IN_FILENAME ifdef (Maxim Kim)
fixes: vim/vim#18411closes: vim/vim#20090c2bda0add9
Co-authored-by: Maxim Kim <habamax@gmail.com>
Problem:
- Various `TermRequest` handlers which all do similar things.
- `tty.query` is specific to `XTGETTCAP DCS`, can't be reused for other kinds of terminal queries.
Solution:
Provide `tty.request()`.
Problem: Wrong behavior when executing register that ends in Insert
mode from Ctrl-O (Emilien Breton)
Solution: Use :startinsert etc. to restore Insert mode after executing
the register contents (zeertzjq).
fixes: vim/vim#20085closes: vim/vim#200916453a7c440
Problem: completion: no support for "noinsert" with 'wildmode' and
commandline completion
Solution: Add "noinsert" value to the 'wildmode' option, mirroring
'completeopt' "noinsert" behaviour (glepnir).
fixes: vim/vim#16551closes: vim/vim#20080af494af5ff
Problem:
If a buffer's filetype changes after the LSP client has already
attached (e.g. from json to jsonc via a modeline), but the client
supports both filetypes, it stays attached. It does not notify the
server of the new languageId, causing the server to incorrectly process
the file using the old languageId.
Solution:
Save the languageId used during textDocument/didOpen, and send
textDocument/didClose + textDocument/didOpen when buffer's languageId
changed.
Lsp spec:
0003fb53f1/_specifications/lsp/3.18/textDocument/didOpen.md (L5)
> If the language id of a document changes, the client
> needs to send a textDocument/didClose to the server followed by a
> textDocument/didOpen with the new language id if the server handles
> the new language id as well.
AI-assisted: Gemini 3.1 Pro
Problem:
1. `vim_getenv` is followed by `TO_SLASH` when getting
path-related variables.
2. cmd exits when launched with forward slash.
Solution:
1. try calling `TO_SLASH` in `vim_getenv`.
2. pass fullpath via `lpApplicationName`, only include `cmd.exe`
in cmdline.
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
Problem:
Similar to clearmatches(), it's always necessary to provide a fallback
that allows the user to do a "global reset" when something goes wrong.
Solution:
vim.img.del(math.huge) clears all images.
Use kitty's d=A command to clear all placements in a single
escape sequence rather than N individual deletes, also freeing stored
image data not referenced by the scrollback buffer.
Problem: Cursor is not adjusted when 'cmdheight' is changed to cover
the cursor with 'splitkeep' ~= "cursor".
Solution: Handle window resize for 'splitkeep' after changing 'cmdheight'.
Ensure previous window height is set when changing 'splitkeep'
(Luuk van Baal).
closes: vim/vim#20043bd0f3e6da5
Co-authored-by: Luuk van Baal <luukvbaal@gmail.com>
Problem: A <Cmd> command in Insert mode can edit the current buffer,
e.g., with setline(). That edit appends to the current undo
block, but Insert mode does not know that the cursor line may
need to be saved again before the next typed edit. If the next
typed edit is a <BS> at the start of a line, it can join away
the line that was changed by the <Cmd> command before Insert
mode saves that updated line. The newest undo entry can then
still refer to the joined-away line, so undo sees a range past
the end of the buffer and fails with E438.
Solution: If a <Cmd> command in Insert mode changes the buffer, set
ins_need_undo so stop_arrow() refreshes Insstart. This lets
the next edit properly decide whether a new undo entry is
needed (Jaehwang Jung)
closes: vim/vim#20087
AI-assisted: Codex
e47daed442
Co-authored-by: Jaehwang Jung <tomtomjhj@gmail.com>
Problem:
Error when querying document symbols using python-lsp-server:
lsp/util.lua:1955: attempt to concatenate field 'containerName' (a userdata value)
Solution:
Check for `vim.NIL`.
Problem:
`:tselect` and `z=` (spell suggest) have their own bespoke select menus.
Solution:
- Delegate to `vim.ui.select` instead.
- Bonus:
- `:tselect` gains mouse support. `print_tag_list` didn't suport mouseclick.
This causes some minor regressions, which are not blockers:
- `z=` no longer draws the list right-left if 'rightleft' is set.
- TODO: can/should `vim.ui.select` / `vim.fn.inputlist()` handle that?
- `:tselect`
- No "column" headings (`# pri kind tag file`).
- No highlighting: (HLF_T: tag name, HLF_D: file, HLF_CM: extra fields).
- TODO: can `vim.ui.select()` support highlighted chunks (`[[text, hl_id], ...]`) ?
fix https://github.com/neovim/neovim/issues/25814
fix https://github.com/neovim/neovim/issues/31987
After an edit, LanguageTree:_edit() updates the current trees. When the
LanguageTree manages explicit regions, _edit() also refreshes _regions
from tree:included_ranges(true), so those regions have the edited byte
offsets.
A later injection pass may call set_included_regions() with a different
number of child regions. That path discards the old trees and emits
changedtree callbacks for them. invalidate(true) does the same when a
buffer is reloaded. Before this change, both discard paths called
tree:included_ranges(true) for every old tree, even if _edit() had just
collected those exact ranges.
That duplicate range extraction is expensive with many injection trees.
Realistic shapes include generated C files with many macro bodies parsed
by the C preproc_arg injection, Markdown documents with many fenced blocks
of the same language, and template files with many embedded-language
islands. The stock highlighter registers recursive changedtree callbacks,
so this is on the normal highlighting edit path.
Track whether _regions currently came from tree:included_ranges(true)
with _regions_from_tree_ranges. _do_changedtree_callbacks() reuses
_regions only in that state; otherwise it falls back to calling
tree:included_ranges(true). Clear the marker when regions are replaced by
injection ranges, when a tree is reparsed, or when trees are discarded.
This avoids keeping a second copy of the ranges while preserving callback
precision: changedtree still receives tree:included_ranges(true) for the
old tree, not the broader managed region.
Benchmark on 100k C macro injections, one-line edit, recursive
changedtree callback:
- HEAD median: edited parse 84.2 ms, child region replacement 58.7 ms
- This change: edited parse 34.6 ms, child region replacement 8.5 ms
That is about 2.4x faster for the edit parse and 6.9x faster for child
region replacement in this workload.
Add a regression test that replacing injection regions still fires
changedtree and still reports the old tree's exact included ranges.
AI-assisted: Codex
Problem: No message kind and multiple events for :recover and
(non-prompt) swapfile attention messages.
Solution: Assign these the "list_cmd" and "wmsg" kind.
Problem: when jumping to tags, will open URLs
(Srinivas Piskala Ganesh Babu)
Solution: Disallow trying to open remote files.
closes: vim/vim#20068
Supported by AI
ae196b2d58
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: Modeline-tainted 'complete' values can invoke completion
callbacks outside the sandbox.
Solution: Enter the sandbox for both 'complete' callback phases and add
a regression test (Barrett Ruth)
closes: vim/vim#20078dd9b31fb62
Spell decorations from other lines aren't relevant to the current line.
Also, decor_redraw_col() can only go forward, while spell navigation
needs to go both forward and backward.