feat(lsp): support completion itemDefaults

This commit is contained in:
Maria José Solano 2024-02-26 11:42:51 -08:00 committed by Christian Clason
parent 3d96e3f9f2
commit 63f9c2da9a
5 changed files with 93 additions and 1 deletions

View File

@ -125,6 +125,15 @@ The following changes may require adaptations in user config or plugins.
• Returning any truthy value from a callback passed to |nvim_create_autocmd()|
(rather than just `true`) will delete the autocommand.
• |vim.lsp.util.extract_completion_items()| will no longer return reliable
results, since it does not apply `itemDefaults` when its input is a
`CompletionList`.
Moreover, since support for LSP `completionList.itemDefaults` was added,
some third party plugins might be negatively impacted in case the language
servers support the feature but the plugin does not.
If necessary, the respective capability can be
removed when calling |vim.lsp.protocol.make_client_capabilities()|.
==============================================================================
BREAKING CHANGES IN HEAD *news-breaking-dev*
@ -213,6 +222,11 @@ The following new APIs and features were added.
the original LSP `Location` or `LocationLink`.
• Added support for connecting to servers using named pipes (Windows) or
unix domain sockets (Unix) via |vim.lsp.rpc.domain_socket_connect()|.
• Added support for `completionList.itemDefaults`, reducing overhead when
computing completion items where properties often share the same value
(e.g. `commitCharacters`). Note that this might affect plugins and
language servers that don't support the feature, and in such cases the
respective capability can be unset.
• Treesitter
• Bundled parsers and queries (highlight, folds) for Markdown, Python, and

View File

@ -6,6 +6,14 @@ local ms = protocol.Methods
--- @alias vim.lsp.CompletionResult lsp.CompletionList | lsp.CompletionItem[]
-- TODO(mariasolos): Remove this declaration once we figure out a better way to handle
-- literal/anonymous types (see https://github.com/neovim/neovim/pull/27542/files#r1495259331).
--- @class lsp.ItemDefaults
--- @field editRange lsp.Range | { insert: lsp.Range, replace: lsp.Range } | nil
--- @field insertTextFormat lsp.InsertTextFormat?
--- @field insertTextMode lsp.InsertTextMode?
--- @field data any
---@param input string unparsed snippet
---@return string parsed snippet
local function parse_snippet(input)
@ -39,13 +47,43 @@ local function get_completion_word(item)
return item.label
end
--- Applies the given defaults to the completion item, modifying it in place.
---
--- @param item lsp.CompletionItem
--- @param defaults lsp.ItemDefaults?
local function apply_defaults(item, defaults)
if not defaults then
return
end
item.insertTextFormat = item.insertTextFormat or defaults.insertTextFormat
item.insertTextMode = item.insertTextMode or defaults.insertTextMode
item.data = item.data or defaults.data
if defaults.editRange then
local textEdit = item.textEdit or {}
item.textEdit = textEdit
textEdit.newText = textEdit.newText or item.textEditText or item.insertText
if defaults.editRange.start then
textEdit.range = textEdit.range or defaults.editRange
elseif defaults.editRange.insert then
textEdit.insert = defaults.editRange.insert
textEdit.replace = defaults.editRange.replace
end
end
end
---@param result vim.lsp.CompletionResult
---@return lsp.CompletionItem[]
local function get_items(result)
if result.items then
for _, item in ipairs(result.items) do
---@diagnostic disable-next-line: param-type-mismatch
apply_defaults(item, result.itemDefaults)
end
return result.items
else
return result
end
return result
end
--- Turns the result of a `textDocument/completion` request into vim-compatible

View File

@ -764,6 +764,14 @@ function protocol.make_client_capabilities()
return res
end)(),
},
completionList = {
itemDefaults = {
'editRange',
'insertTextFormat',
'insertTextMode',
'data',
},
},
-- TODO(tjdevries): Implement this
contextSupport = false,

View File

@ -551,6 +551,10 @@ end
--- Can be used to extract the completion items from a
--- `textDocument/completion` request, which may return one of
--- `CompletionItem[]`, `CompletionList` or null.
---
--- Note that this method doesn't apply `itemDefaults` to `CompletionList`s, and hence the returned
--- results might be incorrect.
---
---@deprecated
---@param result table The result of a `textDocument/completion` request
---@return lsp.CompletionItem[] List of completion items

View File

@ -248,4 +248,32 @@ describe('vim.lsp._completion', function()
item.user_data = nil
eq(expected, item)
end)
it('uses defaults from itemDefaults', function()
--- @type lsp.CompletionList
local completion_list = {
isIncomplete = false,
itemDefaults = {
editRange = {
start = { line = 1, character = 1 },
['end'] = { line = 1, character = 4 },
},
insertTextFormat = 2,
data = 'foobar',
},
items = {
{
label = 'hello',
data = 'item-property-has-priority',
textEditText = 'hello',
},
},
}
local result = complete('|', completion_list)
eq(1, #result.items)
local item = result.items[1].user_data.nvim.lsp.completion_item --- @type lsp.CompletionItem
eq(2, item.insertTextFormat)
eq('item-property-has-priority', item.data)
eq({ line = 1, character = 1 }, item.textEdit.range.start)
end)
end)