Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Conversation

@glepnir
Copy link
Member

@glepnir glepnir commented Nov 19, 2025

Problem: No default completion item was preselected by LSP.

Solution: Added preselect option to always move the preselected item to the first.

@github-actions github-actions bot added the lsp label Nov 19, 2025
@glepnir glepnir marked this pull request as draft November 19, 2025 07:36
@glepnir glepnir marked this pull request as ready for review November 19, 2025 08:20
runtime/lua/vim/lsp/completion.lua Show resolved Hide resolved
Comment on lines 1291 to 1292
{ label = 'zzz', sortText = 'a', preselect = true },
{ label = 'aaa', sortText = 'z' },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually testing the preselect behavior? sortText = 'a' means this would be the first result even without the preselect change.

Is there a concrete example of a language user making use of preselect?

Given that neovim controls the preselection using the preinsert/noinsert/noselect completeopt I wonder if there's even any point in supporting this at all - given the that the intention from the spec seems to be to change the selection instead of changing the sort ordering.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a concrete example of a language user making use of preselect?

Rust-Analyzer uses preselect for fields that match the variable name in an assignment, see: helix-editor/helix#4480. The idea seems to be that since the server doesn't control sorting, preselect provides a way to prioritize completions based on stronger signals. When there is no prefix, the server can still mark a completion as more relevant. Another example I can think of is when completing missing type declarations when the server can infer the required type and there is only one correct fix. But if the user is refactoring, returning only that single completion would be poor behavior, and relying on sorting alone may fail to pick it if the client uses custom sorting.

Given that neovim controls the preselection using the preinsert/noinsert/noselect completeopt I wonder if there's even any point in supporting this at all - given the that the intention from the spec seems to be to change the selection instead of changing the sort ordering.

Based on microsoft/vscode#35551 and microsoft/vscode-languageserver-node#371, the client is supposed to keep the original order but move the selection to the preselected item. VS Code appears to behave this way. I'm not sure how different this is from simply placing that item first from a UX perspective, but it does seem incompatible with Neovim’s noselect anyway.

Copy link
Member

@mfussenegger mfussenegger Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea seems to be that since the server doesn't control sorting

The linked issue (microsoft/vscode#35551) even mentions this bit about server being able to control sorting:

Still, you can achieve this by utilising the 'sortText'-property. The VSCode UI always sorts the completion list by "rank" (in contrast to VS which selects the best match). These "ranks" are computed by looking at the text left of the cursor or, when there is no text, by using the 'sortText'-property

Relevant part from the spec:

to achieve consistency across languages and to honor different clients usually the client is responsible for filtering and sorting. This has also the advantage that client can experiment with different filter and sorting models. However servers can enforce different behavior by setting a filterText / sortText

A bit strange that they added another means to control priority of the completion candidates, but the screenshot also shows that the pre-selected entry is not the first - maybe for cases where you want to sort alphanumeric but have one prioritized anyway? I can't always follow MS logic.

In any case, seems to me that in order for neovim to support this properly it would need to extend the complete mechanism to declare preselect as part of the complete-items structure, and then also support controlling the behavior via completeopt.

That said, if adding the preselected item as first item (without duplicating it) is useful behavior in practice I'm also not really opposed. Main concern was with the test.

Copy link
Member Author

@glepnir glepnir Nov 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would need to extend the complete mechanism to declare preselect as part of the complete-items structure, and then also support controlling the behavior via completeopt.

For now, keeping it always as the first item allows us to respect noselect. if noselect isn’t included in cot, it always select the first item like preselect ? maybe we can set preselect to not vim.o.cot:find("noselect")

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mfussenegger how do you feel now

runtime/doc/news.txt Outdated Show resolved Hide resolved
@glepnir glepnir force-pushed the lsp_preselect branch 3 times, most recently from 0255856 to 1239672 Compare November 22, 2025 12:03
runtime/doc/lsp.txt Outdated Show resolved Hide resolved
@glepnir glepnir force-pushed the lsp_preselect branch 3 times, most recently from 6c196bf to 9ce5fe3 Compare November 24, 2025 02:38
--- @field autotrigger? boolean (default: false) When true, completion triggers automatically based on the server's `triggerCharacters`.
--- @field convert? fun(item: lsp.CompletionItem): table Transforms an LSP CompletionItem to |complete-items|.
--- @field cmp? fun(a: table, b: table): boolean Comparator for sorting merged completion items from all servers.
--- @field preselect? boolean moves the item with `lsp.CompletionItem.preselect` to the first. Default: enabled if "noselect" is not present in `completeopt`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
--- @field preselect? boolean moves the item with `lsp.CompletionItem.preselect` to the first. Default: enabled if "noselect" is not present in `completeopt`.
--- @field preselect? boolean moves the item with `lsp.CompletionItem.preselect` to the first. Default: `false` if "noselect" is present in `completeopt`, `true` otherwise.

Feel free to ignore this though. I just find the double-negative confusing, but I can't English sometimes so maybe this is a me-issue.

@justinmk any thoughts on clarity here?

runtime/doc/news.txt Outdated Show resolved Hide resolved
@glepnir glepnir force-pushed the lsp_preselect branch 3 times, most recently from fdbabf0 to ddae7ba Compare December 1, 2025 08:58
Problem: No default completion item was preselected by LSP.

Solution: Added preselect option to always move the preselected
item to the first.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.