aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/lsp/handlers.lua
diff options
context:
space:
mode:
authorMichael Lingelbach <m.j.lbach@gmail.com>2021-08-28 00:12:30 -0400
committerMichael Lingelbach <m.j.lbach@gmail.com>2021-09-05 10:04:30 -0700
commitdf17d7844ed7dedcb80f9405f7078a046a12524a (patch)
treeaa1cd7c325aefe6ad6d48a95316df08fcaf25a11 /runtime/lua/vim/lsp/handlers.lua
parent5d633546bf5990d03e4b4dc1df213f88316115e6 (diff)
downloadrneovim-df17d7844ed7dedcb80f9405f7078a046a12524a.tar.gz
rneovim-df17d7844ed7dedcb80f9405f7078a046a12524a.tar.bz2
rneovim-df17d7844ed7dedcb80f9405f7078a046a12524a.zip
feat(lsp)!: change handler signature
Previously, the handler signature was: function(err, method, params, client_id, bufnr, config) In order to better support external plugins that wish to extend the protocol, there is other information which would be advantageous to forward to the client, such as the original params of the request that generated the callback. In order to do this, we would need to break symmetry of the handlers, to add an additional "params" as the 7th argument. Instead, this PR changes the signature of the handlers to: function(err, result, ctx, config) where ctx (the context) includes params, client_id, and bufnr. This also leaves flexibility for future use-cases. BREAKING_CHANGE: changes the signature of the built-in client handlers, requiring updating handler calls
Diffstat (limited to 'runtime/lua/vim/lsp/handlers.lua')
-rw-r--r--runtime/lua/vim/lsp/handlers.lua110
1 files changed, 58 insertions, 52 deletions
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index befb9fcec3..22627c85e8 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -18,19 +18,20 @@ local function err_message(...)
end
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
-M['workspace/executeCommand'] = function()
+M['workspace/executeCommand'] = function(_, _, _, _)
-- Error handling is done implicitly by wrapping all handlers; see end of this file
end
---@private
-local function progress_handler(_, _, params, client_id)
+local function progress_handler(_, result, ctx, _)
+ local client_id = ctx.client_id
local client = vim.lsp.get_client_by_id(client_id)
local client_name = client and client.name or string.format("id=%d", client_id)
if not client then
err_message("LSP[", client_name, "] client has shut down after sending the message")
end
- local val = params.value -- unspecified yet
- local token = params.token -- string or number
+ local val = result.value -- unspecified yet
+ local token = result.token -- string or number
if val.kind then
@@ -62,9 +63,10 @@ end
M['$/progress'] = progress_handler
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_workDoneProgress_create
-M['window/workDoneProgress/create'] = function(_, _, params, client_id)
+M['window/workDoneProgress/create'] = function(_, result, ctx)
+ local client_id = ctx.client_id
local client = vim.lsp.get_client_by_id(client_id)
- local token = params.token -- string or number
+ local token = result.token -- string or number
local client_name = client and client.name or string.format("id=%d", client_id)
if not client then
err_message("LSP[", client_name, "] client has shut down after sending the message")
@@ -74,11 +76,11 @@ M['window/workDoneProgress/create'] = function(_, _, params, client_id)
end
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessageRequest
-M['window/showMessageRequest'] = function(_, _, params)
+M['window/showMessageRequest'] = function(_, result)
- local actions = params.actions
- print(params.message)
- local option_strings = {params.message, "\nRequest Actions:"}
+ local actions = result.actions
+ print(result.message)
+ local option_strings = {result.message, "\nRequest Actions:"}
for i, action in ipairs(actions) do
local title = action.title:gsub('\r\n', '\\r\\n')
title = title:gsub('\n', '\\n')
@@ -95,7 +97,8 @@ M['window/showMessageRequest'] = function(_, _, params)
end
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability
-M['client/registerCapability'] = function(_, _, _, client_id)
+M['client/registerCapability'] = function(_, _, ctx)
+ local client_id = ctx.client_id
local warning_tpl = "The language server %s triggers a registerCapability "..
"handler despite dynamicRegistration set to false. "..
"Report upstream, this warning is harmless"
@@ -107,24 +110,24 @@ M['client/registerCapability'] = function(_, _, _, client_id)
end
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
-M['textDocument/codeAction'] = function(_, _, actions)
- if actions == nil or vim.tbl_isempty(actions) then
+M['textDocument/codeAction'] = function(_, result)
+ if result == nil or vim.tbl_isempty(result) then
print("No code actions available")
return
end
- local option_strings = {"Code Actions:"}
- for i, action in ipairs(actions) do
+ local option_strings = {"Code actions:"}
+ for i, action in ipairs(result) 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
+ if choice < 1 or choice > #result then
return
end
- local action_chosen = actions[choice]
+ local action_chosen = result[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
@@ -155,28 +158,29 @@ M['workspace/applyEdit'] = function(_, _, workspace_edit)
end
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration
-M['workspace/configuration'] = function(_, _, params, client_id)
+M['workspace/configuration'] = function(_, result, ctx)
+ local client_id = ctx.client_id
local client = vim.lsp.get_client_by_id(client_id)
if not client then
err_message("LSP[id=", client_id, "] client has shut down after sending the message")
return
end
- if not params.items then
+ if not result.items then
return {}
end
- local result = {}
- for _, item in ipairs(params.items) do
+ local response = {}
+ for _, item in ipairs(result.items) do
if item.section then
local value = util.lookup_section(client.config.settings, item.section) or vim.NIL
-- For empty sections with no explicit '' key, return settings as is
if value == vim.NIL and item.section == '' then
value = client.config.settings or vim.NIL
end
- table.insert(result, value)
+ table.insert(response, value)
end
end
- return result
+ return response
end
M['textDocument/publishDiagnostics'] = function(...)
@@ -200,16 +204,16 @@ end
---@param map_result function `((resp, bufnr) -> list)` to convert the response
---@param entity name of the resource used in a `not found` error message
local function response_to_list(map_result, entity)
- return function(_, _, result, _, bufnr, config)
+ return function(_,result, ctx, config)
if not result or vim.tbl_isempty(result) then
vim.notify('No ' .. entity .. ' found')
else
config = config or {}
if config.loclist then
- util.set_loclist(map_result(result, bufnr))
+ util.set_loclist(map_result(result, ctx.bufnr))
api.nvim_command("lopen")
else
- util.set_qflist(map_result(result, bufnr))
+ util.set_qflist(map_result(result, ctx.bufnr))
api.nvim_command("copen")
end
end
@@ -227,25 +231,25 @@ M['textDocument/documentSymbol'] = response_to_list(util.symbols_to_items, 'docu
M['workspace/symbol'] = response_to_list(util.symbols_to_items, 'symbols')
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename
-M['textDocument/rename'] = function(_, _, result)
+M['textDocument/rename'] = function(_, result, _)
if not result then return end
util.apply_workspace_edit(result)
end
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting
-M['textDocument/rangeFormatting'] = function(_, _, result, _, bufnr)
+M['textDocument/rangeFormatting'] = function(_, result, ctx, _)
if not result then return end
- util.apply_text_edits(result, bufnr)
+ util.apply_text_edits(result, ctx.bufnr)
end
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
-M['textDocument/formatting'] = function(_, _, result, _, bufnr)
+M['textDocument/formatting'] = function(_, result, ctx, _)
if not result then return end
- util.apply_text_edits(result, bufnr)
+ util.apply_text_edits(result, ctx.bufnr)
end
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
-M['textDocument/completion'] = function(_, _, result)
+M['textDocument/completion'] = function(_, result, _, _)
if vim.tbl_isempty(result or {}) then return end
local row, col = unpack(api.nvim_win_get_cursor(0))
local line = assert(api.nvim_buf_get_lines(0, row-1, row, false)[1])
@@ -270,9 +274,9 @@ end
--- - border: (default=nil)
--- - Add borders to the floating window
--- - See |vim.api.nvim_open_win()|
-function M.hover(_, method, result, _, _, config)
+function M.hover(_, result, ctx, config)
config = config or {}
- config.focus_id = method
+ config.focus_id = ctx.method
if not (result and result.contents) then
-- return { 'No information available' }
return
@@ -292,12 +296,12 @@ M['textDocument/hover'] = M.hover
---@private
--- Jumps to a location. Used as a handler for multiple LSP methods.
---@param _ (not used)
----@param method (string) LSP method name
---@param result (table) result of LSP method; a location or a list of locations.
+---@param ctx (table) table containing the context of the request, including the method
---(`textDocument/definition` can return `Location` or `Location[]`
-local function location_handler(_, method, result)
+local function location_handler(_, result, ctx, _)
if result == nil or vim.tbl_isempty(result) then
- local _ = log.info() and log.info(method, 'No location found')
+ local _ = log.info() and log.info(ctx.method, 'No location found')
return nil
end
@@ -339,9 +343,9 @@ M['textDocument/implementation'] = location_handler
--- - border: (default=nil)
--- - Add borders to the floating window
--- - See |vim.api.nvim_open_win()|
-function M.signature_help(_, method, result, client_id, bufnr, config)
+function M.signature_help(_, result, ctx, config)
config = config or {}
- config.focus_id = method
+ config.focus_id = ctx.method
-- When use `autocmd CompleteDone <silent><buffer> lua vim.lsp.buf.signature_help()` to call signatureHelp handler
-- If the completion item doesn't have signatures It will make noise. Change to use `print` that can use `<silent>` to ignore
if not (result and result.signatures and result.signatures[1]) then
@@ -350,9 +354,9 @@ function M.signature_help(_, method, result, client_id, bufnr, config)
end
return
end
- local client = vim.lsp.get_client_by_id(client_id)
+ local client = vim.lsp.get_client_by_id(ctx.client_id)
local triggers = client.resolved_capabilities.signature_help_trigger_characters
- local ft = api.nvim_buf_get_option(bufnr, 'filetype')
+ local ft = api.nvim_buf_get_option(ctx.bufnr, 'filetype')
local lines, hl = util.convert_signature_help_to_markdown_lines(result, ft, triggers)
lines = util.trim_empty_lines(lines)
if vim.tbl_isempty(lines) then
@@ -372,9 +376,9 @@ end
M['textDocument/signatureHelp'] = M.signature_help
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight
-M['textDocument/documentHighlight'] = function(_, _, result, _, bufnr, _)
+M['textDocument/documentHighlight'] = function(_, result, ctx, _)
if not result then return end
- util.buf_highlight_references(bufnr, result)
+ util.buf_highlight_references(ctx.bufnr, result)
end
---@private
@@ -385,7 +389,7 @@ end
---@returns `CallHierarchyIncomingCall[]` if {direction} is `"from"`,
---@returns `CallHierarchyOutgoingCall[]` if {direction} is `"to"`,
local make_call_hierarchy_handler = function(direction)
- return function(_, _, result)
+ return function(_, result)
if not result then return end
local items = {}
for _, call_hierarchy_call in pairs(result) do
@@ -411,9 +415,10 @@ M['callHierarchy/incomingCalls'] = make_call_hierarchy_handler('from')
M['callHierarchy/outgoingCalls'] = make_call_hierarchy_handler('to')
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_logMessage
-M['window/logMessage'] = function(_, _, result, client_id)
+M['window/logMessage'] = function(_, result, ctx, _)
local message_type = result.type
local message = result.message
+ local client_id = ctx.client_id
local client = vim.lsp.get_client_by_id(client_id)
local client_name = client and client.name or string.format("id=%d", client_id)
if not client then
@@ -432,9 +437,10 @@ M['window/logMessage'] = function(_, _, result, client_id)
end
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessage
-M['window/showMessage'] = function(_, _, result, client_id)
+M['window/showMessage'] = function(_, result, ctx, _)
local message_type = result.type
local message = result.message
+ local client_id = ctx.client_id
local client = vim.lsp.get_client_by_id(client_id)
local client_name = client and client.name or string.format("id=%d", client_id)
if not client then
@@ -451,14 +457,14 @@ end
-- Add boilerplate error validation and logging for all of these.
for k, fn in pairs(M) do
- M[k] = function(err, method, params, client_id, bufnr, config)
- local _ = log.debug() and log.debug('default_handler', method, {
- params = params, client_id = client_id, err = err, bufnr = bufnr, config = config
+ M[k] = function(err, result, ctx, config)
+ local _ = log.debug() and log.debug('default_handler', ctx.method, {
+ err = err, result = result, ctx=vim.inspect(ctx), config = config
})
if err then
- local client = vim.lsp.get_client_by_id(client_id)
- local client_name = client and client.name or string.format("client_id=%d", client_id)
+ local client = vim.lsp.get_client_by_id(ctx.client_id)
+ local client_name = client and client.name or string.format("client_id=%d", ctx.client_id)
-- LSP spec:
-- interface ResponseError:
-- code: integer;
@@ -467,7 +473,7 @@ for k, fn in pairs(M) do
return err_message(client_name .. ': ' .. tostring(err.code) .. ': ' .. err.message)
end
- return fn(err, method, params, client_id, bufnr, config)
+ return fn(err, result, ctx, config)
end
end