ray-x / lsp_signature.nvim

LSP signature hint as you type
Apache License 2.0
2.09k stars 58 forks source link

Floating window keeps turning on and off #302

Open PMassicotte opened 11 months ago

PMassicotte commented 11 months ago

I have this very simple config:

return {
  'ray-x/lsp_signature.nvim',
  event = 'VeryLazy',
  config = function()
    require('lsp_signature').setup({
      bind = true,
      handler_opts = {
        border = 'rounded',
      },
      floating_window = true,
      floating_window_above_cur_line = true,
      hint_enable = false,
      -- highlight group used to highlight the current parameter
      hi_parameter = 'LspSignatureActiveParameter',
      -- toggle signature on and off in insert mode
      toggle_key = '<M-x>',
    })
  end,
}

When I type, the signature windows keep popping on and off on every keystroke. Is this a bug, or can I modify something to change that behavior?

Peek 2023-12-14 11-52

ray-x commented 11 months ago

Looks like a bug to me. Do you have a full config. More specifically the lspconfig and language server setup so I can reproduce this bug?

PMassicotte commented 11 months ago

Is it ok with that information?

Content of my lspconfig file ```lua return { -- NOTE: This is where your plugins related to LSP can be installed. -- The configuration is done below. Search for lspconfig to find it below. { -- LSP Configuration & Plugins 'neovim/nvim-lspconfig', dependencies = { -- Automatically install LSPs to stdpath for neovim { 'williamboman/mason.nvim', config = true }, 'williamboman/mason-lspconfig.nvim', 'WhoIsSethDaniel/mason-tool-installer.nvim', -- Useful status updates for LSP -- NOTE: `opts = {}` is the same as calling `require('fidget').setup({})` { 'j-hui/fidget.nvim', opts = { -- options }, }, -- Additional lua configuration, makes nvim stuff amazing! 'folke/neodev.nvim', 'simrat39/rust-tools.nvim', }, config = function() vim.g.LanguageClient_serverCommands = { r = { 'R', '--slave', '-e', 'languageserver::run()' }, } -- [[ Configure LSP ]] -- This function gets run when an LSP connects to a particular buffer. local on_attach = function(_, bufnr) -- NOTE: Remember that lua is a real programming language, and as such it is possible -- to define small helper and utility functions so you don't have to repeat yourself -- many times. -- -- In this case, we create a function that lets us more easily define mappings specific -- for LSP related items. It sets the mode, buffer and description for us each time. local nmap = function(keys, func, desc) if desc then desc = 'LSP: ' .. desc end vim.keymap.set('n', keys, func, { buffer = bufnr, desc = desc }) end -- l nmap('lr', ':Lspsaga rename', 'Rename') nmap('la', ':Lspsaga code_action', 'Code action') nmap('K', 'Lspsaga hover_doc', 'Hover Documentation') nmap('lk', 'Lspsaga hover_doc', 'Hover Documentation') nmap( 'ls', require('telescope.builtin').lsp_dynamic_workspace_symbols, 'Workspace Symbols' ) nmap( 'ld', ':Lspsaga show_buf_diagnostics', 'Buffer diagnostics' ) nmap( 'lD', ':Lspsaga show_workspace_diagnostics', 'Workspace diagnostics' ) nmap('lh', ':Lspsaga finder', 'Finder') nmap('lt', ':Lspsaga term_toggle', 'Toggle terminal') nmap('lp', ':Lspsaga peek_definition', 'Peek definition') nmap('lo', ':Lspsaga outline', 'Open outline') -- Diagnostic keymaps vim.keymap.set( 'n', '[d', vim.diagnostic.goto_prev, { desc = 'Go to previous diagnostic message' } ) vim.keymap.set( 'n', ']d', vim.diagnostic.goto_next, { desc = 'Go to next diagnostic message' } ) -- vim.keymap.set('n', 'vd', vim.diagnostic.open_float, { desc = 'Open floating diagnostic message' }) -- vim.keymap.set('n', 'q', vim.diagnostic.setloclist, { desc = 'Open diagnostics list' }) -- g -- nmap('gd', 'Lspsaga peek_definition', '[G]oto [D]efinition') nmap('gd', vim.lsp.buf.definition, '[G]oto [D]efinition') nmap('gD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') nmap('gI', vim.lsp.buf.implementation, '[G]oto [I]mplementation') nmap('D', vim.lsp.buf.type_definition, 'Type [D]efinition') nmap('gK', ':Lspsaga signature_help', 'Show signature') nmap( 'gr', require('telescope.builtin').lsp_references, '[G]oto [R]eferences' ) -- See `:help K` for why this keymap -- nmap('K', vim.lsp.buf.hover, 'Hover Documentation') nmap('', vim.lsp.buf.signature_help, 'Signature Documentation') -- Lesser used LSP functionality nmap( 'wa', vim.lsp.buf.add_workspace_folder, '[W]orkspace [A]dd Folder' ) nmap( 'wr', vim.lsp.buf.remove_workspace_folder, '[W]orkspace [R]emove Folder' ) nmap('wl', function() print(vim.inspect(vim.lsp.buf.list_workspace_folders())) end, '[W]orkspace [L]ist Folders') -- Create a command `:Format` local to the LSP buffer vim.api.nvim_buf_create_user_command(bufnr, 'Format', function(_) vim.lsp.buf.format() end, { desc = 'Format current buffer with LSP' }) end -- Enable the following language servers -- Feel free to add/remove any LSPs that you want here. They will automatically be installed. -- -- Add any additional override configuration in the following tables. They will be passed to -- the `settings` field of the server config. You must look up that documentation yourself. local servers = { clangd = {}, -- gopls = {}, pyright = {}, -- rust_analyzer = {}, jsonls = {}, marksman = {}, r_language_server = { -- filetypes = { 'r', 'rmd', 'quarto' }, }, lua_ls = { Lua = { workspace = { checkThirdParty = false }, telemetry = { enable = false }, }, }, } -- [[ Setup neovim lua configuration ]] require('neodev').setup() -- nvim-cmp supports additional completion capabilities, so broadcast that to servers local capabilities = vim.lsp.protocol.make_client_capabilities() capabilities = require('cmp_nvim_lsp').default_capabilities(capabilities) -- Ensure the servers above are installed local mason_lspconfig = require('mason-lspconfig') mason_lspconfig.setup({ ensure_installed = vim.tbl_keys(servers), }) mason_lspconfig.setup_handlers({ function(server_name) require('lspconfig')[server_name].setup({ capabilities = capabilities, on_attach = on_attach, settings = servers[server_name], filetypes = (servers[server_name] or {}).filetypes, }) end, }) -- Install language formatters and linters local mason_tool_installer = require('mason-tool-installer') mason_tool_installer.setup({ ensure_installed = { 'prettier', -- prettier formatter 'stylua', -- lua formatter 'autopep8', -- python formatter 'black', -- python formatter 'yapf', -- python formatter 'sql-formatter', -- sql formatter }, }) -- Autoformatting on save local format_is_enabled = true vim.api.nvim_create_user_command('KickstartFormatToggle', function() format_is_enabled = not format_is_enabled print('Setting autoformatting to: ' .. tostring(format_is_enabled)) end, {}) -- Create an augroup that is used for managing our formatting autocmds. -- We need one augroup per client to make sure that multiple clients can -- attach to the same buffer without interfering with each other. local _augroups = {} local get_augroup = function(client) if not _augroups[client.id] then local group_name = 'kickstart-lsp-format-' .. client.name local id = vim.api.nvim_create_augroup(group_name, { clear = true }) _augroups[client.id] = id end return _augroups[client.id] end -- Whenever an LSP attaches to a buffer, we will run this function. -- -- See `:help LspAttach` for more information about this autocmd event. vim.api.nvim_create_autocmd('LspAttach', { group = vim.api.nvim_create_augroup( 'kickstart-lsp-attach-format', { clear = true } ), -- This is where we attach the autoformatting for reasonable clients callback = function(args) local client_id = args.data.client_id local client = vim.lsp.get_client_by_id(client_id) local bufnr = args.buf -- Only attach to clients that support document formatting if not client.server_capabilities.documentFormattingProvider then return end -- Tsserver usually works poorly. Sorry you work with bad languages -- You can remove this line if you know what you're doing :) if client.name == 'tsserver' then return end -- Create an autocmd that will run *before* we save the buffer. Run -- the formatting command for the LSP that has just attached. -- vim.api.nvim_create_autocmd('BufWritePre', { -- group = get_augroup(client), -- buffer = bufnr, -- callback = function() -- if not format_is_enabled then -- return -- end -- -- vim.lsp.buf.format { -- async = false, -- filter = function(c) -- return c.id == client.id -- end, -- } -- end, -- }) end, }) end, }, } ```
rqpt commented 11 months ago

