Make triggering signature help more robust

main
Bryan 2024-12-20 08:13:15 -06:00
parent 2b21a2aa51
commit 867ac5b1df
1 changed files with 640 additions and 612 deletions

View File

@ -47,7 +47,7 @@ function SignatureHelp.new()
max_width = 40, max_width = 40,
floating_window_above_cur_line = true, floating_window_above_cur_line = true,
preview_parameters = true, preview_parameters = true,
debounce_time = 30, debounce_time = 100,
dock_toggle_key = "<Leader>sd", dock_toggle_key = "<Leader>sd",
toggle_key = "<C-k>", toggle_key = "<C-k>",
dock_mode = { dock_mode = {
@ -70,7 +70,7 @@ local function signature_index_comment(index)
if #vim.bo.commentstring ~= 0 then if #vim.bo.commentstring ~= 0 then
return vim.bo.commentstring:format(index) return vim.bo.commentstring:format(index)
else else
return '(' .. index .. ')' return "(" .. index .. ")"
end end
end end
@ -92,45 +92,34 @@ local function markdown_for_signature_list(signatures, config)
end end
table.insert(labels, #lines + 1) table.insert(labels, #lines + 1)
local suffix = number and (' ' .. signature_index_comment(index)) or '' local suffix = number and (" " .. signature_index_comment(index)) or ""
local padding = config.render_style.align_icons local padding = config.render_style.align_icons and string.rep(" ", max_method_len - #signature.label) or " "
and string.rep(" ", max_method_len - #signature.label)
or " "
-- Method signature with syntax highlighting -- Method signature with syntax highlighting
table.insert(lines, string.format("```%s", vim.bo.filetype)) table.insert(lines, string.format("```%s", vim.bo.filetype))
-- table.insert(lines, string.format("%s Method:", config.icons.method)) -- table.insert(lines, string.format("%s Method:", config.icons.method))
table.insert(lines, string.format("%s %s%s%s", table.insert(lines, string.format("%s %s%s%s", config.icons.method, signature.label, padding, suffix))
config.icons.method,
signature.label,
padding,
suffix
))
table.insert(lines, "```") table.insert(lines, "```")
-- Parameters section -- -- Parameters section
-- if signature.parameters and #signature.parameters > 0 then -- if signature.parameters and #signature.parameters > 0 then
-- if config.render_style.separator then -- if config.render_style.separator then
-- table.insert(lines, string.rep("─", 40)) -- table.insert(lines, string.rep("─", 40))
-- end -- end
-- table.insert(lines, string.format("%s Parameters:", config.icons.parameter)) -- table.insert(lines, string.format("%s Parameters:", config.icons.parameter))
-- for _, param in ipairs(signature.parameters) do -- for _, param in ipairs(signature.parameters) do
-- local param_doc = param.documentation and -- local param_doc = param.documentation and string.format(" - %s", vim.inspect(param.documentation))
-- string.format(" - %s", param.documentation.value or param.documentation) or "" -- table.insert(lines, string.format(" • %s = %s", vim.inspect(param.label), param_doc))
-- table.insert(lines, string.format(" • %s = %s", param.label, param_doc))
-- end -- end
-- end -- end
-- Documentation section -- Documentation section
if signature.documentation then if signature.documentation then
if config.render_style.separator then if config.render_style.separator then
table.insert(lines, string.rep("-", 40)) table.insert(lines, string.rep("", 40))
end end
table.insert(lines, string.format("%s Documentation:", config.icons.documentation)) table.insert(lines, string.format("%s Documentation:", config.icons.documentation))
local doc_lines = vim.split( local doc_lines = vim.split(signature.documentation.value or signature.documentation, "\n")
signature.documentation.value or signature.documentation,
"\n"
)
for _, line in ipairs(doc_lines) do for _, line in ipairs(doc_lines) do
table.insert(lines, " " .. line) table.insert(lines, " " .. line)
end end
@ -176,13 +165,12 @@ function SignatureHelp:create_float_window(contents)
self.win = api.nvim_open_win(self.buf, false, win_config) self.win = api.nvim_open_win(self.buf, false, win_config)
end end
api.nvim_buf_set_option(self.buf, "modifiable", true) vim.bo[self.buf].modifiable = true
api.nvim_buf_set_lines(self.buf, 0, -1, false, contents) api.nvim_buf_set_lines(self.buf, 0, -1, false, contents)
api.nvim_buf_set_option(self.buf, "modifiable", false) vim.bo[self.buf].modifiable = false
api.nvim_win_set_option(self.win, "foldenable", false) vim.wo[self.win][self.buf].foldenable = false
api.nvim_win_set_option(self.win, "wrap", true) vim.wo[self.win][self.buf].wrap = true
api.nvim_win_set_option(self.win, "winblend", self.config.winblend) vim.wo[self.win][self.buf].winblend = self.config.winblend
self.visible = true self.visible = true
end end
@ -206,6 +194,7 @@ function SignatureHelp:hide()
self.buf = nil self.buf = nil
end end
self.current_signatures = nil
self.visible = false self.visible = false
-- Restore focus -- Restore focus
@ -224,26 +213,29 @@ function SignatureHelp:find_parameter_range(signature_str, parameter_label)
local escaped_label = vim.pesc(parameter_label) local escaped_label = vim.pesc(parameter_label)
-- Look for the parameter with word boundaries -- Look for the parameter with word boundaries
local pattern = [[\b]] .. escaped_label .. [[\b]] local pattern = [[\<]] .. escaped_label .. [[\>]]
local start_pos = signature_str:find(pattern) local start_pos, end_pos = signature_str:find(pattern)
if not start_pos then if not start_pos then
-- Fallback: try finding exact match if word boundary search fails -- Fallback: try finding exact match if word boundary search fails
start_pos = signature_str:find(escaped_label) start_pos, end_pos = signature_str:find(escaped_label)
end end
if not start_pos then return nil, nil end if not start_pos then
return nil, nil
end
local end_pos = start_pos + #parameter_label - 1 -- local end_pos = start_pos + #parameter_label
return start_pos, end_pos return start_pos, end_pos
end end
function SignatureHelp:extract_default_value(param_info) function SignatureHelp:extract_default_value(param_info)
-- Check if parameter has documentation that might contain default value -- Check if parameter has documentation that might contain default value
if not param_info.documentation then return nil end if not param_info.documentation then
return nil
end
local doc = type(param_info.documentation) == "string" local doc = type(param_info.documentation) == "string" and param_info.documentation
and param_info.documentation
or param_info.documentation.value or param_info.documentation.value
-- Look for common default value patterns -- Look for common default value patterns
@ -255,14 +247,18 @@ function SignatureHelp:extract_default_value(param_info)
for _, pattern in ipairs(patterns) do for _, pattern in ipairs(patterns) do
local default = doc:match(pattern) local default = doc:match(pattern)
if default then return default end if default then
return default
end
end end
return nil return nil
end end
function SignatureHelp:set_active_parameter_highlights(active_parameter, signatures, labels) function SignatureHelp:set_active_parameter_highlights(active_parameter, signatures, labels)
if not self.buf or not api.nvim_buf_is_valid(self.buf) then return end if not self.buf or not api.nvim_buf_is_valid(self.buf) then
return
end
-- Clear existing highlights -- Clear existing highlights
api.nvim_buf_clear_namespace(self.buf, -1, 0, -1) api.nvim_buf_clear_namespace(self.buf, -1, 0, -1)
@ -277,12 +273,25 @@ function SignatureHelp:set_active_parameter_highlights(active_parameter, signatu
local signature_str = signature.label local signature_str = signature.label
local start_pos, end_pos = self:find_parameter_range(signature_str, label) local start_pos, end_pos = self:find_parameter_range(signature_str, label)
if start_pos and end_pos then if start_pos and end_pos then
api.nvim_buf_add_highlight(self.buf, -1, "LspSignatureActiveParameter", labels[index], start_pos, api.nvim_buf_add_highlight(
end_pos) self.buf,
-1,
"LspSignatureActiveParameter",
labels[index],
start_pos,
end_pos
)
end end
elseif type(label) == "table" then elseif type(label) == "table" then
local start_pos, end_pos = unpack(label) local start_pos, end_pos = unpack(label)
api.nvim_buf_add_highlight(self.buf, -1, "LspSignatureActiveParameter", labels[index], start_pos + 5, end_pos + 5) api.nvim_buf_add_highlight(
self.buf,
-1,
"LspSignatureActiveParameter",
labels[index],
start_pos + 6,
end_pos + 6
)
end end
end end
end end
@ -322,14 +331,7 @@ function SignatureHelp:highlight_icons()
local line = api.nvim_buf_get_lines(self.buf, line_num, line_num + 1, false)[1] local line = api.nvim_buf_get_lines(self.buf, line_num, line_num + 1, false)[1]
local start_col = line:find(vim.pesc(icon)) local start_col = line:find(vim.pesc(icon))
if start_col then if start_col then
api.nvim_buf_add_highlight( api.nvim_buf_add_highlight(self.buf, -1, hl_group, line_num, start_col - 1, start_col - 1 + #icon)
self.buf,
-1,
hl_group,
line_num,
start_col - 1,
start_col - 1 + #icon
)
end end
line_num = line_num + 1 line_num = line_num + 1
end end
@ -347,8 +349,11 @@ function SignatureHelp:display(result)
local current_buf = api.nvim_get_current_buf() local current_buf = api.nvim_get_current_buf()
-- Prevent duplicate displays of identical content -- Prevent duplicate displays of identical content
if self.current_signatures and vim.deep_equal(result.signatures, self.current_signatures) and if
result.activeParameter == self.current_active_parameter then self.current_signatures
and vim.deep_equal(result.signatures, self.current_signatures)
and result.activeParameter == self.current_active_parameter
then
return return
end end
@ -406,7 +411,10 @@ function SignatureHelp:apply_treesitter_highlighting()
end end
function SignatureHelp:trigger() function SignatureHelp:trigger()
if not self.enabled then return end if not self.enabled then
return
end
vim.notify("trigger")
local params = vim.lsp.util.make_position_params() local params = vim.lsp.util.make_position_params()
vim.lsp.buf_request(0, "textDocument/signatureHelp", params, function(err, result, _, _) vim.lsp.buf_request(0, "textDocument/signatureHelp", params, function(err, result, _, _)
@ -454,26 +462,31 @@ function SignatureHelp:setup_autocmds()
local group = api.nvim_create_augroup("LspSignatureHelp", { clear = true }) local group = api.nvim_create_augroup("LspSignatureHelp", { clear = true })
local function debounced_trigger() local function debounced_trigger()
-- vim.defer_fn(function()
-- self:trigger()
-- end, 30)
if self.timer then if self.timer then
vim.fn.timer_stop(self.timer) vim.fn.timer_stop(self.timer)
end end
self.timer = vim.fn.timer_start(30, function() self.timer = vim.fn.timer_start(self.debounce_time, function()
self:trigger() self:trigger()
end) end)
end end
api.nvim_create_autocmd({ "CursorMovedI", "TextChangedI" }, { api.nvim_create_autocmd({ "InsertEnter", "CursorMovedI" }, {
group = group, group = group,
callback = function() callback = function()
local cmp_visible = require("cmp").visible() -- vim.notify("trigger")
if cmp_visible then
self:hide() -- local cmp_visible = require("cmp").visible()
elseif vim.fn.pumvisible() == 0 then -- if cmp_visible then
-- self:hide()
-- elseif vim.fn.pumvisible() == 0 then
debounced_trigger() debounced_trigger()
else -- else
self:hide() -- self:hide()
end -- end
end end,
}) })
api.nvim_create_autocmd({ "CursorMoved" }, { api.nvim_create_autocmd({ "CursorMoved" }, {
@ -482,15 +495,15 @@ function SignatureHelp:setup_autocmds()
if self.normal_mode_active then if self.normal_mode_active then
debounced_trigger() debounced_trigger()
end end
end end,
}) })
api.nvim_create_autocmd({ "InsertLeave", "BufHidden", "BufLeave" }, { api.nvim_create_autocmd({ "InsertLeave" }, {
group = group, group = group,
callback = function() callback = function()
self:hide() self:hide()
self.normal_mode_active = false self.normal_mode_active = false
end end,
}) })
api.nvim_create_autocmd("LspAttach", { api.nvim_create_autocmd("LspAttach", {
@ -499,7 +512,7 @@ function SignatureHelp:setup_autocmds()
vim.defer_fn(function() vim.defer_fn(function()
self:check_capability() self:check_capability()
end, 100) end, 100)
end end,
}) })
api.nvim_create_autocmd("ColorScheme", { api.nvim_create_autocmd("ColorScheme", {
@ -507,9 +520,13 @@ function SignatureHelp:setup_autocmds()
callback = function() callback = function()
if self.visible then if self.visible then
self:apply_treesitter_highlighting() self:apply_treesitter_highlighting()
self:set_active_parameter_highlights(self.current_signatures.activeParameter, self.current_signatures, {}) self:set_active_parameter_highlights(
end self.current_signatures.activeParameter,
self.current_signatures,
{}
)
end end
end,
}) })
end end
@ -541,9 +558,7 @@ function SignatureHelp:create_dock_window()
local padding = self.config.dock_mode.padding local padding = self.config.dock_mode.padding
local dock_width = win_width - (padding * 2) local dock_width = win_width - (padding * 2)
local row = self.config.dock_mode.position == "bottom" local row = self.config.dock_mode.position == "bottom" and win_height - dock_height - padding or padding
and win_height - dock_height - padding
or padding
-- Create dock window with enhanced config -- Create dock window with enhanced config
self.dock_win = api.nvim_open_win(self.dock_buf, false, { self.dock_win = api.nvim_open_win(self.dock_buf, false, {
@ -575,11 +590,21 @@ function SignatureHelp:create_dock_window()
-- Set up dock window keymaps -- Set up dock window keymaps
local dock_buf_keymaps = { local dock_buf_keymaps = {
["q"] = function() self:hide() end, ["q"] = function()
["<Esc>"] = function() self:hide() end, self:hide()
["<C-c>"] = function() self:hide() end, end,
["<C-n>"] = function() self:next_signature() end, ["<Esc>"] = function()
["<C-p>"] = function() self:prev_signature() end, self:hide()
end,
["<C-c>"] = function()
self:hide()
end,
["<C-n>"] = function()
self:next_signature()
end,
["<C-p>"] = function()
self:prev_signature()
end,
} }
for key, func in pairs(dock_buf_keymaps) do for key, func in pairs(dock_buf_keymaps) do
@ -598,7 +623,9 @@ end
function SignatureHelp:close_dock_window() function SignatureHelp:close_dock_window()
-- Fast check for existing dock window -- Fast check for existing dock window
if not self.dock_win_id then return end if not self.dock_win_id then
return
end
-- Try to find window by ID -- Try to find window by ID
local wins = api.nvim_list_wins() local wins = api.nvim_list_wins()
@ -622,7 +649,9 @@ end
-- Add navigation between multiple signatures -- Add navigation between multiple signatures
function SignatureHelp:next_signature() function SignatureHelp:next_signature()
if not self.current_signatures then return end if not self.current_signatures then
return
end
self.current_signature_idx = (self.current_signature_idx or 0) + 1 self.current_signature_idx = (self.current_signature_idx or 0) + 1
if self.current_signature_idx > #self.current_signatures then if self.current_signature_idx > #self.current_signatures then
self.current_signature_idx = 1 self.current_signature_idx = 1
@ -630,12 +659,14 @@ function SignatureHelp:next_signature()
self:display({ self:display({
signatures = self.current_signatures, signatures = self.current_signatures,
activeParameter = self.current_active_parameter, activeParameter = self.current_active_parameter,
activeSignature = self.current_signature_idx - 1 activeSignature = self.current_signature_idx - 1,
}) })
end end
function SignatureHelp:prev_signature() function SignatureHelp:prev_signature()
if not self.current_signatures then return end if not self.current_signatures then
return
end
self.current_signature_idx = (self.current_signature_idx or 1) - 1 self.current_signature_idx = (self.current_signature_idx or 1) - 1
if self.current_signature_idx < 1 then if self.current_signature_idx < 1 then
self.current_signature_idx = #self.current_signatures self.current_signature_idx = #self.current_signatures
@ -643,7 +674,7 @@ function SignatureHelp:prev_signature()
self:display({ self:display({
signatures = self.current_signatures, signatures = self.current_signatures,
activeParameter = self.current_active_parameter, activeParameter = self.current_active_parameter,
activeSignature = self.current_signature_idx - 1 activeSignature = self.current_signature_idx - 1,
}) })
end end
@ -675,7 +706,7 @@ function SignatureHelp:toggle_dock_mode()
if current_sigs then if current_sigs then
self:display({ self:display({
signatures = current_sigs, signatures = current_sigs,
activeParameter = current_active activeParameter = current_active,
}) })
end end
@ -712,10 +743,7 @@ function M.setup(opts)
local signature_help = SignatureHelp.new() local signature_help = SignatureHelp.new()
-- Deep merge user config with defaults -- Deep merge user config with defaults
signature_help.config = vim.tbl_deep_extend("force", signature_help.config = vim.tbl_deep_extend("force", signature_help._default_config, opts)
signature_help._default_config,
opts
)
-- Setup highlights with user config -- Setup highlights with user config
local function setup_highlights() local function setup_highlights()