diff options
author | Fredrik Ekre <ekrefredrik@gmail.com> | 2022-05-12 18:48:02 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-12 18:48:02 +0200 |
commit | a9d25e94725d5cfc41c2fabff22b2284e109fa0c (patch) | |
tree | 1f7382012d1ecded52011e600c651c48e406bd77 | |
parent | de5ccf2348a1fabf3867da9256e4740a7dfcf004 (diff) | |
download | rneovim-a9d25e94725d5cfc41c2fabff22b2284e109fa0c.tar.gz rneovim-a9d25e94725d5cfc41c2fabff22b2284e109fa0c.tar.bz2 rneovim-a9d25e94725d5cfc41c2fabff22b2284e109fa0c.zip |
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
-rw-r--r-- | runtime/lua/vim/lsp/buf.lua | 32 | ||||
-rw-r--r-- | test/functional/fixtures/fake-lsp-server.lua | 15 | ||||
-rw-r--r-- | test/functional/plugin/lsp_spec.lua | 21 |
3 files changed, 65 insertions, 3 deletions
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 1cfbcd1259..b0bf2c6e5b 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -691,10 +691,38 @@ end --- `codeAction/resolve` local function on_code_action_results(results, ctx, options) 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 _, 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 }) end end diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index f589f5955f..86cdf4ef56 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -766,8 +766,21 @@ function tests.code_action_filter() isPreferred = true, 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() + return nil, { action, preferred_action, quickfix_action, quickfix_foo_action, } + end) expect_request('textDocument/codeAction', function() - return nil, { action, preferred_action, } + return nil, { action, preferred_action, quickfix_action, quickfix_foo_action, } end) notify('shutdown') end; diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 33a8976b79..4cb7636825 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -2753,12 +2753,33 @@ describe('LSP', function() vim.lsp.commands['executed_preferred'] = function() 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() 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({ + -- 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 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() end end |