fix(lsp): resolve CompletionItem if resolvable fields aren't populated

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`.
This commit is contained in:
Marcus Caisey
2026-05-13 16:02:15 +01:00
parent 10a53e7637
commit ce7df01391
2 changed files with 80 additions and 36 deletions

View File

@@ -439,7 +439,7 @@ function M._lsp_to_complete_items(
word = word,
abbr = ('%s%s'):format(item.label, vim.tbl_get(item, 'labelDetails', 'detail') or ''),
kind = kind,
menu = vim.tbl_get(item, 'labelDetails', 'description') or item.detail or '',
menu = vim.tbl_get(item, 'labelDetails', 'description') or '',
info = get_doc(item),
icase = 1,
dup = 1,
@@ -795,16 +795,18 @@ local function on_completechanged(group, bufnr)
desc = 'Request and display LSP completion item documentation via completionItem/resolve',
}, function(ev)
local completed_item = vim.v.event.completed_item or {}
local lsp_item = vim.tbl_get(completed_item, 'user_data', 'nvim', 'lsp', 'completion_item')
local lsp_item = vim.tbl_get(completed_item, 'user_data', 'nvim', 'lsp', 'completion_item') --[[@as lsp.CompletionItem?]]
if not lsp_item then
return
end
local data = vim.fn.complete_info({ 'selected' })
if (completed_item.info or '') ~= '' then
local kind = vim.tbl_get(lsp_item or {}, 'documentation', 'kind')
local kind = vim.tbl_get(lsp_item, 'documentation', 'kind')
update_popup_window(
data.preview_winid,
data.preview_bufnr,
kind or protocol.MarkupKind.Markdown
)
return
end
if
@@ -816,7 +818,6 @@ local function on_completechanged(group, bufnr)
then
if
has_completeopt('popup')
and lsp_item
and lsp_item.insertTextFormat == protocol.InsertTextFormat.Snippet
then
-- Shows snippet preview in doc popup if completeopt=popup.
@@ -832,7 +833,7 @@ local function on_completechanged(group, bufnr)
-- Retrieve the raw LSP completionItem from completed_item as the parameter for
-- the completionItem/resolve request
if lsp_item then
if not lsp_item.detail or not lsp_item.documentation then
Context.resolve_handler = Context.resolve_handler or CompletionResolver.new()
Context.resolve_handler:request(ev.buf, lsp_item, completed_item.word)
end