Last Updated: February 25, 2016
·
556
· avovsya

Simple way to close anything

Vim has a lot of ways to close buffers and windows -
:bw, :bd, :bun, :q, :close and so on. What I really wanted is simply close windows and files like in "ordinary" editors(sublime, notepad++, etc.), but with a power of Vim's buffers. My ideal algorithm for this looks like this:

  1. I'm pressing one key chord
  2. If there more then one buffer in Vim - close current buffer, but leave the window
  3. Otherwise if the buffer is empty - quit Vim
  4. Otherwise if the buffer opened in multiple windows - close window
  5. This is a last buffer and there is only one window - close buffer and leave empty window

The code snippet for this flow looks like this(it is requires bufkill.vim plugin)

function! CountListedBuffers() 
  let cnt = 0 
  for nr in range(1,bufnr("$")) 
    if buflisted(nr) 
      let cnt += 1 
    endif 
  endfor 
  return cnt 
endfunction 

function! SmartExit()
    let s:BufferToKill = bufnr('%')
    let s:EmptyBuffer = 0

    if bufname('%') == '' && ! &modified && &modifiable
        if &buftype == 'nofile' && &swapfile == 0
            " Is scratch buffer, not empty
        else
            let s:EmptyBuffer = 1
        endif
    endif

    " Get a list of all windows which have this buffer loaded
    let s:WindowListWithBufferLoaded = []
    let i = 1
    let buf = winbufnr(i)
    while buf != -1
        if buf == s:BufferToKill
            let s:WindowListWithBufferLoaded += [i]
        endif
        let i = i + 1
        let buf = winbufnr(i)
    endwhile

    " Check that the buffer is last
    if(CountListedBuffers() < 2)
        let s:LastBuffer = 1
    else
        let s:LastBuffer = 0
    endif

    if s:LastBuffer
        if len(s:WindowListWithBufferLoaded) > 1
            execute "close"
        else
            if ! s:EmptyBuffer
                execute "bw | bw"
            else
                execute "q"
            endif
        endif
    else
        let g:BufKillActionWhenBufferDisplayedInAnotherWindow="kill"
        execute "BW"
        let g:BufKillActionWhenBufferDisplayedInAnotherWindow="confirm"
    endif
endfunction

nmap <Leader>q :call SmartExit() " Maps SmarExit function to Leader + q

P.S. May be at first glance this algorithm doesn't look so obvious, but you should try it, and say how it is