aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Fussenegger <f.mathias@zignar.net>2025-02-14 14:06:47 +0100
committerMathias Fußenegger <mfussenegger@users.noreply.github.com>2025-02-14 19:49:08 +0100
commitf20335a54ce7f240902d4ee14d726620a38f95bc (patch)
tree40531a7feae68d6410b90a4bc2c30c93da1e1325
parentc091bc3b9abc220fa5d512966d89893f56f20691 (diff)
downloadrneovim-f20335a54ce7f240902d4ee14d726620a38f95bc.tar.gz
rneovim-f20335a54ce7f240902d4ee14d726620a38f95bc.tar.bz2
rneovim-f20335a54ce7f240902d4ee14d726620a38f95bc.zip
feat(lsp): add support for completionItem.command resolving
`command` was already resolved via a `completionItem/resolve` request but only if `additionalTextEdits` were also present, and the `resolveSupport` capability wasn't listed. Closes https://github.com/neovim/neovim/issues/32406
-rw-r--r--runtime/lua/vim/lsp/completion.lua7
-rw-r--r--runtime/lua/vim/lsp/protocol.lua1
-rw-r--r--test/functional/plugin/lsp/completion_spec.lua70
3 files changed, 69 insertions, 9 deletions
diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua
index f287304508..d99b1ffd0d 100644
--- a/runtime/lua/vim/lsp/completion.lua
+++ b/runtime/lua/vim/lsp/completion.lua
@@ -610,13 +610,14 @@ local function on_complete_done()
clear_word()
if err then
vim.notify_once(err.message, vim.log.levels.WARN)
- elseif result and result.additionalTextEdits then
- lsp.util.apply_text_edits(result.additionalTextEdits, bufnr, position_encoding)
+ elseif result then
+ if result.additionalTextEdits then
+ lsp.util.apply_text_edits(result.additionalTextEdits, bufnr, position_encoding)
+ end
if result.command then
completion_item.command = result.command
end
end
-
apply_snippet_and_command()
end, bufnr)
else
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index fbfd0cd6b0..33d029420b 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -458,6 +458,7 @@ function protocol.make_client_capabilities()
resolveSupport = {
properties = {
'additionalTextEdits',
+ 'command',
},
},
tagSupport = {
diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua
index 33c025daba..d101e68273 100644
--- a/test/functional/plugin/lsp/completion_spec.lua
+++ b/test/functional/plugin/lsp/completion_spec.lua
@@ -770,20 +770,25 @@ end)
--- @param name string
--- @param completion_result lsp.CompletionList
---- @param trigger_chars? string[]
+--- @param opts? {trigger_chars?: string[], resolve_result?: lsp.CompletionItem}
--- @return integer
-local function create_server(name, completion_result, trigger_chars)
+local function create_server(name, completion_result, opts)
+ opts = opts or {}
return exec_lua(function()
local server = _G._create_server({
capabilities = {
completionProvider = {
- triggerCharacters = trigger_chars or { '.' },
+ triggerCharacters = opts.trigger_chars or { '.' },
+ resolveProvider = opts.resolve_result ~= nil,
},
},
handlers = {
['textDocument/completion'] = function(_, _, callback)
callback(nil, completion_result)
end,
+ ['completionItem/resolve'] = function(_, _, callback)
+ callback(nil, opts.resolve_result)
+ end,
},
})
@@ -794,7 +799,7 @@ local function create_server(name, completion_result, trigger_chars)
cmd = server.cmd,
on_attach = function(client, bufnr0)
vim.lsp.completion.enable(true, client.id, bufnr0, {
- autotrigger = trigger_chars ~= nil,
+ autotrigger = opts.trigger_chars ~= nil,
convert = function(item)
return { abbr = item.label:gsub('%b()', '') }
end,
@@ -968,7 +973,7 @@ describe('vim.lsp.completion: protocol', function()
},
},
}
- create_server('dummy1', results1, { 'e' })
+ create_server('dummy1', results1, { trigger_chars = { 'e' } })
local results2 = {
isIncomplete = false,
items = {
@@ -977,7 +982,7 @@ describe('vim.lsp.completion: protocol', function()
},
},
}
- create_server('dummy2', results2, { 'h' })
+ create_server('dummy2', results2, { trigger_chars = { 'h' } })
feed('h')
exec_lua(function()
@@ -1042,6 +1047,59 @@ describe('vim.lsp.completion: protocol', function()
end)
end)
+ it('resolves and executes commands', function()
+ local completion_list = {
+ isIncomplete = false,
+ items = {
+ {
+ label = 'hello',
+ },
+ },
+ }
+ local client_id = create_server('dummy', completion_list, {
+ resolve_result = {
+ label = 'hello',
+ command = {
+ arguments = { '1', '0' },
+ command = 'dummy',
+ title = '',
+ },
+ },
+ })
+ exec_lua(function()
+ _G.called = false
+ local client = assert(vim.lsp.get_client_by_id(client_id))
+ client.commands.dummy = function()
+ _G.called = true
+ end
+ end)
+
+ feed('ih')
+ trigger_at_pos({ 1, 1 })
+
+ local item = completion_list.items[1]
+ exec_lua(function()
+ vim.v.completed_item = {
+ user_data = {
+ nvim = {
+ lsp = {
+ client_id = client_id,
+ completion_item = item,
+ },
+ },
+ },
+ }
+ end)
+
+ feed('<C-x><C-o><C-y>')
+
+ assert_matches(function(matches)
+ eq(1, #matches)
+ eq('hello', matches[1].word)
+ eq(true, exec_lua('return _G.called'))
+ end)
+ end)
+
it('enable(…,{convert=fn}) custom word/abbr format', function()
create_server('dummy', {
isIncomplete = false,