mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
fix(lsp): perform client side filtering of code actions (#18392)
Implement filtering of actions based on the kind when passing the 'only' parameter to code_action(). Action kinds are hierachical with a '.' as the separator, and the filter thus allows, for example, both 'quickfix' and 'quickfix.foo' when requestiong only 'quickfix'. Fix https://github.com/neovim/neovim/pull/18221#issuecomment-1110179121
This commit is contained in:
parent
de5ccf2348
commit
a9d25e9472
@ -691,10 +691,38 @@ end
|
|||||||
--- `codeAction/resolve`
|
--- `codeAction/resolve`
|
||||||
local function on_code_action_results(results, ctx, options)
|
local function on_code_action_results(results, ctx, options)
|
||||||
local action_tuples = {}
|
local action_tuples = {}
|
||||||
local filter = options and options.filter
|
|
||||||
|
---@private
|
||||||
|
local function action_filter(a)
|
||||||
|
-- filter by specified action kind
|
||||||
|
if options and options.context and options.context.only then
|
||||||
|
if not a.kind then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local found = false
|
||||||
|
for _, o in ipairs(options.context.only) do
|
||||||
|
-- action kinds are hierachical with . as a separator: when requesting only
|
||||||
|
-- 'quickfix' this filter allows both 'quickfix' and 'quickfix.foo', for example
|
||||||
|
if a.kind:find('^' .. o .. '$') or a.kind:find('^' .. o .. '%.') then
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not found then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- filter by user function
|
||||||
|
if options and options.filter and not options.filter(a) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
-- no filter removed this action
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
for client_id, result in pairs(results) do
|
for client_id, result in pairs(results) do
|
||||||
for _, action in pairs(result.result or {}) do
|
for _, action in pairs(result.result or {}) do
|
||||||
if not filter or filter(action) then
|
if action_filter(action) then
|
||||||
table.insert(action_tuples, { client_id, action })
|
table.insert(action_tuples, { client_id, action })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -766,8 +766,21 @@ function tests.code_action_filter()
|
|||||||
isPreferred = true,
|
isPreferred = true,
|
||||||
command = 'preferred_command',
|
command = 'preferred_command',
|
||||||
}
|
}
|
||||||
|
local quickfix_action = {
|
||||||
|
title = 'Action 3',
|
||||||
|
kind = 'quickfix',
|
||||||
|
command = 'quickfix_command',
|
||||||
|
}
|
||||||
|
local quickfix_foo_action = {
|
||||||
|
title = 'Action 4',
|
||||||
|
kind = 'quickfix.foo',
|
||||||
|
command = 'quickfix_foo_command',
|
||||||
|
}
|
||||||
expect_request('textDocument/codeAction', function()
|
expect_request('textDocument/codeAction', function()
|
||||||
return nil, { action, preferred_action, }
|
return nil, { action, preferred_action, quickfix_action, quickfix_foo_action, }
|
||||||
|
end)
|
||||||
|
expect_request('textDocument/codeAction', function()
|
||||||
|
return nil, { action, preferred_action, quickfix_action, quickfix_foo_action, }
|
||||||
end)
|
end)
|
||||||
notify('shutdown')
|
notify('shutdown')
|
||||||
end;
|
end;
|
||||||
|
@ -2753,12 +2753,33 @@ describe('LSP', function()
|
|||||||
vim.lsp.commands['executed_preferred'] = function()
|
vim.lsp.commands['executed_preferred'] = function()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
vim.lsp.commands['quickfix_command'] = function(cmd)
|
||||||
|
vim.lsp.commands['executed_quickfix'] = function()
|
||||||
|
end
|
||||||
|
end
|
||||||
local bufnr = vim.api.nvim_get_current_buf()
|
local bufnr = vim.api.nvim_get_current_buf()
|
||||||
vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
|
vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
|
||||||
vim.lsp.buf.code_action({ filter = function(a) return a.isPreferred end, apply = true, })
|
vim.lsp.buf.code_action({ filter = function(a) return a.isPreferred end, apply = true, })
|
||||||
|
vim.lsp.buf.code_action({
|
||||||
|
-- expect to be returned actions 'quickfix' and 'quickfix.foo'
|
||||||
|
context = { only = {'quickfix'}, },
|
||||||
|
apply = true,
|
||||||
|
filter = function(a)
|
||||||
|
if a.kind == 'quickfix.foo' then
|
||||||
|
vim.lsp.commands['filtered_quickfix_foo'] = function() end
|
||||||
|
return false
|
||||||
|
elseif a.kind == 'quickfix' then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
assert(nil, 'unreachable')
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
]])
|
]])
|
||||||
elseif ctx.method == 'shutdown' then
|
elseif ctx.method == 'shutdown' then
|
||||||
eq('function', exec_lua[[return type(vim.lsp.commands['executed_preferred'])]])
|
eq('function', exec_lua[[return type(vim.lsp.commands['executed_preferred'])]])
|
||||||
|
eq('function', exec_lua[[return type(vim.lsp.commands['filtered_quickfix_foo'])]])
|
||||||
|
eq('function', exec_lua[[return type(vim.lsp.commands['executed_quickfix'])]])
|
||||||
client.stop()
|
client.stop()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user