aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/lsp/completion.lua
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
* 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.
* perf(lsp): read options once per completion response #42106glepnir2026-09-27
| | | | | | | | Problem: Converting completion items reads 'completeopt' through vim.opt, 'ignorecase' and 'smartcase' for every item. Solution: Read them once per response.
* fix(lua): enable assignment type checking in runtime codeLewis Russell2026-09-25
| | | | | | | | | | | Enable EmmyLua's assign-type-mismatch diagnostic after correcting the runtime annotations and assignments it flags. Correct option, tuple, and return types, and use separate locals when a value changes representation. Add guards and narrow casts where needed so the runtime passes the stricter check. Regenerate the affected docs. AI-assisted
* fix(lua): enable nil-safety diagnostics in runtime codeLewis Russell2026-09-25
| | | | | | | | | | | | Enable EmmyLua's need-check-nil diagnostic and resolve nullable values through more precise types, explicit invariants, and guards for missing runtime state. Keep analyzer-specific workarounds local and update the affected API documentation. Exclude the bundled re.lua from analysis so its nil-check warnings do not fail CI. AI-assisted
* fix(lua): add missing param annotations (#41911)Lewis Russell2026-09-15
|
* 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'.
* build: enable more EmmyLua checksLewis Russell2026-09-09
| | | | | | | | | | Enable checks for unused code, deprecated calls, return types, and annotations. Fix the warnings and replace the deprecated highlight function. Keep exceptions where old APIs are still needed or the checker gets it wrong. 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.
* 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): 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.
* 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.
* docs: misc, remove some old help tags #40214Justin M. Keyes2026-07-18
| | | | | | | | | | - Remove old help tags: they add noise to cmdline completion. Co-authored-by: acehinnnqru <acehinnnqru@gmail.com> Co-authored-by: KangaZero <samuelyongw@gmail.com> Co-authored-by: Simone Ragusa <hi@interrato.dev> Co-authored-by: Chinmay Dalal <~chinmay/public-inbox@lists.sr.ht> Co-authored-by: coyaSONG <66289470+coyaSONG@users.noreply.github.com> Co-authored-by: Olivia Kinnear <git@superatomic.dev>
* 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.
* refactor(api): omit optional paramJustin M. Keyes2026-07-13
|
* feat(api): add nvim_win_resize()XiaowenHu962026-07-05
| | | | | | | | | | | | | | | Ref #6645 Problem: When a window is resized it takes space from the window right/below first, and only falls back to the window left/above when there is no more room. Sometimes a user wants the space to come from a specific direction. Solution: Add nvim_win_resize(win, width, height, {anchor}) which resizes a window with a choosable anchor edge, letting a window grow leftwards or upwards by taking space from the window to the left or above first. The default anchor reproduces nvim_win_set_width()/nvim_win_set_height().
* 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.
* docs: misc, lspJustin M. Keyes2026-06-03
| | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: This doc on `vim.lsp.completion.get()`: --- Used by the default LSP |omnicompletion| provider |vim.lsp.omnifunc()|, thus |i_CTRL-X_CTRL-O| --- invokes this in LSP-enabled buffers. Use CTRL-Y to select an item from the completion menu. --- |complete_CTRL-Y| ...makes two wrong claims: 1. "Used by the default LSP omnicompletion provider vim.lsp.omnifunc()" - `_omnifunc` does not call `M.get()`, it calls the internal `trigger()` directly. 2. "thus |i_CTRL-X_CTRL-O| invokes this in LSP-enabled buffers" - The two paths use different client sets: - `M.get()` reads `buf_handles[bufnr].clients` (clients explicitly registered via `vim.lsp.completion.enable(true, ...)`). - `_omnifunc` reads `lsp.get_clients({method='textDocument/completion'})` (every completion client, regardless of `enable()`). Solution: Update docs. Co-authored-by: Koichi Shiraishi <zchee.io@gmail.com> Co-authored-by: y9san9 / Alex Sokol <y9san9@gmail.com> Co-authored-by: adv0r <>
* refactor(lsp): centralise complete item info generation logicMarcus Caisey2026-05-21
| | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: The logic for generating the complete item `info` is spread across `_lsp_to_complete_items`, the `CompleteChanged` event handler, and `CompletionResolver:request`. This has previously caused the `info` shown for resolved (via `completionItem/resolve`) and unresolved items to differ. Solution: Centralise the logic in a new `complete_item_info` function which is now solely responsible for determining: 1. The `info` to show. 2. The markup kind of the `info`. 3. Whether the `info` is complete. This simplifies the interaction between the 3 functions mentioned in the problem: - `_lsp_to_complete_items` calls `complete_item_info` and passes along the markup kind and whether the item needs resolving via the complete item's `user_data`. - The `CompleteChanged` consumes the markup kind and whether the item needs resolving from the complete item's `user_data`. - `CompletionResolver:request`, like `_lsp_to_complete_items` calls `complete_item_info` again and updates the current `info` if it's changed.
* fix(lsp): show detail in popup when server can't completionItem/resolveMarcus Caisey2026-05-21
| | | | | | | | | | | | | | | | | | | Problem: `CompletionItem.detail` is only shown in the info popup if the server supports `completionItem/resolve`. Solution: If the server doesn't support `completionItem/resolve`, prepend the complete item `info` with `CompletionItem.detail` in a fenced codeblock, same as we do when the server supports `completionItem/resolve`. To ensure that completion items are displayed in the same way, regardless of whether the server supports `completionItem/resolve`, i've extracted out the test logic from the `selecting an item triggers completionItem/resolve + (snippet) preview` case so that we can run the same tests against a server which supports `completionItem/resolve` and one which doesn't. Hopefully this should prevent the two behaviours diverging again.
* fix(lsp): resolve CompletionItem if resolvable fields aren't populatedMarcus Caisey2026-05-21
| | | | | | | | | | | | | | | | | | | | | Problem: If `CompletionItem.documentation` is populated but `detail` is not, then `detail` is not resolved. Solution: Ensure that we resolve a `CompletionItem` if either `detail` or `documentation` are not populated. I've also removed `detail` from the popup menu since otherwise it will be populated in both the popup menu and the info popup after the `CompletionItem` has been resolved. I think the info popup is the best place for it anyway as when there is a completion item with a long popup menu entry (when `detail` is a medium/long function signature for instance), the whole popup menu gets widened and this steals horizontal space that could be used to display the `documentation`. Now with `detail` and `documentation` in the info popup, they share the same horizontal space. This also aligns with how VSCode, nvim-cmp, blink.cmp, and mini.nvim display `detail`.
* fix(lsp): generate snippet preview from resolved textEdit.newTextMarcus Caisey2026-05-21
| | | | | | | | | Problem: When a resolved `CompletionItem` with kind `Snippet` populates `textEdit` instead of `insertText`, the contents are not previewed. Solution: Generate the snippet preview from `textEdit.newText` as well.
* refactor: introduce nvim_on internally #39883Justin M. Keyes2026-05-20
| | | | | | | | | Problem: `nvim_create_autocmd` is too verbose and its `callback` requires extra "nesting". Solution: Introduce `nvim_on`. Start using it internally. Then we can get a feel for how it should look before making it public.
* fix(lsp): preserve trigger chars on completion #39850glepnir2026-05-18
| | | | | | | | Problem: After 767fbd8, typing trigger chars would open completion but the chars were removed. Solution: Use filterText fallback so selected item respects typed trigger chars.
* fix(lsp): fallback to filterText for non-matching PlainText items #39695glepnir2026-05-17
| | | | | | | | | | Problem: PlainText completion items used `textEdit.newText` or `insertText` as the completion word even when they did not match the typed prefix. This could break popup completion behavior like 'completeopt+=longest'. Solution: Fall back to `filterText` when `newText` or `insertText` does not match the typed prefix.
* feat(lua)!: vim.isnil, vim.nonnil, deprecate vim.F #39495Olivia Kinnear2026-05-06
|
* fix(lsp): util.lua attempt to concatenate userdata #39225Olivia Kinnear2026-04-28
| | | | | | | | | 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`.
* fix(lsp): show meaningful error on invalid completion response #39445glepnir2026-04-28
| | | | | | | | | Problem: vim.NIL is truthy in Lua, so `#(result.items or result)` crashes on `#vim.NIL` when servers return null. Solution: skip spec-allowed result=null silently, raise an error on items=null with the server name. https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
* fix(lsp): show CompletionItem.detail in info popup #38904glepnir2026-04-18
| | | | | | | 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.
* feat(completion): completeopt=preselect, LSP CompletionItem.preselect #36613glepnir2026-04-13
| | | | | | | | | | Problem: LSP CompletionItem.preselect is not supported. https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionClientCapabilities Solution: - Add "preselect" field to complete-items and "preselect" flag to 'completeopt'. - Set preselectSupport=true in LSP client capabilities.
* feat(api): rename buffer to buf #35330Jordan2026-04-08
| | | | | | | | | | | | 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: Justin M. Keyes <justinkz@gmail.com>
* fix(lsp): highlight snippet preview when server can't completionItem/resolve ↵Marcus Caisey2026-03-29
| | | | | | | | | | | | | | | | | | (#38534) Problem: The snippet preview is not being highlighted by treesitter for completion items from servers which don't support `completionItem/resolve` (like gopls). This was broken by #38428. Solution: Call `update_popup_window` after updating the completion item with the snippet preview. I've added assertions to the `selecting an item triggers completionItem/resolve + (snippet) preview` test case which covers the snippet preview being shown since no tests failed when I removed the `nvim__complete_set` call which actually populates the preview on this codepath.
* fix(lsp): completion word includes leading space from label #38435glepnir2026-03-23
| | | | | | | | | | Problem: clangd prepends a space/bullet indicator to label. With labelDetailsSupport enabled, the signature moves to labelDetails, making label shorter. This flips the length comparison in get_completion_word, causing it to use item.label directly and insert the indicator into the buffer. Solution: only prefer filterText over label when label starts with non-keyword character in get_completion_word fallback branch.
* fix(lsp): snippet preview blocked completionItem/resolve request #38428glepnir2026-03-23
| | | | | | | | Problem: Generating snippet preview in get_doc() populated the documentation field before resolve, so the resolve request was never sent. Solution: Move snippet preview logic into on_completechanged and the resolve callback so it no longer blocks the resolve request.
* feat(lsp): support CompletionItem.labelDetails #38403glepnir2026-03-21
| | | | | | | | | Problem: CompletionItem.labelDetails is ignored, losing function signatures and module info in the completion menu. Solution: Append labelDetails.detail to abbr and use labelDetails.description for menu with fallback to item.detail. https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItemLabelDetails
* fix(lsp): handle completion/resolve response arriving after on_insert_leaveMathias Fussenegger2026-03-20
| | | | | | If a user accepts completion and immediately exits insert mode, it could happen that `Context.cursor` was nil by the time the `completion/resolve` response arrives, leading to an error.
* docs: misc, terminalJustin M. Keyes2026-03-18
| | | | | | | | Close #38319 Close #38348 Co-authored-by: zeertzjq <zeertzjq@outlook.com> Co-authored-by: Barrett Ruth <br.barrettruth@gmail.com>
* fix(lsp): respect documentation markup kind in completion preview #38338glepnir2026-03-17
| | | | | | | Problem: Completion preview always assumes plain text, ignoring LSP documentation "kind". Solution: Pass markup kind from completion item to info window, or fallback to PlainText.
* fix(lsp): handle non-string documentation in completion items #38291glepnir2026-03-14
| | | | | | | Problem: `get_doc` throws error with "attempt to get length of a userdata value" when `item.documentation` is truthy but not a string (e.g. vim.NIL from a JSON null). Solution: Check `type(item.documentation)` before taking its length.
* refactor: rename _ensure_integer => _assert_integerJustin M. Keyes2026-03-13
|
* refactor: integer functions, optimize asserts #34112Lewis Russell2026-03-12
| | | | | | | | | | | | refactor(lua): add integer coercion helpers Add vim._tointeger() and vim._ensure_integer(), including optional base support, and switch integer-only tonumber()/assert call sites in the Lua runtime to use them. This also cleans up related integer parsing in LSP, health, loader, URI, tohtml, and Treesitter code. supported by AI