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)
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)
fix(lsp): use LspNotify for document_color #40571
Problem: The document_color lsp module was already using the capability
framework but was still using raw buffer events to handle requests and
reloading. This means that every keystroke was sending a document_color
request to the server since there was no debounce in the raw handlers.
Solution: Switch to using LspNotify autocmd events. LspNotify fires just
after new document versions are synced with the server and provides a
built in debounce mechanism for changes. It also provides the signal for
when the current state should be cleared (didClose). The detach part is
already handled by the capability framework.
Fixes#39785
(cherry picked from commit 29db6ce84c)
Problem: A previous refactor removed the BufWinEnter autocmd that
initiated a token request. When an LSP server sends a refresh
notification, then buffers that aren't shown in any window lost their
only trigger to request new tokens.
Solution: Add the BufWinEnter autocmd back which simply requests tokens
for all clients attached to the buffer.
Some servers register `workspace/didChangeWatchedFiles` watchers for URI
schemes that cannot be watched locally. Skipping the unsupported glob
and keep the rest of the registration batch active.
(cherry picked from commit 4d9e5acfb5)
Problem: LspNotify autocmds were not being triggered for didChange
requests when being used during undo/redo (and possibly other) actions.
autocmds are blocked when calling on_lines() callbacks while doing the
undo/redo action.
Solution: Defer firing the autocmd until after the action is complete.
This is closer to what existed before, but now there's a check in the
deferred function to only fire the autocmd if the client is still
active and the buffer is still attached, if applicable.
(cherry picked from commit 3c924d13fe)
Problem: LspNotify never passed a buffer when executing the autocmds, so
buffer-local LspNotify autocmd subscriptions didn't have the correct buf
in the event metadata. It was also wrapped in a schedule() so the actual
autocmd was delayed until after the event loop.
This could result in the wrong buffer receiving the notification if
multiple LspNotify autocmds with buffer filters were added. Only the
"latest" one would actually receive non-buffer-filtered autocmds, not
the matching one. It also caused listeners to receive the notification
"out of sync" with when the notification is actually sent. If a buffer
is being deleted (which fires a textDocument/didClose notification), the
notification is scheduled and fired after the buffer is already gone.
Solution: For LSP notifications that pertain to a particular buffer, set
it when executing the LspNotify autocmds so the callback functions that
are filtered on that buffer will get the correct notifications and the
metadata buf field will be correct. Additionally, there is no need to
wrap the LspNotify callback in vim.schedule when it can be called inline
when the notification to the rpc server is fired.
This is tested by removing now-unnecessary autocmds from semantic tokens
(InsertEnter and BufWinEnter should no longer be necessary now that
requests are fired by LspNotify). Without this fix, simply modifying a
buffer doesn't actually trigger LspNotify correctly, and the test for
that fails.
(cherry picked from commit 54188fa242)
Co-authored-by: jdrouhard <john@drouhard.dev>
Problem: When multiline semantic token support was introduced, the loop
that finds the end line for a particular token didn't sanitize the token
length sent back by the LSP server. If the server returned an overflowed
length (near uint32 max), neovim would burn cpu and loop for an
extremely long time while trying to find the "end line" represented by
the massively large token, causing neovim to seemingly hang.
Solution: Stop looping once the calculated end_line reaches the actual
last line of the buffer.
Fixes#36257
(cherry picked from commit 6bc6461eac)
Co-authored-by: jdrouhard <john@drouhard.dev>
Today there is a constraint that these arguments to the enable filter be
mutually exclusive, but I do not know why such a constraint exists (it
is perfectly reasonable to want to enable a capabilility for just one
buffer and just one client).
(cherry picked from commit ed267268b8)
Problem: The refactor to use Capability left around some cruft and
semi-broken configuration for debounce.
Solution: Clean up now-unnecessary helper methods and simplify
deprecated ones to pass through to the non-deprecated ones. `debounce`
now defaults to 200 for all buffers but is overridable via the
deprecated start() method, which continues to take the max value
specified for any client attached to the buffer.
If we wish to expose changing the debounce in a non-deprecated way, we
will need to consider a "configuration" function, or even a bespoke
method to set the debounce time on the main metaclass (or provide
options to override for a particular buffer). General configuration of
specific LSP features is an as-of-yet unsolved problem.
(cherry picked from commit 859790e244)
feat(lsp): use LspNotify for semantic tokens
Problem: The semantic token module is using its own debounce timer for
the buffer on_lines event. If its internal debounce is shorter than the
changetracking module's debounce, it's possible for semantic token
requests to fire for changed buffers before the textDocument/didChange
notification is sent to the server.
Solution: Trigger semantic token requests from the LspNotify autocmd
when the method is the didChange or didOpen notifications, which
enforces a strict happens-before relationship for the sync change
notification followed by a semantic token request.
Note: There is still an internal debounce mechanism in the semantic
token module to handle other debouncing needs specific to its
functionality, such as debouncing server refresh notifications and
handling WinScrolled events when using range requests.
Co-authored-by: jdrouhard <john@drouhard.dev>
Problem:
A text edit positioned entirely past the last buffer line, with
newText ending in a newline, leaves a stray blank line: the
past-the-end path appends the trailing empty fragment produced by
vim.split() and does not set has_eol_text_edit, so the end-of-buffer
cleanup is skipped. Formatting servers emit such edits whenever
formatting moves text to the end of a document.
Regression from ec94014cd1 (#20137), which split the past-the-end
fast path off the clamp path that sets the flag.
Solution:
Set has_eol_text_edit in the past-the-end path, like the adjacent
path that clamps end_row.
(cherry picked from commit d42f7ee9dc)
Co-authored-by: Aaron Tinio <aptinio@gmail.com>
Problem:
When a server sends workspace/codeLens/refresh while an automatic codelens
request is already scheduled, Nvim ignores the server refresh. This can leave
rendered codelens text stale until another buffer edit triggers a new request.
Solution:
Cancel the pending automatic request and send the server-requested refresh
immediately. This preserves request coalescing while giving explicit server
refreshes priority.
Co-authored-by: Tristan Knight <admin@snappeh.com>
Problem:
Flickering may occur when paging up/down in big files, as ranges for semantic
tokens are requested. This happens with LSP servers like gopls which return
"/full" semantic tokens if the file is too big, where we fall back to
viewport-range token retrievals.
Solution:
Broaden the requested ranges to one viewport of "overscan" on each side plus
some padding if possible:
(viewport_topline - viewport_height)..(viewport_botline + viewport_height)
(cherry picked from commit 3ed78daf83)
feat(ui): vim.ui.input(opts.scope) #39570
Problem: There is no way for a `vim.ui.input` caller to indicate for
which scope the input is. As in "This input is for something at cursor
scope". This information can be useful for `vim.ui.input`
implementation to tweak its behavior and presentation:
- Show different floating window depending on the scope. For example:
- Near cursor for "cursor" scope.
- At line start for "line" scope.
- In window corner for "buffer" and "window" scopes.
- In whole editor corner for "tabpage", "editor", "project" scopes.
- Navigate through history only for inputs with the same scope.
Solution: Document new `opts.scope` for `vim.ui.input`. Use it in the
codebase.
Problem:
Linter missed backtick and double-quote keynames in the quasi-keyset of
the `nvim_create_user_command` docstring.
Solution:
Update the linter to check backtick-surrounded and quote-surrounded key
names.
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)
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.
(cherry picked from commit 578727c25e)
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)
Problem:
Since `foldclose` is async, it must wait for the request to return before actually executing, at which point the original window may no longer be valid.
Solution:
Check whether the window is valid before actually performing `foldclose`.
(cherry picked from commit 775c7d1b53)
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.
(cherry picked from commit f83d0b9653)
Problem:
Use vim.lsp.util.apply_text_edits to re-apply the same textedit causes
an incorrect edit, because apply_text_edits silently modifies the
parameter.
Solution:
- Avoid changing `text_edit._index`.
- Document this fun feature.
Helped-by: Riley Bruins <ribru17@hotmail.com>
Helped-by: Yi Ming <ofseed@foxmail.com>
(cherry picked from commit 790a8be5f3)
Co-authored-by: geril07 <62308020+geril07@users.noreply.github.com>
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
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.
(cherry picked from commit ecb8402197)
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)
(cherry picked from commit 7e006b06c4)
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:
After on_refresh() sends a textDocument/codeLens request, the buffer may
be deleted before the response arrives. The response callback then tries
to redraw that deleted buffer and raises Invalid buffer id error.
Solution:
Check buffer validity before redrawing.
AI-assisted: Codex
Co-authored-by: Yi Ming <ofseed@foxmail.com>
(cherry picked from commit 97caa88972)
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.
(cherry picked from commit b351afb1b1)
test: lint naming conventions
Problem:
Naming conventions are not automatically checked.
Solution:
Add a check to the doc generator. Eventually we should extract this
somehow, but that will require refactoring the doc generator...
Note: this also checks non-public functions, basically anything that
passes through `gen_eval_files.lua` and `gen_vimdoc.lua`. And that's
a good thing.
Problem
Some variables use the wrong type (ClientToServer instead of ServerToClient)
and some use vaguer types that could be more strict.
Solution
Use the correct types.
(cherry picked from commit 530cfa1323)
continues d0af4cd909.
This commit renames positional parameters. This is only "cosmetic", but
is intended to make it extra clear which name is preferred, since people
often copy existing code despite the guidelines in `:help dev-naming`.
(cherry picked from commit 71ac4db335)
Problem: vim.lsp.util.show_document insert mode is unable
to set the cursor after the target character position if the target character
is at end of line.
Solution: Move cursor after the target character (in append position)
in this case.
(cherry picked from commit 891bb0e6ce)
Problem: _get_and_set_name edits the name for the whole group,
thus only one client per group gets the didOpen message.
Solution: move the logic to _changetracking and loop over every
client per group.
(cherry picked from commit 37eb1b9979)
Problem: hover/signature callback lacked consistency checks, so slow LSP servers
could open a float after the cursor had already moved away.
Solution: guard the callback with buf validity, buf version, and cursor
position checks before opening the float. Also fix table capacity calculation.
(cherry picked from commit af9a72d8c1)
feat(api): rename buffer to buf
Problem:
`:help dev-name-common` states that "buf" should be used instead of
"buffer" but there are cases where buffer is mentioned in the lua API.
Solution:
- Rename occurrences of "buffer" to "buf" for consistency with the
documentation.
- Support (but deprecate) "buffer" for backwards compatibility.
Co-authored-by: Jordan <46637683+JordanllHarper@users.noreply.github.com>
Problem:
Since 2f6d1d3c88, `apply_text_edits`
unconditionally sets `buflisted=true`, causing spurious BufDelete events
if plugins restore the original 'buflisted' state on unlisted buffers:
65ef6cec1c/src/nvim/option.c (L2159-L2169)
Solution:
- Don't set 'buflisted' in `apply_text_edits`. Set it more narrowly, in
`apply_workspace_edit` where the semantics requires affected buffers
to be visible to the user.
- Also skip setting 'buflisted' if it would not be changed, to avoid
redundant `OptionSet` events.
(cherry picked from commit 6473d007e7)
fix(health): misleading warnings re filetypes registered w/ vim.filetype.add() #38867
Problem:
`:checkhealth vim.lsp` validates configured filetypes against
`getcompletion('', 'filetype')`. This only reflects runtime support
files.
This causes false warnings in `:checkhealth vim.lsp` for configured
filetypes that are known to the Lua filetype registry, including
values added with `vim.filetype.add()` and built-in registry-only
filetypes.
Solution:
Build the healthcheck's known-filetype set from both
`getcompletion('', 'filetype')` and `vim.filetype.inspect()`.
(cherry picked from commit 20a3254ad4)
Co-authored-by: Barrett Ruth <62671086+barrettruth@users.noreply.github.com>
Problem:
The current LSP diagnostic implementation can't differ between a pull
diagnostic with no identifier and a set of diagnostics provided via push
diagnostics.
"Anonymous pull providers" are expected by the protocol https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnosticOptions
, depending on how the capability was registered:
- Dynamic registrations have an identifier.
- Static registrations will not.
Solution:
Restore the `is_pull` argument removed in
https://github.com/neovim/neovim/pull/37938, keeping the identifier of
pull diagnostic collections.
(cherry picked from commit 665ebce569)