From adbe7f368397da21465f27181e254dd3694820e9 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Tue, 31 Oct 2023 14:18:44 +0200 Subject: [PATCH] fix(lsp): call `on_list()` even for single location (#25830) Problem: Currently there is no way of customizing behavior of `declaration`, `definition`, `typeDefinition`, and `implementation` methods in `vim.lsp.buf` when LSP server returns `Location`. Instead, cursor jumps to that location directly. Solution: Normalize LSP response to be `Location[]` for those four cases. --- runtime/doc/lsp.txt | 16 +++++++-------- runtime/lua/vim/lsp/buf.lua | 12 +++++++---- runtime/lua/vim/lsp/handlers.lua | 35 ++++++++++++++++---------------- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index e62a411233..b727cff2cd 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1179,8 +1179,8 @@ declaration({options}) *vim.lsp.buf.declaration()* • {options} (table|nil) additional options • reuse_win: (boolean) Jump to existing window if buffer is already open. - • on_list: (function) handler for list results. See - |lsp-on-list-handler| + • on_list: (function) |lsp-on-list-handler| replacing the + default handler. Called for any non-empty result. definition({options}) *vim.lsp.buf.definition()* Jumps to the definition of the symbol under the cursor. @@ -1189,8 +1189,8 @@ definition({options}) *vim.lsp.buf.definition()* • {options} (table|nil) additional options • reuse_win: (boolean) Jump to existing window if buffer is already open. - • on_list: (function) handler for list results. See - |lsp-on-list-handler| + • on_list: (function) |lsp-on-list-handler| replacing the + default handler. Called for any non-empty result. document_highlight() *vim.lsp.buf.document_highlight()* Send request to the server to resolve document highlights for the current @@ -1271,8 +1271,8 @@ implementation({options}) *vim.lsp.buf.implementation()* Parameters: ~ • {options} (table|nil) additional options - • on_list: (function) handler for list results. See - |lsp-on-list-handler| + • on_list: (function) |lsp-on-list-handler| replacing the + default handler. Called for any non-empty result. incoming_calls() *vim.lsp.buf.incoming_calls()* Lists all the call sites of the symbol under the cursor in the |quickfix| @@ -1329,8 +1329,8 @@ type_definition({options}) *vim.lsp.buf.type_definition()* • {options} (table|nil) additional options • reuse_win: (boolean) Jump to existing window if buffer is already open. - • on_list: (function) handler for list results. See - |lsp-on-list-handler| + • on_list: (function) |lsp-on-list-handler| replacing the + default handler. Called for any non-empty result. workspace_symbol({query}, {options}) *vim.lsp.buf.workspace_symbol()* Lists all symbols in the current workspace in the quickfix window. diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 9436fbbf56..b9b7aefae6 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -62,7 +62,8 @@ end --- ---@param options table|nil additional options --- - reuse_win: (boolean) Jump to existing window if buffer is already open. ---- - on_list: (function) handler for list results. See |lsp-on-list-handler| +--- - on_list: (function) |lsp-on-list-handler| replacing the default handler. +--- Called for any non-empty result. function M.declaration(options) local params = util.make_position_params() request_with_options(ms.textDocument_declaration, params, options) @@ -72,7 +73,8 @@ end --- ---@param options table|nil additional options --- - reuse_win: (boolean) Jump to existing window if buffer is already open. ---- - on_list: (function) handler for list results. See |lsp-on-list-handler| +--- - on_list: (function) |lsp-on-list-handler| replacing the default handler. +--- Called for any non-empty result. function M.definition(options) local params = util.make_position_params() request_with_options(ms.textDocument_definition, params, options) @@ -82,7 +84,8 @@ end --- ---@param options table|nil additional options --- - reuse_win: (boolean) Jump to existing window if buffer is already open. ---- - on_list: (function) handler for list results. See |lsp-on-list-handler| +--- - on_list: (function) |lsp-on-list-handler| replacing the default handler. +--- Called for any non-empty result. function M.type_definition(options) local params = util.make_position_params() request_with_options(ms.textDocument_typeDefinition, params, options) @@ -92,7 +95,8 @@ end --- quickfix window. --- ---@param options table|nil additional options ---- - on_list: (function) handler for list results. See |lsp-on-list-handler| +--- - on_list: (function) |lsp-on-list-handler| replacing the default handler. +--- Called for any non-empty result. function M.implementation(options) local params = util.make_position_params() request_with_options(ms.textDocument_implementation, params, options) diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index d153b956ee..6fde55cf04 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -407,25 +407,24 @@ local function location_handler(_, result, ctx, config) -- textDocument/definition can return Location or Location[] -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition - - if vim.tbl_islist(result) then - local title = 'LSP locations' - local items = util.locations_to_items(result, client.offset_encoding) - - if config.on_list then - assert(type(config.on_list) == 'function', 'on_list is not a function') - config.on_list({ title = title, items = items }) - else - if #result == 1 then - util.jump_to_location(result[1], client.offset_encoding, config.reuse_win) - return - end - vim.fn.setqflist({}, ' ', { title = title, items = items }) - api.nvim_command('botright copen') - end - else - util.jump_to_location(result, client.offset_encoding, config.reuse_win) + if not vim.tbl_islist(result) then + result = { result } end + + local title = 'LSP locations' + local items = util.locations_to_items(result, client.offset_encoding) + + if config.on_list then + assert(type(config.on_list) == 'function', 'on_list is not a function') + config.on_list({ title = title, items = items }) + return + end + if #result == 1 then + util.jump_to_location(result[1], client.offset_encoding, config.reuse_win) + return + end + vim.fn.setqflist({}, ' ', { title = title, items = items }) + api.nvim_command('botright copen') end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration