1

I'd like to maximize NERDTree when I enter the NERDTree buffer. The command I have so far is:

autocmd BufEnter NERD_tree_* <A>

...but the <A> part is wrong. I get the error:

E21: Cannot make changes, 'modifiable' is off: <A>

The maximize command is shift-A, and there's not any type of :NERDTreeMaximize command - I can't figure out what to put as the final step of that BufEnter command.

Any help is greatly appreciated, thanks!

Edit: I used a combination of the answers below to come up with this snippet, that maximizes on enter, and sets back to regular size when you leave the nerdtree buffer:

function NERDTreeMaximize()    
  if !exists("b:NERDTreeZoomed") || !b:NERDTreeZoomed    
    call NERDTreeMaximizeToggle()                                        
  endif                                                                      
endfunction                                                                  

function NERDTreeMinimize()                                                  
  if exists("b:NERDTreeZoomed") && b:NERDTreeZoomed    
    call NERDTreeMaximizeToggle()    
  endif                                                                      
endfunction                                                                  

function NERDTreeMaximizeToggle()                                            
  call b:NERDTree.ui.toggleZoom()                                            
endfunction                                                                  

augroup vimrc_nerdtree                                                       
  autocmd BufEnter NERD_tree_* :call NERDTreeMaximize()    
  autocmd BufLeave NERD_tree_* :call NERDTreeMinimize()    
augroup END

I'm not sure of the etiquette here, but I'll upvote all answers, and choose one as the correct one - I want everyone to get as many internet points as possible. Thanks to all!

3 Answers 3

2

TL;DR: You can use this auto-command to maximize the width of your NERDTree window when opened:

autocmd FileType nerdtree let b:NERDTreeZoomed = 1 | wincmd |

Alternatively, you can consider increasing the width of the window by setting the g:NERDTreeWinSize variable to a higher value (defaults to 30), you can set it to something very high to get the same effect as maximizing it:

let g:NERDTreeWinSize = 99999

First let's look at what's wrong with your command. autocmd takes an actual command (as in, one you start with :), so if you want to run a normal command (such as A, which has a special key-binding), you need to use the :normal command.

autocmd BufEnter NERD_tree_* normal A

This doesn't really work though, first because the buffer only gets a NERD_tree_* name after it's created and entered (so the BufEnter event will not happen right after you open the NERDTree window) and also because the BufEnter event will trigger every other time you enter the NERDTree window (so it will toggle zoom every time you enter it again!)

A better event is FileType, which is set to nerdtree on the NERDTree window and that is done only once, so you can use that event to trigger the zooming you want. So you'd think this would work:

autocmd FileType nerdtree normal A

Alas, it doesn't. Probably because the A binding was still not set by NERDTree at the time this auto-command happens. So what it's probably doing here is an "append", which is the default keybinding for A, but without any text, so a no-op overall...

So I found it's possible to get something to a similar effect by just using the equivalent of <C-w>|, which maximizes the window horizontally. There is :wincmd which allows accessing these <C-w> commands conveniently from normal mode, so this one works:

autocmd FileType nerdtree wincmd |

This solution still has a small shortcoming in that it's expanding the window width but not using NERDTree's "zoom" command, so the first time you use the A command from within NERDTree nothing will happen (it will "zoom" the window, but it will look the same.) The second time you do so, you will successfully "unzoom" it.

You can actually fix this by setting a buffer variable used by NERDTree to control whether the window is zoomed or not. The complete autocmd including setting the variable would be:

autocmd FileType nerdtree let b:NERDTreeZoomed = 1 | wincmd |

Of course, autocmds should live in their augroup (always, that is), so make sure you create an appropriate augroup or reuse one you might have in your .vimrc for this kind of customizations:

augroup vimrc_nerdtree
  autocmd!
  autocmd FileType nerdtree let b:NERDTreeZoomed = 1 | wincmd |
augroup END

Alternatively, NERDTree has a configuration variable to set the initial width of the window, so setting that one is also a possibility. If all you want is a larger window (not necessarily maximized), just increase it from 30 to something more reasonable such as 50 or 60 or whatever you prefer. If you want it maximized, just set it to something much higher than the number of columns you might have:

