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: The `with-external-deps` workflow keeps failing because
adding the neovim-ppa/stable times out.
Solution: Don't add the PPA; it doesn't look to be necessary for
installing current dependencies.
Problem: popup: wrapped cmdline truncated with wildoptions=pum
Solution: Call msg_starthere() in redrawcmd() to reset lines_left
before each redraw (Yasuhiro Matsumoto).
redrawcmd() leaves lines_left at its previous value, which decrements
across successive redraws (e.g. when wildtrigger() refreshes the popup
on every keystroke) until 0, after which msg_no_more aborts drawing
the wrapped cmdline. Call msg_starthere() to reset it.
related: vim/vim#20081587447ec64
The problem mentioned in the PR cannot be reproduced in Nvim. It's not
clear if this change will solve or cause any problems in Nvim, so let's
first try it without adding the test.
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
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: Optional CI reevaluates on unrelated label events and shares
one workflow-wide concurrency group. One optional label change can
cancel in-flight jobs for the other optional suite.
Solution: Only reevaluate each optional job when its own label changes,
and move concurrency to the job level. This keeps `s390x` and
`windows-asan` from restarting each other.
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: C formatting is enforced in CI via uncrustify, but when working
on C code clangd formats on save via clang-format, forcing users to
manually run `make formatc` after they're done.
Solution: disable clang-format.
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
(-).
docs: update instructions for debugging LSP
Previously, it was suggested to set:
vim.lsp.log.set_format_func(vim.inspect)
This made sense before f72c13341a, when
`format_func` was called once per argument being logged, but since that
commit it's called with the log level followed by the other args, so the
suggested setting would call `vim.inspect(log_level, ....)` which would
just print the human readable name of the current log level and no other
details, for example with this set I saw in my logs:
"DEBUG""DEBUG""DEBUG""DEBUG"
Instead just rely on the default formatter, which will:
> ... log the level, date, source and line number of the
caller, followed by the arguments.
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:
The threshold to consider a color as bright is too high, and for some colors the
foreground is set to white when it should be black.
Solution:
Change the threshold to 0.179. This value is taken from pastel-textcolor.
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