bug: scrolling gets stuck when using mini.animate
aeddi opened this issue · comments
Did you check docs and existing issues?
- I have read all the noice.nvim docs
- I have searched the existing issues of noice.nvim
- I have searched the existing issues of plugins related to this issue
Neovim version (nvim -v)
0.9.5
Operating system/version
macOS 14.0 (23A344)
Describe the bug
If the mini.animate plugin is loaded and the scroll animation is enabled (which is the default config), the hover/signature window scrolling will get stuck if you try to scroll up/down when the window is already displaying the top/bottom of the buffer.
See the attached video.
stuck.mp4
Steps To Reproduce
- Create a minimal configuration file based on the one in the documentation.
- Install
mini.animate
plugin and call its setup method without any argument. Add and configure an LSP server (in this example lua_lsp) and a few keymaps to interact with the hover window (see details below). - Display a hover window (by pressing the
K
key in normal mode in my case) then userequire("noice.lsp").scroll
with a negative number as argument (by pressing<C-b>
in my case). The scrolling is now stuck on this window, you can't scroll down anymore (by pressing<C-f>
in my case). - Display a hover window (by pressing the
K
key in normal mode in my case) then userequire("noice.lsp").scroll
until the last line of the buffer is displayed (by pressing<C-f>
several times in my case) then press<C-f>
one more time. The scrolling is now stuck on this window, you can't scroll up anymore (by pressing<C-b>
in my case).
Expected Behavior
The hover/signature window should not get stuck.
Repro
local root = vim.fn.fnamemodify("./.repro", ":p")
-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end
-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath, })
end
vim.opt.runtimepath:prepend(lazypath)
-- install plugins
local plugins = {
"folke/tokyonight.nvim",
{
"folke/noice.nvim",
dependencies = {
"MunifTanjim/nui.nvim",
"rcarriga/nvim-notify",
},
},
-- add any other plugins here
"neovim/nvim-lspconfig",
"echasnovski/mini.animate",
}
require("lazy").setup(plugins, {
root = root .. "/plugins",
})
vim.cmd.colorscheme("tokyonight")
-- add anything else here
require("noice").setup()
require("lspconfig").lua_ls.setup({
settings = {
Lua = {
workspace = {
library = {
vim.env.VIMRUNTIME,
},
},
},
},
})
require("mini.animate").setup()
-- keymap for lsp hover interactions
vim.keymap.set("n", "K", vim.lsp.buf.hover)
vim.keymap.set({ "n", "i", "s" }, "<c-f>", function()
if not require("noice.lsp").scroll(4) then
return "<c-f>"
end
end, { silent = true, expr = true })
vim.keymap.set({ "n", "i", "s" }, "<c-b>", function()
if not require("noice.lsp").scroll(-4) then
return "<c-b>"
end
end, { silent = true, expr = true })
After a bit of investigation and debugging on both noice and mini.animate plugins, I found this part of the code to be problematic (although I'm not sure why) :
noice.nvim/lua/noice/util/nui.lua
Lines 248 to 249 in 0cbe3f8
1) When scrolling is not yet stuck, each of these lines emits a WinSrolled
event, except that each of them occurs with a different window handle and buffer handle (???).
This can be easily tested by displaying the return of vim.api.nvim_get_current_buf()
and vim.api.nvim_get_current_win()
, or by adding debugging in the get_scroll_state()
function of mini.animate (here).
2) When you try to scroll up/down when you're already at the top/bottom of the buffer, only the second line emits a WinScrolled
event.
So if the top
value is identical to the vim.fn.getwininfo(win)[1].topline
value, the command "noautocmd silent! normal! " .. top .. "zt"
emits nothing.
3) It's the same thing once scrolling gets stuck and you try to scroll in the "right" direction (scroll down when on top / scroll up when on bottom): only the second line still emits an event.
The first line emits nothing, even though the top
and vim.fn.getwininfo(win)[1].topline
values are now different.
Potential FIxes
1) I don't understand the point of the second line, which manually triggers a WinScrolled
event, or why the noautocmd
on the first line doesn't seem to work.
But by deleting the second line, the scrolling no longer gets stuck and everything seems to work fine.
@@ -246,7 +246,6 @@ function M.scroll(win, delta)
vim.defer_fn(function()
vim.api.nvim_buf_call(buf, function()
vim.api.nvim_command("noautocmd silent! normal! " .. top .. "zt")
- vim.api.nvim_exec_autocmds("WinScrolled", { modeline = false })
end)
end, 0)
end
2) By skipping the execution of the two lines if the top
and vim.fn.getwininfo(win)[1].topline
values are identical, once again : the scrolling no longer gets stuck and everything seems to work fine.
@@ -243,12 +243,14 @@ function M.scroll(win, delta)
top = math.max(top, 1)
top = math.min(top, M.win_buf_height(win) - info.height + 1)
- vim.defer_fn(function()
- vim.api.nvim_buf_call(buf, function()
- vim.api.nvim_command("noautocmd silent! normal! " .. top .. "zt")
- vim.api.nvim_exec_autocmds("WinScrolled", { modeline = false })
- end)
- end, 0)
+ if info.topline ~= top then
+ vim.defer_fn(function()
+ vim.api.nvim_buf_call(buf, function()
+ vim.api.nvim_command("noautocmd silent! normal! " .. top .. "zt")
+ vim.api.nvim_exec_autocmds("WinScrolled", { modeline = false })
+ end)
+ end, 0)
+ end
end
return M