barbar.nvim
barbar.nvim copied to clipboard
buffer order is reset after focusing the NvimTree window
Description
I usually have a nvim window split with the left part as a NvimTree and the right part my text buffers. I order the buffers in an order that is significant to me (I have a small macro that sort buffers in most recently used order, most recent in front). Whenever I focus the NvimTree and open a new file, the new file is opened in front (as per the settings I set) but the others buffers are reset to their buffer number order instead of the order I had set up.
To Reproduce
I'll try to fix this on my side instead...
touch a b c dnvim a:lua print(vim.inspect(require"bufferline.state".buffers))shows{ 1 }- open tree and open
b - order is now
{ 5, 1 } - with the tree open
c - order is now
{ 6, 5, 1 } - the buffers are in the order c b a, change order to a b c
- order is now
{ 1, 5, 6 } - with the tree open
d - the buffers are in order d a c b instead of d a b c and order is
{ 7, 1, 6, 5 }
Screenshots
I set up a command that logs info at specific times and that monitors the state.buffers variable in the bufferline.state module. Here is a log I can see when the problem happens:
buffers: tree_item_component.rb { 28, 23, 27, 26 }
buffers: NvimTree_1 {}
buffer order changed
from: NvimTree_1 {}
to: tree_item_component.rb { 28, 27, 26, 23 }
Here, we can see that state.buffers is reset to an empty table at some point, and then later on, the buffers gets put back into it but the order was lost.
Informations
NVIM v0.7.2
Build type: RelWithDebInfo
LuaJIT 2.1.0-beta3
Compilation: /usr/bin/gcc -O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=1 -DNVIM_TS_HAS_SET_MATCH_LIMIT -DNVIM_TS_HAS_SET_ALLOCATOR -O2 -g -Og -g -Wall -Wextra -pedantic -Wno-unused-parameter -Wstrict-prototypes -std=gnu99 -Wshadow -Wconversion -Wdouble-promotion -Wmissing-noreturn -Wmissing-format-attribute -Wmissing-prototypes -Wimplicit-fallthrough -Wsuggest-attribute=pure -Wsuggest-attribute=const -Wsuggest-attribute=malloc -Wsuggest-attribute=cold -Wvla -fstack-protector-strong -fno-common -fdiagnostics-color=auto -DINCLUDE_GENERATED_DECLARATIONS -D_GNU_SOURCE -DNVIM_MSGPACK_HAS_FLOAT32 -DNVIM_UNIBI_HAS_VAR_FROM -DMIN_LOG_LEVEL=3 -I/builddir/build/BUILD/neovim-0.7.2/redhat-linux-build/config -I/builddir/build/BUILD/neovim-0.7.2/src -I/usr/include -I/usr/include/luajit-2.1 -I/builddir/build/BUILD/neovim-0.7.2/redhat-linux-build/src/nvim/auto -I/builddir/build/BUILD/neovim-0.7.2/redhat-linux-build/include
Compiled by mockbuild@koji
Features: +acl +iconv +tui
See ":help feature-compile"
system vimrc file: "$VIM/sysinit.vim"
fall-back for $VIM: "/usr/share/nvim"
Run :checkhealth for more info
Additional Info
I set up the following command in my init.vim:
local buf_is_valid = vim.api.nvim_buf_is_valid
local bufferline = require 'bufferline'
local state = require 'bufferline.state'
local last_order = ''
local last_buf = ''
vim.api.nvim_create_user_command('BufferMoveStart', function(opts)
local old_order = vim.inspect(state.buffers)
if old_order ~= last_order then
print("buffer order changed\nfrom: " .. last_buf .. ' ' .. last_order .. "\nto: " .. vim.fn.expand('%') .. ' ' .. old_order)
end
pcall(state.move_current_buffer_to, 1)
local new_order = vim.inspect(state.buffers)
if old_order ~= new_order then
-- print("buffers: " .. old_order .. " -> " .. new_order)
print("buffers: " .. vim.fn.expand('%') .. ' ' .. new_order)
end
last_order = new_order
last_buf = vim.fn.expand('%')
end, { nargs = 0, desc = "BufferMoveStart" })
And the code to sort buffers in revcently used order
let g:vimrc_mru = 1
function Vimrc_toggle_mru()
if g:vimrc_mru
let g:vimrc_mru=0
else
let g:vimrc_mru=1
end
endfunction
let g:vimrc_ignoreWinScrolled = 0
function Vimrc_WinScrolled()
if g:vimrc_ignoreWinScrolled
let g:vimrc_ignoreWinScrolled = 0
elseif g:vimrc_mru
BufferMoveStart
endif
endfunction
let g:vimrc_ignoreCursorMoved = 0
function Vimrc_CursorMoved()
if g:vimrc_ignoreCursorMoved
let g:vimrc_ignoreCursorMoved = 0
elseif g:vimrc_mru
BufferMoveStart
endif
endfunction
function Vimrc_BufEnter()
let g:vimrc_ignoreWinScrolled = 1
let g:vimrc_ignoreCursorMoved = 1
endfunction
augroup vimrc_barbar
au!
au CursorMoved * call Vimrc_CursorMoved()
au CursorMovedI * BufferMoveStart
au TextChanged * BufferMoveStart
au TextChangedi * BufferMoveStart
au InsertEnter * BufferMoveStart
au InsertLeave * BufferMoveStart
au WinScrolled * call Vimrc_WinScrolled()
au BufEnter * call Vimrc_BufEnter()
augroup END
smallest reproducer:
touch a b c dnvim a b c:lua print(vim.inspect(require"bufferline.state".buffers))shows{ 1, 2, 3 }- order is c a b, reorder to a b c
:lua print(vim.inspect(require"bufferline.state".buffers))shows{ 3, 2, 1 }- open NvimTree
- with the tree open
d - the buffers are in order d a c b instead of d a b c and order is
{ 7, 1, 2, 3 }
I noticed a strance stack trace sometimes when the reordering happens:
Error executing vim.schedule lua callback: ...ldred/.vim/bundle/barbar.nvim/lua/bufferline/animate.lua:27: attempt to perform arithmetic on local 'final'
(a nil value)
stack traceback:
...ldred/.vim/bundle/barbar.nvim/lua/bufferline/animate.lua:27: in function 'lerp'
...mildred/.vim/bundle/barbar.nvim/lua/bufferline/state.lua:476: in function 'move_buffer_animated_tick'
...mildred/.vim/bundle/barbar.nvim/lua/bufferline/state.lua:541: in function 'fn'
...ldred/.vim/bundle/barbar.nvim/lua/bufferline/animate.lua:52: in function 'animate_tick'
...ldred/.vim/bundle/barbar.nvim/lua/bufferline/animate.lua:77: in function ''
Removing animations fixes the stack trace but not the issue
Ok, that seems to be within my own code... state.move_current_buffer_to does not work when the current buffer is not within the state table...
When the current buffer is not in the buffer list, state.move_current_buffer_to computes the index of the current buffer (via utils.index_of) to nil, and end up calling table.remove(state.buffers, nil) instead of calling table.remove(state.buffers, <index of non existant buffer>), which removes the first buffer from the list and it is put back to the end later on.
You're not supposed to be calling any functions not mentioned in the documentation (i.e. you shouldn't import bufferline.state outside of the explicit use case for adjusting the offset). As for :BufferMoveStart, we have :BufferMovePrevious <large number> which can accomplish similar (for testing purposes)
Are you able to reproduce this issue if you only use functions which are exposed intentionally?
Well, no, the error was caused by my own code that was calling move_current_buffer_to in the context of the current buffer not being in the state.
If I use BufferMovePrevious 100 for example, instead of the stack trace above (which was cause by my own code again) I get the following nvim error:
- Open NVim:
nvim a - Open tree
:BufferMovePrevious 100- there is an error:
Current buffer (3) not found in bufferline.nvim's list of buffers: { 1 }
closing because the error is caused by my own code.
With the check you added Current buffer (3) not found in bufferline.nvim's list of buffers: { 1 } I can no longer reproduce the error because the code stops before it tries to reorder with a nil from_idx