Automatically quit vim if NERDTree is last and only buffer - vim

I have the following in my .vimrc:
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Open NERDTree by default
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
autocmd VimEnter * NERDTree
autocmd VimEnter * wincmd p
So,
% vim file.txt
opens NERDTree and focuses the cursor in the file.txt buffer. I make my edits, and hit :q on the buffer, and I'm left with . . . NERDTree. This is annoying.
I could use :qa to close all buffers, and exit vim, but I'm used to the :q trope. So I'm wondering if there's a way to detect that the only remaining buffer is NERDTree, and "unify" the two buffers, for purposes of :q
Edit
Ask and ye shall receive: https://github.com/scrooloose/nerdtree/issues#issue/21

A script to do exactly this has been posted on the NERDTree issue list. Checkout issue-21 on GitHub for nerdtree.
This leads to the single line command for your vimrc here:
autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif

function! s:CloseIfOnlyControlWinLeft()
if winnr("$") != 1
return
endif
if (exists("t:NERDTreeBufName") && bufwinnr(t:NERDTreeBufName) != -1)
\ || &buftype == 'quickfix'
q
endif
endfunction
augroup CloseIfOnlyControlWinLeft
au!
au BufEnter * call s:CloseIfOnlyControlWinLeft()
augroup END
From my vimrc, based on a version from janus repo.
Enhancements: also close if only a quickfix window is left.
It uses the BufEnter autocommand instead, which is required for &bt to work properly.

