jistr / vim-nerdtree-tabs

NERDTree and tabs together in Vim, painlessly
Apache License 2.0
1.43k stars 130 forks source link

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

Open mattmartini opened 1 year ago

mattmartini commented 1 year ago

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 https://github.com/preservim/nerdtree/issues/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 commented 1 year ago

The error also does not occur on MacVim 9.0.472

mjeffe commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

Matt,

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

Matt

mattmartini commented 1 year ago

Using: call feedkeys(":tabc\:\") 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 commented 1 year ago

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 commented 1 year ago

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\:\") call timer_start(200, {-> execute('vertical resize 31') }) " close endif endif endfun

mjeffe commented 1 year ago

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 commented 1 year ago

Thanks for your addition of wincmd w !!

On Feb 1, 2023, at 5:43 PM, Matt Jeffery @.***> wrote:

Nice work @mattmartini https://github.com/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 — Reply to this email directly, view it on GitHub https://github.com/jistr/vim-nerdtree-tabs/issues/102#issuecomment-1412841300, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAM6OTNBP56LG3M4J7LJD3WVLRJJANCNFSM6AAAAAAUGWWMUA. You are receiving this because you were mentioned.

Jack12816 commented 1 year ago

@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 commented 1 year ago

@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 commented 1 year ago

@Jack12816 God, your code save my life, finally

JonDum commented 1 year ago

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 https://github.com/jistr/vim-nerdtree-tabs/blob/07d19f0299762669c6f93fbadb8249da6ba9de62/nerdtree_plugin/vim-nerdtree-tabs.vim#L337 and replacing it with the patch.

mjeffe commented 1 year ago

@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 commented 1 year ago

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 https://github.com/jistr/vim-nerdtree-tabs/commit/cefef278c2f0263a9d86bfc6a64d8fbf3c8d962f 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 commented 1 year ago

@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 commented 11 months ago

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.