Search code examples
vimnerdtree

VIM and NERD Tree - closing a buffer properly


Does anyone know how to close a buffer in VIM when using NERDTree without messing up all your windows? NERD Tree normally breaks up your display into two vertical windows (the browser on your left, and then your main window on the right). If you close a buffer, then you are reduced to one giant file browsing window. If you select another file, then it opens up a second window but separating it horizontally. Any ideas?


Solution

  • I don't use NERD Tree, but if I understand correctly, you wish to close a buffer without closing a window. If my reasoning is correct, try this script.

    " Delete buffer while keeping window layout (don't close buffer's windows).
    " Version 2008-11-18 from http://vim.wikia.com/wiki/VimTip165
    if v:version < 700 || exists('loaded_bclose') || &cp
    finish
    endif
    let loaded_bclose = 1
    if !exists('bclose_multiple')
    let bclose_multiple = 1
    endif
    
    " Display an error message.
    function! s:Warn(msg)
    echohl ErrorMsg
    echomsg a:msg
    echohl NONE
    endfunction
    
    " Command ':Bclose' executes ':bd' to delete buffer in current window.
    " The window will show the alternate buffer (Ctrl-^) if it exists,
    " or the previous buffer (:bp), or a blank buffer if no previous.
    " Command ':Bclose!' is the same, but executes ':bd!' (discard changes).
    " An optional argument can specify which buffer to close (name or number).
    function! s:Bclose(bang, buffer)
    if empty(a:buffer)
    let btarget = bufnr('%')
    elseif a:buffer =~ '^\d\+$'
    let btarget = bufnr(str2nr(a:buffer))
    else
    let btarget = bufnr(a:buffer)
    endif
    if btarget < 0
    call s:Warn('No matching buffer for '.a:buffer)
    return
    endif
    if empty(a:bang) && getbufvar(btarget, '&modified')
    call s:Warn('No write since last change for buffer '.btarget.' (use :Bclose!)')
    return
    endif
    " Numbers of windows that view target buffer which we will delete.
    let wnums = filter(range(1, winnr('$')), 'winbufnr(v:val) == btarget')
    if !g:bclose_multiple && len(wnums) > 1
    call s:Warn('Buffer is in multiple windows (use ":let bclose_multiple=1")')
    return
    endif
    let wcurrent = winnr()
    for w in wnums
    execute w.'wincmd w'
    let prevbuf = bufnr('#')
    if prevbuf > 0 && buflisted(prevbuf) && prevbuf != w
    buffer #
    else
    bprevious
    endif
    if btarget == bufnr('%')
    " Numbers of listed buffers which are not the target to be deleted.
    let blisted = filter(range(1, bufnr('$')), 'buflisted(v:val) && v:val != btarget')
    " Listed, not target, and not displayed.
    let bhidden = filter(copy(blisted), 'bufwinnr(v:val) < 0')
    " Take the first buffer, if any (could be more intelligent).
    let bjump = (bhidden + blisted + [-1])[0]
    if bjump > 0
    execute 'buffer '.bjump
    else
    execute 'enew'.a:bang
    endif
    endif
    endfor
    execute 'bdelete'.a:bang.' '.btarget
    execute wcurrent.'wincmd w'
    endfunction
    command! -bang -complete=buffer -nargs=? Bclose call <SID>Bclose('<bang>', '<args>')
    nnoremap <silent> <Leader>bd :Bclose<CR>
    nnoremap <silent> <Leader>bD :Bclose!<CR>