Problem: tests: Test_backupskip() may read from $HOME
Solution: Set $HOME to an empty value, use --clean
(D Ben Knoble)
Even though we unset HOME, we can see via scriptnames that user files
are still sourced! One of my installed plugins warns when not compiled
with +python3, so this test has a "press Enter" prompt.
Use `--clean` like most other GetVimProg()'s do to fix it. Some tests
use `system()` instead, but that turns this test into a failure rather
than passing; I'm not sure why other tests don't suffer from this.
To prove to ourselves, we can use code like this:
diff --git i/src/testdir/test_options.vim w/src/testdir/test_options.vim
index a408e20e1..044364a54 100644
--- i/src/testdir/test_options.vim
+++ w/src/testdir/test_options.vim
@@ -1179,6 +1179,7 @@ func Test_backupskip()
" P_NODUP). Run this in a separate instance and write v:errors in a file,
" so that we see what happens on startup.
let after =<< trim [CODE]
+ call writefile([execute('scriptnames')], 'foo')
let bsklist = split(&backupskip, ',')
call assert_equal(uniq(copy(bsklist)), bsklist)
call writefile(['errors:'] + v:errors, 'Xtestout')
@@ -1196,7 +1197,7 @@ func Test_backupskip()
" unset $HOME, so that it won't try to read init files
let saveenv['HOME'] = getenv("HOME")
call setenv('HOME', v:null)
- exe 'silent !' . cmd
+ exe 'silent !' . cmd .. ' --cmd "echo &rtp"'
call assert_equal(['errors:'], readfile('Xtestout'))
" restore environment variables
Here, that causes "foo" to include a bunch of files under ~/.vim. I'm
not sure why this happens, but lets paper over it for the test.
We can also tell that (orthogonal to --clean) setting HOME='' works too.
Let's do that in addition since unsetting HOME isn't quite enough.
closes: vim/vim#200518d9c383aaf
Co-authored-by: D. Ben Knoble <ben.knoble+github@gmail.com>
(cherry picked from commit 0039a13fe4)
Problem:
Currently, only some filesystems (Btrfs, ext2, ext3, ext4) have full
support of accessing the `dirent` entry-type. On other filesystems,
`uv.fs_scandir_next` may return `nil` for an existing but unsupported
entry-type.
This means consumers (such as `fs.dir()`), cannot know if `nil` means
"non-existent" or "unsupported".
Solution:
Fall back to `uv.fs_lstat` when `etype` is `nil`; return "unknown" if it
fails.
(cherry picked from commit 4b5f026ac9)
Problem: quickfix: can set quickfixtextfunc in restricted/sandbox mode
(tacdm)
Solution: Disallow setting the quickfixtextfunc option from a sandbox
and restricted mode (Yegappan Lakshmanan).
closes: vim/vim#20305cb8510d470
Co-Authored-by: tacdm
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
(cherry picked from commit 1a064abb0a)
Problem: Cmdline ruler may be drawn for autocommand window.
Solution: Check that the current window is not an autocommand window
when deciding whether to draw the ruler.
(cherry picked from commit b58ce1ab79)
Problem: completion: cannot complete user cmd :K with 'ignorecase'
(rendcrx)
Solution: Skip the short-circuit when 'ignorecase' is set
(Yasuhiro Matsumoto)
The set_cmd_index() short-circuit for the :k command treats ":k<X>" as
":k {X}" (mark argument), which makes ":kz<Tab>" never reach the
command-name expansion path. With 'ignorecase' the same prefix on other
letters (":gz<Tab>") completes a user command like :Gz, so the result is
inconsistent. Skip the short-circuit when 'ignorecase' is set; default
behaviour is preserved so the existing :k tests still pass.
fixes: vim/vim#20241closes: vim/vim#20275b54e57ee54
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
(cherry picked from commit dee602e659)
Problem: If there are pending messages when starting to build the
runtime search path, a msg_show callback may invoke
runtime_search_path_validate() recursively.
Solution: Avoid msg_show callback by ensuring messages are flushed.
(cherry picked from commit 53da0c5060)
Problem:
Virtual lines above a line where a fold starts show `foldopen` in
`foldcolumn`.
Solution:
Check if the line below the virtual one is inside a fold that starts
higher up or if it's the start of a fold. In the latter case, don't show
anything in `foldcolumn` for the virtual line.
refactor: lint
(cherry picked from commit 526ae1cc1b)
Problem:
When mouse=n is set
- Dragging the mouse enters visual mode, and then stops listening for
mouse events.
- Double/Triple/Quad clicking performs selections.
- Clicking in visual mode moves the cursor (though not through the TUI).
Solution:
Explicitly gate mouse actions that affect visual mode with a check for
MOUSE_VISUAL. This matches the behavior described in :help mouse.
> If enabled for "v" (Visual mode) then double-click selects word-wise,
> triple-click makes it line-wise, and quadruple-click makes it
> rectangular block-wise.
(cherry picked from commit 24f7182390)
Problem: filetype: some html files are wrongly recognized as htmlangular
Solution: Use the \< atom to anchor ng-template and ng-content to start
of word (truffle)
Prevent false-positive htmlangular detection on words containing
'ng-template' or 'ng-content' as a substring (e.g. 'song-template',
'sing-content'). Anchor both branches with \< to require a word start,
matching the \<DTD\s\+XHTML\s idiom used five lines below.
related: neovim/neovim#39778.
closes: vim/vim#20246354ab1a69e
Co-authored-by: truffle <truffleagent@gmail.com>
(cherry picked from commit f3bb21e71d)
Problem:
Visual selection could end up in the wrong place after
nvim_buf_set_text or nvim_buf_set_lines. In some delete cases,
Visual.lnum was already clamped before the line shift happened, so the
adjustment got skipped.
Solution:
Split fix_cursor_cols into reusable fix_pos_col logic and reuse it
for Visual updates. Also adjust Visual.lnum before changed_lines so
the shift uses the original position before final clamping.
(cherry picked from commit 450ba41436)
Problem:
During startup, we manually trigger a useless and misleading `OptionSet`
event, which doesn't set `v:option_*` values (this is a limitation of
`nvim_exec_autocmds`).
ad4bc2d90c/runtime/lua/vim/_core/defaults.lua (L939).
Solution:
The `nvim_exec_autocmds('OptionSet',…)` call does not serve any purpose
since 5cbb9d613b, so just drop it.
Problem:
After closing and reopening Neovim, ]' and [' fail with E92: Buffer 0
not found for marks restored from ShaDa. Direct jumps like 'a work
because mark_get_local() rewrites fnum before returning, but ]' uses
getnextmark() which does not, leaving fnum = 0.
Solution:
Set .fnum = buf->b_fnum when restoring local marks from ShaDa.
(cherry picked from commit 0b96b3cd52)
Problem:
On "arm clang unittest" CI job, `make unittest` sometimes fails with
lots of these messages:
FAILED test/unit/testutil.lua @ 773: ...
test/unit/testutil.lua:773:
test/unit/testutil.lua:297: declaration specifier expected near '_Static_assert' at line 429
exit code: 256
stack traceback:
test/unit/testutil.lua:773: in function 'itp_parent'
test/unit/testutil.lua:811: in function <test/unit/testutil.lua:801>
Solution:
Update filter_complex_blocks.
(cherry picked from commit adb5d8a646)
Problem:
Using the `DiffTool` plugin (e.g. through `nvim -d ...` or `:DiffTool
<file1> <file2>` fails if a space is in one of the paths. This occurs
because the `diff` wraps the paths with quotes (`'`) if space
characters are present, which the line diff regex fails to parse.
Solution:
Update regex to handle quoted paths by matching the string within the
quotes, if it exists.
(cherry picked from commit 1e09b020e5)
Problem:
When using prompt_appendbuf with multi-element list,
the first item is concated and rest replace the prompt instead of
inserting the lines before the prompt.
Solution:
Concat first element with replace_buf and insert the rest of the list
with set_buffer_lines.
Signed-off-by: Tomas Slusny <slusnucky@gmail.com>
(cherry picked from commit a977e1077b)
Problem: 'title' is updated when changing the name of a non-current
buffer with nvim_buf_set_name().
Solution: Set RedrawingDisabled when renaming the buffer.
(cherry picked from commit 96fc7c150f)
Problem: Message redirection column for captured output is not reset
after :echon since (4260f73, e63346df).
Solution: Ensure msg_ext_append is set before the kind with :echon.
(cherry picked from commit ce9f4f0369)
Problem: The four pointer-resolution loops in u_read_undo() lack
an i != j guard, so a header whose uh_next.seq equals
its own uh_seq resolves uh_next.ptr to itself. On
buffer close, u_freeheader() sees uhp->uh_next.ptr !=
NULL and skips updating b_u_oldhead, so u_blockfree()
dereferences the freed header on the next iteration.
The same pattern applies to uh_prev, uh_alt_next and
uh_alt_prev. A crafted .un~ file in the same directory
as a text file can trigger the use-after-free and
subsequent double-free when the buffer is closed.
(Daniel Cervera)
Solution: Add an i != j guard to each of the four resolution
loops, matching the guard already present in the
duplicate-detection loop above.
closes: vim/vim#20168
Supported by AI
4f610f07b7
Co-authored-by: Christian Brabandt <cb@256bit.org>
(cherry picked from commit 2d5f56c0aa)
Problem: Crash with invalid shellredir/shellpipe value
(bfredl)
Solution: Validate the option and allow only a single "%s".
fixes: vim/vim#20157closes: vim/vim#2015984ae09dd79
Co-authored-by: Christian Brabandt <cb@256bit.org>
(cherry picked from commit ffe87d91f7)
Problem:
- Empty ranges have different `<`, `<=`, `has` and `intersect` semantics compared to regular ranges.
- `to_inclusive_pos` assumes that the end position of a range is exclusive, which is not true for empty ranges
Solution:
Special case empty ranges in these operations.
(cherry picked from commit 416f3482e7)
Problem:
When `:!` writes shell output to a buffer, write_output() splits on `\r`, `\n`,
and `\r\n`, replacing the terminator byte with NUL. For a binary-mode buffer
this is wrong: `\r` should be preserved verbatim, not treated as a line
terminator. This wrong behavior causes a file like `\r\n` round-trips through
`:%!cat` to `\n`.
This was masked when 'shelltemp' was enabled, because output went through a temp
file and the regular file I/O path handled binary-mode correctly. Switching the
default to 'noshelltemp' exposed the bug, since output is now piped directly
into write_output().
Solution:
In `write_output()`, skip the `\r` and `\r\n` splits for a binary-mode buffer;
only split on `\n`.
(cherry picked from commit 832a68835b)
Problem: select_spec tests a public function, but uses private enums.
Solution: Replace private enums with public enums.
(cherry picked from commit a61c8f3580)
feat(tui): restore 'ttyfast' to control tty requests
Problem:
When running nvim on a remote machine over SSH, if there is high ping,
then bg detection may not complete in time. This results in a warning
every time nvim is started. #38648
Solution:
Restore 'ttyfast' option and allow it to control whether or not bg
detection is performed. Because this is during startup and before any
user config or commands, we use the environment variable
`NVIM_NOTTYFAST` to allow disabling `ttyfast` during initialization.
Co-authored-by: Kyle <50718101+kylesower@users.noreply.github.com>
Problem: read_compound() in spellfile.c computes the size of the regex
pattern buffer using signed-int arithmetic on the attacker
controlled SN_COMPOUND sectionlen. With sectionlen=0x40000008
and UTF-8 encoding active the multiplication wraps to 27 while
the per-byte loop writes up to ~1B bytes, overflowing the heap.
Reachable when loading a crafted .spl file (e.g. via 'set spell'
after a modeline sets 'spelllang'). The cp/ap/crp allocations
have the same int + 1 overflow class (Daniel Cervera)
Solution: Use type size_t as buffer size and reject values larger than
COMPOUND_MAX_LEN (100000). Apply the same size_t treatment to
the cp/ap/crp allocations.
Github Advisory:
https://github.com/vim/vim/security/advisories/GHSA-q4jv-r9gj-6cwv9299332917
Co-authored-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
(cherry picked from commit 0976ce255b)
Problem:
parser_gc() calls ts_parser_delete() but leaves the userdata pointer
pointing to freed memory. If the GC finalizer runs at an unexpected time
(e.g. inside nvim_buf_get_lines #39411), a stale pointer could cause a crash.
Solution:
- NULL out `*ud` after ts_parser_delete() in parser_gc()
- Update parser_check() to handle NULL with a clear error message,
guarding all parser methods against UAF
Co-authored-by: Lewis Russell <lewis6991@gmail.com>
Signed-off-by: Szymon Wilczek <swilczek.lx@gmail.com>
(cherry picked from commit 0c3e6e1b0e)
Problem:
For a given position, it is not easy to compare which of several other positions is closest to it.
Solution:
Add support for converting `vim.Pos` to a buffer byte offset.
This allows for sorting, e.g:
```lua
table.sort(positions, function(pos1, pos2)
return pos1:to_offset() < pos2:to_offset()
end
```
Or a binary search, e.g:
```lua
vim.list.bisect(positions, pos, { key = function(pos) return pos:to_offset() end })
```
Co-authored-by: Yi Ming <ofseed@foxmail.com>
Problem: Entering the pager fails if <ESC> is remapped to :fclose by user.
Solution: Avoid executing mappings with nvim_feedkeys() that closes expanded cmdline.
(cherry picked from commit 2b7a00746d)
Problem: When closing gvim with an unsaved unnamed buffer, choosing
"Yes" in the "Save changes?" dialog and then "Cancel" in the
file selection dialog either silently writes the buffer to a
file named "Untitled" (overwriting any existing file with
that name) or discards the buffer altogether
(vibs29, after v9.1.0265).
Solution: In dialog_changed(), if browse_save_fname() leaves the buffer
without a file name, treat it as a cancel and return without
saving. Also stop clearing the modified flag in the restore
path on write failure, so the unsaved changes are kept and
the caller (e.g. gui_shell_closed()) can also cancel the
close. Pre-fill the file dialog with "Untitled" to match
the preceding "Save changes to ..." prompt. Add a test for
the write-failure path (Hirohito Higashi).
fixes: vim/vim#20132closes: vim/vim#20143cf947e7ef0
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
(cherry picked from commit 2bb426ce4a)
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>
(cherry picked from commit d1c3d6fbaa)
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>
(cherry picked from commit b06f8b174f)
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.
(cherry picked from commit 78111e5371)
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.
(cherry picked from commit 19a2ef5afa)
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.
(cherry picked from commit cbedd537ac)
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>
(cherry picked from commit 0e69a38026)
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.
(cherry picked from commit 7ed5609439)
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
(cherry picked from commit 344d984ed2)
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
(-).
(cherry picked from commit 84ae70c172)
fix(lsp): send didClose, didOpen when languageId changes
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
Co-authored-by: phanium <91544758+phanen@users.noreply.github.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`.
(cherry picked from commit 1799aaebda)
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.
(cherry picked from commit 46c83ce321)