Problem: An OSC 52 sequence from a :terminal job passes the decoded
payload to the clipboard provider as a single list item. Command-line
providers (pbcopy, xclip, ...) receive it with channel semantics, where
a newline inside an item is sent as NUL (:h chansend()), so multiline
copies arrive with NUL bytes instead of newlines.
Solution: Split the payload on newlines into a proper list of lines.
A trailing newline yields a final empty item, which chansend() turns
back into a newline, so payloads round-trip exactly.
(cherry picked from commit e58f29ca3e)
Problem: "zb" scrolls incorrectly with cursor just above fold.
Solution: Handle boff.lnum being set to the last line of a fold
(zeertzjq).
With the cursor just above fold, botline_forw() moves boff.lnum to the
last line of the fold, but curwin->w_botline is at the first line of the
fold, so the boff.lnum == curwin->w_botline condition never holds.
Instead, check that boff.lnum has just moved to or past w_botline by
comparing its previous value with w_botline.
Also make a similar change to the loff.lnum check above for symmetry.
That one doesn't change behavior, as topline_back() sets loff.lnum to
the first line of a fold.
related: neovim/neovim#41122
closes: vim/vim#20923aee686334c
(cherry picked from commit 21a0227d2f)
Problem:
'breakindent' and 'showbreak' draw their own padding with no
reference to whatever decoration or syntax highlight is currently
active, so it goes unhighlighted even mid-highlight, not just past a
real EOL. Gating this on the decoration's `hl_eol` flag (as an
earlier version of this fix did) missed plain highlights with no
`hl_eol` at all, which have the exact same problem.
Solution:
Snapshot decor_attr into decor_attr_save right before it can be
reset by 'linebreak' filler handling, and pass it into
handle_breakindent()/handle_showbreak_and_filler() to extend into
their padding: it is not a real end of the highlight, just screen
cells with no buffer text. Like the 'linebreak' filler, an
underline/strikethrough/overline is excluded, since it looks like a
broken line drawn over the gap. This also fixes 'breakindent' losing
the highlight right after a real 'linebreak' word-push, since that
reset otherwise leaked into the next row.
(cherry picked from commit 866d61e91a)
Problem:
When 'linebreak' pushes a word entirely to the next screen row, the
filler cells left on the current row keep whatever highlight was set
by the last real character before the break, even when that highlight
should not extend past it (e.g. an underline, which looks broken drawn
over blank cells).
Solution:
Reset decor_attr and area_attr at the filler when their attribute has
an underline, undercurl, strikethrough, or overline; otherwise leave
them, since a plain background or reverse-video highlight looks
correct extending through blank filler cells, regardless of where the
pushed-down word happens to end. search_attr keeps the same check,
plus its pre-existing on_last_col case (its own match ending exactly
here).
(cherry picked from commit 9ff302d0ca)
Problem:
Calling vim.treesitter.start() a second time on a buffer that already
has an active TSHighlighter creates a brand new instance instead of
reusing it, whether the parser tree is unchanged (e.g. calling start()
twice) or different (e.g. switching languages). Either way the old
instance is silently discarded without calling :destroy() on it, so
its on_bytes/on_changedtree/on_detach callbacks stay registered and
its buffer-local state (spelloptions, decoration namespace) is never
restored, both leaking indefinitely for an orphaned instance that
nothing references anymore.
Solution:
Return the existing instance when TSHighlighter.active[source] is
already set for the same parser tree, instead of unconditionally
constructing a new one. When the tree differs instead (e.g. a language
switch), destroy() the old instance first, matching stop() semantics,
before constructing the new one.
(cherry picked from commit 67839a72f7)
Problem: :bwipe crashes if WinLeave wipes all other buffers
(after 9.1.2068).
Solution: Check for NULL pointer.
related: neovim/neovim#41066closes: vim/vim#208883e4019a082
(cherry picked from commit f8872bccbe)
Problem: On MS-Windows it is not possible to switch to a buffer by name
with ":b" (including via command-line completion) when the
buffer name contains '%'.
Solution: Do not escape '%' and '#' for the ":buffer" command on
MS-Windows. Since ":buffer" has no EX_XFILE these are not
expanded, and escaping them as "\%"/"\#" makes buffer name
matching fail when '%'/'#' is in 'isfname' (the backslash is
treated as a path separator).
fixes: vim/vim#20529closes: vim/vim#205481a96e07bf6
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(cherry picked from commit 1cfbf104f5)
Problem:
Cmdline area shows stale ":" after backspacing out of the command line.
Solution:
Clear the command line for empty commands. Note that `:<CR>` will now
clear the command line too.
(cherry picked from commit 1dbc766fa7)
Problem:
Cursor-relative floats can use stale screen coordinates after a cursor move is restored without a redraw.
Solution:
Validate the current cursor before converting cursor-relative coordinates.
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
(cherry picked from commit 089c415cb2)
Problem: Installing plugins during lockfile synchronization always
writes the lockfile, even though its content is used during install.
This might be a problem if the lockfile (itself or its parent
directory) is not writeable (can only be read).
Solution: Do not write the lockfile when installing directly from it.
This is okay since the `src` and `rev` are used directly from the
lockfile and don't change at this step. While potential change in
`version` (that must be written to the lockfile) is handled in other
code path.
(cherry picked from commit 4bba83b4b7)
Problem:
Tree-sitter uses UINT32_MAX for full-document ranges, which becomes -1 on 32-bit platforms and reaches _foldupdate as an invalid end row.
Solution:
Treat negative changed-range end rows as unbounded and clamp them to the buffer line count. Add a regression test that simulates the 32-bit sentinel.
AI-assisted: Codex
(cherry picked from commit 20ff82d9fc)
Problem:
urxvt doesn't support resetting to default cursor style like we assumed.
https://github.com/neovim/neovim/issues/38987#issuecomment-5004636437
Solution:
Instead of the reset sequence, always set it to steady block. This will
still be wrong for users who configured their initial cursor to
underline, but it's about the best we can do.
(cherry picked from commit 28818702e9)
Problem:
The code block query relied on a bug fixed in commit
7ed5609439, where a trailing newline was
not included in a node's text.
Solution:
Fix the query to expect the newline.
(cherry picked from commit fdc09be03c)
build: support variant builds via env-var and cpack overrides
Problem: scripts/genappimage.sh runs `make` with no extra flags and
emits a fixed nvim-linux-<arch>.appimage filename, so packaging a
variant build (e.g. with the bundled PUC-Rio Lua interpreter)
requires editing the Makefile or post-renaming the AppImage, which
breaks the AppImage zsync URL.
Solution: forward DEPS_CMAKE_FLAGS and CMAKE_EXTRA_FLAGS to `make`,
accept OUTPUT so the AppImage (and its zsync Filename:) follows the
caller's chosen name, and mark CPACK_PACKAGE_FILE_NAME as CACHE
STRING on Linux so the resulting tarball/deb follow as well. Default
behavior is unchanged when none of these env vars are set.
Problem: do_sub() only checks the timeout limit after finishing a line.
A pathological regex will run on a single line input unbounded
until the compute is completed.
Solution: Pass the timeout limit to `vim_regexec_multi()` so the
computation on the regex engine is bounded per-line.
Signed-off-by: XiaowenHu96 <me@xiaowenhu.com>
(cherry picked from commit bd73d8c011)
Problem:
on_attach() calls refresh(), but there is no guarantee the attached
buffer is the current buffer. This can make linked editing request
handling assume the wrong window.
Solution:
Call refresh() only if the current buffer is attached. This keeps the
initial highlighting behavior while avoiding making incorrect request.
(cherry picked from commit 9180c6e093)
Problem:
LSP hover erroneously drops blank lines before a 4-space-indented
codeblock, which is not valid Markdown. This causes incorrect parsing
and wrong display.
Solution:
Fix `split_lines` so that it doesn't drop the blank line just before
a 4-space-indented codeblock.
fix https://github.com/neovim/neovim/issues/40860
(cherry picked from commit 317c5ddda6)
fix(path): avoid shell fallback for unknown users
Problem:
Expanding an unknown ~user path falls back to the shell. In a fast event,
this re-enters the event loop and aborts Nvim.
Solution:
Leave unknown users unexpanded when the system account lookup fails.
(cherry picked from commit 9d3edf345f)
Co-authored-by: MAAZIZ Adel Ayoub <adelayoub.maaziz@gmail.com>
test: unreliable "put command . register special … ring the bell"
Problem:
FAILED …/put_spec.lua:894: …/put_spec.lua @ 898: put command . register special tests should ring the bell when deleting if not appropriate
…/put_spec.lua:894: …/put_spec.lua:898: Bell was not rung after action
Snapshot:
screen:expect([[
^ine of words 1 |
Line of words 2 |
{1:~ }|*4
{3:[No Name] [+] }|
|
{1:~ }|*4
{UNKNOWN_HL_ID(4):[No Name] }|
{UNKNOWN_HL_ID(1): }|
]])
stack traceback:
…/ui/screen.lua:917: in function '_wait'
…/ui/screen.lua:540: in function 'expect'
…/editor/put_spec.lua:894: in function 'bell_test'
…/editor/put_spec.lua:940: in function <…/editor/put_spec.lua:932>
Analysis:
The bell was asserted via the UI 'bell' event (screen.bell), but
vim_beep() rate-limits that to 3 per 500ms. These tests share one
long-lived session, so beeps from earlier tests could exhaust the window
and drop the asserted beep.
Solution:
Use assert_beeps()/assert_nobeep(), which check called_vim_beep (set
before the rate-limit gate).
Problem: #40731 may still crash if close_buffer autocmds reinsert the float's
grid. Plus removing the grid (and posting win_close) is unneeded if
win_close_othertab refuses to close the window later, which is possible.
Solution: do the stuff before freeing the window, like win_close.
(cherry picked from commit 1741da8412)
Problem: Closing a floating window from a non-current tab frees its grid
without removing it from the compositor's `layers` table, so the next
`ui_comp_put_grid()` walks a dangling pointer (UAF).
Solution: Call `ui_comp_remove_grid()` (and `ui_call_win_close()` for
multigrid UIs) before `win_free_mem()`, matching `win_close()` since
PR #21551.
(cherry picked from commit 6f370f34f2)
Problem
The current list of properties for inlay hint resolve support includes a
non-existent "location". This field should be "label.location" according
to the specification. Tooltips and commands for inlay hint "parts"
aren't advertised as being resolvable.
Solution
Remove "location" and add "label.location", "label.tooltip", and
"label.command".
Closes#40740
(cherry picked from commit 4bc30d6e10)
All wasm parsers shared a single global TSWasmStore via
ts_parser_set_wasm_store(). A TSWasmStore is owned by exactly one parser:
ts_parser_delete() frees it through ts_wasm_store_delete(). So the first
wasm parser collected freed the shared store, leaving the global pointer
dangling, and creating the next wasm parser dereferenced freed memory in
ts_wasm_store_reset() -> wasmtime_store_context(), crashing with SIGSEGV.
Give each parser its own store via ts_wasm_store_new() instead. This is
the 1:1 store-per-parser model intended by tree-sitter (see
tree-sitter/tree-sitter#3454): the global store remains only as the
language loader, ts_parser_delete() cleanly frees each parser's own
store, and the wasm engine is shared safely because ts_wasm_store_new()
clones its engine reference internally.
AI-assisted: Claude Code
Problem:
A `--listen` path longer than the system socket path limit (~104 bytes on
macOS, 108 on Linux) is silently truncated by `uv_pipe_bind()`. Nvim either
serves a socket at a different path than `v:servername` reports, or fails with
an error that blames the full untruncated path (confusing):
nvim: Failed to --listen: address already in use: "<full path>"
Steps to reproduce:
$ nvim --listen /var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/-Users-rpatterson-Projects-src-github.com-neovide-neovide --embed -p
nvim: Failed to --listen: address already in use: "/var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/-Users-rpatterson-Projects-src-github.com-neovide-neovide"
$ ls /var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/-Users-rpatterson-Projects-src-github.com-neovide-neovide
"/var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/-Users-rpatterson-Projects-src-github.com-neovide-neovide": No such file or directory (os error 2)
$ ls -l /var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/
srwxr-xr-x@ - rpatterson 31 Mar 10:24 -Users-rpatterson-Projects-src-github.com-neovid
Solution:
Bind with `uv_pipe_bind2()` and `UV_PIPE_NO_TRUNCATE` (libuv 1.46+), so
a too-long path fails up front with the actual reason:
nvim: Failed to --listen: invalid argument: "<full path>"
(cherry picked from commit de141b4679)
Problem:
Clearing a register via `:let @a = ""` doesn't persist in shada.
Solution:
Follows the precedent of ee56daebb6 .
Namely, when the live register is empty and *at least as recent* as the copy
that is on disk, drop it instead of writing it back.
(cherry picked from commit aff618536b)
Co-authored-by: Barrett Ruth <62671086+barrettruth@users.noreply.github.com>
Problem:
`:let @/ = ""` doesn't stick after restart (the old search pattern comes back).
Solution:
When the current session cleared the pattern more-recently than stored
shada entry, drop the shada entry instead of restoring it.
Note: similar timestamp-based suppression was used for deleted
marks: ee56daebb6
(cherry picked from commit af9f24b80b)
Problem: :Man unloads hidden buffers, so reopening large pages reruns rendering
even when the width is unchanged.
Solution: keep regular man buffers loaded and refresh them only when the
effective width changes.
(cherry picked from commit a6827be98f)
Problem:
Session files specified at startup `-S [file]`, logically conflict
with `:restart`.
Solution:
Remove `-S [file]` from `v:argv` when doing :restart.
Also for the "bang" variant `:restart!`, just because it's
simpler (if anyone reports a use-case later, we can revisit).
(cherry picked from commit 47958bb4db)
Problem:
`:restart` does not preserve window layout, etc.
Solution:
- Change `:restart` to save/restore a session automatically.
- Introduce "bang" variant `:restart!` to restart *without* session
save/restore.
- Introduce `v:startreason`.
- `ZR` maps to `:restart!`.
(cherry picked from commit 845b66dd4a)
Problem:
- Transient mutation of the parent env is visible to any concurrent
code. Or at least just kinda sloppy.
- Latent bug:`channel_job_start` queues the spawn and returns before
`uv_spawn` runs, so the prior `os_unsetenv` immediately after the call
could in principle race with the deferred spawn.
Solution:
Pass `env` to the channel.
(cherry picked from commit a1da5d1f14)
Problem:
It's clumsy for scripts to handle a "restart", without custom mappings or
global vars.
Solution:
Introduce `v:startreason`
(cherry picked from commit ae426ee465)
The added test shows the context, one expected a JSON field
to be a Object but it was a null value
pros: shows `vim.NIL` instead of `a userdata`
cons: the context `field 'foo'` is lost. I think this is generated
with internal magic which is hard to replicate.
(cherry picked from commit 71b28da0f4)