I'm getting the same issue using the base installation instructions for lazy and with the default configs for everything. Every other keystroke hides/shows the floating window - essentially toggling on and off on every keypress.

  {
    "ray-x/lsp_signature.nvim",
    event = "VeryLazy",
    opts = {},
    config = function(_, opts) require'lsp_signature'.setup(opts) end
  },
ray-x commented 11 months ago

There are too many plugins being used in your setup this makes it hard to check which may conflict with the plugin. You can refer to https://github.com/ray-x/lsp_signature.nvim/blob/master/tests/init_pack.lua on a reference of a minium vimrc.

PMassicotte commented 11 months ago

Thank you @ray-x, I will try to provide a minimal example. Meanwhile, is it possible to disable the plugin for specific filetypes?

kithpradhan commented 10 months ago

I'm having this same problem. I noticed it's popping on and off with R scripts, but seems to be working properly with lua code. I'm using nvchad with a few extra plugins installed.

myself379 commented 10 months ago

I've observed an issue with the HandleFunc() function in Golang's gorilla/mux library where it seems to be glitching, causing disruptions with lsp_signature.toggle_float_win() functionality. Interestingly, this problem doesn't occur with PHP and Lua.

Upon testing without require("lsp_signature").setup(), I noticed that lsp_signature.toggle_float_win() works fine. Other function signatures, such as Fatal(), Encode(), etc., also seem unaffected. I'm curious if this could be related to overloaded signatures? Golang does not have overload

I have both lspconfig and nvim-cmp configured, but I'm unsure about what might have gone wrong. Notably, both HandleFunc() and log.PrintLn() exhibit the glitch issue, while log.Fatal() does not.

I've attached the HandleFunc() and log.Fatal() lsp_signature.nvim logs for reference.

here is my lspconfig ```lua return { "neovim/nvim-lspconfig", -- base lsp event = { "BufReadPre", "BufNewFile" }, dependencies = { "hrsh7th/cmp-nvim-lsp", -- provide lsp protocol to vim.lsp with updated capabilities "folke/neodev.nvim", -- improved lua lsp "ray-x/lsp_signature.nvim" -- signature_help }, config = function() local lspconfig = require("lspconfig") local cmp_nvim_lsp = require("cmp_nvim_lsp") local status_telescope_ok, _ = pcall(require, "telescope") local lsp_signature = require("lsp_signature") lsp_signature.setup({ fix_post = true, handle_opts = { border = "single" }, max_width = 80, }) local custom_attach = function(_, bufnr) local keymap = vim.keymap local function opts(desc) return { desc = "LSP: " .. desc, buffer = bufnr, noremap = true, silent = true } end keymap.set("n", "gd", vim.lsp.buf.definition, opts("Go to definition")) keymap.set("n", "", vim.lsp.buf.definition, opts("Go to definition")) keymap.set("n", "gD", vim.lsp.buf.declaration, opts("Go to declaration")) keymap.set("n", "gt", "Telescope lsp_type_definitions", opts("Show LSP type definitions")) -- keymap.set("n", "K", "lua vim.lsp.buf.hover()", opts("Hover definition")) keymap.set("n", "K", vim.lsp.buf.hover, opts("Hover definition")) keymap.set("n", "gr", vim.lsp.buf.references, opts("Show LSP references")) -- keymap.set("n", "k", vim.lsp.buf.signature_help, opts("LSP [k] signature help")) keymap.set("n", "k", function() lsp_signature.toggle_float_win() end, opts("LSP [k] signature help")) keymap.set("n", "lrn", "lua vim.lsp.buf.rename()", opts("LSP Smart Rename")) keymap.set({ "n", "v" }, "la", vim.lsp.buf.code_action, opts("Code Actions")) keymap.set("n", "lf", vim.lsp.buf.format, opts("Apply Formatting using LSP")) keymap.set("n", "]d", vim.diagnostic.goto_next, opts("Next diagnostic")) keymap.set("n", "[d", vim.diagnostic.goto_prev, opts("Previous diagnostic")) keymap.set("n", "lq", "lua vim.diagnostic.setqflist()", opts("Put diagnostic into quickfix list")) keymap.set("n", "i", "LspInfo", opts("Show LSP info")) keymap.set("n", "I", "Mason", opts("Show LSP installer")) keymap.set("n", "lrs", "LspRestart", opts("Restart LSP")) if status_telescope_ok then keymap.set("n", "lo", "Telescope lsp_document_symbols", opts("LSP Document Symbols")) -- keymap.set("n", "lR", "Telescope lsp_workspace_symbols", opts("LSP Workspace Symbols")) end if false then -- Simply enable this for auto diagnose on CursorHold local diagnostic = vim.diagnostic vim.api.nvim_create_autocmd("CursorHold", { buffer = bufnr, callback = function() local float_opts = { focusable = true, close_events = { "BufLeave", "CursorMoved", "InsertEnter", "FocusLost" }, border = "rounded", source = "always", -- show source in diagnostic popup window prefix = " ", } if not vim.b.diagnostics_pos then vim.b.diagnostics_pos = { nil, nil } end local cursor_pos = vim.api.nvim_win_get_cursor(0) if (cursor_pos[1] ~= vim.b.diagnostics_pos[1] or cursor_pos[2] ~= vim.b.diagnostics_pos[2]) and #diagnostic.get() > 0 then diagnostic.open_float(nil, float_opts) end vim.b.diagnostics_pos = cursor_pos end, }) end end local capabilities = cmp_nvim_lsp.default_capabilities() lspconfig["tsserver"].setup({ capabilities = capabilities, on_attach = custom_attach, }) lspconfig["volar"].setup(vim.tbl_deep_extend("force", { capabilities = capabilities, on_attach = custom_attach, }, require("user.plugins.lsp.settings.vue_volar"))) lspconfig["cssls"].setup({ capabilities = capabilities, on_attach = custom_attach, }) lspconfig["gopls"].setup({ capabilities = capabilities, on_attach = custom_attach, }) lspconfig["pyright"].setup(vim.tbl_deep_extend("force", { capabilities = capabilities, on_attach = custom_attach, }, require("user.plugins.lsp.settings.pyright"))) lspconfig["yamlls"].setup(vim.tbl_deep_extend("force", { capabilities = capabilities, on_attach = custom_attach, }, require("user.plugins.lsp.settings.yamlls"))) lspconfig["tailwindcss"].setup(vim.tbl_deep_extend("force", { capabilities = capabilities, on_attach = custom_attach, }, require("user.plugins.lsp.settings.tailwindcssls"))) lspconfig["intelephense"].setup(vim.tbl_deep_extend("force", { capabilities = capabilities, on_attach = custom_attach, }, require("user.plugins.lsp.settings.intelephense"))) -- LSP lua: selectively loads minimum documentations lua plugins require("neodev").setup({ library = { plugins = { "nvim-treesitter", "plenary.nvim", "telescope.nvim", "hrsh7th/cmp-nvim-lsp", "catppuccin/nvim", "mfussenegger/nvim-dap", "rcarriga/nvim-dap-ui", } } }) lspconfig["lua_ls"].setup(vim.tbl_deep_extend("force", { capabilities = capabilities, on_attach = custom_attach, }, require("user.plugins.lsp.settings.lua_ls"))) local signs = { { name = "DiagnosticSignError", text = "" }, { name = "DiagnosticSignWarn", text = "" }, { name = "DiagnosticSignHint", text = "" }, { name = "DiagnosticSignInfo", text = "" }, } for _, sign in ipairs(signs) do vim.fn.sign_define(sign.name, { texthl = sign.name, text = sign.text, numhl = "" }) end vim.diagnostic.config({ float = { border = "rounded" } }) -- Change border of documentation hover window, See https://github.com/neovim/neovim/pull/13998. vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { border = "rounded", }) vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, { border = "rounded", silent = true, focusable = false }) end, } ```
here is my nvim-cmp luasnip config ```lua return { "hrsh7th/nvim-cmp", -- The completion plugin event = "InsertEnter", dependencies = { "hrsh7th/cmp-buffer", -- text within current buffer completions "hrsh7th/cmp-path", -- file system path completions "hrsh7th/cmp-nvim-lsp", -- provide lsp protocol to nvim-cmp, acting as a 'bridge' "hrsh7th/cmp-nvim-lua", "saadparwaiz1/cmp_luasnip", -- snippet completions for luasnip { "L3MON4D3/LuaSnip", --snippet engine tag = "v2.2.0", run = "make install_jsregexp" }, "rafamadriz/friendly-snippets", -- a bunch of snippets to use -- "hrsh7th/cmp-nvim-lsp-signature-help", -- auto signature_help; disabled }, config = function() local cmp = require("cmp") local luasnip = require("luasnip") -- load vs-code like snippets from plugins (e.g.: friendly-snippets) require("luasnip.loaders.from_vscode").lazy_load() -- vim.opt.completeopt = { "menuone", "noselect" } -- mostly just for cmp vim.opt.pumheight = 10 -- pop up menu height local kind_icons = { Text = " ", Method = " ", Function = "󰊕 ", Constructor = " ", Field = " ", Variable = " ", Class = " ", Interface = " ", Module = " ", Property = " ", Unit = " ", Value = " ", Enum = " ", Keyword = " ", -- Snippet = " ", Snippet = "󰈑 ", Color = " ", File = " ", Reference = " ", Folder = " ", EnumMember = " ", Constant = " ", Struct = " ", Event = " ", Operator = " ", TypeParameter = " ", } local has_words_before = function() unpack = unpack or table.unpack local line, col = unpack(vim.api.nvim_win_get_cursor(0)) return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil end cmp.setup({ completion = { completeopt = "menu,menuone,preview,noselect", }, snippet = { expand = function(args) luasnip.lsp_expand(args.body) -- For `luasnip` users. end, }, mapping = cmp.mapping({ -- Completion using vim ways [""] = cmp.mapping.confirm({ select = true }), [""] = cmp.mapping(cmp.mapping.scroll_docs(-4), { "i", "c" }), [""] = cmp.mapping(cmp.mapping.scroll_docs(4), { "i", "c" }), [""] = cmp.mapping( cmp.mapping.confirm({ behavior = cmp.ConfirmBehavior.Insert, select = true }), { "i", "c" } ), [""] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_next_item() elseif luasnip.expand_or_jumpable() then luasnip.expand_or_jump() elseif has_words_before() then cmp.complete() else fallback() end end, { "i", "s" }), [""] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_prev_item() elseif luasnip.jumpable(-1) then luasnip.jump(-1) else fallback() end end, { "i", "s" }), }), formatting = { fields = { "kind", "abbr", "menu" }, format = function(entry, vim_item) vim_item.kind = string.format("%s", kind_icons[vim_item.kind]) vim_item.menu = ({ nvim_lsp = "󰨞", nvim_lua = "", treesitter = "", luasnip = "󰈑", buffer = "", path = "", emoji = "󰞅", })[entry.source.name] return vim_item end, }, sources = { { name = "nvim_lsp" }, -- { name = "nvim_lua" }, { name = "luasnip" }, { name = "buffer" }, { name = "path" }, -- { name = "nvim_lsp_signature_help" } }, confirm_opts = { behavior = cmp.ConfirmBehavior.Replace, select = false, }, window = { completion = cmp.config.window.bordered(), documentation = cmp.config.window.bordered(), }, experimental = { ghost_text = true, }, }) end, } ```

