Skip to content

Instantly share code, notes, and snippets.

@ishmaelahmed
Created October 28, 2011 13:17
Show Gist options
  • Save ishmaelahmed/1322232 to your computer and use it in GitHub Desktop.
Save ishmaelahmed/1322232 to your computer and use it in GitHub Desktop.
VIM BUFFER LIST SCRIPT 1.3, simple way to keep track of your vim buffers
"=== VIM BUFFER LIST SCRIPT 1.3 ================================================
"= Copyright(c) 2005, Robert Lillack <rob@lillack.de> =
"= Redistribution in any form with or without modification permitted. =
"= =
"= INFORMATION =================================================================
"= Upon keypress this script display a nice list of buffers on the left, which =
"= can be selected with mouse or keyboard. As soon as a buffer is selected =
"= (Return, double click) the list disappears. =
"= The selection can be cancelled with the same key that is configured to open =
"= the list or by pressing 'q'. Movement key and mouse (wheel) should work as =
"= one expects. =
"= Buffers that are visible (in any window) are marked with '*', ones that are =
"= Modified are marked with '+' =
"= To delete a buffer from the list (i.e. close the file) press 'd'. =
"= =
"= USAGE =======================================================================
"= Put this file into you ~/.vim/plugin directory and set up up like this in =
"= your ~/.vimrc: =
"= =
"= NEEDED: =
"= map <silent> <F3> :call BufferList()<CR> =
"= OPTIONAL: =
"= let g:BufferListWidth = 25 =
"= let g:BufferListMaxWidth = 50 =
"= hi BufferSelected term=reverse ctermfg=white ctermbg=red cterm=bold =
"= hi BufferNormal term=NONE ctermfg=black ctermbg=darkcyan cterm=NONE =
"===============================================================================
if exists('g:BufferListLoaded')
finish
endif
let g:BufferListLoaded = 1
if !exists('g:BufferListWidth')
let g:BufferListWidth = 20
endif
if !exists('g:BufferListMaxWidth')
let g:BufferListMaxWidth = 40
endif
" toggled the buffer list on/off
function! BufferList()
" if we get called and the list is open --> close it
if bufexists(bufnr("__BUFFERLIST__"))
exec ':' . bufnr("__BUFFERLIST__") . 'bwipeout'
return
endif
let l:bufcount = bufnr('$')
let l:displayedbufs = 0
let l:activebuf = bufnr('')
let l:activebufline = 0
let l:buflist = ''
let l:bufnumbers = ''
let l:width = g:BufferListWidth
" iterate through the buffers
let l:i = 0 | while l:i <= l:bufcount | let l:i = l:i + 1
let l:bufname = bufname(l:i)
if strlen(l:bufname)
\&& getbufvar(l:i, '&modifiable')
\&& getbufvar(l:i, '&buflisted')
" adapt width and/or buffer name
if l:width < (strlen(l:bufname) + 5)
if strlen(l:bufname) + 5 < g:BufferListMaxWidth
let l:width = strlen(l:bufname) + 5
else
let l:width = g:BufferListMaxWidth
let l:bufname = '...' . strpart(l:bufname, strlen(l:bufname) - g:BufferListMaxWidth + 8)
endif
endif
if bufwinnr(l:i) != -1
let l:bufname = l:bufname . '*'
endif
if getbufvar(l:i, '&modified')
let l:bufname = l:bufname . '+'
endif
" count displayed buffers
let l:displayedbufs = l:displayedbufs + 1
" remember buffer numbers
let l:bufnumbers = l:bufnumbers . l:i . ':'
" remember the buffer that was active BEFORE showing the list
if l:activebuf == l:i
let l:activebufline = l:displayedbufs
endif
" fill the name with spaces --> gives a nice selection bar
" use MAX width here, because the width may change inside of this 'for' loop
while strlen(l:bufname) < g:BufferListMaxWidth
let l:bufname = l:bufname . ' '
endwhile
" add the name to the list
let l:buflist = l:buflist . ' ' .l:bufname . "\n"
endif
endwhile
" generate a variable to fill the buffer afterwards
" (we need this for "full window" color :)
let l:fill = "\n"
let l:i = 0 | while l:i < l:width | let l:i = l:i + 1
let l:fill = ' ' . l:fill
endwhile
" now, create the buffer & set it up
exec 'silent! ' . l:width . 'vne __BUFFERLIST__'
setlocal noshowcmd
setlocal noswapfile
setlocal buftype=nofile
setlocal bufhidden=delete
setlocal nobuflisted
setlocal nomodifiable
setlocal nowrap
setlocal nonumber
" set up syntax highlighting
if has("syntax")
syn clear
syn match BufferNormal / .*/
syn match BufferSelected /> .*/hs=s+1
hi def BufferNormal ctermfg=black ctermbg=white
hi def BufferSelected ctermfg=white ctermbg=black
endif
setlocal modifiable
if l:displayedbufs > 0
" input the buffer list, delete the trailing newline, & fill with blank lines
put! =l:buflist
" is there any way to NOT delete into a register? bummer...
"norm Gdd$
norm GkJ
while winheight(0) > line(".")
put =l:fill
endwhile
else
let l:i = 0 | while l:i < winheight(0) | let l:i = l:i + 1
put! =l:fill
endwhile
norm 0
endif
setlocal nomodifiable
" set up the keymap
noremap <silent> <buffer> <CR> :call LoadBuffer()<CR>
map <silent> <buffer> q :bwipeout<CR>
map <silent> <buffer> j :call BufferListMove("down")<CR>
map <silent> <buffer> k :call BufferListMove("up")<CR>
map <silent> <buffer> d :call BufferListDeleteBuffer()<CR>
map <silent> <buffer> <MouseDown> :call BufferListMove("up")<CR>
map <silent> <buffer> <MouseUp> :call BufferListMove("down")<CR>
map <silent> <buffer> <LeftDrag> <Nop>
map <silent> <buffer> <LeftRelease> :call BufferListMove("mouse")<CR>
map <silent> <buffer> <2-LeftMouse> :call BufferListMove("mouse")<CR>
\:call LoadBuffer()<CR>
map <silent> <buffer> <Down> j
map <silent> <buffer> <Up> k
map <buffer> h <Nop>
map <buffer> l <Nop>
map <buffer> <Left> <Nop>
map <buffer> <Right> <Nop>
map <buffer> i <Nop>
map <buffer> a <Nop>
map <buffer> I <Nop>
map <buffer> A <Nop>
map <buffer> o <Nop>
map <buffer> O <Nop>
map <silent> <buffer> <Home> :call BufferListMove(1)<CR>
map <silent> <buffer> <End> :call BufferListMove(line("$"))<CR>
" make the buffer count & the buffer numbers available
" for our other functions
let b:bufnumbers = l:bufnumbers
let b:bufcount = l:displayedbufs
" go to the correct line
call BufferListMove(l:activebufline)
endfunction
" move the selection bar of the list:
" where can be "up"/"down"/"mouse" or
" a line number
function! BufferListMove(where)
if b:bufcount < 1
return
endif
let l:newpos = 0
if !exists('b:lastline')
let b:lastline = 0
endif
setlocal modifiable
" the mouse was pressed: remember which line
" and go back to the original location for now
if a:where == "mouse"
let l:newpos = line(".")
call BufferListGoto(b:lastline)
endif
" exchange the first char (>) with a space
call setline(line("."), " ".strpart(getline(line(".")), 1))
" go where the user want's us to go
if a:where == "up"
call BufferListGoto(line(".")-1)
elseif a:where == "down"
call BufferListGoto(line(".")+1)
elseif a:where == "mouse"
call BufferListGoto(l:newpos)
else
call BufferListGoto(a:where)
endif
" and mark this line with a >
call setline(line("."), ">".strpart(getline(line(".")), 1))
" remember this line, in case the mouse is clicked
" (which automatically moves the cursor there)
let b:lastline = line(".")
setlocal nomodifiable
endfunction
" tries to set the cursor to a line of the buffer list
function! BufferListGoto(line)
if b:bufcount < 1 | return | endif
if a:line < 1
call cursor(1, 1)
elseif a:line > b:bufcount
call cursor(b:bufcount, 1)
else
call cursor(a:line, 1)
endif
endfunction
" loads the selected buffer
function! LoadBuffer()
" get the selected buffer
let l:str = BufferListGetSelectedBuffer()
" kill the buffer list
bwipeout
" ...and switch to the buffer number
exec ":b " . l:str
endfunction
" deletes the selected buffer
function! BufferListDeleteBuffer()
" get the selected buffer
let l:str = BufferListGetSelectedBuffer()
" kill the buffer list
bwipeout
" delete the selected buffer
exec ":bdelete " . l:str
" and reopen the list
call BufferList()
endfunction
function! BufferListGetSelectedBuffer()
" this is our string containing the buffer numbers in
" the order of the list (separated by ':')
let l:str = b:bufnumbers
" remove all numbers BEFORE the one we want
let l:i = 1 | while l:i < line(".") | let l:i = l:i + 1
let l:str = strpart(l:str, stridx(l:str, ':') + 1)
endwhile
" and everything AFTER
let l:str = strpart(l:str, 0, stridx(l:str, ':'))
return l:str
endfunction
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment