lspsaga.nvim icon indicating copy to clipboard operation
lspsaga.nvim copied to clipboard

Auto trigger HoverDoc or SignatureHelp when typing?

Open flamendless opened this issue 2 years ago • 21 comments

Is it possible, if so, how, to auto show hoverdoc or signature help windows when typing commands like other IDE. Thank you

flamendless avatar Feb 25 '22 13:02 flamendless

Yes, you can try this:

      vim.cmd "autocmd CursorHold <buffer> silent! Lspsaga hover_doc"
      vim.cmd "autocmd CursorHoldI <buffer> silent! Lspsaga signature_help" -- Only in insert mode

you need to add it in on_attach function, try it and let me know

kkharji avatar Feb 25 '22 13:02 kkharji

Thank you!

~~I get a weird behavior though, it shows but my cursor is stuck on the hover doc window. Cant quit the buffer or close it or move to the main buffer haha~~ (overlooked the on_attach instruction)

Oh wait, which on_attach function btw?

flamendless avatar Feb 25 '22 13:02 flamendless

😆 cc @againxx

I noticed that too, when I re-enable the hover autocmd. This because if the hover is open and the user call Lspsaga hover_doc, it would jump to it. In this case either cursor hold is to fast for Lspsaga to close it and then reopen it or Lspsaga hover_doc should maintain internal state. idk

Though I believe this cursor hold hack isn't sufficient, maybe wrap it with vim.loop.new_timer

function AutoHover()
  local hover = require'lspsaga.hover';
  return vim.loop.new_timer():start(2000, function ()
    hover.render_hover_doc()
  end)
end

kkharji avatar Feb 25 '22 14:02 kkharji