Golang-HandleFunc.log Golang-Fatal.log

myself379 commented 8 months ago

I noticed when the symtoms of signature float off is when it ends with "trigger from cursor hold, no need to update floating window". Otherwise, the float window kept floating without any issue.

lsp_signature.log

󰘫  |1: incorrect signature response? |2: {
  cfgActiveSignature = 0,
  signatures = { {
      documentation = {
        kind = "markdown",
        value = "HandleFunc registers a new route with a matcher for the URL path. See Route.Path() and Route.HandlerFunc()."
      },
      label = "HandleFunc(path string, f func(http.ResponseWriter,  *http.Request)) *mux.Route",
      parameters = { {
          label = "path string"
        }, {
          label = "f func(http.ResponseWriter,  *http.Request)"
        } }
    } }
}
 |3: {
  border = "rounded",
  line_to_cursor = "\tr.HandleFunc",
  trigger_from_cursor_hold = true,
  triggered_chars = { "(", "," }
}

󰘫  |1: sig Par |2: 0 |3: {
  label = "path string"
}
 |4: label: |5: HandleFunc(path string, f func(http.ResponseWriter,  *http.Request)) *mux.Route
󰘫  |1: match next pos: |2: path string |3: 12 |4: 22
󰘫  |1: trigger from cursor hold, no need to update floating window
ray-x commented 8 months ago

Pushed a fix for gopls. It related to HandleFunc @myself379 pointed out.

PMassicotte commented 8 months ago

Quick aside question, is it possible to disable this plugin for some problematic filetype (like R in the original question)?

PMassicotte commented 8 months ago

Just noticed that b963a39 fixed the issue with R language. Thank you very much!