Problem:
The LSP client incorrectly checks for server capabilities when determining
support for self-mapped methods (e.g., 'shutdown'), which do not have
corresponding capabilities in the server's response. This leads to false
negatives when checking if such methods are supported.
This was handled correctly for dynamic registrations, but not for static.
Methods such as 'shutdown', do not have a related server capability and should
be assumed to be supported.
Solution:
Update the `supports_method` logic to always return true for self-mapped
methods.
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.
Problem:
Invalid `nvim_create_user_command` calls can leak the
`preview` callback reference after Neovim has taken ownership of it.
1. build with {a,l}san
2. run:
```sh
<path/to/nvim> --headless -u NONE --clean +'lua
for i = 1, 100 do
pcall(vim.api.nvim_create_user_command,
"some very epic stuff" .. i,
{}, -- NOTE: this is INVALID (not a function or string)
{ preview = function() end })
end
vim.cmd("qa!")
' +qa
```
3. see:
```
100 lua references were leaked!
```
Solution:
Clear `preview_luaref` in `err:`.
Problem: `nvim_set_keymap` leaks the `callback` `LuaRef` when the
LHS is too long.
Solution: Make `set_maparg_lhs_rhs` transfer `rhs_lua` to
`MapArguments` up front so the caller always owns the ref.
Problem:
On Windows, path separators may become inconsistent for various reasons,
which makes normalization quite painful.
Solution:
Normalize paths to `/` at the entry boundaries and always use it
internally, converting back only in rare cases where `\` is really
needed (e.g. cmd.exe/bat scripts?).
This is the first commit in a series of incremental steps.
Note:
* some funcs won't respect shellslash. e.g. `expand/fnamemodify`
* some funcs still respect shellslash, but will be updated in a follow
PR. e.g. `ex_pwd/f_chdir/f_getcwd`
* uv's built-in funcs always return `\`. e.g. `uv.cwd/uv.exepath`
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
Problem:
We should not use "\" (backslashes) except where absolutely required.
See references in https://github.com/neovim/neovim/pull/37729
Solution:
There is no reason to use "\" slashes in the trust db, so don't.
Problem: `set all&` resets option values directly and leaves UI-derived state stale for `guicursor`, `laststatus`, and `showtabline`.
Solution: Repair some of the stale UI state in the bulk reset path by reparsing `guicursor`, refreshing statusline state, and recomputing tabline/window rows.
Problem:
LSP spec allows response message to have a null request-id.
This may happen when for example client sends unparseable request.
https://github.com/microsoft/language-server-protocol/issues/196
Solution:
Guard the server response branches against id=vim.NIL (json null),
and handle error responses with null id by logging a warning
and dispatching on error.
Problem:
CI (ubuntu asan, ubuntu tsan, windows) reports `uv_loop_close()
hang?` from the two new null-id response tests. The leaked
handle is the server-side accepted TCP socket created inside
`server:listen` callback. The tests closed only the listener
but not the accepted socket, so libuv could not finish shutting
down the loop and each test session took ~2s extra to exit.
Solution:
Hoist the accepted socket to the outer `exec_lua` scope and
close it at teardown before closing the listener. The close
runs synchronously inside `exec_lua`, so the loop has time to
dispose the handle before the session exits.
* test(lsp): close accepted socket on read-loop exit/error
Match the precedent in the handler test ("handler can return
false as response") and the shared `_create_tcp_server` helper
in `test/functional/plugin/lsp/testutil.lua`: close the
accepted socket from inside the `create_read_loop` exit/error
callbacks. The teardown close added in the previous commit
remains as belt-and-suspenders, so the socket is disposed
whether the server goes away first or the client does.
Problem:
`vim.secure.trust()` hashes an unchanged empty buffer as
a newline, so trusting an empty file by buffer never works.
Solution:
Hash unchanged empty-buffers `''` so buffer-based
trust matches the on-disk empty file.
Problem: Using `version=vim.version.range(...)` in plugin specification
is meant to use semver-like tags. Whether a tag is semver-like was
decided by a plain `vim.version.parse` which is not strict by default.
This allowed treating tags like `nvim-0.6` (which is usually reserved
for the latest revision compatible with Nvim<=0.6 version) like semver
tags and resulted in confusing behavior (preferring `nvim-0.6` tag
over `v0.2.2`, for example).
Solution: Use `vim.version.range(x, { strict = true })` to decide if the
tag name is semver-like or not. This allows tags like both `v1.2.3`
and `1.2.3` while being consistent in what Nvim thinks is a semver
string.
This is technically not a breaking change since it was documented that
only tags like `v<major>.<minor>.<patch>` will be recognized as
semver.
Both for tests and for system wide install, $PREFIX/lib/nvim/parser
is a valid path for tree-sitter parsers. This also brings the build.zig
behavior in line with how we set up the paths in CMakeLists.txt
Problem:
The fromRanges field of the result of callHierarchy/outgoingCalls is
documented as being relative to the caller. Using
vim.lsp.buf.outgoing_calls() opened the qflist with an entry with the
callee's filename, but the caller's line number.
Solution:
Open the qflist with the callers file (the bufnr from the request),
rather than the callees (the uri from the resulting CallHierarchyItem)
Problem:
Cursor-position `vim.lsp.buf.code_action()` requests include all diagnostics on the current line, so unrelated same-line diagnostics affect the returned actions.
Solution:
Filter same-line diagnostics to the cursor position for cursor-position requests.
Problem: Destroying a terminal with pending `TermRequest` events leaks
memory.
Solution: Make `emit_termrequest` the sole owner of its `pending_send`
allocation.
Problem:
Can't expand treesitter-incremental-selection to the next and previous
sibling nodes.
Solution:
Pressing `]N` in visual mode will expand the selection to the next
sibling node, and `[N` will do the same with the previous node.
Problem:
- The `ZR` feature makes it more obvious that we need some sort of flag so that
an `ExitPre` / `QuitPre` / `VimLeave` handler can handle restarts differently
than a normal exit. For example, it's common that users want `:mksession` on
restart, but perhaps not on a normal exit.
- Nvim has no way to report its "uptime".
Solution:
- Introduce `v:starttime`
- Introduce `v:exitreason`
Problem:
b98eefd added `!b_p_bl` to `ignore_buf()`, which also
skips bdelete'd buffers since bdelete unsets `b_p_bl`.
Solution:
Check `b_p_initialized` together with `b_p_bl` so that
bdelete'd buffers (which have b_p_initialized=false) are not
filtered out. Keep `b_p_bl` check only in `shada_get_buflist()`.
benchmark: https://gist.github.com/ofseed/6224529d77c016c36f7ab2f977059848
local rounds = tonumber(arg[1]) or 1000
local count = tonumber(arg[2]) or 1000
-- Load the table.clear function.
local clear = require("table.clear")
local function fill(t, n)
for i = 1, n do
t[i] = i
end
end
local function bench_reassign(n_rounds, n_items)
local t = {}
local start = os.clock()
for _ = 1, n_rounds do
t = {}
collectgarbage("collect")
fill(t, n_items)
end
return os.clock() - start
end
local function bench_reassign_no_gc(n_rounds, n_items)
local t = {}
local start = os.clock()
for _ = 1, n_rounds do
t = {}
fill(t, n_items)
end
return os.clock() - start
end
local function bench_clear(n_rounds, n_items)
local t = {}
local start = os.clock()
for _ = 1, n_rounds do
clear(t)
fill(t, n_items)
end
return os.clock() - start
end
-- Warm up LuaJIT before the real benchmark.
do
local t = {}
for _ = 1, 2000 do
clear(t)
fill(t, count)
end
end
collectgarbage("collect")
local reassign_time = bench_reassign(rounds, count)
collectgarbage("collect")
local reassign_no_gc_time = bench_reassign_no_gc(rounds, count)
collectgarbage("collect")
local clear_time = bench_clear(rounds, count)
print(string.format("rounds=%d count=%d", rounds, count))
print(string.format("t = {} + GC : %.6f s", reassign_time))
print(string.format("t = {} : %.6f s", reassign_no_gc_time))
print(string.format("table.clear : %.6f s", clear_time))
print(string.format("vs + GC : %.2fx", reassign_time / clear_time))
print(string.format("vs no GC : %.2fx", reassign_no_gc_time / clear_time))
benchmark result:
rounds=1000 count=1000
t = {} + GC : 0.022469 s
t = {} : 0.002570 s
table.clear : 0.000387 s
vs + GC : 58.06x
vs no GC : 6.64x
`count` is how many items the table has, and `round` is how many rounds we fill
the table, clear, and then refill it. `table = {}` is clear the table by
resigning a new empty one, because this script does not run persistently like
nvim so GC is not triggered, so I added another extreme control group that
manually triggers GC.
Problem: A vim.ui_attach() callback that redraws to show a 'verbose'
regex message during 'incsearch' results in recusive redrawing.
Solution: Check that curwin was redrawn instead of just any window when
determining if 'incsearch' highlighting was cleared.
Problem:
With GIT_DIR/GIT_WORK_TREE set, the LSP on the vim.pack.update()
confirmation buffer does not show the correct git log on hover.
Solution:
Temporarily remove the git vars from the environment.
Problem: `:write ++patate foo` doesn't error out, instead it turns on
mkdir_p and uses "atate foo" as the filename. Same with ++edit.
The parser just does strncmp without checking what comes after.
Solution: require the next char after the option name to not be a
letter
Problem: Cannot apply 'scrolloff' context lines at end of file
Solution: Add the 'scrolloffpad' option to keep 'scrolloff' context even
when at the end of the file (McAuley Penney).
closes: vim/vim#19040a414630393
Co-authored-by: McAuley Penney <jacobmpenney@gmail.com>
vim-patch:9.2.0374: c_CTRL-{G,T} does not handle offset
Problem: c_CTRL-{G,T} does not handle offset, when cycling between
matches
Solution: Refactor parsing logic into parse_search_pattern_offset() and
handle offsets, note: highlighting does not handle offsets
yet (Barrett Ruth).
fixes: vim/vim#19991closes: vim/vim#19998c62342e5cf
RUN T339 TUI :restart ZR: Uncaught Error: test/client/uv_stream.lua:111: ECONNRESET
stack traceback:
[C]: in function 'error'
test/client/uv_stream.lua:111: in function <test/client/uv_stream.lua:109>
[C]: in function 'run'
test/client/session.lua:240: in function '_run'
test/client/session.lua:216: in function '_blocking_request'
test/client/session.lua:117: in function 'request'
...t_xdg_terminal/test/functional/terminal/tui_spec.lua:223: in function <...t_xdg_terminal/test/functional/terminal/tui_spec.lua:215>
[C]: in function 'pcall'
test/testutil.lua:82: in function 'retry'
...t_xdg_terminal/test/functional/terminal/tui_spec.lua:215: in function 'assert_restarted'
...t_xdg_terminal/test/functional/terminal/tui_spec.lua:275: in function <...t_xdg_terminal/test/functional/terminal/tui_spec.lua:232>
[C]: in function 'xpcall'
/home/runner/work/neovim/neovim/test/harness.lua:693: in function 'run_callable'
/home/runner/work/neovim/neovim/test/harness.lua:1008: in function 'run_test'
/home/runner/work/neovim/neovim/test/harness.lua:1083: in function 'run_suite'
/home/runner/work/neovim/neovim/test/harness.lua:1081: in function 'run_suite'
/home/runner/work/neovim/neovim/test/harness.lua:1081: in function 'run_suite'
/home/runner/work/neovim/neovim/test/harness.lua:1507: in function 'run_test_file'
/home/runner/work/neovim/neovim/test/harness.lua:1577: in function 'run_iteration'
/home/runner/work/neovim/neovim/test/harness.lua:1665: in function 'main'
/home/runner/work/neovim/neovim/test/runner.lua:30: in main chunk
-- Tests exited non-zero: 255
CMake Error at /home/runner/work/neovim/neovim/cmake/RunTests.cmake:135 (message):
functional tests failed with error: 255
Problem: The "Scanning:" completion, bufwrite, and indent (there may be
more) messages which indicate progress can use the "progress" kind
for their msg_show event. Indent message does not have a kind.
Solution: Emit these messages with the "progress" kind. Set the message id
to the replaced kind so that a UI knows to replace it (and to provide
a migration path in case a UI was distinguishing these messages for
whatever reason).
Problem:
On Windows, :restart cannot immediately reuse the canonical --listen
address because named pipe release is asynchronous.
Solution:
Start the new Nvim server on a temporary address; in the new Nvim,
retry serverstart() with the original ("canonical") address until it
succeeds.
Problem: Invalid check for non-typed key to dismiss expanded cmdline.
Unable to delay the timer that removes a message from the msg
window.
Solution: Check for empty string instead of nil to determine whether a
key is typed.
Restart the timer if it expires while the user is in the msg
window. Allow entering the msg window with a mouse click.
Problem: After closing a tabpage while the msg window is showing a
message, it is hidden while the msg window still contains a
message.
Solution: Unhide the msg window after entering a tabpage and it still
contains a message.
Co-authored-by: Linykq <yukunlin590@gmail.com>
Problem: fg_indexed/bg_indexed were dropped from nvim_get_hl output due
to a wrong short_keys guard. HL_FG_INDEXED also wasn't cleared in
hl_blend_attrs, and HLATTRS_DICT_SIZE was too small.
Solution: Remove the short_keys guard, clear HL_FG_INDEXED in
hl_blend_attrs, bump HLATTRS_DICT_SIZE to 24, and clarify docs that
these flags mean rgb is an approximation of the cterm palette index.
vim-patch:9.2.0362: division by zero with smoothscroll and small windows
Problem: Resizing a smoothscrolled wrapped window to its textoff width
with 'showbreak' can leave wrapped continuation lines with
zero text width. win_lbr_chartabsize() still runs the partial max_head_vcol calculation in
that state and divides by width2, crashing during redraw.
Solution: Skip that partial head calculation when the wrapped
continuation width is zero, matching the other width2 guards
in charset.c (Jaehwang Jung)
closes: vim/vim#20012
AI-assisted: Codex
0e31fb024c
Problem:
- Unable to "pin" a window to prevent closing without specifically
being targeted.
- :fclose closes hidden windows (even before visible windows).
Solution:
- Add 'winpinned' window-local option. When set, window is skipped by
:fclose and :only. Pin the ui2 cmdline window (which should always be
visible), so that it is not closed by :only/fclose.
- Skip over hidden (and pinned) windows with :fclose.
Co-authored-by: glepnir <glephunter@gmail.com>
Although `nlua_call_excmd` is semantically for implementing Ex-commands,
the `require()` should never fail, so that's a "Lua error".
But if the call itself fails (the later `semsg` call), that's an "Ex
cmd" error.
Problem:
win_line() falls into infinite loop when a diff window has top filler
above its first visible buffer line, that first visible buffer line is a
closed fold, and the folded line uses normal non-empty foldtext.
Solution:
Allow flushing pending diff filler rows even when the underlying buffer
line is folded with foldtext.
AI-assisted: Codex
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Problem:
`api.nvim_buf_del_mark` already emits a `MarkSet` event with `col` and `line` set to 0. However, `:delmarks` currently emits no events.
Solution:
Change `:delmarks` to emit the same `col==line==0` event.
Problem: completionItem/resolve response's `detail` field is silently
dropped. Only `documentation` is shown in the popup.
Solution: Prepend `detail` as a fenced code block before `documentation`
in the info popup, skipping if documentation already contains it.