aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse <github@jessebakker.com>2020-05-16 01:18:59 +0200
committerGitHub <noreply@github.com>2020-05-16 01:18:59 +0200
commitf559e5249e3aa155687b335272da8f0c73255ee4 (patch)
tree1f2ebdabff710220c717011c57d386fae2cdfd17
parentc37d9fa3da3cea303915f29e75665f50c4c13b41 (diff)
downloadrneovim-f559e5249e3aa155687b335272da8f0c73255ee4.tar.gz
rneovim-f559e5249e3aa155687b335272da8f0c73255ee4.tar.bz2
rneovim-f559e5249e3aa155687b335272da8f0c73255ee4.zip
LSP: Add textDocument/codeAction support (#11607)
* Add textDocument/codeAction * Add callback for workspace/executeCommand * Escape newlines in codeAction titles * Return empty list in get_line_diagnostics if no buffer diagnostics * Add stub documentation * Validate context parameter in code_action * Add support for edit in CodeAction responses * Group diagnostics by line in vim.lsp.util.get_line_diagnostics() * Advertise code action literal support
-rw-r--r--runtime/doc/lsp.txt3
-rw-r--r--runtime/lua/vim/lsp/buf.lua16
-rw-r--r--runtime/lua/vim/lsp/callbacks.lua40
-rw-r--r--runtime/lua/vim/lsp/protocol.lua9
-rw-r--r--runtime/lua/vim/lsp/util.lua37
5 files changed, 97 insertions, 8 deletions
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 249136f32f..9460e600e3 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -731,6 +731,9 @@ transform_schema_to_table()
==============================================================================
Lua module: vim.lsp.buf *lsp-buf*
+code_action({context}) *vim.lsp.buf.code_action()*
+ TODO: Documentation
+
completion({context}) *vim.lsp.buf.completion()*
TODO: Documentation
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 0b45951a56..7a819f3c3d 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -161,5 +161,21 @@ function M.clear_references()
util.buf_clear_references()
end
+function M.code_action(context)
+ validate { context = { context, 't', true } }
+ context = context or { diagnostics = util.get_line_diagnostics() }
+ local params = util.make_range_params()
+ params.context = context
+ request('textDocument/codeAction', params)
+end
+
+function M.execute_command(command)
+ validate {
+ command = { command.command, 's' },
+ arguments = { command.arguments, 't', true }
+ }
+ request('workspace/executeCommand', command)
+end
+
return M
-- vim:sw=2 ts=2 et
diff --git a/runtime/lua/vim/lsp/callbacks.lua b/runtime/lua/vim/lsp/callbacks.lua
index 09ca4b61e4..17f88a5181 100644
--- a/runtime/lua/vim/lsp/callbacks.lua
+++ b/runtime/lua/vim/lsp/callbacks.lua
@@ -3,6 +3,7 @@ local protocol = require 'vim.lsp.protocol'
local util = require 'vim.lsp.util'
local vim = vim
local api = vim.api
+local buf = require 'vim.lsp.buf'
local M = {}
@@ -11,6 +12,45 @@ local function err_message(...)
api.nvim_command("redraw")
end
+M['workspace/executeCommand'] = function(err, _)
+ if err then
+ error("Could not execute code action: "..err.message)
+ end
+end
+
+M['textDocument/codeAction'] = function(_, _, actions)
+ if vim.tbl_isempty(actions) then
+ print("No code actions available")
+ return
+ end
+
+ local option_strings = {"Code Actions:"}
+ for i, action in ipairs(actions) do
+ local title = action.title:gsub('\r\n', '\\r\\n')
+ title = title:gsub('\n', '\\n')
+ table.insert(option_strings, string.format("%d. %s", i, title))
+ end
+
+ local choice = vim.fn.inputlist(option_strings)
+ if choice < 1 or choice > #actions then
+ return
+ end
+ local action_chosen = actions[choice]
+ -- textDocument/codeAction can return either Command[] or CodeAction[].
+ -- If it is a CodeAction, it can have either an edit, a command or both.
+ -- Edits should be executed first
+ if action_chosen.edit or type(action_chosen.command) == "table" then
+ if action_chosen.edit then
+ util.apply_workspace_edit(action_chosen.edit)
+ end
+ if type(action_chosen.command) == "table" then
+ buf.execute_command(action_chosen.command)
+ end
+ else
+ buf.execute_command(action_chosen)
+ end
+end
+
M['workspace/applyEdit'] = function(_, _, workspace_edit)
if not workspace_edit then return end
-- TODO(ashkan) Do something more with label?
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index ee6e29bac0..877d11411b 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -620,6 +620,15 @@ function protocol.make_client_capabilities()
-- Send textDocument/didSave after saving (BufWritePost)
didSave = true;
};
+ codeAction = {
+ dynamicRegistration = false;
+
+ codeActionLiteralSupport = {
+ codeActionKind = {
+ valueSet = {};
+ };
+ };
+ };
completion = {
dynamicRegistration = false;
completionItem = {
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 099a77099b..c92a317d0c 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -720,19 +720,28 @@ do
return severity_highlights[severity]
end
- function M.show_line_diagnostics()
+ function M.get_line_diagnostics()
local bufnr = api.nvim_get_current_buf()
- local line = api.nvim_win_get_cursor(0)[1] - 1
+ local linenr = api.nvim_win_get_cursor(0)[1] - 1
+
+ local buffer_diagnostics = M.diagnostics_by_buf[bufnr]
+
+ if not buffer_diagnostics then
+ return {}
+ end
+
+ local diagnostics_by_line = M.diagnostics_group_by_line(buffer_diagnostics)
+ return diagnostics_by_line[linenr] or {}
+ end
+
+ function M.show_line_diagnostics()
-- local marks = api.nvim_buf_get_extmarks(bufnr, diagnostic_ns, {line, 0}, {line, -1}, {})
-- if #marks == 0 then
-- return
-- end
local lines = {"Diagnostics:"}
local highlights = {{0, "Bold"}}
-
- local buffer_diagnostics = M.diagnostics_by_buf[bufnr]
- if not buffer_diagnostics then return end
- local line_diagnostics = M.diagnostics_group_by_line(buffer_diagnostics)[line]
+ local line_diagnostics = M.get_line_diagnostics()
if not line_diagnostics then return end
for i, diagnostic in ipairs(line_diagnostics) do
@@ -1044,14 +1053,26 @@ function M.try_trim_markdown_code_blocks(lines)
end
local str_utfindex = vim.str_utfindex
-function M.make_position_params()
+local function make_position_param()
local row, col = unpack(api.nvim_win_get_cursor(0))
row = row - 1
local line = api.nvim_buf_get_lines(0, row, row+1, true)[1]
col = str_utfindex(line, col)
+ return { line = row; character = col; }
+end
+
+function M.make_position_params()
return {
textDocument = M.make_text_document_params();
- position = { line = row; character = col; }
+ position = make_position_param()
+ }
+end
+
+function M.make_range_params()
+ local position = make_position_param()
+ return {
+ textDocument = { uri = vim.uri_from_bufnr(0) },
+ range = { start = position; ["end"] = position; }
}
end