diff options
author | Mathias Fußenegger <mfussenegger@users.noreply.github.com> | 2021-09-28 23:04:01 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-28 14:04:01 -0700 |
commit | ec4731d982031e363a59efd4566fc72234bb43c8 (patch) | |
tree | c0f6dabcdd7c0ae86da4fd74da44dd80abe2dba3 /runtime/lua/vim/lsp/buf.lua | |
parent | 3507d58dfb87923aa4031cbefaf1ef576a45dcaf (diff) | |
download | rneovim-ec4731d982031e363a59efd4566fc72234bb43c8.tar.gz rneovim-ec4731d982031e363a59efd4566fc72234bb43c8.tar.bz2 rneovim-ec4731d982031e363a59efd4566fc72234bb43c8.zip |
feat(lsp): add codeAction/resolve support (#15818)
Closes https://github.com/neovim/neovim/issues/15339 and https://github.com/neovim/neovim/issues/15828
Diffstat (limited to 'runtime/lua/vim/lsp/buf.lua')
-rw-r--r-- | runtime/lua/vim/lsp/buf.lua | 93 |
1 files changed, 88 insertions, 5 deletions
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 3e6a5ae2f1..245f29943e 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -450,6 +450,93 @@ function M.clear_references() util.buf_clear_references() end + +---@private +-- +--- This is not public because the main extension point is +--- vim.ui.select which can be overridden independently. +--- +--- Can't call/use vim.lsp.handlers['textDocument/codeAction'] because it expects +--- `(err, CodeAction[] | Command[], ctx)`, but we want to aggregate the results +--- from multiple clients to have 1 single UI prompt for the user, yet we still +--- need to be able to link a `CodeAction|Command` to the right client for +--- `codeAction/resolve` +local function on_code_action_results(results, ctx) + local action_tuples = {} + for client_id, result in pairs(results) do + for _, action in pairs(result.result or {}) do + table.insert(action_tuples, { client_id, action }) + end + end + if #action_tuples == 0 then + vim.notify('No code actions available', vim.log.levels.INFO) + return + end + + ---@private + local function apply_action(action, client) + if action.edit then + util.apply_workspace_edit(action.edit) + end + if action.command then + local command = type(action.command) == 'table' and action.command or action + local fn = vim.lsp.commands[command.command] + if fn then + local enriched_ctx = vim.deepcopy(ctx) + enriched_ctx.client_id = client.id + fn(command, ctx) + else + M.execute_command(command) + end + end + end + + ---@private + local function on_user_choice(action_tuple) + if not action_tuple then + return + end + -- textDocument/codeAction can return either Command[] or CodeAction[] + -- + -- CodeAction + -- ... + -- edit?: WorkspaceEdit -- <- must be applied before command + -- command?: Command + -- + -- Command: + -- title: string + -- command: string + -- arguments?: any[] + -- + local client = vim.lsp.get_client_by_id(action_tuple[1]) + local action = action_tuple[2] + if not action.edit + and client + and type(client.resolved_capabilities.code_action) == 'table' + and client.resolved_capabilities.code_action.resolveProvider then + + client.request('codeAction/resolve', action, function(err, resolved_action) + if err then + vim.notify(err.code .. ': ' .. err.message, vim.log.levels.ERROR) + return + end + apply_action(resolved_action, client) + end) + else + apply_action(action, client) + end + end + + vim.ui.select(action_tuples, { + prompt = 'Code actions:', + format_item = function(action_tuple) + local title = action_tuple[2].title:gsub('\r\n', '\\r\\n') + return title:gsub('\n', '\\n') + end, + }, on_user_choice) +end + + --- Requests code actions from all clients and calls the handler exactly once --- with all aggregated results ---@private @@ -457,11 +544,7 @@ local function code_action_request(params) local bufnr = vim.api.nvim_get_current_buf() local method = 'textDocument/codeAction' vim.lsp.buf_request_all(bufnr, method, params, function(results) - local actions = {} - for _, r in pairs(results) do - vim.list_extend(actions, r.result or {}) - end - vim.lsp.handlers[method](nil, actions, {bufnr=bufnr, method=method}) + on_code_action_results(results, { bufnr = bufnr, method = method, params = params }) end) end |