aboutsummaryrefslogtreecommitdiff
path: root/test/functional/plugin/lsp
Commit message (Collapse)AuthorAge
* fix(lsp): ignore completion items without LSP metadata #42401Volodymyr Chernetskyi4 days
| | | | | | | | | | | | Problem: Accepting an item from another completion source raises an error when its user_data.nvim table does not contain LSP metadata. Solution: Retrieve and guard the nested LSP metadata before accessing its fields. Cover acceptance of a foreign completion item without LSP metadata. AI-assisted
* fix(lsp): keep label fallback for empty snippet insertText #42402Volodymyr Chernetskyi4 days
| | | | | | | | | | | | Problem: An empty snippet insertText falls back to the label during selection, but acceptance clears that label and expands an empty string. Solution: Require nonempty insertText before expanding a snippet without textEdit. Extend the omnifunc acceptance fixture with an empty snippet insertion. AI-assisted
* fix(lsp): preserve explicit completion edit ranges #42399Volodymyr Chernetskyi4 days
| | | | | | | | | | | | Problem: A completion list default edit range can replace the explicit range of an InsertReplaceEdit, filtering out valid items or changing their replacement. Solution: Only synthesize a default text edit when the completion item has none. Extend the existing itemDefaults test for explicit edits with both range variants. AI-assisted
* fix(lsp): prefer textEdit for snippet completion text #42400Volodymyr Chernetskyi4 days
| | | | | | | | | | | | Problem: Snippet completion words and previews prefer insertText even when textEdit is present, although the actual expansion uses textEdit.newText. Solution: Use the text edit before the fallback insertion text in both selectors. Extend the existing precedence test to check the snippet word and preview. AI-assisted
* test: simplify functional test expectationsLewis Russell2026-10-05
| | | | | | | | | | | | Problem: Repeated default fields and field-by-field assertions obscure the values that each functional test is meant to check. Solution: Add eq_partial() to check selected record fields while preserving list length and order. Use local helpers to fill fixed expected defaults where tests need full equality. Keep explicit absence checks and test-specific values at the call sites. AI-assisted
* feat(lsp): support client_id in vim.lsp.completion.get() #42189glepnir2026-10-03
| | | | | | | | | Problem: vim.lsp.completion.get() always asks every client that has completion enabled in the buffer, so a mapping cannot ask just some of them. Solution: Add a "client_id" option that limits the request to the given client, or clients if it is a list.
* Merge pull request #42134 from lewis6991/emmyluaLewis Russell2026-09-30
|\ | | | | fix(lua): enable param-type-mismatch diagnostic
| * fix(lua): enable param-type-mismatch diagnosticLewis Russell2026-09-28
| | | | | | | | | | | | | | | | | | Problem: Argument type mismatches are excluded from EmmyLua checks. Solution: Correct runtime annotations and calls, document local checker workarounds, and enable the diagnostic. AI-assisted
* | fix(lsp): preserve completion state on buffer reload #42135Barrett Ruth2026-09-29
|/ | | | | | | | | | | Problem: After an LSP client restart, the completion reload callback can use an old client ID: autoread: :checktime failed for buffer 17: Vim:Lua callback: ...ed-95df8c0/share/nvim/runtime/lua/vim/lsp/completion.lua:1315: invalid client ID Solution: Use the completion augroup for `BufUnload` cleanup.
* vim-patch:9.2.1114: Visual selection is not highlighted at the cursor ↵Takumi Katase2026-09-27
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | position #42105 vim-patch:9.2.1114: Visual selection is not highlighted at the cursor position Problem: In a terminal the character under the cursor is normally not shown as part of the visual selection. Solution: Don't set "noinvcur" in win_line() (Shane Harper). The problem did not occur in the GUI, only in a terminal. The name "noinvcur" ("don't invert the cursor") was misleading: the variable did not affect the cursor, but whether the character under the cursor could be displayed as part of the visual selection. The "noinvcur" handling may have been meant to help during a visual selection when Visual is shown in reverse video and the terminal draws the cursor by inverting the character under it, as otherwise the character under the cursor would not look highlighted like the rest of the selection. But Vim cannot know in general how a terminal draws the cursor, and when either the cursor is not drawn by inverting the character under it or Visual is not shown in reverse video, the handling just left a character of the visual selection unhighlighted. closes: vim/vim#21317 https://github.com/vim/vim/commit/d10aab4ba6602f8f2f2576d2d62ceb63869db6fb Co-authored-by: Shane Harper <shane@shaneharper.net> AI-assisted
* fix(lsp): silently ignore unknown folding range kinds (#41964)Maria Solano2026-09-18
|
* fix(lsp): snippet is not expanded when resolve races the user #41774glepnir2026-09-11
| | | | | | | | | | | Problem: on_complete_done() defers clear_word() and the snippet expansion until completionItem/resolve answers, and drops both when 'changedtick' moved meanwhile. Typing right after accepting leaves the plain word in the buffer. Solution: Expand before requesting, and anchor the resolved edits with an extmark instead of gating them on 'changedtick'.
* feat(lsp): support timeout_ms for async formatting #41850Barrett Ruth2026-09-11
| | | | | | | | | Problem: `vim.lsp.buf.format()` does not support a timeout for asynchronous requests. Solution: Honor an explicit timeouts per client so formatting can continue. Do not permit a default value for async format requests.
* feat(lsp): support `workspace/foldingRange/refresh` #41780Volodymyr Chernetskyi2026-09-09
| | | | | | | | | | | Problem: Servers cannot request refreshing stale LSP folding ranges after a project-wide change. Solution: Advertise `workspace.foldingRange.refreshSupport` and re-request folding ranges for active buffers when handling `workspace/foldingRange/refresh`. AI-assisted
* fix(lsp): newlines in the completion word from insertText #41801glepnir2026-09-09
| | | | | | | | Problem: A textEdit is cut to its first line but an insertText is not, so its newlines reach the |complete-items| word. Solution: Cut it the same way.
* fix(lsp): completion dynamicRegistration breaks capability readers #41771glepnir2026-09-08
| | | | | | | | | | Problem: A server that supports dynamic registration must not also declare completionProvider at initialize, so server_capabilities.completionProvider is nil for anything reading it directly. Solution: Do not advertise it by default. A client that follows a registration can declare it itself.
* fix(lsp): semantic tokens ignore 'fileformat' when sizing line endings #41733Volodymyr Chernetskyi2026-09-07
| | | | | | | | | | | | | | | | | | | | Problem: The eol_offset used to decode multiline semantic tokens is computed as vim.bo.fileformat[bufnr] == 'dos' and 2 or 1 which indexes the option value rather than the buffer, so it is never "dos" and the offset is always 1. A token that crosses a line boundary in a 'fileformat' of "dos" is then decoded one code unit short per line ending, and the highlight extends past the end of the token. Solution: Read the option with the buffer-scoped form, vim.bo[bufnr].fileformat. The existing multiline test covers both formats now. Its token length of 82 counts the line endings it spans, so the same token reaches four characters less far once the buffer is "dos". AI-assisted
* build: replace LuaLS with EmmyLuaLewis Russell2026-09-07
| | | | | | | | | | | | | | | Problem: LuaLS struggles with the generics used in Nvim's runtime, requiring broad diagnostic suppressions. Indexing is also slow. Solution: Use EmmyLua for type checks in the build and CI. It offers more sophisticated type checking, substantially better support for generics, and much better flow analysis. Correct the affected annotations. Use `@internal`, supported directly by EmmyLua, instead of `@nodoc` for shared internal declarations, and support it in the help parser. AI-assisted
* feat(lsp): support dynamic registration of completionProvider #41748glepnir2026-09-07
| | | | | | | | Problem: dynamicRegistration is declared false, and completionProvider is read from server_capabilities only. Solution: Declare it, and prefer registerOptions per field.
* fix(lsp): separate adjacent nested folding ranges #41428wrvsrx2026-08-31
| | | | | | | | | Problem: Folding range markers are overwritten while ranges are evaluated. A range ending on a row can hide another range starting there, and multiple nested ranges ending together emit only the innermost ending level. Solution: Track starts and the number of ends per row before emitting markers. Prefer starts on shared boundary rows and use the outermost level when nested ranges end together. AI-assisted
* test: fix wrong order of args to eq(), neq() #41499zeertzjq2026-08-26
|
* fix(lsp): advance inline completion range over matching input #41434Étienne Robert2026-08-24
| | | | | | | | | | | | | | | Problem: `Completor:accept()` applies the item against the range the server answered with. Characters typed after the request but before accepting lie inside neither that range nor the replacement, so they are left behind by the insertion: typing `a` after `foob` and accepting `foobar` within the 200 ms debounce yields `foobara`. Solution: Grow the item's range over the characters typed since the request, so that `accept()` replaces them. Only while the candidate still matches, decided by the longest common prefix `show()` already computes, so input that contradicts it is left alone. Snippet items are unaffected, since `accept()` ignores the range for them.
* fix(lsp): clamp inline completion range to the line on accept #41435Étienne Robert2026-08-24
| | | | | | | | | | | | | | | | | | Problem: `Completor:accept()` hands the item's range straight to `nvim_buf_set_text()`. That range is resolved when the response arrives, so text deleted before accepting (backspacing within the 200 ms debounce) leaves the range end past what is left of the line, and the accept aborts with `Invalid 'end_col': out of range`. 18d6436 fixed the same staleness in `Completor:show()`, which drops an item once its range *start* falls outside the buffer. That guard does not cover the range end, and `accept()` was never given one, so this is a hole left by that fix rather than a regression of it. Solution: Clamp the end of the range to the end of the line before writing. The start needs no clamp: `show()` dropped the item one event loop tick earlier if it had gone out of range.
* fix(lsp): completion overwrites text before the word boundary #41463glepnir2026-08-24
| | | | | | | | | Problem: One item with an edit range before the word boundary changes the start column for all items. For tsserver `str.`, completing `str.char` can become `strcharAt` and break filtering. Solution: Prepend the missing text and filter on it.
* fix(lsp): empty filterText/sortText/insertText not treated as unset #41421glepnir2026-08-22
| | | | | | | | | Problem: Empty string is falsy, so the spec's label fallback applies, but there only checks for nil. An empty filterText drops the item, an empty sortText sorts it first, and an empty insertText leaves the word empty. Solution: Treat empty string as unset.
* feat(lsp): fallback to textDocument/formatting from vim.lsp.formatexpr #40079Marcus Caisey2026-08-18
| | | | | | | | | | | | | | | | Problem: With the addition of the `:help al` text object, you can now easily format the whole buffer with `gqal`. However, `vim.lsp.formatexpr` only uses `textDocument/rangeFormatting` which some language servers (like gopls) don't support. Solution: - Fall back to `textDocument/formatting` if the whole buffer is being formatted and the server doesn't support `textDocument/rangeFormatting`. - In theory, these two methods should return the same response if the whole buffer is being formatted, but I preserved the existing behaviour of prioritising `textDocument/rangeFormatting` in case that does not hold (i.e. LS bug). - Also: `vim.lsp.formatexpr` had no tests at all, so actually add tests for it.
* test(lsp-selection): of by onealtermo2026-08-01
| | | | | | | The test uses the position col=5,row=5; but such a position is outside of the buffer. Presume that it was meant to be col=5,row=4...
* fix(lsp): multibyte fragment treated as commit char #41019glepnir2026-07-28
| | | | | | | | | | Problem: commit_chars_str() reads a 0x80-0xBF byte as a 2-byte lead, so "\xA9x" makes "x" a commit character. nvim_get_hl() returns a dict, so `#` on it is 0 whether or not the group exists Solution: use vim.str_utf_end() and drop entries that are not one whole character. use next check dict length.
* test(harness): migrate away from magic globalsJustin M. Keyes2026-07-21
| | | | | | | | | | | | | | | | | | | | | Problem: The magic globals `it`, `describe`, etc., are more trouble than they are worth. - Hooking into `after_each` requires `getfenv()` hacks. - They confuse luals/emmylua, because the top-level `.luarc.json` isn't merged with `test/.luarc.json` (apparently a luals limitation?) - They totally defeat discoverability because the user just has to "know" about the various magic symbols. So they harm DX, which means they serve no purpose at all. Solution: - Expose the test API from `testutil`, so tests can call `t.it()`, `t.describe()`, etc., in the conventional way. - Drop `getfenv()` hacks. - Drop the `setfenv()` injection in `load_chunk`. - Drop `test/_meta.lua`.
* fix(lsp): incorrect rendering of markdown codeblock #40861Justin M. Keyes2026-07-20
| | | | | | | | | | | | 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
* fix(lsp): preview window converted to normal window is auto-closed (#40770)Rocco Vaccone2026-07-19
| | | | | | | | | | | | | Problem: A floating preview window (hover, signature help) converted to a normal window (e.g. with CTRL-W_H or nvim_win_set_config()) is still closed by the open_floating_preview() autocommands, and a later preview may focus or close it as if it were still a float. Solution: When the preview window is no longer floating, remove its auto-close autocommands and stop tracking it as the buffer's floating preview. Closes #36659
* fix(ui): combine float border with window background #40796Artem Krinitsyn2026-07-19
| | | | | | | | | | Problem: Float border highlight groups (FloatBorder, FloatTitle and FloatFooter) fall back to Normal background highlight if no background color set. Solution: Combine border colors with window-local Normal highlight. Fix #38330
* feat(completion): support completionList.applyKind #40769glepnir2026-07-17
| | | | | | | | | | | Problem: values from completionList.itemDefaults always replace the item's own commitCharacters and data. Since 3.18 a server can ask for them to be merged instead. Solution: Handle CompletionList.applyKind and advertise applyKindSupport. Drop itemDefaults once folded into the items: get_items() runs twice on the same result and a Merge isn't idempotent. https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#completionItemApplyKinds
* feat(completion): commitCharacters #38417glepnir2026-07-15
| | | | | | | | | Problem: LSP completion commitCharacters are not handled. Typing a commit character (e.g. `.`, `(`, `;`) while a completion item is selected does not accept the item first. Solution: Store commit characters as a flat string in complete-items. Check it before completion stops, accept the match and let the character be inserted normally.
* fix(lsp): unclear error on malformed server responses #40422Kim A. Brandt2026-07-12
| | | | | | | | | Problem: Malformed server responses with `null` (vim.NIL) values, do not show clear error messages. Solution: Assert two known, specific cases, to avoid user confusion.
* fix(lsp): clear push diagnostics on detach #40634Oleh Volynets2026-07-08
| | | | | | | | | Problem: when an LS client detaches from the buffer, only pull diagnostics are cleared via capability framework. Push diagnostics remain stuck even when client stops/restarts. Solution: clear push diagnostics on client detach. ref #33864
* fix(lsp): refresh document-pull buffers on workspace/diagnostic/refresh #40623Caleb White2026-07-08
| | | | | | | | | | | | | | When a server supports both document and workspace pull diagnostics, `on_refresh` only dispatched a `workspace/diagnostic` request. The workspace response handler skips buffers with `pull_kind == "document"` (i.e. all buffers opened by the user), so their diagnostics went stale until the next `didChange` or `didOpen` event. Change `on_refresh` to always refresh document-pull buffers via `textDocument/diagnostic`, regardless of whether the server also supports workspace diagnostics. This ensures that opened buffers see updated diagnostics (e.g. after a save triggers an external tool like PHPStan) without requiring the user to re-enter insert mode.
* refactor(lsp): use LspNotify for codelens #40604jdrouhard2026-07-07
| | | | | | | | | | | | | | | | | | | | | Problem: The codelens LSP module was using its own raw buffer events and its own debounce mechanism for refreshing code lens in attached buffers. Solution: Switch the module to using the LspNotify autocmd events. LspNotify fires just after document versions are synced with the server and provides a built in debounce mechanism for changes. Additionally, this fixes some bugs with the previous implementation: 1. The workspace/codeLens/refresh handler re-requested codelens for all buffers but when the response came back, it forced an extra redraw after clearing the work the handler had just done. 2. Document synchronization was reworked to be more resilient to multiple clients providing codelens for a single buffer. The latest document version is now separately tracked per client (and per client's lenses per row) instead of for the buffer as a whole. This allows the on_win() function to properly redraw all codelens even when different clients' responses for a particular document version come back at different times.
* test(lsp): retry on-type formatting assertions #40602Barrett Ruth2026-07-05
|
* feat(lsp): convert inlay_hint to capability framework #40569jdrouhard2026-07-05
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Inlay hints used separate global and per-buffer bufstates tables and bespoke global autocmds for managing the inlay hint state across buffers and clients, duplicating the lifecycle logic already provided by the Capability framework. This caused inconsistencies in how client state was handled and inlay hint state lifecycle was managed compared to other LSP features. Solution: Replace the ad-hoc bufstate tracking and global autocmds in vim.lsp.inlay_hint with a proper InlayHint subclass of Capability. This also refactors the way inlay hint state is managed and fixes bugs I found while doing this: 1. For each line with inlay hints, the list of the hints along with whether they have been applied is stored in a current result on the client state. This allows the on_win decorator to clear all inlay hints for an old document version once, and then re-add the new version's hints line-by-line as they are drawn to the screen, modeling the semantic tokens module. 2. It fixes problems with mixing results from multiple clients attached to the buffer by fully moving each client's state to its own table. Previously, only the most recent document version used to populate a line's inlay hints was stored, but there was no distinction for which client the hints may have come from. (Fixes #36318) 3. It fixes the workspace/inlayHint/refresh server->client notification behavior. Previously it would only re-request inlay hints for buffers currently displayed in a window but would not invalidate them in non-displayed buffers (or provide any mechanism for those buffers to re-request at a later time). Model semantic token module here again by invalidating all buffers, and adding a BufWinEnter autocmd to refresh hints. 4. Add a mechanism to cancel in-flight requests if a new request for a newer document version is made before the last one returned 5. Handle stale results by simply dropping them.
* fix(lsp): support -1 column in format range #40570Barrett Ruth2026-07-05
| | | | | | | | | | Problem: `vim.lsp.buf.format()` accepts ranges using nvim indexing, where an end column of -1 means end of line. LSP ranges cannot use that, which is confusing for things like range formatting. Solution: Resolve -1 end columns to the line length before converting the range to LSP positions.
* refactor(lsp): convert diagnostics to capability framework #40433jdrouhard2026-06-26
| | | | | | | | | | | | | | | | | | | | | | | | | Problem: Diagnostic tracking used a separate bufstates table and manual LspDetach/LspNotify autocmd management via _enable()/_refresh(), duplicating the lifecycle logic already provided by the Capability framework. This caused inconsistencies in how client attach/detach and buffer teardown were handled compared to other LSP features. Solution: Replace the ad-hoc bufstate tracking and _enable/_refresh pattern in vim.lsp.diagnostic with a proper Diagnostics subclass of Capability. This cleans up a few random places in the main lsp module and client module that were poking the diagnostics. It also fixes some pre-existing bugs and inconsistencies that were discovered: - Refresh diagnostics immediately on attach instead of lazily by the first didOpen/didChange notification - Fix Capability.active lookup in M.enable() to key by it_bufnr instead of the filter bufnr - Set lsp defaults before calling the _text_document_did_open_handler in Client:on_attach() so defaults are there before any lsp notification occurs - Log (and return early) on any error from a diagnostic request result instead of only returning early for server cancelled errors
* fix(lsp): fire LspNotify didChange autocmds after undo/redo #40404jdrouhard2026-06-25
| | | | | | | | | | | 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.
* fix(lsp): make LspNotify more robust #40332jdrouhard2026-06-20
| | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* fix(lsp): multiline semantic token processing #40339jdrouhard2026-06-20
| | | | | | | | | | | | | 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
* fix(tests): use builtin default attributes in more placesbfredl2026-06-19
|
* fix(lsp): requery empty isIncomplete completion lists #40100glepnir2026-06-15
| | | | | | | | | Problem: an empty `{ isIncomplete = true, items = {} }` ends completion instead of requerying. Solution: keep isIncomplete on empty lists and retrigger on keypress while incomplete. Reset on <C-e> so it doesn't immediately re-query.
* feat(lsp): clean up semantic token initialization and debounce #40254jdrouhard2026-06-15
| | | | | |