/lsp-overloads.nvim

Extends the native nvim-lsp handlers to allow easier navigation through method overloads.

Primary LanguageLuaMIT LicenseMIT

GitHub Workflow Status GitHub release (latest SemVer)

LSP Overloads Nvim

Extends the built-in Neovim LSP signature helper handler to add additional functionality, focussing on enhancements for method overloads.

Screen.Recording.05-07-2022.09-38-32.mp4

Rationale

  • Native LSP signatureHelper handler doesn't provide an easy way to view all the possible overloads and parameter details for signatures
  • Other Neovim LSP plugins either don't support method overloads in the signatureHelper popup view, or don't focus specifically on method overloads and are therefore lacking in the functionality I wanted from handling multiple signatures

Requirements

  • Neovim ≥ 0.7.0

Installation

Install the plugin with the package manager of choice:

--Packer
use { 'Issafalcon/lsp-overloads.nvim'}

Configuration

Within your custom on-attach function that you provide as part of the options to the LSP server, setup the plugin, which will override the built-in signatureHelper LSP handler:

Example without option overrides
  --- Guard against servers without the signatureHelper capability
  if client.server_capabilities.signatureHelpProvider then
    require('lsp-overloads').setup(client, { })
  end

Example with option overrides (defaults shown)
  --- Guard against servers without the signatureHelper capability
  if client.server_capabilities.signatureHelpProvider then
    require('lsp-overloads').setup(client, {
        -- UI options are mostly the same as those passed to vim.lsp.util.open_floating_preview
        ui = {
          border = "single"           -- The border to use for the signature popup window. Accepts same border values as |nvim_open_win()|.
          height = nil,               -- Height of the signature popup window (nil allows dynamic sizing based on content of the help)
          width = nil,                -- Width of the signature popup window (nil allows dynamic sizing based on content of the help)
          wrap = true,                -- Wrap long lines
          wrap_at = nil,              -- Character to wrap at for computing height when wrap enabled
          max_width = nil,            -- Maximum signature popup width
          max_height = nil,           -- Maximum signature popup height
          -- Events that will close the signature popup window: use {"CursorMoved", "CursorMovedI", "InsertCharPre"} to hide the window when typing
          close_events = { "CursorMoved", "BufHidden", "InsertLeave" },
          focusable = true,           -- Make the popup float focusable
          focus = false,              -- If focusable is also true, and this is set to true, navigating through overloads will focus into the popup window (probably not what you want)
          offset_x = 0,               -- Horizontal offset of the floating window relative to the cursor position
          offset_y = 0,                -- Vertical offset of the floating window relative to the cursor position
          floating_window_above_cur_line = false, -- Attempt to float the popup above the cursor position 
                                                 -- (note, if the height of the float would be greater than the space left above the cursor, it will default 
                                                 -- to placing the float below the cursor. The max_height option allows for finer tuning of this)
          silent = true,               -- Prevents noisy notifications (make false to help debug why signature isn't working)
          -- Highlight options is null by default, but this just shows an example of how it can be used to modify the LspSignatureActiveParameter highlight property
          highlight = {
            italic = true,
            bold = true,
            fg = "#ffffff",
            ... -- Other options accepted by the `val` parameter of vim.api.nvim_set_hl()
          }
        },
        keymaps = {
          next_signature = "<C-j>",
          previous_signature = "<C-k>",
          next_parameter = "<C-l>",
          previous_parameter = "<C-h>",
          close_signature = "<A-s>"
        },
        display_automatically = true -- Uses trigger characters to automatically display the signature overloads when typing a method signature
      })
  end

Usage

LSP trigger characters will cause the signature popup to be displayed. If there are any overloads, the popup will indicate this is the case and you will be able to navigate between the overloads.

Regardless of whether or not overloads exist, you will also be able to navigate between the parameters which will change the content of the signature popup to display the details of the highlighted parameter.

Triggering Signature Overload and Parameters

NOTE:

  • In order to allow the mappings to function correctly, you will need to create mappings for the specific buffer that your LSP client is attached to. Therefore, the mapping below should all be created within the custom on_attach function of the LSP-server.

To trigger the lsp-overloads signature popup manually when in normal mode, you can create the following mapping, as an example:

  -- Inside the on_attach function (which passes in 'client' and 'bufnr' params)
  ...
  if client.server_capabilities.signatureHelpProvider then
    vim.api.nvim_set_keymap("n", "<A-s>", ":LspOverloadsSignature<CR>", { noremap = true, silent = true, buffer = bufnr })
  end

It is also useful to create the corresponding trigger mapping for insert mode too (helps when toggling the popup while in insert mode)

  -- Inside the on_attach function (which passes in 'client' and 'bufnr' params)
  ...
  if client.server_capabilities.signatureHelpProvider then
    vim.api.nvim_set_keymap("i", "<A-s>", "<cmd>LspOverloadsSignature<CR>", { noremap = true, silent = true, buffer = bufnr })
  end

Closing the popup while typing can be done using the pre-configured close_signature keybind created when the signature window is created (see Keybinds)

  • It is recommended to override this to match the keybind you use to trigger the overload popup manually, so toggling is more intuitive

Toggling automatic display

lsp-overloads automatically shows itself by default when you are inside of a function signature and begin typing. You can toggle this feature using

:LspOverloadsSignatureAutoToggle

You can disable this automatic triggering of lsp-overloads by setting 'display_automatically' to false as part of the config.

Keybinds

The default mappings are used to navigate between various signature overloads and parameters when the signature popup is displayed:

  • next_signature = "<C-j>"
  • previous_signature = "<C-k>"
  • next_parameter = "<C-l>"
  • previous_parameter = "<C-h>"
  • close_signature = "<A-s>"

NOTE: If you already have a keybinding that matches one of the above, it will only get overwritten when the signature popup is open. When the popup is closed, your original keybinding will be restored in the buffer. If you still need to keep your original mappings while the signature popup is open, you will need to modify these bindings so they no longer conflict

Additional Tips

  • Any calls to vim.lsp.buf.signature_help() made while the plugin's signature popup is displayed, will behave in the same way as the built-in signature popup (i.e. When focusable set to true Cursor will enter the popup in normal mode, allowing scrolling behaviour)

  • If signatures aren't showing up when you expect them to, try setting silent to false. If you then see a popup that states No signature help found, then at least you know it's probably the LSP that isn't returning the signature help.

Credits

  • omnisharp-vim - For providing the approach that I used to handle the signature overloads and keymappings
  • lsp_signature.nvim - The fully featured LSP signature enhancement plugin that I took inspiration from for this plugin
  • seblj dotfiles - The starter code I used in this plugin to kick off the signature request
  • Neovim core codebase - The handler code that has been modified for this plugin