Sorry (very new to neovim's lua/vim), but how do i use that function?

flamendless avatar Feb 25 '22 15:02 flamendless

I think you shouldn't as is, I believe it will just give u wrong popup, I wanted to delay cursor hold callback a bit.

u can do lua AutoHover() after adding it to init.lua

kkharji avatar Feb 25 '22 15:02 kkharji

This works:

function AutoHover()
	local hover = require'lspsaga.hover';
	return vim.loop.new_timer():start(2000, 0, vim.schedule_wrap(function()
		hover.render_hover_doc()
	end))
end

vim.cmd "autocmd CursorHold <buffer> lua AutoHover()"

but still suffers from getting stuck in the hover doc, however, i can now close the hover doc window with :q. Maybe there's a lspsaga command to close the hover doc window if open or perhaps a lspsaga setting that will not autojump to hover doc window when opening?

I saw this for the first option and it works, but imo is unintuitive, perhaps the latter (the setting approach) would be best

augroup lspsaga_filetypes
  autocmd!
  autocmd FileType LspsagaHover nnoremap <buffer><nowait><silent> <Esc> <cmd>close!<cr>
augroup END

btw the vim.cmd "autocmd CursorHoldI <buffer> silent! Lspsaga signature_help" works great!

flamendless avatar Feb 26 '22 02:02 flamendless

@tami5 Maybe we should finally create a configuration item for the jumpable floating window to mimic the exact builtin behavior? What's your idea?

againxx avatar Feb 26 '22 11:02 againxx

This works:

function AutoHover()
	local hover = require'lspsaga.hover';
	return vim.loop.new_timer():start(2000, 0, vim.schedule_wrap(function()
		hover.render_hover_doc()
	end))
end

vim.cmd "autocmd CursorHold <buffer> lua AutoHover()"

but still suffers from getting stuck in the hover doc,

try calling hover.close_hover_window() right before hover.render_hover_doc(), I think that this will ensure it is closed. and should fix the issue for ur use case temporarily.

@tami5 Maybe we should finally create a configuration item for the jumpable floating window to mimic the exact builtin behavior? What's your idea?

Hmmm what do u mean by configuration item? like focus = false/true? 🤔 I kinda had an argument about why isn't focus false is the default but anyways, nah that won't make sense.

Not sure, maybe exposing autocmd? with the hot fix above? or maybe a wrapper to delay the popup for few seconds. I noticed a huge delay in my cursor movement because of that. every nav key would call lsp server, 😆. with wrappers maybe we can keep state, make auto hover crazy good. What do u think

kkharji avatar Feb 26 '22 11:02 kkharji

try calling hover.close_hover_window() right before hover.render_hover_doc(), I think that this will ensure it is closed. and should fix the issue for ur use case temporarily.

Now it flickers (closes then opens again) every now and then. but i think this is okay for now temporarily. thank you!

flamendless avatar Feb 26 '22 12:02 flamendless

Hmmm what do u mean by configuration item? like focus = false/true? thinking I kinda had an argument about why isn't focus false is the default but anyways, nah that won't make sense.

Yes, I mean a focusable boolean like nvim_open_win.

I agree that the auto hover may not need to appear so quickly like signature help. So some kind of wrappers for throttling seems a good idea.

againxx avatar Feb 26 '22 12:02 againxx

Put render_hover_doc() inside an if-statement seems to solve the flicker in my case. @flamendless

function AutoHover()
  local hover = require "lspsaga.hover"
  vim.loop.new_timer():start(
    2000,
    0,
    vim.schedule_wrap(function()
      if not hover.has_saga_hover() then
        hover.render_hover_doc()
      end
    end)
  )
end

vim.cmd "autocmd CursorHold <buffer> lua AutoHover()"

againxx avatar Feb 26 '22 12:02 againxx

@tami5

Not sure, maybe exposing autocmd? with the hot fix above? or maybe a wrapper to delay the popup for few seconds. I noticed a huge delay in my cursor movement because of that. every nav key would call lsp server, laughing. with wrappers maybe we can keep state, make auto hover crazy good. What do u think

Seems that we have already saved some data in the main window's variable lspsaga_hoverwin_data for scrolling.

againxx avatar Feb 26 '22 12:02 againxx

function AutoHover()
  local hover = require "lspsaga.hover"
  vim.loop.new_timer():start(
    2000,
    0,
    vim.schedule_wrap(function()
      if not hover.has_saga_hover() then
        hover.render_hover_doc()
      end
    end)
  )
end

Thank you! this works perfectly

flamendless avatar Feb 26 '22 12:02 flamendless

Hmmm so I played around a little and I noticed some issues with current approach

  • Sometimes it open after entering insert mode, and stays open. To fix that I added InsertEnter to close the float
  • Can't help but feel slight delay.
  • sometime the timeout just get ignored

Anyways, here is my progress so far.

    _G.auto_hover = true
    _G.should_ignore = false
    function AutoHover()
      -- don't bother if mode isn't normal and auto hover is disabled.
      if vim.fn.mode() ~= "n" or not _G.auto_hover then
        return
      end

      local timer = vim.loop.new_timer()
      local job = function()
        -- if should ignore or mode is no longer normal. ignore
        if should_ignore or vim.fn.mode() ~= "n" then
          should_ignore = false
          return
        end
        local hover = require "lspsaga.hover"
        if not hover.has_saga_hover() then
          hover.render_hover_doc()
        end
      end

      -- Just ignore if on cursor moved.
      vim.cmd "autocmd CursorMoved <buffer> ++once lua should_ignore = true"
      _G.should_ignore = false

      -- Start the timer job
      timer:start(3000, 0, vim.schedule_wrap(job))
    end

@againxx any ideas?

kkharji avatar Feb 26 '22 16:02 kkharji

Seems that we have already saved some data in the main window's variable lspsaga_hoverwin_data for scrolling.

could we reuse it for rows and columns trigger before hand?

kkharji avatar Feb 26 '22 16:02 kkharji

@tami5 I have tried your approach. I observed that the time delay isn't consistent between popups. I suspect vim.cmd "autocmd CursorMoved <buffer> ++once lua should_ignore = true" isn't enough to guarantee that the popup will only open when the cursor holds after an amount of time. Maybe we should keep track of the last cursor moved time, like this?

_G.auto_hover = true
_G.last_cursor_moved = vim.loop.now()
function AutoHover()
  -- don't bother if mode isn't normal and auto hover is disabled.
  if vim.fn.mode() ~= "n" or not _G.auto_hover then
    return
  end

  local timer = vim.loop.new_timer()
  local job = function()
    -- if should ignore or mode is no longer normal. ignore
    if vim.loop.now() - last_cursor_moved < 3000 or vim.fn.mode() ~= "n" then
      return
    end
    local hover = require "lspsaga.hover"
    if not hover.has_saga_hover() then
      hover.render_hover_doc()
    end
  end

  -- Start the timer job
  timer:start(3000, 0, vim.schedule_wrap(job))
end

vim.cmd "autocmd CursorMoved <buffer> lua last_cursor_moved = vim.loop.now()"
vim.cmd "autocmd CursorHold <buffer> lua AutoHover()"

So I assume that the user's "expected" way is auto hover when the cursor is "still" for 3s.

could we reuse it for rows and columns trigger before hand?

Do you mean to save the last cursor position when calling render_hover_doc? It's not straightforward for me why we need the position. Can you give me some further explanation?

againxx avatar Feb 27 '22 02:02 againxx

@againxx oh that's far better then what I had in mind.. I'll keep testing it,

Do you mean to save the last cursor position when calling render_hover_doc? It's not straightforward for me why we need the position. Can you give me some further explanation?

Yes, for optimization and responsiveness purposes, I'm feeling that it might be better to avoid call lsp when the result can be cached. but I now think it might not hold that much difference

kkharji avatar Feb 27 '22 06:02 kkharji

Ok, I'd be glad to help if we have some further ideas.

againxx avatar Feb 27 '22 08:02 againxx

Hey is there any way to open signature_help window only in insert mode like lsp_signature do?

Iamafnan avatar Mar 01 '22 15:03 Iamafnan

@Iamafnan Hi, this autocmd vim.cmd "autocmd CursorHoldI <buffer> silent! Lspsaga signature_help" should only trigger signature_help in insert mode. Can you share your use case?

againxx avatar Mar 01 '22 15:03 againxx

I tried it, but it seems it doesn't work.((

EpsilonKu avatar May 17 '22 04:05 EpsilonKu