Make signature and documentation seperate. Signature opens automatically and documentation
opens by calling the open documentation function which can be assigned to keys (ie. <C-S-k>)main
parent
9b4a44c441
commit
3a2a09ea38
|
|
@ -21,11 +21,14 @@ local function get_parameter_label(result)
|
||||||
return ""
|
return ""
|
||||||
end
|
end
|
||||||
|
|
||||||
if activeParameter > #signature.parameters then
|
if activeParameter >= #signature.parameters then
|
||||||
activeParameter = 0
|
activeParameter = #signature.parameters - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if signature.parameters[activeParameter + 1] == nil then
|
||||||
|
return ""
|
||||||
end
|
end
|
||||||
|
|
||||||
-- local nextParameter = signature.parameters[activeParameter + 1]
|
|
||||||
local param = signature.parameters[activeParameter + 1].label
|
local param = signature.parameters[activeParameter + 1].label
|
||||||
local param_str
|
local param_str
|
||||||
-- Handle both string and table parameter labels
|
-- Handle both string and table parameter labels
|
||||||
|
|
@ -34,7 +37,7 @@ local function get_parameter_label(result)
|
||||||
local e = param[2]
|
local e = param[2]
|
||||||
param_str = string.sub(signature.label, s, e)
|
param_str = string.sub(signature.label, s, e)
|
||||||
elseif type(param) == "string" then
|
elseif type(param) == "string" then
|
||||||
param_str = label
|
param_str = signature.label
|
||||||
end
|
end
|
||||||
|
|
||||||
return param_str
|
return param_str
|
||||||
|
|
@ -86,9 +89,9 @@ local function _wrap_lines(str, maxlen, opts)
|
||||||
return lines
|
return lines
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param signature_help table
|
--@param signature_help string[]
|
||||||
---@param maxlen integer
|
--@param maxlen integer
|
||||||
local function convert_signature_help_to_lines(signature_help, maxlen)
|
local function make_signature_lines(signature_help, maxlen)
|
||||||
if not signature_help.signatures then
|
if not signature_help.signatures then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
@ -97,6 +100,7 @@ local function convert_signature_help_to_lines(signature_help, maxlen)
|
||||||
if active_signature >= #signature_help.signatures or active_signature < 0 then
|
if active_signature >= #signature_help.signatures or active_signature < 0 then
|
||||||
active_signature = 0
|
active_signature = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
local signature = signature_help.signatures[active_signature + 1]
|
local signature = signature_help.signatures[active_signature + 1]
|
||||||
if not signature then
|
if not signature then
|
||||||
return
|
return
|
||||||
|
|
@ -111,27 +115,28 @@ local function convert_signature_help_to_lines(signature_help, maxlen)
|
||||||
return wrapped_lines
|
return wrapped_lines
|
||||||
end
|
end
|
||||||
|
|
||||||
local function apply_treesitter_highlighting(buf, syntax)
|
local function make_doc_lines(result, ft)
|
||||||
if not api.nvim_buf_is_valid(buf) then
|
local active_signature = result.activeSignature or 0
|
||||||
|
local signature = result.signatures[active_signature + 1]
|
||||||
|
local doc_lines = {}
|
||||||
|
if not signature then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
if signature.documentation then
|
||||||
if not pcall(require, "nvim-treesitter") then
|
-- if LSP returns plain string, we treat it as plaintext. This avoids
|
||||||
return
|
-- special characters like underscore or similar from being interpreted
|
||||||
|
-- as markdown font modifiers
|
||||||
|
if type(signature.documentation) == "string" then
|
||||||
|
signature.documentation = { kind = "plaintext", value = signature.documentation }
|
||||||
end
|
end
|
||||||
|
vim.lsp.util.convert_input_to_markdown_lines(signature.documentation, doc_lines)
|
||||||
-- Store current window and buffer
|
end
|
||||||
local current_win = api.nvim_get_current_win()
|
for _, parameter in ipairs(signature.parameters) do
|
||||||
local current_buf = api.nvim_get_current_buf()
|
if parameter.documentation then
|
||||||
|
vim.lsp.util.convert_input_to_markdown_lines(parameter.documentation, doc_lines)
|
||||||
-- Apply treesitter highlighting
|
end
|
||||||
pcall(function()
|
end
|
||||||
require("nvim-treesitter.highlight").attach(buf, syntax)
|
return doc_lines
|
||||||
end)
|
|
||||||
|
|
||||||
-- Restore focus
|
|
||||||
api.nvim_set_current_win(current_win)
|
|
||||||
api.nvim_set_current_buf(current_buf)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local _make_floating_popup_size = function(contents, opts)
|
local _make_floating_popup_size = function(contents, opts)
|
||||||
|
|
@ -147,7 +152,7 @@ local _make_floating_popup_size = function(contents, opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- local border_width = get_border_size(opts).width
|
-- local border_width = get_border_size(opts).width
|
||||||
local border_width = 2 --TODO: do we need to deal with this parametrically?
|
local border_width = 2 --TODO: do we need to deal with this programmatically?
|
||||||
local screen_width = api.nvim_win_get_width(0)
|
local screen_width = api.nvim_win_get_width(0)
|
||||||
width = math.min(width, screen_width)
|
width = math.min(width, screen_width)
|
||||||
width = math.min(width, max_width)
|
width = math.min(width, max_width)
|
||||||
|
|
@ -179,133 +184,188 @@ end
|
||||||
---@param content table window content
|
---@param content table window content
|
||||||
---@param opts table window options
|
---@param opts table window options
|
||||||
---@returns (table) Options
|
---@returns (table) Options
|
||||||
local function _make_floating_popup_options(content, opts)
|
local function _make_floating_popup_options(sig_content, doc_content, opts)
|
||||||
local width, height = _make_floating_popup_size(content, opts)
|
local sig_width, sig_height = _make_floating_popup_size(sig_content, opts)
|
||||||
|
local doc_width, doc_height = _make_floating_popup_size(doc_content, opts)
|
||||||
|
local border_height = 2 --TODO: get this from opts
|
||||||
|
|
||||||
local offset_y = opts.offset_y or 0
|
local offset_y = opts.offset_y or 0
|
||||||
local offset_x = opts.offset_x or 0
|
local offset_x = opts.offset_x or 0
|
||||||
|
|
||||||
local anchor_bias = opts.anchor_bias or "auto"
|
local anchor_bias = opts.anchor_bias or "auto"
|
||||||
local relative = opts.relative or "cursor"
|
local relative = "win"
|
||||||
local anchor = ""
|
local sig_anchor
|
||||||
local row, col
|
local doc_anchor
|
||||||
|
local sig_row, sig_col
|
||||||
|
local doc_row, doc_col
|
||||||
|
local curs_row = vim.fn.winline()
|
||||||
|
local curs_col = vim.fn.wincol()
|
||||||
|
|
||||||
local lines_above = opts.relative == "mouse" and vim.fn.getmousepos().line - 1 or vim.fn.winline() - 1
|
local lines_above = curs_row - 1
|
||||||
local lines_below = vim.fn.winheight(0) - lines_above
|
local lines_below = vim.fn.winheight(0) - lines_above
|
||||||
|
|
||||||
if
|
if -- figure out signature anchor and height
|
||||||
lines_above < height
|
lines_above < sig_height + border_height
|
||||||
or (anchor_bias == "below" and lines_below > height + offset_y)
|
or (anchor_bias == "below" and lines_below > sig_height + border_height + offset_y)
|
||||||
or (anchor_bias == "auto" and lines_below > lines_above)
|
or (anchor_bias == "auto" and lines_below > lines_above)
|
||||||
then
|
then
|
||||||
anchor = anchor .. "N"
|
sig_anchor = "N"
|
||||||
height = math.min(lines_below - offset_y, height)
|
sig_height = math.min(lines_below - offset_y, sig_height)
|
||||||
row = 1 + offset_y
|
sig_row = curs_row + offset_y
|
||||||
else
|
else
|
||||||
anchor = anchor .. "S"
|
sig_anchor = "S"
|
||||||
height = math.min(lines_above - offset_y, height)
|
sig_height = math.min(lines_above - offset_y, sig_height)
|
||||||
row = 0 - offset_y
|
sig_row = curs_row - 1 - offset_y
|
||||||
end
|
end
|
||||||
|
|
||||||
local wincol = opts.relative == "mouse" and vim.fn.getmousepos().column or vim.fn.wincol()
|
if sig_anchor == "N" then
|
||||||
|
lines_below = lines_below - (sig_height + border_height) --new lines_below including sig
|
||||||
if wincol + width + offset_x <= vim.o.columns then
|
|
||||||
anchor = anchor .. "W"
|
|
||||||
col = 0 - wincol
|
|
||||||
else
|
else
|
||||||
anchor = anchor .. "E"
|
lines_above = lines_above - (sig_height + border_height) --new lines_above including sig
|
||||||
col = 1 - wincol
|
|
||||||
end
|
end
|
||||||
|
|
||||||
offset_x = opts.offset_x or 0
|
if -- figure out documentation anchor and height
|
||||||
|
lines_above < doc_height + border_height
|
||||||
|
or (anchor_bias == "below" and lines_below > doc_height + border_height)
|
||||||
|
or (anchor_bias == "auto" and lines_below > lines_above)
|
||||||
|
then
|
||||||
|
doc_anchor = "N"
|
||||||
|
doc_height = math.min(lines_below, doc_height)
|
||||||
|
if sig_anchor == "N" then --docs and sigs below
|
||||||
|
doc_row = curs_row + offset_y + (sig_height + border_height) - 1
|
||||||
|
else --docs above sigs below
|
||||||
|
doc_row = curs_row - 1 - offset_y
|
||||||
|
end
|
||||||
|
else
|
||||||
|
doc_anchor = "S"
|
||||||
|
doc_height = math.min(lines_above, doc_height)
|
||||||
|
if sig_anchor == "S" then --docs and sigs above
|
||||||
|
doc_row = curs_row - (offset_y + sig_height + border_height)
|
||||||
|
else --docs below sigs above
|
||||||
|
doc_row = curs_row - 1 - offset_y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local wincol = vim.fn.wincol()
|
||||||
|
if wincol + sig_width + offset_x <= vim.o.columns then
|
||||||
|
sig_anchor = sig_anchor .. "W"
|
||||||
|
doc_anchor = doc_anchor .. "W"
|
||||||
|
sig_col = curs_col - wincol
|
||||||
|
doc_col = curs_col - wincol
|
||||||
|
else
|
||||||
|
sig_anchor = sig_anchor .. "E"
|
||||||
|
doc_anchor = doc_anchor .. "E"
|
||||||
|
sig_col = curs_col + 1 - wincol
|
||||||
|
doc_col = curs_col + 1 - wincol
|
||||||
|
end
|
||||||
local first_col = vim.fn.getwininfo(vim.fn.win_getid())[1].textoff
|
local first_col = vim.fn.getwininfo(vim.fn.win_getid())[1].textoff
|
||||||
|
|
||||||
return {
|
return { --signature window options
|
||||||
anchor = anchor,
|
anchor = sig_anchor,
|
||||||
row = row,
|
row = sig_row,
|
||||||
col = col + first_col + offset_x,
|
col = sig_col + first_col + offset_x,
|
||||||
width = width,
|
width = sig_width,
|
||||||
height = height,
|
height = sig_height,
|
||||||
focusable = opts.focusable,
|
focusable = opts.focusable,
|
||||||
relative = relative,
|
relative = relative,
|
||||||
style = "minimal",
|
style = "minimal",
|
||||||
border = opts.border or "rounded",
|
border = opts.border or "rounded",
|
||||||
zindex = opts.zindex or 50,
|
zindex = opts.zindex or 50,
|
||||||
|
-- winblend = opts.winblend or 10,
|
||||||
|
}, { --documentation window options
|
||||||
|
anchor = doc_anchor,
|
||||||
|
row = doc_row,
|
||||||
|
col = doc_col + first_col + offset_x,
|
||||||
|
width = doc_width,
|
||||||
|
height = doc_height,
|
||||||
|
focusable = opts.focusable,
|
||||||
|
relative = relative,
|
||||||
|
style = "minimal",
|
||||||
|
border = opts.border or "rounded",
|
||||||
|
zindex = opts.zindex or 50,
|
||||||
|
-- winblend = opts.winblend or 10,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local function create_float_window(content, syntax, opts)
|
---@param result string[] signature help result
|
||||||
|
---@param syntax string syntax language for highlighting. i.e. "lua" or "markdown"
|
||||||
|
---@param opts table window options
|
||||||
|
---@return function function to open signature window
|
||||||
|
---@return function function to open documentation window
|
||||||
|
local function create_float_windows(result, syntax, opts)
|
||||||
local npcall = vim.F.npcall
|
local npcall = vim.F.npcall
|
||||||
vim.validate({
|
vim.validate({
|
||||||
contents = { content, "t" },
|
result = { result, "t" },
|
||||||
syntax = { syntax, "s", true },
|
syntax = { syntax, "s", true },
|
||||||
opts = { opts, "t", true },
|
opts = { opts, "t", true },
|
||||||
})
|
})
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
|
|
||||||
local bufnr = api.nvim_get_current_buf()
|
local bufnr = api.nvim_get_current_buf()
|
||||||
local existing_float = npcall(api.nvim_buf_get_var, bufnr, "lsp_floating_preview")
|
local existing_sig_win = npcall(api.nvim_buf_get_var, bufnr, "lsp_sig_win")
|
||||||
|
local existing_doc_win = npcall(api.nvim_buf_get_var, bufnr, "lsp_doc_win")
|
||||||
|
|
||||||
if existing_float and api.nvim_win_is_valid(existing_float) then
|
if existing_sig_win and api.nvim_win_is_valid(existing_sig_win) then
|
||||||
api.nvim_win_close(existing_float, true)
|
api.nvim_win_close(existing_sig_win, true)
|
||||||
|
end
|
||||||
|
if existing_doc_win and api.nvim_win_is_valid(existing_doc_win) then
|
||||||
|
api.nvim_win_close(existing_doc_win, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Create the buffer
|
-- Create the buffers
|
||||||
local floating_bufnr = api.nvim_create_buf(false, true)
|
local sig_bufnr = api.nvim_create_buf(false, true)
|
||||||
|
local doc_bufnr = api.nvim_create_buf(false, true)
|
||||||
|
|
||||||
if syntax then
|
syntax = syntax or "text"
|
||||||
vim.bo[floating_bufnr].syntax = syntax
|
vim.bo[sig_bufnr].syntax = syntax
|
||||||
vim.bo[floating_bufnr].ft = syntax
|
vim.bo[sig_bufnr].ft = syntax
|
||||||
vim.treesitter.start(floating_bufnr)
|
vim.treesitter.start(sig_bufnr)
|
||||||
end
|
vim.bo[doc_bufnr].syntax = "markdown"
|
||||||
api.nvim_buf_set_lines(floating_bufnr, 0, -1, true, content)
|
vim.bo[doc_bufnr].ft = "markdown"
|
||||||
|
vim.treesitter.start(doc_bufnr)
|
||||||
|
|
||||||
local float_options = _make_floating_popup_options(content, opts)
|
local sig_content = make_signature_lines(result, opts.max_width)
|
||||||
local floating_winnr = api.nvim_open_win(floating_bufnr, false, float_options)
|
local doc_content = make_doc_lines(result, syntax)
|
||||||
|
api.nvim_buf_set_lines(sig_bufnr, 0, -1, true, sig_content)
|
||||||
|
api.nvim_buf_set_lines(doc_bufnr, 0, -1, true, doc_content)
|
||||||
|
|
||||||
vim.wo[floating_winnr].conceallevel = 2
|
local sig_float_options, doc_float_options = _make_floating_popup_options(sig_content, doc_content, opts)
|
||||||
vim.wo[floating_winnr].foldenable = false
|
return function()
|
||||||
vim.bo[floating_bufnr].modifiable = false
|
local sig_winnr = api.nvim_open_win(sig_bufnr, false, sig_float_options)
|
||||||
vim.bo[floating_bufnr].bufhidden = "wipe"
|
vim.wo[sig_winnr].conceallevel = 2
|
||||||
|
vim.wo[sig_winnr].foldenable = false
|
||||||
api.nvim_buf_set_keymap(
|
vim.bo[sig_bufnr].modifiable = false
|
||||||
floating_bufnr,
|
vim.bo[sig_bufnr].bufhidden = "hide"
|
||||||
"n",
|
-- save focus_id
|
||||||
"q",
|
api.nvim_buf_set_var(bufnr, "lsp_sig_win", sig_winnr)
|
||||||
"<cmd>bdelete<cr>",
|
return sig_bufnr, sig_winnr, sig_content
|
||||||
{ silent = true, noremap = true, nowait = true }
|
end, function()
|
||||||
)
|
local doc_winnr = api.nvim_open_win(doc_bufnr, false, doc_float_options)
|
||||||
|
vim.wo[doc_winnr].conceallevel = 2
|
||||||
|
vim.wo[doc_winnr].foldenable = false
|
||||||
|
vim.bo[doc_bufnr].modifiable = false
|
||||||
|
vim.bo[doc_bufnr].bufhidden = "hide"
|
||||||
|
|
||||||
-- save focus_id
|
-- save focus_id
|
||||||
api.nvim_buf_set_var(bufnr, "lsp_floating_preview", floating_winnr)
|
api.nvim_buf_set_var(doc_bufnr, "lsp_doc_win", doc_winnr)
|
||||||
|
return doc_bufnr, doc_winnr
|
||||||
return floating_bufnr, floating_winnr
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function close_float_window(win, buf)
|
local function close_float_window(winnr)
|
||||||
-- Store current window and buffer
|
if winnr and api.nvim_win_is_valid(winnr) then
|
||||||
local current_win = api.nvim_get_current_win()
|
pcall(api.nvim_win_close, winnr, true)
|
||||||
local current_buf = api.nvim_get_current_buf()
|
|
||||||
|
|
||||||
if win and api.nvim_win_is_valid(win) then
|
|
||||||
pcall(api.nvim_win_close, win, true)
|
|
||||||
end
|
end
|
||||||
if buf and api.nvim_buf_is_valid(buf) then
|
end
|
||||||
pcall(api.nvim_buf_delete, buf, { force = true })
|
|
||||||
end
|
|
||||||
win = nil
|
|
||||||
buf = nil
|
|
||||||
|
|
||||||
-- Restore focus
|
local function delete_buffer(bufnr)
|
||||||
pcall(api.nvim_set_current_win, current_win)
|
if bufnr and api.nvim_buf_is_valid(bufnr) then
|
||||||
pcall(api.nvim_set_current_buf, current_buf)
|
pcall(api.nvim_buf_delete, bufnr, { force = true })
|
||||||
-- end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
get_parameter_label = get_parameter_label,
|
get_parameter_label = get_parameter_label,
|
||||||
convert_signature_help_to_lines = convert_signature_help_to_lines,
|
create_float_windows = create_float_windows,
|
||||||
apply_treesitter_highlighting = apply_treesitter_highlighting,
|
|
||||||
create_float_window = create_float_window,
|
|
||||||
close_float_window = close_float_window,
|
close_float_window = close_float_window,
|
||||||
|
delete_buffer = delete_buffer,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,13 @@ SignatureHelp.__index = SignatureHelp
|
||||||
|
|
||||||
function SignatureHelp.new()
|
function SignatureHelp.new()
|
||||||
local instance = setmetatable({
|
local instance = setmetatable({
|
||||||
sig_win = nil,
|
_display_sig_win = function() end, -- function to open signatures window
|
||||||
sig_buf = nil,
|
_display_doc_win = function() end, -- function to open documentation window
|
||||||
doc_win = nil,
|
sig_content = nil, -- current signature buffer content
|
||||||
doc_buf = nil,
|
sig_winnr = nil,
|
||||||
showing = false,
|
sig_bufnr = nil,
|
||||||
|
sig_win_height = nil,
|
||||||
|
sig_win_showing = false,
|
||||||
ns = nil,
|
ns = nil,
|
||||||
markid = nil,
|
markid = nil,
|
||||||
timer = nil,
|
timer = nil,
|
||||||
|
|
@ -20,6 +22,11 @@ function SignatureHelp.new()
|
||||||
enabled = false,
|
enabled = false,
|
||||||
normal_mode_active = false,
|
normal_mode_active = false,
|
||||||
current_signature_idx = nil,
|
current_signature_idx = nil,
|
||||||
|
|
||||||
|
doc_winnr = nil,
|
||||||
|
doc_bufnr = nil,
|
||||||
|
doc_win_showing = false,
|
||||||
|
doc_win_focused = false,
|
||||||
config = nil,
|
config = nil,
|
||||||
}, SignatureHelp)
|
}, SignatureHelp)
|
||||||
|
|
||||||
|
|
@ -28,8 +35,8 @@ function SignatureHelp.new()
|
||||||
number = true,
|
number = true,
|
||||||
icons = {
|
icons = {
|
||||||
parameter = "",
|
parameter = "",
|
||||||
method = "",
|
method = " ",
|
||||||
documentation = "",
|
documentation = " ",
|
||||||
},
|
},
|
||||||
colors = {
|
colors = {
|
||||||
parameter = "#86e1fc",
|
parameter = "#86e1fc",
|
||||||
|
|
@ -47,7 +54,7 @@ function SignatureHelp.new()
|
||||||
winblend = 10,
|
winblend = 10,
|
||||||
zindex = 200,
|
zindex = 200,
|
||||||
focusable = false,
|
focusable = false,
|
||||||
max_height = 10,
|
max_height = 20,
|
||||||
max_width = 80,
|
max_width = 80,
|
||||||
anchor_bias = "below", -- below|above|auto
|
anchor_bias = "below", -- below|above|auto
|
||||||
relative = "cursor",
|
relative = "cursor",
|
||||||
|
|
@ -59,7 +66,6 @@ function SignatureHelp.new()
|
||||||
auto_close = true,
|
auto_close = true,
|
||||||
preview_parameters = true,
|
preview_parameters = true,
|
||||||
debounce_time = 100,
|
debounce_time = 100,
|
||||||
toggle_key = "<C-k>",
|
|
||||||
render_style = {
|
render_style = {
|
||||||
separator = true,
|
separator = true,
|
||||||
compact = true,
|
compact = true,
|
||||||
|
|
@ -70,122 +76,28 @@ function SignatureHelp.new()
|
||||||
return instance
|
return instance
|
||||||
end
|
end
|
||||||
|
|
||||||
-- local function signature_index_comment(index)
|
|
||||||
-- if #vim.bo.commentstring ~= 0 then
|
|
||||||
-- return vim.bo.commentstring:format(index)
|
|
||||||
-- else
|
|
||||||
-- return "(" .. index .. ")"
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
|
|
||||||
-- local function markdown_for_signature_list(signatures, config)
|
|
||||||
-- local lines, labels = {}, {}
|
|
||||||
-- local number = config.number and #signatures > 1
|
|
||||||
-- local max_method_len = 0
|
|
||||||
--
|
|
||||||
-- -- First pass to calculate alignment
|
|
||||||
-- if config.render_style.align_icons then
|
|
||||||
-- for _, signature in ipairs(signatures) do
|
|
||||||
-- max_method_len = math.max(max_method_len, #signature.label)
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- for index, signature in ipairs(signatures) do
|
|
||||||
-- if not config.render_style.compact then
|
|
||||||
-- table.insert(lines, "")
|
|
||||||
-- end
|
|
||||||
-- table.insert(labels, #lines + 1)
|
|
||||||
--
|
|
||||||
-- local suffix = number and (" " .. signature_index_comment(index)) or ""
|
|
||||||
-- local padding = config.render_style.align_icons and string.rep(" ", max_method_len - #signature.label) or " "
|
|
||||||
--
|
|
||||||
-- -- Method signature with syntax highlighting
|
|
||||||
-- 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 %s%s%s", config.icons.method, signature.label, padding, suffix))
|
|
||||||
-- table.insert(lines, "```")
|
|
||||||
--
|
|
||||||
-- -- -- Parameters section
|
|
||||||
-- -- if signature.parameters and #signature.parameters > 0 then
|
|
||||||
-- -- if config.render_style.separator then
|
|
||||||
-- -- table.insert(lines, string.rep("─", 40))
|
|
||||||
-- -- end
|
|
||||||
-- -- table.insert(lines, string.format("%s Parameters:", config.icons.parameter))
|
|
||||||
-- -- for _, param in ipairs(signature.parameters) do
|
|
||||||
-- -- local param_doc = param.documentation and string.format(" - %s", vim.inspect(param.documentation))
|
|
||||||
-- -- table.insert(lines, string.format(" • %s = %s", vim.inspect(param.label), param_doc))
|
|
||||||
-- -- end
|
|
||||||
-- -- end
|
|
||||||
--
|
|
||||||
-- -- Documentation section
|
|
||||||
-- if signature.documentation then
|
|
||||||
-- if config.render_style.separator then
|
|
||||||
-- table.insert(lines, string.rep("─", 40))
|
|
||||||
-- end
|
|
||||||
-- table.insert(lines, string.format("%s Documentation:", config.icons.documentation))
|
|
||||||
-- local doc_lines = vim.split(signature.documentation.value or signature.documentation, "\n")
|
|
||||||
-- for _, line in ipairs(doc_lines) do
|
|
||||||
-- table.insert(lines, " " .. line)
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- if index ~= #signatures and config.render_style.separator then
|
|
||||||
-- table.insert(lines, string.rep("═", 40))
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
-- return lines, labels
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- function SignatureHelp:create_float_window(contents)
|
|
||||||
-- local max_width = math.min(self.config.max_width, vim.o.columns)
|
|
||||||
-- local max_height = math.min(self.config.max_height, #contents)
|
|
||||||
--
|
|
||||||
-- -- Calculate optimal position
|
|
||||||
-- local cursor = api.nvim_win_get_cursor(0)
|
|
||||||
-- local cursor_line = cursor[1]
|
|
||||||
-- local screen_line = vim.fn.screenpos(0, cursor_line, 1).row
|
|
||||||
--
|
|
||||||
-- local row_offset = self.config.floating_window_above_cur_line and -max_height - 1 or 1
|
|
||||||
-- if screen_line + row_offset < 1 then
|
|
||||||
-- row_offset = 2 -- Show below if not enough space above
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- local win_config = {
|
|
||||||
-- relative = "cursor",
|
|
||||||
-- row = row_offset - 1,
|
|
||||||
-- col = 0,
|
|
||||||
-- width = max_width,
|
|
||||||
-- height = max_height,
|
|
||||||
-- style = "minimal",
|
|
||||||
-- border = self.config.border,
|
|
||||||
-- zindex = 50, -- Ensure it's above most other floating windows
|
|
||||||
-- }
|
|
||||||
--
|
|
||||||
-- if self.win and api.nvim_win_is_valid(self.win) then
|
|
||||||
-- api.nvim_win_set_config(self.win, win_config)
|
|
||||||
-- api.nvim_win_set_buf(self.win, self.buf)
|
|
||||||
-- else
|
|
||||||
-- self.buf = api.nvim_create_buf(false, true)
|
|
||||||
-- self.win = api.nvim_open_win(self.buf, false, win_config)
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- vim.bo[self.buf].modifiable = true
|
|
||||||
-- api.nvim_buf_set_lines(self.buf, 0, -1, false, contents)
|
|
||||||
-- vim.bo[self.buf].modifiable = false
|
|
||||||
-- vim.wo[self.win][self.buf].foldenable = false
|
|
||||||
-- vim.wo[self.win][self.buf].wrap = true
|
|
||||||
-- vim.wo[self.win][self.buf].winblend = self.config.winblend
|
|
||||||
-- self.visible = true
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
function SignatureHelp:hide_sig_win()
|
function SignatureHelp:hide_sig_win()
|
||||||
helper.close_float_window(self.sig_win, self.sig_buf)
|
if self.sig_win_showing then
|
||||||
|
helper.close_float_window(self.sig_winnr)
|
||||||
|
end
|
||||||
|
helper.delete_buffer(self.sig_bufnr)
|
||||||
|
helper.delete_buffer(self.doc_bufnr)
|
||||||
|
|
||||||
|
self:hide_doc_win()
|
||||||
|
|
||||||
|
self.sig_winnr = nil
|
||||||
|
self.sig_bufnr = nil
|
||||||
|
self.doc_bufnr = nil -- we want to nil this here and not when we hide the doc win in case we want to reopen the doc win
|
||||||
self.current_signatures = nil
|
self.current_signatures = nil
|
||||||
self.showing = false
|
self.sig_win_showing = false
|
||||||
end
|
end
|
||||||
|
|
||||||
function SignatureHelp:hide_doc_win()
|
function SignatureHelp:hide_doc_win()
|
||||||
helper.close_float_window(self.doc_win, self.doc_buf)
|
if self.doc_win_showing then
|
||||||
|
helper.close_float_window(self.doc_winnr)
|
||||||
|
self.doc_winnr = nil
|
||||||
|
self.doc_win_showing = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SignatureHelp:extract_default_value(param_info)
|
function SignatureHelp:extract_default_value(param_info)
|
||||||
|
|
@ -215,7 +127,7 @@ function SignatureHelp:extract_default_value(param_info)
|
||||||
end
|
end
|
||||||
|
|
||||||
function SignatureHelp:set_active_parameter_highlights(param_str, lines)
|
function SignatureHelp:set_active_parameter_highlights(param_str, lines)
|
||||||
if not self.sig_buf or not api.nvim_buf_is_valid(self.sig_buf) then
|
if not self.sig_bufnr or not api.nvim_buf_is_valid(self.sig_bufnr) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -234,7 +146,7 @@ function SignatureHelp:set_active_parameter_highlights(param_str, lines)
|
||||||
|
|
||||||
if s and e and s > 0 then
|
if s and e and s > 0 then
|
||||||
self.markid = api.nvim_buf_set_extmark(
|
self.markid = api.nvim_buf_set_extmark(
|
||||||
self.sig_buf,
|
self.sig_bufnr,
|
||||||
self.ns,
|
self.ns,
|
||||||
line_num,
|
line_num,
|
||||||
s,
|
s,
|
||||||
|
|
@ -243,21 +155,59 @@ function SignatureHelp:set_active_parameter_highlights(param_str, lines)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SignatureHelp:display(result)
|
function SignatureHelp:display_sig_win(result)
|
||||||
if not result or not result.signatures or #result.signatures == 0 then
|
if not result or not result.signatures or #result.signatures == 0 then
|
||||||
self:hide_sig_win()
|
self:hide_sig_win()
|
||||||
|
if self.doc_win_showing then
|
||||||
|
self:hide_doc_win()
|
||||||
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local content = helper.convert_signature_help_to_lines(result, self.config.win_opts.max_width)
|
if not self.sig_win_showing then
|
||||||
if not self.showing then
|
local ft = vim.bo.ft
|
||||||
self.sig_buf, self.sig_win = helper.create_float_window(content, "lua", self.config.win_opts) -- TODO: programmatically set file type:
|
self._display_sig_win, self._display_doc_win = helper.create_float_windows(result, ft, self.config.win_opts)
|
||||||
|
self.sig_bufnr, self.sig_winnr, self.sig_content = self._display_sig_win()
|
||||||
|
|
||||||
local param_str = helper.get_parameter_label(result)
|
local param_str = helper.get_parameter_label(result)
|
||||||
self:set_active_parameter_highlights(param_str, content)
|
self:set_active_parameter_highlights(param_str, self.sig_content)
|
||||||
self.showing = true
|
self.sig_win_showing = true
|
||||||
end
|
end
|
||||||
local param_str = helper.get_parameter_label(result)
|
local param_str = helper.get_parameter_label(result)
|
||||||
self:set_active_parameter_highlights(param_str, content)
|
self:set_active_parameter_highlights(param_str, self.sig_content)
|
||||||
|
end
|
||||||
|
|
||||||
|
function SignatureHelp:display_doc_win()
|
||||||
|
if self.doc_win_showing then
|
||||||
|
return
|
||||||
|
else
|
||||||
|
self.doc_bufnr, self.doc_winnr = self._display_doc_win()
|
||||||
|
self.doc_win_showing = true
|
||||||
|
self.doc_win_focused = true
|
||||||
|
local active_winnr = vim.api.nvim_get_current_win()
|
||||||
|
vim.api.nvim_set_current_win(self.doc_winnr)
|
||||||
|
|
||||||
|
exit_docs = function()
|
||||||
|
vim.api.nvim_set_current_win(active_winnr)
|
||||||
|
vim.fn.feedkeys("i", "t") --put us back into insert mode
|
||||||
|
self.doc_win_focused = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.doc_bufnr ~= nil then
|
||||||
|
vim.keymap.set(
|
||||||
|
"n",
|
||||||
|
"q",
|
||||||
|
exit_docs,
|
||||||
|
{ silent = true, noremap = true, nowait = true, buffer = self.doc_bufnr }
|
||||||
|
)
|
||||||
|
vim.keymap.set(
|
||||||
|
"n",
|
||||||
|
"<esc>",
|
||||||
|
exit_docs,
|
||||||
|
{ silent = true, noremap = true, nowait = true, buffer = self.doc_bufnr }
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SignatureHelp:trigger()
|
function SignatureHelp:trigger()
|
||||||
|
|
@ -272,14 +222,17 @@ function SignatureHelp:trigger()
|
||||||
vim.notify("Error in LSP Signature Help: " .. vim.inspect(err), vim.log.levels.ERROR)
|
vim.notify("Error in LSP Signature Help: " .. vim.inspect(err), vim.log.levels.ERROR)
|
||||||
end
|
end
|
||||||
self:hide_sig_win()
|
self:hide_sig_win()
|
||||||
|
self:hide_doc_win()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if result and result.signatures and #result.signatures > 0 then
|
if result and result.signatures and #result.signatures > 0 then
|
||||||
self.current_signatures = result.signatures
|
self.current_signatures = result.signatures
|
||||||
self:display(result)
|
|
||||||
|
self:display_sig_win(result)
|
||||||
else
|
else
|
||||||
self:hide_sig_win()
|
self:hide_sig_win()
|
||||||
|
self:hide_doc_win()
|
||||||
-- Only notify if not silent and if there was actually no signature help
|
-- Only notify if not silent and if there was actually no signature help
|
||||||
if not self.config.silent and result then
|
if not self.config.silent and result then
|
||||||
vim.notify("No signature help available", vim.log.levels.INFO)
|
vim.notify("No signature help available", vim.log.levels.INFO)
|
||||||
|
|
@ -299,22 +252,10 @@ function SignatureHelp:check_capability()
|
||||||
self.enabled = false
|
self.enabled = false
|
||||||
end
|
end
|
||||||
|
|
||||||
function SignatureHelp:toggle_normal_mode()
|
|
||||||
self.normal_mode_active = not self.normal_mode_active
|
|
||||||
if self.normal_mode_active then
|
|
||||||
self:trigger()
|
|
||||||
else
|
|
||||||
self:hide_sig_win()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SignatureHelp:setup_autocmds()
|
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
|
||||||
|
|
@ -326,8 +267,6 @@ function SignatureHelp:setup_autocmds()
|
||||||
api.nvim_create_autocmd({ "InsertEnter", "CursorMovedI" }, {
|
api.nvim_create_autocmd({ "InsertEnter", "CursorMovedI" }, {
|
||||||
group = group,
|
group = group,
|
||||||
callback = function()
|
callback = function()
|
||||||
-- vim.notify("trigger")
|
|
||||||
|
|
||||||
-- local cmp_visible = require("cmp").visible()
|
-- local cmp_visible = require("cmp").visible()
|
||||||
-- if cmp_visible then
|
-- if cmp_visible then
|
||||||
-- self:hide()
|
-- self:hide()
|
||||||
|
|
@ -351,8 +290,11 @@ function SignatureHelp:setup_autocmds()
|
||||||
api.nvim_create_autocmd({ "InsertLeave" }, {
|
api.nvim_create_autocmd({ "InsertLeave" }, {
|
||||||
group = group,
|
group = group,
|
||||||
callback = function()
|
callback = function()
|
||||||
|
if self.doc_win_focused == false then
|
||||||
self:hide_sig_win()
|
self:hide_sig_win()
|
||||||
|
self:hide_doc_win()
|
||||||
self.normal_mode_active = false
|
self.normal_mode_active = false
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -375,7 +317,7 @@ function SignatureHelp:next_signature()
|
||||||
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
|
||||||
end
|
end
|
||||||
self:display({
|
self:display_sig_win({
|
||||||
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,
|
||||||
|
|
@ -390,21 +332,28 @@ function SignatureHelp:prev_signature()
|
||||||
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
|
||||||
end
|
end
|
||||||
self:display({
|
self:display_sig_win({
|
||||||
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:setup_keymaps()
|
function SignatureHelp:toggle_docs()
|
||||||
-- Setup toggle keys using the actual config
|
-- vim.notify("doc_win_showing: " .. vim.inspect(self.doc_win_showing))
|
||||||
local toggle_key = self.config.toggle_key
|
if self.doc_win_showing then
|
||||||
|
self:hide_doc_win()
|
||||||
|
elseif self.sig_win_showing then
|
||||||
|
self:display_doc_win()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if toggle_key then
|
function SignatureHelp:toggle_normal_mode()
|
||||||
vim.keymap.set("n", toggle_key, function()
|
self.normal_mode_active = not self.normal_mode_active
|
||||||
self:toggle_normal_mode()
|
if self.normal_mode_active then
|
||||||
end, { noremap = true, silent = true, desc = "Toggle signature help in normal mode" })
|
self:trigger()
|
||||||
|
else
|
||||||
|
self:hide_sig_win()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -447,14 +396,22 @@ function M.setup(opts)
|
||||||
callback = setup_highlights,
|
callback = setup_highlights,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Setup autocmds and keymaps
|
-- Setup autocmds
|
||||||
signature_help:setup_autocmds()
|
signature_help:setup_autocmds()
|
||||||
signature_help:setup_keymaps()
|
|
||||||
|
|
||||||
-- Store instance for potential reuse
|
-- Store instance for potential reuse
|
||||||
M._initialized = true
|
M._initialized = true
|
||||||
M._instance = signature_help
|
M._instance = signature_help
|
||||||
|
|
||||||
|
-- Add API methods for external use
|
||||||
|
M.toggle_docs = function()
|
||||||
|
signature_help:toggle_docs()
|
||||||
|
end
|
||||||
|
|
||||||
|
M.toggle_normal_mode = function()
|
||||||
|
signature_help:toggle_normal_mode()
|
||||||
|
end
|
||||||
|
|
||||||
return signature_help
|
return signature_help
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -464,6 +421,4 @@ M.dependencies = {
|
||||||
"nvim-treesitter/nvim-treesitter",
|
"nvim-treesitter/nvim-treesitter",
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Add API methods for external use
|
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue