nvim-lualine / lualine.nvim

A blazing fast and easy to configure neovim statusline plugin written in pure lua.
MIT License
5.95k stars 462 forks source link

Bug: Cursor in insert mode changes position after calling Ex command in another buffer. #755

Closed lvimuser closed 2 years ago

lvimuser commented 2 years ago

Self Checks

How to reproduce the problem

Enable winbar.

Expected behaviour

Cursor doesn't change position/assert doesn't fail.

Actual behaviour

Cursor is off by one, assert fails.

Minimal config to reproduce the issue

call plug#begin("/tmp/lualinerepo/.local/share/nvim/plugged")
Plug 'nvim-lualine/lualine.nvim'

call plug#end()

lua << END
require'lualine'.setup {
  winbar = { lualine_a = { 'filename', 'filetype'}, },
  inactive_winbar = { lualine_a = { 'filename', 'filetype'}},
}
END

script

local bufnr = vim.api.nvim_create_buf(false, true)
vim.cmd("startinsert")

vim.api.nvim_feedkeys("asdf", "nti", false)

local pos
vim.schedule_wrap(function()
    pos = vim.api.nvim_win_get_cursor(0)
end)()

vim.defer_fn(function()
    vim.schedule(function()
        vim.api.nvim_buf_call(bufnr, function()
            vim.api.nvim_command("normal! zt")
        end)
    end)
end, 500)

vim.defer_fn(function()
    local after = vim.api.nvim_win_get_cursor(0)
    assert(vim.deep_equal(pos, after), vim.inspect({ expected = pos, actual = after }))
end, 2000)

Aditional information

NVIM v0.8.0-dev-666-g1a2560c2dc

Possible culprits:

lualine_stl_refresh  BufEnter
    *         call v:lua.require'lualine'.refresh({'kind': 'window', 'place': ['statusline'], 'trigger': 'autocmd'})
lualine_tal_refresh  BufEnter
    *         call v:lua.require'lualine'.refresh({'kind': 'tabpage', 'place': ['tabline'], 'trigger': 'autocmd'})
lualine_wb_refresh  BufEnter
    *         call v:lua.require'lualine'.refresh({'kind': 'tabpage', 'place': ['winbar'], 'trigger': 'autocmd'})

It doesn't appear to happen if I run lua vim.api.nvim_del_augroup_by_name('lualine_wb_refresh') though, so it might be a winbar only issue.

Found when trying to scroll completion docs with nvim-cmp (scroll docs) https://github.com/hrsh7th/nvim-cmp/blob/main/lua/cmp/view/docs_view.lua#L115-L130. It's annoying bc the cursor moves, triggering completion again, but on the wrong char.

The following patch fixes it, but i'm not familiar with the codebase. It also solves winbar flickering when calling vim.lsp.buf.hover(). (related https://github.com/nvim-lualine/lualine.nvim/issues/751)

diff --git a/lua/lualine.lua b/lua/lualine.lua
index 32c6613..5e563db 100644
--- a/lua/lualine.lua
+++ b/lua/lualine.lua
@@ -335,9 +335,12 @@ local function refresh(opts)
     end
   elseif opts.kind == 'tabpage' then
     if vim.tbl_contains(opts.place, 'statusline') or vim.tbl_contains(opts.place, 'winbar') then
-      wins = vim.tbl_filter(function(win)
-        return vim.fn.win_gettype(win) ~= 'popup'
-      end, vim.api.nvim_tabpage_list_wins(0))
+      local is_relative = vim.api.nvim_win_get_config(0)['relative'] ~= ''
+      if not is_relative then
+        wins = vim.tbl_filter(function(win)
+          return vim.fn.win_gettype(win) ~= 'popup'
+        end, vim.api.nvim_tabpage_list_wins(0))
+      end
     end
   elseif opts.kind == 'window' then
     wins = { vim.api.nvim_get_current_win() }

Checking for each 'win' inside the filter is not sufficient.

shadmansaleh commented 2 years ago

I don't think I fully understand what's going on here. We aren't changing position of cursor and setting winbar option in autocommad shouldn't change position of cursor.

I think this might be caused by an upstream bug. I'll have to look into that. Since winbar is still only available only on nightly some bugs are too be expected I've actually found several already while working on the winbar feature for lualine. See if you can reproduce this issue without lualine.

The patch you've given is halting update of statusline & winbar while you're in a floating window. That's not what we want as the statusline & winbar of other windows should still update even if you're in floating window. It's also odd that it fixes the issue since you don't need floating window to reproduce it.

lvimuser commented 2 years ago

I think this only happens when the cursor is at the last character/column.

First, I thought it was 'ModeChanged' being triggered inside that buffer, however, it's also triggered on nvim --clean.

I wonder if https://github.com/vim/vim/issues/10780 might be related? (but the issue occurs on lualine on nightly and on 1a2560c2dc which is before the ml_get patch).

I don't think I fully understand what's going on here. We aren't changing position of cursor and setting winbar option in autocommad shouldn't change position of cursor.

I have no idea either, so I can't provide more info.

I think this might be caused by an upstream bug. I'll have to look into that. See if you can reproduce this issue without lualine.

Do you any ideas? I couldn't repro with nvim --clean -u __init.lua a.lua then source script.lua (tested on nightly and 1a2560c2dc).

`__init.lua`: ```lua local c = 0 local active_win = function() c = c + 1 pcall(function() vim.wo.winbar = "%{mode()} count:" .. tostring(c) .. "%#LineNrAbove#%=%m " .. vim.fn.expand("%:~") .. "/%#LineNr#%f %#Comment#(%n)" end) end local group = vim.api.nvim_create_augroup("MyActiveWin", { clear = true }) vim.api.nvim_create_autocmd( { "ModeChanged", "FileType", "VimEnter", "WinEnter", "BufEnter", "OptionSet", "VimResized" }, { callback = active_win, group = group } ) ``` `script.lua`: ```lua local g = vim.api.nvim_create_augroup("__buf", { clear = false }) local create_buf = function() local bufnr = vim.api.nvim_create_buf(false, true) vim.api.nvim_create_autocmd( { "ModeChanged", "FileType", "VimEnter", "WinEnter", "BufEnter", "OptionSet", "VimResized" }, { group = g, buffer = bufnr, callback = function() print("entered!") end, } ) return bufnr end local bufnr = create_buf() vim.cmd("startinsert") vim.api.nvim_feedkeys("asdf", "nti", false) local pos vim.schedule_wrap(function() pos = vim.api.nvim_win_get_cursor(0) end)() vim.defer_fn(function() for _ = 1, 10, 1 do vim.api.nvim_buf_call(bufnr, function() vim.api.nvim_command("normal! zt") end) end end, 200) vim.defer_fn(function() local after = vim.api.nvim_win_get_cursor(0) assert(vim.deep_equal(pos, after), vim.inspect({ expected = pos, actual = after })) print("ok") end, 2000) vim.keymap.set("i", "", function() vim.api.nvim_buf_call(bufnr, function() vim.api.nvim_command("normal! zt") end) end, { desc = "..." }) vim.keymap.set("i", "", function() vim.api.nvim_buf_call(bufnr, function() vim.api.nvim_command("silent! normal! zt") end) end, { desc = "..." }) ```

The patch you've given is halting update of statusline & winbar while you're in a floating window. That's not what we want as the statusline & winbar of other windows should still update even if you're in floating window.

yea that makes sense

shadmansaleh commented 2 years ago

fixed in 2d6108e07f5888a42dee37598570bac990ca1297