let g:NERDTreeWinSize = 99999

This solution (with a very large window size) has the issue with A no longer working as expected, just like the previous solution. In fact, in this case zooming and un-zooming with repeated As won't do a thing, since the "unzoomed" size of the window is already as large as possible.

Using a smaller window size but larger than the default of 30 might be a good alternative, since you'll get more than you get by default but still be able to "zoom" and "unzoom" if you need to see more.

12
  • The autocommand you settled on looks like trouble to me. Writing to internal variables is a risky proposition in general. Doing so before the parent code is guaranteed to be fully initialized ramps up the risk that much more.
    – B Layer
    Commented Jul 16, 2019 at 17:45
  • 1
    Anyways, if for some reason this solution didn't work for you initially, I'd be happy to see if I can help, if you let me know more details of what issue you were having with it... This site has been helping me improve my Vim skills enormously, so I'm really grateful to all those who are really active here and have been helping me grow!
    – filbranden
    Commented Jul 19, 2019 at 22:49
  • 1
    That being said I agree with pretty much all of what you're saying. And I much prefer collaboration/cooperation/civility among the regulars over the alternative including, last comment aside, general avoidance of comparing degrees of hackiness. :) We all post hacks now and then for the reasons you state. Hey, I'm glad you're aboard. You obviously have pretty deep Vim knowledge already. The more the merrier.
    – B Layer
    Commented Jul 19, 2019 at 23:08
  • 1
    Awesome! This discussion made my day, thanks for following up! 😁
    – filbranden
    Commented Jul 19, 2019 at 23:20
  • 1
    X = ((Looked at the associated source) + (it works consistently)) * Y. For Y = "launch controller programmer" : X => "You're fired!". For Y = "Vi&Vim SE contributor" : X => "Good enough!" :)
    – B Layer
    Commented Jul 19, 2019 at 23:34
1

Try normal A in your autocommand

3
  • This should actually be normal A since it's simply an uppercase A... It doesn't work for other reasons, I'll post an answer to expand on that.
    – filbranden
    Commented Jul 15, 2019 at 23:53
  • @filbranden doh
    – D. Ben Knoble
    Commented Jul 16, 2019 at 0:00
  • 1
    :-) I actually spent some time looking at this one. Unfortunately it's one of those you dig and dig and keep digging... See my answer for more details of why each of the steps doesn't work.
    – filbranden
    Commented Jul 16, 2019 at 0:17
1

This is one of those tricky scenarios where you can't be sure whether something is fully initialized at the time an autocommand is invoked. A hack is to delay some arbitrary amount of time before doing whatever it is you want to do. Slightly less hacky is to delay a bit, try, if it fails delay/try again some limited number of times. If no joy then give up.

Combining that with knowledge of the function actually used to do zooms we could try something like this...

func! NerdMax(timerid)
  if !exists("b:NERDTree")
      "echoerr "The plugin isn't initialized yet"
      return
  endif

  if !exists("b:NERDTreeZoomed") || b:NERDTreeZoomed == 0
      call b:NERDTree.ui.toggleZoom()
  else
      "echom "NERDTree is already zoomed"
  endif

  " Prevent any further calls
  call timer_stop(a:timerid)
endfunc

augroup nerdmax
  autocmd!
  autocmd FileType nerdtree call timer_start(500, 'NerdMax', {'repeat': 3})
augroup END

This seems to do the trick for me though one annoyance that I haven't explored yet is that sometimes the zoomed state doesn't take up the entire width.

Update: Based on my observations so far we might not actually need an artificial delay. It may be enough that we're executing the function in a different thread/context. Perhaps everything is allowed to finish initializing before Vim starts doing timer calls. If this is the actual reality (and I've seen similar behavior before) then everything could be reduced to...

func! NerdMax(timerid)
  if !exists("b:NERDTreeZoomed") || b:NERDTreeZoomed == 0
      call b:NERDTree.ui.toggleZoom()
  endif
endfunc

augroup nerdmax
  autocmd!
  autocmd FileType nerdtree call timer_start(50, 'NerdMax')
augroup END

(Come to think of it, now we can just use norm A instead of the toggleZoom() call!)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.