feat(lsp): support for resolving code action command (#32704)

* fix(lsp): don't call codeAction_resolve with commands

* feat(lsp): support for resolving code action command
This commit is contained in:
Maria José Solano
2025-03-06 00:21:47 -08:00
committed by GitHub
parent 0c0352783f
commit 41b07b128c
5 changed files with 66 additions and 8 deletions

View File

@ -309,6 +309,8 @@ LSP
• |vim.lsp.config()| has been added to define default configurations for • |vim.lsp.config()| has been added to define default configurations for
servers. In addition, configurations can be specified in `lsp/<name>.lua`. servers. In addition, configurations can be specified in `lsp/<name>.lua`.
• |vim.lsp.enable()| has been added to enable servers. • |vim.lsp.enable()| has been added to enable servers.
• |vim.lsp.buf.code_action()| resolves the `command` property during the
`codeAction/resolve` request.
LUA LUA

View File

@ -1129,6 +1129,7 @@ local function on_code_action_results(results, opts)
if not choice then if not choice then
return return
end end
-- textDocument/codeAction can return either Command[] or CodeAction[] -- textDocument/codeAction can return either Command[] or CodeAction[]
-- --
-- CodeAction -- CodeAction
@ -1140,12 +1141,18 @@ local function on_code_action_results(results, opts)
-- title: string -- title: string
-- command: string -- command: string
-- arguments?: any[] -- arguments?: any[]
--
local client = assert(lsp.get_client_by_id(choice.ctx.client_id)) local client = assert(lsp.get_client_by_id(choice.ctx.client_id))
local action = choice.action local action = choice.action
local bufnr = assert(choice.ctx.bufnr, 'Must have buffer number') local bufnr = assert(choice.ctx.bufnr, 'Must have buffer number')
if not action.edit and client:supports_method(ms.codeAction_resolve) then -- Only code actions are resolved, so if we have a command, just apply it.
if type(action.title) == 'string' and type(action.command) == 'string' then
apply_action(action, client, choice.ctx)
return
end
if not action.edit or not action.command and client:supports_method(ms.codeAction_resolve) then
client:request(ms.codeAction_resolve, action, function(err, resolved_action) client:request(ms.codeAction_resolve, action, function(err, resolved_action)
if err then if err then
if action.command then if action.command then

View File

@ -424,7 +424,7 @@ function protocol.make_client_capabilities()
isPreferredSupport = true, isPreferredSupport = true,
dataSupport = true, dataSupport = true,
resolveSupport = { resolveSupport = {
properties = { 'edit' }, properties = { 'edit', 'command' },
}, },
}, },
codeLens = { codeLens = {

View File

@ -789,15 +789,19 @@ function tests.code_action_with_resolve()
end, end,
body = function() body = function()
notify('start') notify('start')
local cmd = { local cmd = { title = 'Action 1' }
title = 'Command 1',
command = 'dummy1',
}
expect_request('textDocument/codeAction', function() expect_request('textDocument/codeAction', function()
return nil, { cmd } return nil, { cmd }
end) end)
expect_request('codeAction/resolve', function() expect_request('codeAction/resolve', function()
return nil, cmd return nil,
{
title = 'Action 1',
command = {
title = 'Command 1',
command = 'dummy1',
},
}
end) end)
notify('shutdown') notify('shutdown')
end, end,

View File

@ -4591,6 +4591,51 @@ describe('LSP', function()
eq('workspace/executeCommand', result[5].method) eq('workspace/executeCommand', result[5].method)
eq('command:1', result[5].params.command) eq('command:1', result[5].params.command)
end) end)
it('Resolves command property', function()
clear()
exec_lua(create_server_definition)
local result = exec_lua(function()
local server = _G._create_server({
capabilities = {
executeCommandProvider = {
commands = { 'command:1' },
},
codeActionProvider = {
resolveProvider = true,
},
},
handlers = {
['textDocument/codeAction'] = function(_, _, callback)
callback(nil, {
{ title = 'Code Action 1' },
})
end,
['codeAction/resolve'] = function(_, _, callback)
callback(nil, {
title = 'Code Action 1',
command = {
title = 'Command 1',
command = 'command:1',
},
})
end,
},
})
local client_id = assert(vim.lsp.start({
name = 'dummy',
cmd = server.cmd,
}))
vim.lsp.buf.code_action({ apply = true })
vim.lsp.stop_client(client_id)
return server.messages
end)
eq('codeAction/resolve', result[4].method)
eq('workspace/executeCommand', result[5].method)
eq('command:1', result[5].params.command)
end)
end) end)
describe('vim.lsp.commands', function() describe('vim.lsp.commands', function()