I am writing a vimscript function which should keep in a consistent state a "home made buffer manager". The idea is that I want to keep a trace of my buffers in the tabs they were open in.
This "buffer manager" simply is a dictionary which has the numbers of the tabs as keys and lists of buffers numbers as values.
To add the different buffers to this dictionary I created the following autocommand:
autocmd! BufEnter * call AddBufferToTab()
And then I have my function:
function! AddBufferToTab() let newBufNr = bufnr("%") " create an entry for the current tab if necessary if !has_key(g:BuffersManager, tabpagenr()) let g:BuffersManager[tabpagenr()] =  endif " Add the buffer to the tab if buflisted(newBufNr) && index(g:BuffersManager[tabpagenr()], newBufNr) == -1 call add (g:BuffersManager[tabpagenr()],newBufNr) endif endfunction
When vim enters a buffer the function is called, an empty list is created if the tab wasn't already managed.
Then I test if the buffer is listed by
buflisted(newBufNr) and if the buffer is already in the list of the tab.
It is important to note that the first test seems to work: I don't want to add buffers which are not listed by
:ls and when I open an help buffer for example, the buffer is not added
The function seems to work properly excepted for one use case:
When I open NERDTree with
:NERDTreeToggle the function doesn't seems to be executed (at least the debug
echom that I used never appeared) and the buffer still end added to the manager.
Note that when I add
echom "ADD " . bufnr("%") . " " . bufname("%") . " " . buflisted(bufnr("%"))
To the function the informations seems to be the good ones (the ones of the currently entered buffer).
I also checked that NERDTree buffer have their property
buflisted to 0.
I have been working on this problem for several days now and I really can't figure out what's happening.
TL;DR Why NERDTree buffers are added to the dictionary when the function is meant to ignore
NOTE If ones wants a big picture of the problem the function is a part of a plug-in I'm developing and which is available on github
NOTE 2 Of course if someone needs any additional information I'll gladly add them to this question, ask in the comments.
I followed the comment of @VanLaser and splitted the
if condition and based my test also on the name of the buffer. I also added some debugging message, here is the function in "debugging state":
function! AddBufferToTab() let newBufNr = bufnr("%") " create an entry for the current tab if necessary if !has_key(g:BuffersManager, tabpagenr()) let g:BuffersManager[tabpagenr()] =  endif " Get conditions to add the tab let isListed = buflisted(newBufNr) let isAlreadyInManager = 1 if (index(g:BuffersManager[tabpagenr()], newBufNr) == -1) let isAlreadyInManager = 0 endif let isNERDTreeBuffer = 0 if (bufname("%") =~ "NERD_Tree_") let isNERDTreeBuffer = 1 endif " Debugging messages echom bufname("%") if (isListed) echom "is Listed" else echom "is not Listed" endif if (isAlreadyInManager) echom "is AlreadyInManager" else echom "is not AlreadyInManager" endif if (isNERDTreeBuffer) echom "is NERDTreeBuffer" else echom "is not NERDTreeBuffer" endif echom "=========" " Add the buffer to the tab if isListed && !isAlreadyInManager && !isNERDTreeBuffer call add (g:BuffersManager[tabpagenr()],newBufNr) endif endfunction
I am sure that I don't have a call to the
add function anywhere else than in this function.
I then followed this workflow:
- sourcing the file, the buffer manager is empty
:e %(add the current file to the manager)
- select the first file
And here is the log I had:
As you can see the opening of NerdTree doesn't seem to trigger the function (since I don't have any message about it in the log) BUT when I output the content of my dictionnary I get:
As I said I don't have any other call to
add in my whole file (I gave sooner in the post the link to the github repo if anyone wants to check).
I don't understand how the buffer can be added when it doesn't even trigger the function.
More infos to follow the investigations of @VanLaser in the comments (many thanks to him):
First, to quote
Each buffer has a unique number. That number will not change, so you can always go to a specific buffer with
N CTRL-^, where N is the buffer number.
So in theory if I get the number of the buffer I'm using it shouldn't change in the future.
Also I added the following lines at the very beginning of my function:
echom bufnr('%') echom expand('<abuf>') if bufnr('%') != expand('<abuf>') echom "RETURN" return endif
and with the same workflow I get the same results, also I checked that the buffer numbers was the good ones:
Here is the output of
The output of
And finally the content of my dictionary:
As you can see it seems that the numbers are correctly returned, but once again NERDTree is launched but doesn't trigger the function.
More infos to follow the comments of @lcd047
I changed the autocommand to
autocmd! BufEnter * call AddBufferToTab(expand('<abuf>'))
The function prototype to
and I replaced
let newBufNr = bufnr("%") with
let newBufNr = a:bufNumber and the behavior gets even weirder:
I added after the assignation of
newBufNr the following debugging echos:
echom newBufNr echom bufnr('%') echom expand('<abuf>') echom a:bufNumber
For every buffers they show the same number (so using
<abuf> in the autocommand doesn't make a difference in the cases I tried).
But it get even weirder because then every buffers appears as not listed: for a reason that I don't understand
buflisted(expand('<abuf>')) returns 0 for every buffers.
PS I'm sorry for the length of this post I'm just trying to give as much informations as possible because I really absolutely don't understand what's happening there.