perf(lsp): don't copy completion items in filter pass

This commit is contained in:
Mathias Fussenegger
2024-05-30 10:24:54 +02:00
committed by Mathias Fußenegger
parent 1d091e52f0
commit cc1f2d2ca6

View File

@ -201,6 +201,24 @@ local function get_items(result)
end end
end end
---@param item lsp.CompletionItem
---@return string
local function get_doc(item)
local doc = item.documentation
if not doc then
return ''
end
if type(doc) == 'string' then
return doc
end
if type(doc) == 'table' and type(doc.value) == 'string' then
return doc.value
end
vim.notify('invalid documentation value: ' .. vim.inspect(doc), vim.log.levels.WARN)
return ''
end
--- Turns the result of a `textDocument/completion` request into vim-compatible --- Turns the result of a `textDocument/completion` request into vim-compatible
--- |complete-items|. --- |complete-items|.
--- ---
@ -216,58 +234,48 @@ function M._lsp_to_complete_items(result, prefix, client_id)
return {} return {}
end end
if prefix ~= '' then local matches = prefix == '' and function()
---@param item lsp.CompletionItem return true
local function match_prefix(item) end or function(item)
if item.filterText then if item.filterText then
return next(vim.fn.matchfuzzy({ item.filterText }, prefix)) return next(vim.fn.matchfuzzy({ item.filterText }, prefix))
end
return true
end end
return true
items = vim.tbl_filter(match_prefix, items) --[[@as lsp.CompletionItem[]|]]
end end
table.sort(items, function(a, b) local candidates = {}
return (a.sortText or a.label) < (b.sortText or b.label)
end)
local matches = {}
for _, item in ipairs(items) do for _, item in ipairs(items) do
local info = '' if matches(item) then
local documentation = item.documentation local word = get_completion_word(item)
if documentation then table.insert(candidates, {
if type(documentation) == 'string' and documentation ~= '' then word = word,
info = documentation abbr = item.label,
elseif type(documentation) == 'table' and type(documentation.value) == 'string' then kind = protocol.CompletionItemKind[item.kind] or 'Unknown',
info = documentation.value menu = item.detail or '',
else info = get_doc(item),
vim.notify( icase = 1,
('invalid documentation value %s'):format(vim.inspect(documentation)), dup = 1,
vim.log.levels.WARN empty = 1,
) user_data = {
end nvim = {
end lsp = {
local word = get_completion_word(item) completion_item = item,
table.insert(matches, { client_id = client_id,
word = word, },
abbr = item.label,
kind = protocol.CompletionItemKind[item.kind] or 'Unknown',
menu = item.detail or '',
info = #info > 0 and info or '',
icase = 1,
dup = 1,
empty = 1,
user_data = {
nvim = {
lsp = {
completion_item = item,
client_id = client_id,
}, },
}, },
}, })
}) end
end end
return matches ---@diagnostic disable-next-line: no-unknown
table.sort(candidates, function(a, b)
---@type lsp.CompletionItem
local itema = a.user_data.nvim.lsp.completion_item
---@type lsp.CompletionItem
local itemb = b.user_data.nvim.lsp.completion_item
return (itema.sortText or itema.label) < (itemb.sortText or itemb.label)
end)
return candidates
end end
--- @param lnum integer 0-indexed --- @param lnum integer 0-indexed