An idea in need of implementation:
You could write a function which, when called, checks if the only buffer remaining (or perhaps the only non-help buffer, if you prefer) is a NERDTree buffer and, if so, deletes it (or just quits).
Then have an autocmd run it whenever a buffer is deleted / hidden / whatever actually happens when you :q (it shames me to admit I'm not entirely sure!).

You could :cabbrv q qa but I'd advise against that because you'll forget about it when you actually want q.

I like to do this: cmap bq :bufdo q<CR> to close all buffers with two keystrokes in command mode.

Related

Close vim if no "unhidden" buffers open

Is there any script that closes vim if there are only utility buffers open? I have seen some scrips for NERDTree (Close vim NERDtree on close of file), but none that is more general.
An example, because I am unsure if it is clear what I mean.
Tagbar, Magit and a file are open
I close the file
only utility buffers are open (both buffers are hidden from :ls) -> vim closes
Is there an easy way to do this?
You can use the following script to do what you want:
augroup auto_close_win
autocmd!
autocmd BufEnter * call s:quit_current_win()
augroup END
" Quit Nvim if we have only one window, and its filetype match our pattern.
function! s:quit_current_win() abort
let quit_filetypes = ['qf', 'vista']
let buftype = getbufvar(bufnr(), '&filetype')
if winnr('$') == 1 && index(quit_filetypes, buftype) != -1
quit
endif
endfunction
We use autocmd BufEnter to check if we have only one window left and the filetype of the current buffer is in the blacklist.
Update the list quit_filetypes to include the filetypes you have in mind.

Can VIM automatically close NERDTree when deleting a buffer?

Problem:
In VIM, open NERDTree
Select a file and open it in a new buffer (Enter)
Do some work on buffer and save it
Delete buffer with :bd
Now NERDTree takes up the whole window - this isn't a problem per se, but...
Go to next buffer with :bnext
Continue working
Now try opening NERDTree again by hitting Ctrl-N
You see, NERDTree stays "maximised" and you have to resize it.
My attempt at solving this issue:
My approach was what is stated in the title: close NERDTree automatically when deleting a buffer, then reopen it when entering another.
function! g:CloseNERDTree()
if exists("g:NERDTree") && g:NERDTree.IsOpen()
NERDTreeClose
else
echo "already closed"
endif
endfunction
autocmd BufDelete * call CloseNERDTree()
function! g:OpenNERDTree()
if exists("g:NERDTree") && g:NERDTree.IsOpen()
echo "already open"
else
NERDTree
endif
endfunction
autocmd BufEnter * call OpenNERDTree()
This causes VIM to become unusable and my VimScript knowledge isn't enough to know what's going on.
I cannot reproduce your particular problem (for me, NERDTree always opens in a sidebar), but I think the (or one) problem with your approach is with the BufDelete event. :help BufDelete has the following caveat:
Don't change to another buffer, it will cause problems.
I think it would be better to trigger on WinEnter, and use the number of visible windows (winnr('$')) for the check, like this (untested):
function! OnWinEnter()
if winnr('$') == 1
if exists("g:NERDTree") && g:NERDTree.IsOpen()
NERDTreeClose
endif
else
if ! (exists("g:NERDTree") && g:NERDTree.IsOpen())
NERDTreeOpen
endif
endif
endfunction
autocmd WinEnter * call OnWinEnter()

How do I run an autocommand on every filetype but one?

I have my vim set up to save files whenever I change buffers and on checktime. The problem is that I use Netrw and end up saving Netrw buffers. Can I run an autocommand on every type of file except netrw?
You can use an :if in your autocmd to guard against netrw files. e.g.
autocmd FileType * if &ft != 'netrw' | echo "do something" | endif
However this still isn't quite right. You have stopped from saving netrw buffers, but there are other buffers that shouldn't be saved. I would suggest checking 'buftype' and looking for files that start with a protocol e.g. foo://.
Here is an example of auto creating intermediary directories using such an approach:
" create parent directories
" https://stackoverflow.com/questions/4292733/vim-creating-parent-directories-on-save
function! s:MkNonExDir(file, buf)
if empty(getbufvar(a:buf, '&buftype')) && a:file!~#'\v^\w+\:\/'
let dir=fnamemodify(a:file, ':h')
if !isdirectory(dir)
call mkdir(dir, 'p')
endif
endif
endfunction
augroup BWCCreateDir
autocmd!
autocmd BufWritePre * :call s:MkNonExDir(expand('<afile>'), +expand('<abuf>'))
augroup END

How to prevent quitting vim accidentally?

Is there a way to rebind :q in vim to a more complex command to prevent accidentally exiting vim?
What you want is :close. It acts like :q but won't let you close the last window:
http://vimdoc.sourceforge.net/htmldoc/windows.html#:close
You can set an alias for the q command to map to close:
cabbrev q <c-r>=(getcmdtype()==':' && getcmdpos()==1 ? 'close' : 'q')<CR>
Thanks #Paradoxial for this :cabbrev trick.
I know, I know, it is a very old question, but I had the same question today and I found this post first. I developed a short script to put in .vimrc
function! ConfirmQuit(writeFile)
if (a:writeFile)
if (expand('%:t')=="")
echo "Can't save a file with no name."
return
endif
:write
endif
if (winnr('$')==1 && tabpagenr('$')==1)
if (confirm("Do you really want to quit?", "&Yes\n&No", 2)==1)
:quit
endif
else
:quit
endif
endfu
cnoremap <silent> q<CR> :call ConfirmQuit(0)<CR>
cnoremap <silent> x<CR> :call ConfirmQuit(1)<CR>
I hope this helps someone.
What are you afraid of? Vim won't let you quit (without a ! command modifier, anyway) when you still have unsaved changes, so the only thing you'll potentially lose is the window position, size, and maybe taskbar position of GVIM.
Anyway, to override built-in commands like :q, you can use the cmdalias plugin, like this:
:Alias q if\ winnr('$')>1||tabpagenr('$')>1||confirm('Really\ quit?',\ "&OK\\n&Cancel")==1|quit|endif
This checks for the last window (:q does not necessarily exit Vim), and inserts a confirmation.
You can use something like this to remove the :q command:
:cabbrev q <c-r>=(getcmdtype()==':' && getcmdpos()==1 ? 'echo' : 'q')<CR>
This abbreviates q to echo in command mode, but doesn't allow the abbreviation to trigger if the q isn't in the first column. This way, edit q won't abbreviate to edit echo.
ConfirmQuit.vim : Provides a confirm dialog when you try to quit vim
http://www.vim.org/scripts/script.php?script_id=1072
I adapted this by using
autocmd bufenter c:/intranet/notes.txt cnoremap <silent> wq<cr> call ConfirmQuit(1)<cr>
As I only wanted this on this for a particular file
Using the coot/cmdalias_vim plugin, I effectively disabled the short, impulsive quit commands :q, :q!, and :wq. Hopefully this will slow me down and make me think about whether I really want to use :quit or, say, :bdelete. Here's a condensed version of the "autocmd section" of my .vimrc file:
if has("autocmd")
augroup VIMRC_aliases
au!
au VimEnter * CmdAlias wqu\%[it] write|quit
au VimEnter * CmdAlias q echo\ "Use\ :qu[it]\ instead\ of\ :q"
au VimEnter * CmdAlias q! echo\ "Use\ :qu[it]!\ instead\ of\ :q!"
au VimEnter * CmdAlias wq echo\ "Use\ :wqu[it]\ instead\ of\ :wq"
augroup END
endif

Auto-open NERDTree in "EVERY" tab

Is it possible to open NERDTree in every tab with pressing t or T in NERDTree, if yes, How?
autocmd VimEnter * NERDTree
autocmd BufEnter * NERDTreeMirror
edit: The above command seems to open the new tab in NERDTree's buffer. Instead use this as mentioned by wejrowski in the comment below :
autocmd BufWinEnter * NERDTreeMirror
I wrote a vim plugin that does this and also adds some goodies on top (i.e. keeps all trees in sync, ensures meaningful tab captions - not captions like 'NERD_tree_1' etc.).
It's here on Github: https://github.com/jistr/vim-nerdtree-tabs
autocmd VimEnter * NERDTree
autocmd BufEnter * NERDTreeMirror
autocmd VimEnter * wincmd w
This one is a little better than Dustin's one because it places the cursor directly on the file you are intending to edit for quick edits. Thanks dustin for the original example ^^
A better solution is to open NERDTree only if there are no command line arguments set.
" Open NERDTree in new tabs and windows if no command line args set
autocmd VimEnter * if !argc() | NERDTree | endif
autocmd BufEnter * if !argc() | NERDTreeMirror | endif
NERDTree is e.g. not helpful if you do a git commit or something similiar.
This is probably not the best way, but if you edit plugin/NERDTree.vim and change this:
exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenInTab ." :call <SID>openInNewTab(0)<cr>"
to this:
exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenInTab ." :call <SID>openInNewTab(0)<cr>:NERDTree<cr>"
it will alter the binding of 't' in the NERDTree view to first open the file and then open NERDTree. Note, that the NERDTree views will not keep in sync.
How about toggling it.
" in .vimrc
" NERDTree, Use F3 for toggle NERDTree
nmap <silent> <F3> :NERDTreeToggle<CR>
In OSX, you just need to fn-F3 to toggle NERDTree.
This problem was actually mentioned in the official Repository's Readme file including three situations related to opening NERDTree automatically:
How can I open a NERDTree automatically when vim starts up?
Stick this in your vimrc: autocmd vimenter * NERDTree
How can I open a NERDTree automatically when vim starts up if no files were specified?
Stick this in your vimrc:
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 0 && !exists("s:std_in") | NERDTree | endif
Note: Now start vim with plain vim, not vim .
How can I open NERDTree automatically when vim starts up on opening a directory?
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 1 && isdirectory(argv()[0]) && !exists("s:std_in") | exe 'NERDTree' argv()[0] | wincmd p | ene | endif
This window is tab-specific, meaning it's used by all windows in the tab. This trick also prevents NERDTree from hiding when first selecting a file.

Resources