From 90a4b1a59cf0c204cb39ec7789ab8783626e449d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 28 May 2024 03:07:13 -0700 Subject: refactor: deprecate vim.region() #28416 Problem: `vim.region()` is redundant with `getregionpos()`. Solution: Deprecate `vim.region()`. --- runtime/lua/vim/lsp/buf.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp/buf.lua') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 49833eaeec..299b68e134 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -135,7 +135,7 @@ end ---@param mode "v"|"V" ---@return table {start={row,col}, end={row,col}} using (1, 0) indexing local function range_from_selection(bufnr, mode) - -- TODO: Use `vim.region()` instead https://github.com/neovim/neovim/pull/13896 + -- TODO: Use `vim.fn.getregionpos()` instead. -- [bufnum, lnum, col, off]; both row and column 1-indexed local start = vim.fn.getpos('v') -- cgit From 5581a95534e44b8714e715c925c9de2d95ae1c21 Mon Sep 17 00:00:00 2001 From: Tom Praschan <13141438+tom-anders@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:54:56 +0200 Subject: feat(lsp): vim.lsp.buf.format() supports textDocument/rangesFormatting #27323 While this relies on a proposed LSP 3.18 feature, it's fully backwards compatible, so IMO there's no harm in adding this already. Looks like some servers already support for this e.g. - gopls: https://go-review.googlesource.com/c/tools/+/510235 - clangd: https://github.com/llvm/llvm-project/pull/80180 Fixes #27293 --- runtime/lua/vim/lsp/buf.lua | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'runtime/lua/vim/lsp/buf.lua') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 299b68e134..f20730b8e6 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -205,9 +205,11 @@ end --- Range to format. --- Table must contain `start` and `end` keys with {row,col} tuples using --- (1,0) indexing. +--- Can also be a list of tables that contain `start` and `end` keys as described above, +--- in which case `textDocument/rangesFormatting` support is required. --- (Default: current selection in visual mode, `nil` in other modes, --- formatting the full buffer) ---- @field range? {start:integer[],end:integer[]} +--- @field range? {start:[integer,integer],end:[integer, integer]}|{start:[integer,integer],end:[integer,integer]}[] --- Formats a buffer using the attached (and optionally filtered) language --- server clients. @@ -218,10 +220,20 @@ function M.format(opts) local bufnr = opts.bufnr or api.nvim_get_current_buf() local mode = api.nvim_get_mode().mode local range = opts.range + -- Try to use visual selection if no range is given if not range and mode == 'v' or mode == 'V' then range = range_from_selection(bufnr, mode) end - local method = range and ms.textDocument_rangeFormatting or ms.textDocument_formatting + + local passed_multiple_ranges = (range and #range ~= 0 and type(range[1]) == 'table') + local method ---@type string + if passed_multiple_ranges then + method = ms.textDocument_rangesFormatting + elseif range then + method = ms.textDocument_rangeFormatting + else + method = ms.textDocument_formatting + end local clients = vim.lsp.get_clients({ id = opts.id, @@ -241,10 +253,14 @@ function M.format(opts) --- @param params lsp.DocumentFormattingParams --- @return lsp.DocumentFormattingParams local function set_range(client, params) - if range then - local range_params = - util.make_given_range_params(range.start, range['end'], bufnr, client.offset_encoding) - params.range = range_params.range + local to_lsp_range = function(r) ---@return lsp.DocumentRangeFormattingParams|lsp.DocumentRangesFormattingParams + return util.make_given_range_params(r.start, r['end'], bufnr, client.offset_encoding).range + end + + if passed_multiple_ranges then + params.ranges = vim.tbl_map(to_lsp_range, range) + elseif range then + params.range = to_lsp_range(range) end return params end -- cgit From 720b309c786c4a258adccc9c468d433fb0f755b9 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Thu, 1 Aug 2024 16:01:15 +0200 Subject: fix(lsp): don't send foreign diagnostics to servers in buf.code_action (#29501) `buf.code_action` always included diagnostics on a given line from all clients. Servers should only receive diagnostics they published, and in the exact same format they sent it. Should fix https://github.com/neovim/neovim/issues/29500 --- runtime/lua/vim/lsp/buf.lua | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'runtime/lua/vim/lsp/buf.lua') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index f20730b8e6..a512d48a06 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -852,14 +852,10 @@ function M.code_action(opts) if opts.diagnostics or opts.only then opts = { options = opts } end - local context = opts.context or {} + local context = opts.context and vim.deepcopy(opts.context) or {} if not context.triggerKind then context.triggerKind = vim.lsp.protocol.CodeActionTriggerKind.Invoked end - if not context.diagnostics then - local bufnr = api.nvim_get_current_buf() - context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics(bufnr) - end local mode = api.nvim_get_mode().mode local bufnr = api.nvim_get_current_buf() local win = api.nvim_get_current_win() @@ -901,6 +897,18 @@ function M.code_action(opts) else params = util.make_range_params(win, client.offset_encoding) end + if not context.diagnostics then + local ns_push = vim.lsp.diagnostic.get_namespace(client.id, false) + local ns_pull = vim.lsp.diagnostic.get_namespace(client.id, true) + local diagnostics = {} + local lnum = api.nvim_win_get_cursor(0)[1] - 1 + vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_pull, lnum = lnum })) + vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_push, lnum = lnum })) + ---@diagnostic disable-next-line: no-unknown + context.diagnostics = vim.tbl_map(function(d) + return d.user_data.lsp + end, diagnostics) + end params.context = context client.request(ms.textDocument_codeAction, params, on_result, bufnr) end -- cgit From 7031949be065870f0daf74a9f1be3df47f83312c Mon Sep 17 00:00:00 2001 From: Grzegorz Rozdzialik Date: Wed, 7 Aug 2024 17:28:01 +0200 Subject: fix(lsp): avoid reusing diagnostics from different servers in actions (#30002) Problem: When preparing the parameters for a code actions LSP request, the code set `context.diagnostics` when processing the first LSP client, and then reused those `context.diagnostics` for subsequent LSP clients. This meant that the second and next LSP clients got diagnostics that did not originate from them, and they did not get the diagnostics that they sent. Solution: Avoid setting `context.diagnostics` (which is referenced by all clients). Instead, set `params.context.diagnostics` directly, which is specific to a single client. Fixes #30001 Caused by #29501 --- runtime/lua/vim/lsp/buf.lua | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'runtime/lua/vim/lsp/buf.lua') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index a512d48a06..d7463d74f8 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -897,19 +897,23 @@ function M.code_action(opts) else params = util.make_range_params(win, client.offset_encoding) end - if not context.diagnostics then + if context.diagnostics then + params.context = context + else local ns_push = vim.lsp.diagnostic.get_namespace(client.id, false) local ns_pull = vim.lsp.diagnostic.get_namespace(client.id, true) local diagnostics = {} local lnum = api.nvim_win_get_cursor(0)[1] - 1 vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_pull, lnum = lnum })) vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_push, lnum = lnum })) - ---@diagnostic disable-next-line: no-unknown - context.diagnostics = vim.tbl_map(function(d) - return d.user_data.lsp - end, diagnostics) + params.context = vim.tbl_extend('force', context, { + ---@diagnostic disable-next-line: no-unknown + diagnostics = vim.tbl_map(function(d) + return d.user_data.lsp + end, diagnostics), + }) end - params.context = context + client.request(ms.textDocument_codeAction, params, on_result, bufnr) end end -- cgit From d9ccd828b0d46754b9bcb9b17f47c2a51968db05 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Mon, 26 Aug 2024 08:37:36 -0700 Subject: fix(lsp): return call hierarchy item, not the index (#30145) --- runtime/lua/vim/lsp/buf.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp/buf.lua') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index d7463d74f8..e51727ef13 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -464,7 +464,7 @@ local function pick_call_hierarchy_item(call_hierarchy_items) if choice < 1 or choice > #items then return end - return choice + return call_hierarchy_items[choice] end --- @param method string -- cgit From 8654a9700690a715e35baa600bb982f4ea608ead Mon Sep 17 00:00:00 2001 From: James Trew <66286082+jamestrew@users.noreply.github.com> Date: Fri, 13 Sep 2024 11:59:49 +0000 Subject: fix(lsp): handle empty call hierarchy items #30349 Ensure that the function `pick_call_hierarchy_item` correctly handles the case where `call_hierarchy_items` is nil or an empty table. This prevents potential errors when the function is called with no items. --- runtime/lua/vim/lsp/buf.lua | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'runtime/lua/vim/lsp/buf.lua') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index e51727ef13..a43ad8a690 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -447,11 +447,9 @@ function M.document_symbol(opts) request_with_opts(ms.textDocument_documentSymbol, params, opts) end ---- @param call_hierarchy_items lsp.CallHierarchyItem[]? +--- @param call_hierarchy_items lsp.CallHierarchyItem[] +--- @return lsp.CallHierarchyItem? local function pick_call_hierarchy_item(call_hierarchy_items) - if not call_hierarchy_items then - return - end if #call_hierarchy_items == 1 then return call_hierarchy_items[1] end @@ -476,7 +474,7 @@ local function call_hierarchy(method) vim.notify(err.message, vim.log.levels.WARN) return end - if not result then + if not result or vim.tbl_isempty(result) then vim.notify('No item resolved', vim.log.levels.WARN) return end -- cgit From adbaaa522550a098e3b8e4efe0909cb3aa6e1d83 Mon Sep 17 00:00:00 2001 From: Tristan Knight Date: Thu, 19 Sep 2024 16:00:08 +0100 Subject: docs(lsp): hover window controls #30347 --- runtime/lua/vim/lsp/buf.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp/buf.lua') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index a43ad8a690..301c1f0cb6 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -29,7 +29,12 @@ local function request(method, params, handler) end --- Displays hover information about the symbol under the cursor in a floating ---- window. Calling the function twice will jump into the floating window. +--- window. The window will be dismissed on cursor move. +--- Calling the function twice will jump into the floating window +--- (thus by default, "KK" will open the hover window and focus it). +--- In the floating window, all commands and mappings are available as usual, +--- except that "q" dismisses the window. +--- You can scroll the contents the same as you would any other buffer. function M.hover() local params = util.make_position_params() request(ms.textDocument_hover, params) -- cgit