aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/lsp/buf.lua
diff options
context:
space:
mode:
authorLewis Russell <lewis6991@gmail.com>2024-11-01 12:30:36 +0000
committerLewis Russell <me@lewisr.dev>2024-11-04 11:55:39 +0000
commit6e68fed37441096bf9fd2aa27b9bf6e7d7eae550 (patch)
treec6255b3480683658213642f3e570682051e3b8a6 /runtime/lua/vim/lsp/buf.lua
parent0da4d89558a05fb86186253e778510cfd859caea (diff)
downloadrneovim-6e68fed37441096bf9fd2aa27b9bf6e7d7eae550.tar.gz
rneovim-6e68fed37441096bf9fd2aa27b9bf6e7d7eae550.tar.bz2
rneovim-6e68fed37441096bf9fd2aa27b9bf6e7d7eae550.zip
feat(lsp): multi-client support for signature_help
Signatures can be cycled using `<C-s>` when the user enters the floating window.
Diffstat (limited to 'runtime/lua/vim/lsp/buf.lua')
-rw-r--r--runtime/lua/vim/lsp/buf.lua116
1 files changed, 82 insertions, 34 deletions
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 152226a757..6d7597c5ff 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -258,6 +258,33 @@ function M.implementation(opts)
get_locations(ms.textDocument_implementation, opts)
end
+--- @param results table<integer,{err: lsp.ResponseError?, result: lsp.SignatureHelp?}>
+local function process_signature_help_results(results)
+ local signatures = {} --- @type [vim.lsp.Client,lsp.SignatureInformation][]
+
+ -- Pre-process results
+ for client_id, r in pairs(results) do
+ local err = r.err
+ local client = assert(lsp.get_client_by_id(client_id))
+ if err then
+ vim.notify(
+ client.name .. ': ' .. tostring(err.code) .. ': ' .. err.message,
+ vim.log.levels.ERROR
+ )
+ api.nvim_command('redraw')
+ else
+ local result = r.result --- @type lsp.SignatureHelp
+ if result and result.signatures and result.signatures[1] then
+ for _, sig in ipairs(result.signatures) do
+ signatures[#signatures + 1] = { client, sig }
+ end
+ end
+ end
+ end
+
+ return signatures
+end
+
local sig_help_ns = api.nvim_create_namespace('vim_lsp_signature_help')
--- @class vim.lsp.buf.signature_help.Opts : vim.lsp.util.open_floating_preview.Opts
@@ -270,58 +297,79 @@ local sig_help_ns = api.nvim_create_namespace('vim_lsp_signature_help')
function M.signature_help(config)
local method = ms.textDocument_signatureHelp
- config = config or {}
+ config = config and vim.deepcopy(config) or {}
config.focus_id = method
- lsp.buf_request(0, method, client_positional_params(), function(err, result, ctx)
- local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
-
- if err then
- vim.notify(
- client.name .. ': ' .. tostring(err.code) .. ': ' .. err.message,
- vim.log.levels.ERROR
- )
- api.nvim_command('redraw')
- return
- end
-
+ lsp.buf_request_all(0, method, 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
- -- 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 or not result.signatures or not result.signatures[1] then
+ local signatures = process_signature_help_results(results)
+
+ if not next(signatures) then
if config.silent ~= true then
print('No signature help available')
end
return
end
- local triggers =
- vim.tbl_get(client.server_capabilities, 'signatureHelpProvider', 'triggerCharacters')
-
local ft = vim.bo[ctx.bufnr].filetype
- local lines, hl = util.convert_signature_help_to_markdown_lines(result, ft, triggers)
- if not lines or vim.tbl_isempty(lines) then
- if config.silent ~= true then
- print('No signature help available')
+ local total = #signatures
+ local idx = 0
+
+ --- @param update_win? integer
+ local function show_signature(update_win)
+ idx = (idx % total) + 1
+ local client, result = signatures[idx][1], signatures[idx][2]
+ --- @type string[]?
+ local triggers =
+ vim.tbl_get(client.server_capabilities, 'signatureHelpProvider', 'triggerCharacters')
+ local lines, hl =
+ util.convert_signature_help_to_markdown_lines({ signatures = { result } }, ft, triggers)
+ if not lines then
+ return
end
- return
+
+ local sfx = total > 1 and string.format(' (%d/%d) (<C-s> to cycle)', idx, total) or ''
+ local title = string.format('Signature Help: %s%s', client.name, sfx)
+ if config.border then
+ config.title = title
+ else
+ table.insert(lines, 1, '# ' .. title)
+ if hl then
+ hl[1] = hl[1] + 1
+ hl[3] = hl[3] + 1
+ end
+ end
+
+ config._update_win = update_win
+
+ local buf, win = util.open_floating_preview(lines, 'markdown', config)
+
+ if hl then
+ vim.api.nvim_buf_clear_namespace(buf, sig_help_ns, 0, -1)
+ vim.hl.range(
+ buf,
+ sig_help_ns,
+ 'LspSignatureActiveParameter',
+ { hl[1], hl[2] },
+ { hl[3], hl[4] }
+ )
+ end
+ return buf, win
end
- local fbuf = util.open_floating_preview(lines, 'markdown', config)
+ local fbuf, fwin = show_signature()
- -- Highlight the active parameter.
- if hl then
- vim.hl.range(
- fbuf,
- sig_help_ns,
- 'LspSignatureActiveParameter',
- { hl[1], hl[2] },
- { hl[3], hl[4] }
- )
+ if total > 1 then
+ vim.keymap.set('n', '<C-s>', function()
+ show_signature(fwin)
+ end, {
+ buffer = fbuf,
+ desc = 'Cycle next signature',
+ })
end
end)
end