aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim
diff options
context:
space:
mode:
authorLewis Russell <lewis6991@gmail.com>2024-10-29 09:51:14 +0000
committerGitHub <noreply@github.com>2024-10-29 09:51:14 +0000
commit2cd6abf0d7b1fb0ff71c2cb75913170025f8c915 (patch)
treefe906621455c9070d43fc2095a02e3cfc32c70f4 /runtime/lua/vim
parent8f9401f5c80a8a72128b8bd8279689daf13f3a04 (diff)
parent8260e4860b27a54a061bd8e2a9da23069993953a (diff)
downloadrneovim-2cd6abf0d7b1fb0ff71c2cb75913170025f8c915.tar.gz
rneovim-2cd6abf0d7b1fb0ff71c2cb75913170025f8c915.tar.bz2
rneovim-2cd6abf0d7b1fb0ff71c2cb75913170025f8c915.zip
Merge pull request #30935 from lewis6991/feat/lsp_multi_hover
Diffstat (limited to 'runtime/lua/vim')
-rw-r--r--runtime/lua/vim/lsp.lua38
-rw-r--r--runtime/lua/vim/lsp/_meta.lua1
-rw-r--r--runtime/lua/vim/lsp/buf.lua77
-rw-r--r--runtime/lua/vim/lsp/handlers.lua5
4 files changed, 97 insertions, 24 deletions
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index a41a3f1585..a8ae283f64 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -916,35 +916,31 @@ end
---
---@param bufnr (integer) Buffer handle, or 0 for current.
---@param method (string) LSP method name
----@param params (table|nil) Parameters to send to the server
----@param handler fun(results: table<integer, {error: lsp.ResponseError?, result: any}>) (function)
+---@param params? table|(fun(client: vim.lsp.Client, bufnr: integer): table?) Parameters to send to the server.
+--- Can also be passed as a function that returns the params table for cases where
+--- parameters are specific to the client.
+---@param handler lsp.MultiHandler (function)
--- Handler called after all requests are completed. Server results are passed as
--- a `client_id:result` map.
---@return function cancel Function that cancels all requests.
function lsp.buf_request_all(bufnr, method, params, handler)
- local results = {} --- @type table<integer,{error: lsp.ResponseError?, result: any}>
- local result_count = 0
- local expected_result_count = 0
-
- local set_expected_result_count = once(function()
- for _, client in ipairs(lsp.get_clients({ bufnr = bufnr })) do
- if client.supports_method(method, { bufnr = bufnr }) then
- expected_result_count = expected_result_count + 1
- end
+ local results = {} --- @type table<integer,{err: lsp.ResponseError?, result: any}>
+ local remaining --- @type integer?
+
+ local _, cancel = lsp.buf_request(bufnr, method, params, function(err, result, ctx, config)
+ if not remaining then
+ -- Calculate as late as possible in case a client is removed during the request
+ remaining = #lsp.get_clients({ bufnr = bufnr, method = method })
end
- end)
- local function _sync_handler(err, result, ctx)
- results[ctx.client_id] = { error = err, result = result }
- result_count = result_count + 1
- set_expected_result_count()
+ -- The error key is deprecated and will be removed in 0.13
+ results[ctx.client_id] = { err = err, error = err, result = result }
+ remaining = remaining - 1
- if result_count >= expected_result_count then
- handler(results)
+ if remaining == 0 then
+ handler(results, ctx, config)
end
- end
-
- local _, cancel = lsp.buf_request(bufnr, method, params, _sync_handler)
+ end)
return cancel
end
diff --git a/runtime/lua/vim/lsp/_meta.lua b/runtime/lua/vim/lsp/_meta.lua
index be3222828d..589a49c003 100644
--- a/runtime/lua/vim/lsp/_meta.lua
+++ b/runtime/lua/vim/lsp/_meta.lua
@@ -2,6 +2,7 @@
error('Cannot require a meta file')
---@alias lsp.Handler fun(err: lsp.ResponseError?, result: any, context: lsp.HandlerContext, config?: table): ...any
+---@alias lsp.MultiHandler fun(results: table<integer,{err: lsp.ResponseError?, result: any}>, context: lsp.HandlerContext, config?: table): ...any
---@class lsp.HandlerContext
---@field method string
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 5f50e361c4..dd06b1b6c0 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -20,6 +20,9 @@ local function client_positional_params(params)
end
end
+--- @class vim.lsp.buf.hover.Opts : vim.lsp.util.open_floating_preview.Opts
+--- @field silent? boolean
+
--- Displays hover information about the symbol under the cursor in a floating
--- window. The window will be dismissed on cursor move.
--- Calling the function twice will jump into the floating window
@@ -27,8 +30,78 @@ end
--- 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()
- lsp.buf_request(0, ms.textDocument_hover, client_positional_params())
+--- @param config? vim.lsp.buf.hover.Opts
+function M.hover(config)
+ config = config or {}
+ config.focus_id = ms.textDocument_hover
+
+ lsp.buf_request_all(0, ms.textDocument_hover, client_positional_params(), function(results, ctx)
+ if api.nvim_get_current_buf() ~= ctx.bufnr then
+ -- Ignore result since buffer changed. This happens for slow language servers.
+ return
+ end
+
+ -- Filter errors from results
+ local results1 = {} --- @type table<integer,lsp.Hover>
+
+ for client_id, resp in pairs(results) do
+ local err, result = resp.err, resp.result
+ if err then
+ lsp.log.error(err.code, err.message)
+ elseif result then
+ results1[client_id] = result
+ end
+ end
+
+ if #results1 == 0 then
+ if config.silent ~= true then
+ vim.notify('No information available')
+ end
+ return
+ end
+
+ local contents = {} --- @type string[]
+
+ local nresults = #vim.tbl_keys(results1)
+
+ local format = 'markdown'
+
+ for client_id, result in pairs(results1) do
+ if nresults > 1 then
+ -- Show client name if there are multiple clients
+ contents[#contents + 1] = string.format('# %s', lsp.get_client_by_id(client_id).name)
+ end
+ if type(result.contents) == 'table' and result.contents.kind == 'plaintext' then
+ if #results1 == 1 then
+ format = 'plaintext'
+ contents = vim.split(result.contents.value or '', '\n', { trimempty = true })
+ else
+ -- Surround plaintext with ``` to get correct formatting
+ contents[#contents + 1] = '```'
+ vim.list_extend(
+ contents,
+ vim.split(result.contents.value or '', '\n', { trimempty = true })
+ )
+ contents[#contents + 1] = '```'
+ end
+ else
+ vim.list_extend(contents, util.convert_input_to_markdown_lines(result.contents))
+ end
+ contents[#contents + 1] = '---'
+ end
+
+ -- Remove last linebreak ('---')
+ contents[#contents] = nil
+
+ if vim.tbl_isempty(contents) then
+ if config.silent ~= true then
+ vim.notify('No information available')
+ end
+ return
+ end
+
+ lsp.util.open_floating_preview(contents, format, config)
+ end)
end
local function request_with_opts(name, params, opts)
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index a905f76fda..ad827cfd34 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -317,7 +317,7 @@ M[ms.textDocument_formatting] = function(_, result, ctx, _)
util.apply_text_edits(result, ctx.bufnr, client.offset_encoding)
end
---- @deprecated
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
M[ms.textDocument_completion] = function(_, result, _, _)
if vim.tbl_isempty(result or {}) then
@@ -334,6 +334,7 @@ M[ms.textDocument_completion] = function(_, result, _, _)
vim.fn.complete(textMatch + 1, matches)
end
+--- @deprecated
--- |lsp-handler| for the method "textDocument/hover"
---
--- ```lua
@@ -384,7 +385,9 @@ function M.hover(_, result, ctx, config)
return util.open_floating_preview(contents, format, config)
end
+--- @deprecated remove in 0.13
--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
+--- @diagnostic disable-next-line: deprecated
M[ms.textDocument_hover] = M.hover
local sig_help_ns = api.nvim_create_namespace('vim_lsp_signature_help')