Bug: (my code, looking for recommendation) cursor doesn't move as expected between rows if using a `cond` for showing the `buffers` component in tabline
Amar1729 opened this issue · 3 comments
Self Checks
- I'm using the latest lualine. (commit 2248ef25)
- I didn't find the issue in existing issues or PRs.
- macOS, neovim installed by
bob
$ nvim --version
NVIM v0.10.0-dev-594ff34
Build type: RelWithDebInfo
LuaJIT 2.1.1696795921
Run "nvim -V1 -v" for more info
How to reproduce the problem
Expected behaviour
When moving the cursor in vim between rows, the colum position is kept if no horizontal movements have been made. e.g. when pressing j
twice in the following lines, the cursor position would be represented by |
:
long line with cursor near |end
short|
a longer line where the cur|sor will be in the middle
Actual behaviour
Instead, the cursor falls back to the most-left column where there is text.
long line with cursor near |end
shor|t
a lo|nger line where the cursor will be in the middle
Minimal config to reproduce the issue
call plug#begin("/private/tmp/lualine-dbg/.local/share/nvim/plugged")
Plug 'nvim-lualine/lualine.nvim'
call plug#end()
lua << END
local has_multiple_buffers = function ()
local len = 0
for buffer = 1, vim.fn.bufnr('$') do
if vim.fn.buflisted(buffer) == 1 then
len = len + 1
-- early exit if we have more than 1 buffer
if len > 1 then
break
end
end
end
-- i'm sure it's inefficient to set this on every check
-- is there a better way to re-hide the tabline if i close out buffers?
if len < 2 then
vim.opt.showtabline = 1
return false
else
vim.opt.showtabline = 2
return true
end
end
-- Your lua part of config goes here
require("lualine").setup {
tabline = {
lualine_a = {
{
-- show buffers if we have > 1
'buffers',
-- default max length (2/3) too short
max_length = function () return vim.o.columns * 95 / 100 end,
cond = has_multiple_buffers,
},
},
},
}
END
Additional information
Sorry for logging this issue - it's more that i'm looking for advice in something i might have missed. it seems that the broken code is my function has_multiple_buffers
; you'll notice if you comment out cond = has_multiple_buffers
the cursor issue isn't present. If i change it to a simple cond = function () return false end
movement works as expected, so i'm somewhat convinced the error(?) is in my function. Am i doing something obviously wrong in that function? is there a way i could make it better? (the point is that i only want to show the tabline at all if i have more than one buffer open)
Thanks. feel free to close if you don't want to spend maintainer time on a this.
buffer numbers are not in ordered eg. u can have buffer 1 and buffer 50,only tabs are in order.
and u can hide the tab line outside of the component for performance.
local autocmd = vim.api.nvim_create_autocmd
autocmd({ "BufDelete","BufNew"}, {
pattern = { "*" },
callback = function(ev)
local tab_count = vim.fn.tabpagenr('$')
local buflist = {}
for i = 1, tab_count, 1 do
buflist = { unpack(buflist), unpack(vim.fn.tabpagebuflist(i)) }
end
local len = 0
for _,buf in pairs(buflist) do
if vim.fn.buflisted(buf) then
len = len + 1
end
if len > 1 then
vim.o.showtabline = 2
return
end
end
vim.o.showtabline = 0
end
})
hmm, interesting. For some reason, your solution doesn't seem to work for me: even though :h tabpagebuflist
indicates a similar snippet to "get a list of all buffers in all tabs", i end up with a buflist
that does not have all listed buffers in certain situations.
I've gone with a slightly modified autocmd solution which (mostly) works. There's a bit of an edge case sometimes when i close all but the last buffer, since BufDelete
happens before a buffer gets deleted. Not sure why showtabline
doesn't correctly get set during the following proc of the BufEnter
event, but ... 🤷
local has_multiple_buffers = function ()
local found = false
for buffer = 1, vim.fn.bufnr('$') do
if vim.fn.buflisted(buffer) == 1 then
-- early exit if we've already found a buffer (i.e. have more than 1)
if found == true then return found end
found = true
end
end
return false
end
local set_tabline = function ()
if has_multiple_buffers() then
vim.opt.showtabline = 2
else
vim.opt.showtabline = 1
end
end
-- TODO: for some reason, the bufenter event doesn't seem to happen until after a buffer
-- gets unloaded (???). so, the tabline won't go away until after some other buffer event
-- happens, eg a help page or a command
-- hacky solution for now by also proccing this cmd on CmdlineEnter, and i just type ':<Esc>'
-- after closing buffers down to only 1.
--
-- also, it seems like cmp-cmd is a buffer, so can i filter on stuff like that?
-- i guess it doesn't really matter cause that's not a visible buffer
-- but it causes this autocmd to run more often, which may be unwanted
vim.api.nvim_create_autocmd({
-- events that should hide tabline
"CmdlineEnter", "BufEnter", "BufDelete",
-- events that might create multiple buffers (show tabline)
"VimEnter", "BufNew",
}, {
pattern = "*",
callback = set_tabline,
})
require("lualine").setup {
tabline = {
lualine_a = {
{
-- show buffers if we have > 1
'buffers',
-- default max length (2/3) too short
max_length = function () return vim.o.columns * 95 / 100 end,
cond = has_multiple_buffers,
},
},
},
}
the issues was tabpagebuflist can return the same buffer twice,
i updated the code to only use unique buffers and not count floating window's buffers.
i used fmt to ignore the autocmd headaches.
require("lualine").setup {
tabline = {
lualine_a = {
{
...
fmt = function(name)
local tab_count = vim.fn.tabpagenr('$')
local winlist
for i = 1, tab_count, 1 do
if winlist ~= nil then
winlist = { unpack(winlist), unpack(vim.fn.nvim_tabpage_list_wins(i)) }
else
winlist = vim.api.nvim_tabpage_list_wins(i)
end
end
local buflist = {}
for _, win in pairs(winlist) do
local is_float = vim.api.nvim_win_get_config(win).relative ~= ""
if not is_float then
local buf = vim.api.nvim_win_get_buf(win)
if vim.fn.buflisted(buf) then
buflist[#buflist + 1] = buf
end
end
end
buflist = vim.fn.uniq(buflist)
if #buflist > 1 then
vim.o.showtabline = 2
else
vim.o.showtabline = 0
end
return name
end
},
},
},
}