Skip to content
This repository has been archived by the owner on Apr 5, 2024. It is now read-only.

Error on closing a buffer if more than one tab open #102

Open
mattmartini opened this issue Jan 25, 2023 · 17 comments
Open

Error on closing a buffer if more than one tab open #102

mattmartini opened this issue Jan 25, 2023 · 17 comments

Comments

@mattmartini
Copy link

Issue:

While NERDTree is open, if there is more than one open tab and you close a tab (:q) the following error
is reported:

Error detected while processing WinEnter Autocommands for "*"..function <SNR>147_WinEnterHandler
[10]..<SNR>147_CloseIfOnlyNerdTreeLeft:

After acknowledging the error, the buffer in the tab is replaced by a full width NERDTree and NERDTree becomes about 80% width in all other open tabs.

If there is only one tab open then :q closes that tab and vim quits.

This seems to be caused by the function CloseIfOnlyNerdTreeLeft in nerdtree_plugin/vim-nerdtree-tabs.vim
specifically:

if exists("t:NERDTreeBufName") && bufwinnr(t:NERDTreeBufName) != -1 && winnr("$") == 1

Similarly:

In the NERDTree issue preservim/nerdtree#21 there is a discussion around a similar
problem and it is noted that t:NERDTreeBufName no longer exists.

I tried replacing the if statement with a few suggestions from that issue, to no avail. I tried:

if (winnr("$") == 1 && exists("b:NERDTreeType") && b:NERDTreeType == "primary")

and

if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree())

I understand that this project is no longer actively maintained, however I wanted to report the issue in case others are seeing similar problems.

Versions:

Error occurs:

vim 9.0.1200 on macOS 11.7.2 (Big Sur)
vim 9.0.1151 on macOS 13.1 (Ventura)

Error does not occur:

vim 9.0.920 on macOS 11.7.2 (Big Sur)
vim 8.0.3741 on ubuntu 18.04.6 LTS (Bionic Beaver)

@mattmartini
Copy link
Author

The error also does not occur on MacVim 9.0.472

@mjeffe
Copy link

mjeffe commented Jan 27, 2023

I'm seeing the same behavior. This started for me after an upgrade from MacOs 12 to 13 (Ventura). I would love to solve this, so will add what I've found so far.

I suspect this issue is related to a recent change in the way auto commands are processed. In this discussion Bram essentially says "you can no longer close your current buffer from within an autocmd". To confirm my suspicion, I used :9verbose q instead of simply :q to see debug print. This shows

E1312: Not allowed to change the window layout in this autocmd

So it seems to me we need to find a way in vimscript to quit the current buffer without using an autocmd?

Workaround

My current workaround is to use :tabc rather than :q, but this is far from ideal (muscle memory is hard to change).

Versions

Error occurs:

vim 9.0.1200 on macOS 13.1 (22C65) (Ventura)

Error does not occur:

vim 8.2.4919 on ubuntu 22.04.1 LTS (Jammy Jellyfish)

@mattmartini
Copy link
Author

Matt,

I added to the discussion you referenced above, asking if Gary J found a solution/work around. [because I am a new member to the group, my message is moderated and may not show up right away]. I'm hoping that he found a way to use SafeState or some other method which we could employ.

Matt

@mattmartini
Copy link
Author

Matt,

Gary responded with a few possible solutions. I will give them a try and report what works.

Matt

@mattmartini
Copy link
Author

Using:
call feedkeys(":tabc<CR>:<BS>")
instead of
q
CloseIfOnlyNerdTreeLeft

works, however the NERDTree window in all the other tabs becomes wide.
I was trying to use:
execute 'silent vertical resize ' . g:NERDTreeWinSize
which works on the commandline, to resize the window, but I am not sure what function to put it into.

@mattmartini
Copy link
Author

call timer_start(1, {-> execute('tabc') })

also works (and might avoid a race condition) yet it has the same problem of the NERDTree window resizing to wide.

@mattmartini
Copy link
Author

Here is the work-around I put together. It works pretty well.

fun! s:CloseIfOnlyNerdTreeLeft()
" Only take action when we are in NERDTree window, and no more window
" with normal buffer open.
if exists("t:NERDTreeBufName") && bufwinnr(t:NERDTreeBufName) == winnr() && s:NextNormalWindow() == -1
if tabpagenr('$') == 1
" Before quitting Vim, delete the buffer so that the '0 mark
" is correctly set to the previous buffer. This avoids NERDTree
" buffer being the last displayed buffer if Vim fails to quit
" due to the last file in the argument list has not been edited
" yet. Also disable autocmd on this command to avoid unnecessary
" autocmd nesting.
if winnr('$') == 1
noautocmd bdelete
endif
" Quit as usual, we have autocmd nesting open, so this command
" will trigger other plugin window's quiting behavior. If we are
" quiting Vim, our current buffer is successfully reset to the
" last file buffer, no need to warry about failure.
quit
else
call feedkeys(":tabc<CR>:<BS>")
call timer_start(200, {-> execute('vertical resize 31') })
" close
endif
endif
endfun

@mjeffe
Copy link

mjeffe commented Feb 1, 2023

Nice work @mattmartini! I'm so happy to have vim-nerdtree-tabs back to functional! I futzed with this earlier in the week with no luck, so I appreciate your work.

Your solution didn't exactly work for me, but led me to one that does. For some reason, the feedkeys command causes weird side effects, so I replaced it with the start_timer version. Also, I added a wincmd w so my focus ends up in the next buffer's window rather than the NerdTree window. Here is what I am using. I will post back if I run into issues or modify it more.

