From 1ab3e8ec95780d977af486fcf4a4893bfe5c0b82 Mon Sep 17 00:00:00 2001 From: Dan7h3x Date: Wed, 20 Nov 2024 13:13:31 +0330 Subject: [PATCH] Fix Bugs --- lua/signup/init.lua | 121 +++++++++----- lua/signup/initBack.lua | 340 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 419 insertions(+), 42 deletions(-) create mode 100644 lua/signup/initBack.lua diff --git a/lua/signup/init.lua b/lua/signup/init.lua index c666c94..5375653 100644 --- a/lua/signup/init.lua +++ b/lua/signup/init.lua @@ -1,38 +1,51 @@ local api = vim.api +local lsp = vim.lsp +local fn = vim.fn +local cmd = vim.cmd local M = {} +-- SignatureHelp class definition local SignatureHelp = {} SignatureHelp.__index = SignatureHelp -function SignatureHelp.new() - return setmetatable({ - win = nil, - buf = nil, - timer = nil, - visible = false, - current_signatures = nil, - enabled = false, - normal_mode_active = false, - config = { - silent = false, - number = true, - icons = { - parameter = " ", - method = " ", - documentation = " ", - }, - colors = { - parameter = "#86e1fc", - method = "#c099ff", - documentation = "#4fd6be", - }, - border = "rounded", - winblend = 10, - } - }, SignatureHelp) +-- Constructor for SignatureHelp +function SignatureHelp.new(config) + local self = setmetatable({}, SignatureHelp) + self.config = vim.tbl_deep_extend("force", { + silent = false, + number = true, + icons = { + parameter = " ", + method = " ", + documentation = " ", + }, + colors = { + parameter = "#86e1fc", + method = "#c099ff", + documentation = "#4fd6be", + }, + border = "rounded", + winblend = 10, + offset = { + x = 6, + y = 1, + }, + }, config or {}) + + self.win = nil + self.buf = nil + self.timer = nil + self.visible = false + self.current_signatures = nil + self.enabled = false + self.normal_mode_active = false + self.active_parameter_index = 0 + + return self end +-- Helper function to generate comment string for signature index local function signature_index_comment(index) if #vim.bo.commentstring ~= 0 then return vim.bo.commentstring:format(index) @@ -41,6 +54,7 @@ local function signature_index_comment(index) end end +-- Function to generate markdown content for signature list local function markdown_for_signature_list(signatures, config) local lines, labels = {}, {} local number = config.number and #signatures > 1 @@ -74,17 +88,26 @@ local function markdown_for_signature_list(signatures, config) return lines, labels end +-- Function to create a floating window for displaying signatures function SignatureHelp:create_float_window(contents) local width = math.min(45, vim.o.columns) local height = math.min(#contents, 10) local cursor = api.nvim_win_get_cursor(0) local row = cursor[1] - api.nvim_win_get_cursor(0)[1] + local col = cursor[2] + + -- Check if nvim-cmp is visible + local cmp_visible = fn.exists('*cmp#visible') == 1 and fn.eval('cmp#visible()') == 1 + if cmp_visible then + row = row + self.config.offset.y + col = col + self.config.offset.x + end local win_config = { - relative = "editor", + relative = "cursor", row = row + 1, - col = 0, + col = col, width = width, height = height, style = "minimal", @@ -109,6 +132,7 @@ function SignatureHelp:create_float_window(contents) self.visible = true end +-- Function to hide the floating window function SignatureHelp:hide() if self.visible then pcall(api.nvim_win_close, self.win, true) @@ -117,9 +141,11 @@ function SignatureHelp:hide() self.buf = nil self.visible = false self.current_signatures = nil + self.active_parameter_index = 0 end end +-- Function to set active parameter highlights 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 @@ -128,11 +154,16 @@ function SignatureHelp:set_active_parameter_highlights(active_parameter, signatu for index, signature in ipairs(signatures) do local parameter = signature.activeParameter or active_parameter if parameter and parameter >= 0 and parameter < #signature.parameters then - local label = signature.parameters[parameter + 1].label + local param = signature.parameters[parameter + 1] + local label = param.label if type(label) == "string" then - vim.fn.matchadd("LspSignatureActiveParameter", "\\<" .. label .. "\\>") + local start_col, end_col = string.find(signature.label, label, 1, true) + if start_col and end_col then + api.nvim_buf_add_highlight(self.buf, -1, "LspSignatureActiveParameter", labels[index] - 1, start_col - 1, + end_col) + end elseif type(label) == "table" then - api.nvim_buf_add_highlight(self.buf, -1, "LspSignatureActiveParameter", labels[index], unpack(label)) + api.nvim_buf_add_highlight(self.buf, -1, "LspSignatureActiveParameter", labels[index] - 1, unpack(label)) end end end @@ -158,6 +189,7 @@ function SignatureHelp:set_active_parameter_highlights(active_parameter, signatu end end +-- Function to display the signature help function SignatureHelp:display(result) if not result or not result.signatures or #result.signatures == 0 then self:hide() @@ -182,6 +214,7 @@ function SignatureHelp:display(result) end end +-- Function to apply treesitter highlighting function SignatureHelp:apply_treesitter_highlighting() if not pcall(require, "nvim-treesitter") then return @@ -190,11 +223,12 @@ function SignatureHelp:apply_treesitter_highlighting() require("nvim-treesitter.highlight").attach(self.buf, "markdown") end +-- Function to trigger the signature help function SignatureHelp:trigger() if not self.enabled then return end - local params = vim.lsp.util.make_position_params() - vim.lsp.buf_request(0, "textDocument/signatureHelp", params, function(err, result, _, _) + local params = lsp.util.make_position_params() + lsp.buf_request(0, "textDocument/signatureHelp", params, function(err, result, _, _) if err then if not self.config.silent then vim.notify("Error in LSP Signature Help: " .. vim.inspect(err), vim.log.levels.ERROR) @@ -214,8 +248,9 @@ function SignatureHelp:trigger() end) end +-- Function to check if the LSP client supports signature help function SignatureHelp:check_capability() - local clients = vim.lsp.get_clients() + local clients = lsp.get_clients() for _, client in ipairs(clients) do if client.server_capabilities.signatureHelpProvider then self.enabled = true @@ -225,6 +260,7 @@ function SignatureHelp:check_capability() self.enabled = false end +-- Function to toggle signature help in normal mode function SignatureHelp:toggle_normal_mode() self.normal_mode_active = not self.normal_mode_active if self.normal_mode_active then @@ -234,14 +270,15 @@ function SignatureHelp:toggle_normal_mode() end end +-- Function to setup autocommands for triggering signature help function SignatureHelp:setup_autocmds() local group = api.nvim_create_augroup("LspSignatureHelp", { clear = true }) local function debounced_trigger() if self.timer then - vim.fn.timer_stop(self.timer) + fn.timer_stop(self.timer) end - self.timer = vim.fn.timer_start(30, function() + self.timer = fn.timer_start(30, function() self:trigger() end) end @@ -249,10 +286,10 @@ function SignatureHelp:setup_autocmds() api.nvim_create_autocmd({ "CursorMovedI", "TextChangedI" }, { group = group, callback = function() - local cmp_visible = vim.fn.exists('*cmp#visible') == 1 and vim.fn.eval('cmp#visible()') == 1 + local cmp_visible = fn.exists('*cmp#visible') == 1 and fn.eval('cmp#visible()') == 1 if cmp_visible then self:hide() - elseif vim.fn.pumvisible() == 0 then + elseif fn.pumvisible() == 0 then debounced_trigger() else self:hide() @@ -297,10 +334,10 @@ function SignatureHelp:setup_autocmds() }) end +-- Setup function for the plugin function M.setup(opts) opts = opts or {} - local signature_help = SignatureHelp.new() - signature_help.config = vim.tbl_deep_extend("force", signature_help.config, opts) + local signature_help = SignatureHelp.new(opts) signature_help:setup_autocmds() local toggle_key = opts.toggle_key or "" @@ -319,7 +356,7 @@ function M.setup(opts) }) end - vim.cmd(string.format([[ + cmd(string.format([[ highlight default LspSignatureActiveParameter guifg=#c8d3f5 guibg=#4ec9b0 gui=bold highlight default link FloatBorder Normal highlight default NormalFloat guibg=#1e1e1e guifg=#d4d4d4 @@ -330,7 +367,7 @@ function M.setup(opts) signature_help.config.colors.documentation)) if opts.override then - vim.lsp.handlers["textDocument/signatureHelp"] = function(_, result, context, config) + lsp.handlers["textDocument/signatureHelp"] = function(_, result, context, config) config = vim.tbl_deep_extend("force", signature_help.config, config or {}) signature_help:display(result) end diff --git a/lua/signup/initBack.lua b/lua/signup/initBack.lua new file mode 100644 index 0000000..c666c94 --- /dev/null +++ b/lua/signup/initBack.lua @@ -0,0 +1,340 @@ +local api = vim.api + +local M = {} + +local SignatureHelp = {} +SignatureHelp.__index = SignatureHelp + +function SignatureHelp.new() + return setmetatable({ + win = nil, + buf = nil, + timer = nil, + visible = false, + current_signatures = nil, + enabled = false, + normal_mode_active = false, + config = { + silent = false, + number = true, + icons = { + parameter = " ", + method = " ", + documentation = " ", + }, + colors = { + parameter = "#86e1fc", + method = "#c099ff", + documentation = "#4fd6be", + }, + border = "rounded", + winblend = 10, + } + }, SignatureHelp) +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 + for index, signature in ipairs(signatures) do + table.insert(labels, #lines + 1) + + local suffix = number and (' ' .. signature_index_comment(index)) or '' + + table.insert(lines, string.format("```%s", vim.bo.filetype)) + table.insert(lines, string.format("%s %s%s", config.icons.method, signature.label, suffix)) + table.insert(lines, "```") + + if signature.parameters and #signature.parameters > 0 then + table.insert(lines, "") + table.insert(lines, string.format("%s Parameters:", config.icons.parameter)) + for _, param in ipairs(signature.parameters) do + table.insert(lines, string.format(" • %s", param.label)) + end + end + + if signature.documentation then + table.insert(lines, "") + table.insert(lines, string.format("%s Documentation:", config.icons.documentation)) + vim.list_extend(lines, vim.split(signature.documentation.value or signature.documentation, "\n")) + end + + if index ~= #signatures then + table.insert(lines, "---") + end + end + return lines, labels +end + +function SignatureHelp:create_float_window(contents) + local width = math.min(45, vim.o.columns) + local height = math.min(#contents, 10) + + local cursor = api.nvim_win_get_cursor(0) + local row = cursor[1] - api.nvim_win_get_cursor(0)[1] + + local win_config = { + relative = "editor", + row = row + 1, + col = 0, + width = width, + height = height, + style = "minimal", + border = self.config.border, + } + + 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 + + api.nvim_buf_set_option(self.buf, "modifiable", true) + api.nvim_buf_set_lines(self.buf, 0, -1, false, contents) + api.nvim_buf_set_option(self.buf, "modifiable", false) + api.nvim_win_set_option(self.win, "foldenable", false) + api.nvim_win_set_option(self.win, "wrap", false) + api.nvim_win_set_option(self.win, "winblend", self.config.winblend) + + self.visible = true +end + +function SignatureHelp:hide() + if self.visible then + pcall(api.nvim_win_close, self.win, true) + pcall(api.nvim_buf_delete, self.buf, { force = true }) + self.win = nil + self.buf = nil + self.visible = false + self.current_signatures = nil + end +end + +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 + + api.nvim_buf_clear_namespace(self.buf, -1, 0, -1) + + for index, signature in ipairs(signatures) do + local parameter = signature.activeParameter or active_parameter + if parameter and parameter >= 0 and parameter < #signature.parameters then + local label = signature.parameters[parameter + 1].label + if type(label) == "string" then + vim.fn.matchadd("LspSignatureActiveParameter", "\\<" .. label .. "\\>") + elseif type(label) == "table" then + api.nvim_buf_add_highlight(self.buf, -1, "LspSignatureActiveParameter", labels[index], unpack(label)) + end + end + end + + -- Add icon highlights + local icon_highlights = { + { self.config.icons.method, "SignatureHelpMethod" }, + { self.config.icons.parameter, "SignatureHelpParameter" }, + { self.config.icons.documentation, "SignatureHelpDocumentation" }, + } + + for _, icon_hl in ipairs(icon_highlights) do + local icon, hl_group = unpack(icon_hl) + local line_num = 0 + while line_num < api.nvim_buf_line_count(self.buf) do + local line = api.nvim_buf_get_lines(self.buf, line_num, line_num + 1, false)[1] + local start_col = line:find(vim.pesc(icon)) + if start_col then + api.nvim_buf_add_highlight(self.buf, -1, hl_group, line_num, start_col - 1, start_col + #icon - 1) + end + line_num = line_num + 1 + end + end +end + +function SignatureHelp:display(result) + if not result or not result.signatures or #result.signatures == 0 then + self:hide() + return + end + + local markdown, labels = markdown_for_signature_list(result.signatures, self.config) + + if vim.deep_equal(result.signatures, self.current_signatures) then + return + end + + self.current_signatures = result.signatures + + if #markdown > 0 then + self:create_float_window(markdown) + api.nvim_buf_set_option(self.buf, "filetype", "markdown") + self:set_active_parameter_highlights(result.activeParameter, result.signatures, labels) + self:apply_treesitter_highlighting() + else + self:hide() + end +end + +function SignatureHelp:apply_treesitter_highlighting() + if not pcall(require, "nvim-treesitter") then + return + end + + require("nvim-treesitter.highlight").attach(self.buf, "markdown") +end + +function SignatureHelp:trigger() + if not self.enabled then return end + + local params = vim.lsp.util.make_position_params() + vim.lsp.buf_request(0, "textDocument/signatureHelp", params, function(err, result, _, _) + if err then + if not self.config.silent then + vim.notify("Error in LSP Signature Help: " .. vim.inspect(err), vim.log.levels.ERROR) + end + self:hide() + return + end + + if result then + self:display(result) + else + self:hide() + if not self.config.silent then + vim.notify("No signature help available", vim.log.levels.INFO) + end + end + end) +end + +function SignatureHelp:check_capability() + local clients = vim.lsp.get_clients() + for _, client in ipairs(clients) do + if client.server_capabilities.signatureHelpProvider then + self.enabled = true + return + end + end + self.enabled = false +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() + end +end + +function SignatureHelp:setup_autocmds() + local group = api.nvim_create_augroup("LspSignatureHelp", { clear = true }) + + local function debounced_trigger() + if self.timer then + vim.fn.timer_stop(self.timer) + end + self.timer = vim.fn.timer_start(30, function() + self:trigger() + end) + end + + api.nvim_create_autocmd({ "CursorMovedI", "TextChangedI" }, { + group = group, + callback = function() + local cmp_visible = vim.fn.exists('*cmp#visible') == 1 and vim.fn.eval('cmp#visible()') == 1 + if cmp_visible then + self:hide() + elseif vim.fn.pumvisible() == 0 then + debounced_trigger() + else + self:hide() + end + end + }) + + api.nvim_create_autocmd({ "CursorMoved" }, { + group = group, + callback = function() + if self.normal_mode_active then + debounced_trigger() + end + end + }) + + api.nvim_create_autocmd({ "InsertLeave", "BufHidden", "BufLeave" }, { + group = group, + callback = function() + self:hide() + self.normal_mode_active = false + end + }) + + api.nvim_create_autocmd("LspAttach", { + group = group, + callback = function() + vim.defer_fn(function() + self:check_capability() + end, 100) + end + }) + + api.nvim_create_autocmd("ColorScheme", { + group = group, + callback = function() + if self.visible then + self:apply_treesitter_highlighting() + self:set_active_parameter_highlights(self.current_signatures.activeParameter, self.current_signatures, {}) + end + end + }) +end + +function M.setup(opts) + opts = opts or {} + local signature_help = SignatureHelp.new() + signature_help.config = vim.tbl_deep_extend("force", signature_help.config, opts) + signature_help:setup_autocmds() + + local toggle_key = opts.toggle_key or "" + vim.keymap.set("n", toggle_key, function() + signature_help:toggle_normal_mode() + end, { noremap = true, silent = true, desc = "Toggle signature help in normal mode" }) + + if pcall(require, "nvim-treesitter") then + require("nvim-treesitter").define_modules({ + signature_help_highlighting = { + module_path = "signature_help.highlighting", + is_supported = function(lang) + return lang == "markdown" + end, + }, + }) + end + + vim.cmd(string.format([[ + highlight default LspSignatureActiveParameter guifg=#c8d3f5 guibg=#4ec9b0 gui=bold + highlight default link FloatBorder Normal + highlight default NormalFloat guibg=#1e1e1e guifg=#d4d4d4 + highlight default SignatureHelpMethod guifg=%s + highlight default SignatureHelpParameter guifg=%s + highlight default SignatureHelpDocumentation guifg=%s + ]], signature_help.config.colors.method, signature_help.config.colors.parameter, + signature_help.config.colors.documentation)) + + if opts.override then + vim.lsp.handlers["textDocument/signatureHelp"] = function(_, result, context, config) + config = vim.tbl_deep_extend("force", signature_help.config, config or {}) + signature_help:display(result) + end + end +end + +return M