From dff684fdb3d2e787ac6d6fd49ec52ede604fd0ce Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Tue, 8 Oct 2024 19:04:28 +0200 Subject: [PATCH] feat(lsp)!: support multiple clients in lsp.buf.references Relates to: - https://github.com/neovim/neovim/issues/17712 - https://github.com/neovim/neovim/issues/30034 --- runtime/doc/news.txt | 3 ++ runtime/lua/vim/lsp/buf.lua | 58 +++++++++++++++++++++++++++++--- runtime/lua/vim/lsp/handlers.lua | 25 -------------- 3 files changed, 56 insertions(+), 30 deletions(-) diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index f2338331fa..def66a0773 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -77,6 +77,9 @@ LSP customizing the transformation of an LSP CompletionItem to |complete-items|. • |vim.lsp.diagnostic.from()| can be used to convert a list of |vim.Diagnostic| objects into their LSP diagnostic representation. +• |vim.lsp.buf.references()| now handles multiple clients but no longer + triggers the global `textDocument/references` handler from + `vim.lsp.handlers` LUA diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index f6837a627f..8803c0495a 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -438,11 +438,59 @@ end ---@param opts? vim.lsp.ListOpts function M.references(context, opts) validate('context', context, 'table', true) - local params = util.make_position_params() - params.context = context or { - includeDeclaration = true, - } - request_with_opts(ms.textDocument_references, params, opts) + local clients = vim.lsp.get_clients({ method = ms.textDocument_references }) + if not next(clients) then + return + end + local win = api.nvim_get_current_win() + local bufnr = api.nvim_get_current_buf() + opts = opts or {} + + local all_items = {} + local title = 'References' + + local function on_done() + if not next(all_items) then + vim.notify('No references found') + else + local list = { + title = title, + items = all_items, + context = { + method = ms.textDocument_references, + bufnr = bufnr, + }, + } + if opts.loclist then + vim.fn.setloclist(0, {}, ' ', list) + vim.cmd.lopen() + elseif opts.on_list then + assert(vim.is_callable(opts.on_list), 'on_list is not a function') + opts.on_list(list) + else + vim.fn.setqflist({}, ' ', list) + vim.cmd('botright copen') + end + end + end + + local remaining = #clients + for _, client in ipairs(clients) do + local params = util.make_position_params(win, client.offset_encoding) + + ---@diagnostic disable-next-line: inject-field + params.context = context or { + includeDeclaration = true, + } + client.request(ms.textDocument_references, params, function(_, result) + local items = util.locations_to_items(result or {}, client.offset_encoding) + vim.list_extend(all_items, items) + remaining = remaining - 1 + if remaining == 0 then + on_done() + end + end) + end end --- Lists all symbols in the current buffer in the quickfix window. diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 8e538242d9..3306e480dd 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -242,31 +242,6 @@ M[ms.textDocument_inlayHint] = function(...) return vim.lsp.inlay_hint.on_inlayhint(...) end ---- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references -M[ms.textDocument_references] = function(_, result, ctx, config) - if not result or vim.tbl_isempty(result) then - vim.notify('No references found') - return - end - - local client = assert(vim.lsp.get_client_by_id(ctx.client_id)) - config = config or {} - local title = 'References' - local items = util.locations_to_items(result, client.offset_encoding) - - local list = { title = title, items = items, context = ctx } - if config.loclist then - vim.fn.setloclist(0, {}, ' ', list) - vim.cmd.lopen() - elseif config.on_list then - assert(vim.is_callable(config.on_list), 'on_list is not a function') - config.on_list(list) - else - vim.fn.setqflist({}, ' ', list) - vim.cmd('botright copen') - end -end - --- Return a function that converts LSP responses to list items and opens the list --- --- The returned function has an optional {config} parameter that accepts |vim.lsp.ListOpts|