aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/news.txt14
-rw-r--r--runtime/lua/vim/lsp/_completion.lua40
-rw-r--r--runtime/lua/vim/lsp/protocol.lua8
-rw-r--r--runtime/lua/vim/lsp/util.lua4
-rw-r--r--test/functional/plugin/lsp/completion_spec.lua28
5 files changed, 93 insertions, 1 deletions
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index 9ce96b7a67..6895254a42 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -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
diff --git a/runtime/lua/vim/lsp/_completion.lua b/runtime/lua/vim/lsp/_completion.lua
index 3a38c1b5e1..a169f96565 100644
--- a/runtime/lua/vim/lsp/_completion.lua
+++ b/runtime/lua/vim/lsp/_completion.lua
@@ -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
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index 82e8c4a7de..fb41311961 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -764,6 +764,14 @@ function protocol.make_client_capabilities()
return res
end)(),
},
+ completionList = {
+ itemDefaults = {
+ 'editRange',
+ 'insertTextFormat',
+ 'insertTextMode',
+ 'data',
+ },
+ },
-- TODO(tjdevries): Implement this
contextSupport = false,
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index e371cb0e15..3973e606f8 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -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
diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua
index b49f970385..655eb76be6 100644
--- a/test/functional/plugin/lsp/completion_spec.lua
+++ b/test/functional/plugin/lsp/completion_spec.lua
@@ -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)