Show signature_help on insert mode

I want to show the current function signature under the cursor while I’m in insert mode and didn’t typed anything for a while.

My first try was to use the plugin https://github.com/ray-x/lsp_signature.nvim but I find it too distracting.

After that I found about CursorHold and I tried to use it in an autocmd like this:

    augroup lsp
        autocmd!
        autocmd CursorHoldI *.* lua vim.lsp.buf.signature_help()
    augroup END

It works but with a big problem: the signature_help is executed even when the signature help window is opened, which changes the current window focus on the signature help window and enters normal mode again (since the signature help window is not editable).

I tried to use ++once in the autocmd but then it only works once per buffer.

Any ideas on how can I prevent the the focus to change to the signature help window, or any other way to implement this?

To prevent focusing the signature popup, you can add this to your init.lua:

vim.lsp.handlers['textDocument/signatureHelp'] = vim.lsp.with(
  vim.lsp.handlers.signature_help,
  { focusable = false }
)

Thanks, it works but has two problems:

  • I lose the ability to focus on the signature help window, e.g. to scroll in it.
  • the signature help window flickers constantly.

use focus = false, not focusable (for point 1)

1 Like

Thanks but as you said it only fixes problem 1, the flickering is still there.

Anyway with a different approach I found a solution :slight_smile:
The idea is:

  • get the floating win ID.
  • when the window is still opened, the handler should do nothing, or not be called at all.
  • when pressing <C-k> to show the signature, call the handler even if the window is still opened, to be able to change the focus on the floating window.

The first point was the hardest.
After reading some Neovim code in the LSP handling I found that the function that creates the floating window returns the buffer and window ID but it get lost in the handler so I wrapped that function to retrieve the win ID and manage it:

signature_help_window_opened = false
signature_help_forced = false
function my_signature_help_handler(handler)
    return function (...)
        if _G.signature_help_forced and _G.signature_help_window_opened then
            _G.signature_help_forced = false
            return handler(...)
        end
        if _G.signature_help_window_opened then
            return
        end
        local fbuf, fwin = handler(...)
        _G.signature_help_window_opened = true
        vim.api.nvim_exec("autocmd WinClosed "..fwin.." lua _G.signature_help_window_opened=false", false)
        return fbuf, fwin
    end
end

function force_signature_help()
    _G.signature_help_forced = true
    vim.lsp.buf.signature_help()
end

Then, when configuring the LSP:

-- These mappings allow to focus on the floating window when opened.
buf_set_keymap('n', '<C-k>', '<cmd>lua force_signature_help()<CR>', opts)
buf_set_keymap('i', '<C-k>', '<cmd>lua force_signature_help()<CR>', opts)

-- Replacing the handler with my own, which manage the floating window.
vim.lsp.handlers['textDocument/signatureHelp'] = vim.lsp.with(
    my_signature_help_handler(vim.lsp.handlers.signature_help),
    {}
)

And finally show the floating window in CursorHoldI:

augroup lsp
    autocmd!
    autocmd CursorHoldI *.* lua vim.lsp.buf.signature_help()
augroup END

I hope this helps someone.