fun! s:CloseIfOnlyNerdTreeLeft()
  if exists("t:NERDTreeBufName") && bufwinnr(t:NERDTreeBufName) != -1 && winnr("$") == 1
    if has('patch-9.0.907')
      " Vim forbids closing the window inside an autocommand
      " Ref: https://groups.google.com/g/vim_dev/c/Cw8McBH6DDM?pli=1
      " So let's do it afterwards. Solution came from @mattmartini
      " Ref: https://github.com/jistr/vim-nerdtree-tabs/issues/102
      call timer_start(1, {-> execute('q') }) " close buffer after we exit autocmd
      call timer_start(20, {-> execute('vertical resize 31') }) " window sizing is goofed up, so fix it
      call timer_start(25, {-> execute('wincmd w') }) " shift focus from NerdTree window to buffer window
    else
      q
    endif
  endif
endfun

@mattmartini
Copy link
Author

mattmartini commented Feb 2, 2023 via email

@Jack12816
Copy link

@mjeffe I'm getting E930: Cannot use :redir inside execute() with vim 9.0 1-1302 with your solution. :( Also the timings for my setup vary. Here's my customized version:

fun! s:CloseIfOnlyNerdTreeLeft()
  if exists("t:NERDTreeBufName") && bufwinnr(t:NERDTreeBufName) != -1 && winnr("$") == 1
    if has('patch-9.0.907')
      " Vim forbids closing the window inside an autocommand
      " Ref: https://groups.google.com/g/vim_dev/c/Cw8McBH6DDM?pli=1
      " So let's do it afterwards. Solution came from @mattmartini
      " Ref: https://github.com/jistr/vim-nerdtree-tabs/issues/102
      call timer_start(1, {-> execute('q', 'silent!') }) " close buffer after we exit autocmd
      call timer_start(100, {-> execute('vertical resize 31', 'silent!') }) " window sizing is goofed up, so fix it
      call timer_start(250, {-> execute('wincmd w', 'silent!') }) " shift focus from NerdTree window to buffer window
    else
      q
    endif
  endif
endfun   

@mjeffe
Copy link

mjeffe commented Feb 23, 2023

@Jack12816, my version has been working well for me. Does it work for you with the longer timer_start() waits? If not, be sure to post back if you find a solution.

@huangyingjie
Copy link

@Jack12816 God, your code save my life, finally

@JonDum
Copy link

JonDum commented Jul 20, 2023

I've been plagued by this problem for literally years. Thank you guys so much for tracing this down! @mjeffe's solution works great!

I'm still getting this error unfortunately:

Error detected while processing WinEnter Autocommands for "*"..function <SNR>127_CloseIfOnlyNerdTreeLeft:
line    4:
E1312: Not allowed to change the window layout in this autocmd  

But it's infinitely better dismissing one error message versus having all my tab sizes messed up!

Maybe I did something wrong with that function? Right now I'm commenting out the original function in

fun! s:CloseIfOnlyNerdTreeLeft()
and replacing it with the patch.

@mjeffe
Copy link

mjeffe commented Jul 20, 2023

@JonDum the error message you are seeing is the original error message that we encountered, so it makes me suspect the patched function is not actually running. To answer your question, yes I simply replaced the CloseIfOnlyNerdTreeLeft() function in ~/.vim/bundle/vim-nerdtree-tabs/nerdtree_plugin/vim-nerdtree-tabs.vim with my patched version.

You might try removing the if has('patch-9.0.907') check. Perhaps that patch version is not being detected correctly. You could also try increasing the timer_start times like @Jack12816 and @mattmartini have above. I used shorter wait times because my machines seem to run quickly enough and it prevents the screen flashing. So the combined suggestions would look like this

fun! s:CloseIfOnlyNerdTreeLeft()
  if exists("t:NERDTreeBufName") && bufwinnr(t:NERDTreeBufName) != -1 && winnr("$") == 1
    call timer_start(1, {-> execute('q') }) " close buffer after we exit autocmd
    call timer_start(200, {-> execute('vertical resize 31') }) " window sizing is goofed up, so fix it
    call timer_start(250, {-> execute('wincmd w') }) " shift focus from NerdTree window to buffer window
  endif
endfun

@JonDum
Copy link

JonDum commented Jul 21, 2023

I'm a big dummy it turns out. Kinda. 😅

I had figured as much about the patching and that's what I had done as well! I even ran rg -uuu CloseIfOnlyNerdTreeLeft in ~/.vim to look for any other occurrences of that function. Notta. I added some echom calls in the function and they didn't show up. So now I'm really puzzled. I deleted it entirely and still got the error message! What the heck? I then sifted through :verbose function and... boom there's the culprit. It turns out I actually had a duplicate function in my .gvimrc! I can't even remember the last time I opened .gvimrc haha

I'm guessing I had it in there from before it was even added into nerd-tree-tabs!


I was curious how long ago this was so I did a little digging. I found this issue from twelve years ago that matches the function I had.

It wasn't until six months later that auto close was added to nerd-tree-tabs via cefef27 so I guess I had that lingering there as a duplicate all this time! Ain't software development neat.

Anyways it's all working now and my god is un-exaggeratedly life changing. Thanks again guys! 😆

@mjeffe
Copy link

mjeffe commented Jul 21, 2023

@JonDum glad you figured it out! I was pretty distressed as well when vim-nerdtree-tabs quit working, so I'm really glad that together we have been able to keep it alive. Thanks for posting back, so we have a record.

@lafrech
Copy link

lafrech commented Dec 6, 2023

Also impacted. Debian Bookworm. vim 9.0.1499.

Thank you guys so much for providing a workaround.

Not proficient in vim tweaking, I figured from @JonDum's comment above I could paste that function in my .vimrc but it didn't work. It works, however, if I patch the plugin file itself as instructed in @mjeffe's comment above.

Obviously, it would be nice if this was fixed "upstream" but I understand much too few of the internals to have an idea what that implies.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants