diff --git a/README.md b/README.md index 18594a7..b0e7ed6 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,11 @@ VIM bufferlist ============== -This is an implementation of [EMACS bufferlist](http://github.com/rockpiper/emacs-bufferlist) for [VIM](http://www.vim.org). +Deprecation warning +------------------- -About ------ - -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 bufferlist.vim file into your `~/.vim/plugin` directory and set it up -like this in your `~/.vimrc`: - -### Needed - - map :call BufferList() - -### 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 +Project moved here: [Vim NextBufferList](https://github.com/szw/vim-next_bufferlist). The further +development will continued only there. License ------- @@ -42,3 +13,4 @@ License Copyright(c) 2005, Robert Lillack Redistribution in any form with or without modification permitted. +Modifications (c) 2013, Szymon Wrozynski diff --git a/plugin/bufferlist.vim b/plugin/bufferlist.vim index fedb730..ff14ae9 100644 --- a/plugin/bufferlist.vim +++ b/plugin/bufferlist.vim @@ -1,11 +1,14 @@ -"=== VIM BUFFER LIST SCRIPT 1.3 ================================================ +"=== VIM BUFFER LIST SCRIPT 1.5 ================================================ "= Copyright(c) 2005, Robert Lillack = "= Redistribution in any form with or without modification permitted. = "= = +"= Modifications and further improvements = +"= (c) 2013 Szymon Wrozynski , https://github.com/szw = +"= = "= 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. = +"= ('Return' (or 's', 'v', 't'), 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. = @@ -18,8 +21,10 @@ "= your ~/.vimrc: = "= = "= NEEDED: = -"= map :call BufferList() = +"= map :BufferList = "= OPTIONAL: = +"= let g:BufferListShowUnnamed = 1 = +"= let g:BufferListShowTabFriends = 1 = "= let g:BufferListWidth = 25 = "= let g:BufferListMaxWidth = 50 = "= hi BufferSelected term=reverse ctermfg=white ctermbg=red cterm=bold = @@ -39,12 +44,35 @@ if !exists('g:BufferListMaxWidth') let g:BufferListMaxWidth = 40 endif +if !exists('g:BufferListShowUnnamed') + let g:BufferListShowUnnamed = 2 +endif + +if !exists('g:BufferListShowTabFriends') + let g:BufferListShowTabFriends = 2 +endif + +if g:BufferListShowTabFriends + au BufEnter * call BufferListAddTabFriend() +endif + +command! -nargs=0 -range BufferList :call BufferList(0) + " toggled the buffer list on/off -function! BufferList() +function! BufferList(internal) + if !a:internal + let s:tabfriendstoggle = (g:BufferListShowTabFriends == 2) + endif + " if we get called and the list is open --> close it if bufexists(bufnr("__BUFFERLIST__")) - exec ':' . bufnr("__BUFFERLIST__") . 'bwipeout' - return + let l:buflistnr = bufnr("__BUFFERLIST__") + let l:buflistwindow = bufwinnr(l:buflistnr) + exec ':' . l:buflistnr . 'bwipeout' + " if the list wasn't open, just the buffer existed, proceed with opening + if l:buflistwindow != -1 + return + endif endif let l:bufcount = bufnr('$') @@ -56,32 +84,40 @@ function! BufferList() 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:i = 0 | while l:i <= l:bufcount | let l:i += 1 + if s:tabfriendstoggle && !exists('t:BufferListTabFriends[' . l:i . ']') + continue + endif + let l:bufname = bufname(l:i) - if strlen(l:bufname) - \&& getbufvar(l:i, '&modifiable') - \&& getbufvar(l:i, '&buflisted') + if g:BufferListShowUnnamed && !strlen(l:bufname) + if !((g:BufferListShowUnnamed == 2) && !getbufvar(l:i, '&modified')) || (bufwinnr(l:i) != -1) + let l:bufname = '[' . l:i . '*No Name]' + endif + endif + + 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) + let l:bufname = '…' . strpart(l:bufname, strlen(l:bufname) - g:BufferListMaxWidth + 6) endif endif if bufwinnr(l:i) != -1 - let l:bufname = l:bufname . '*' + let l:bufname .= '*' endif if getbufvar(l:i, '&modified') - let l:bufname = l:bufname . '+' + let l:bufname .= '+' endif " count displayed buffers - let l:displayedbufs = l:displayedbufs + 1 + let l:displayedbufs += 1 " remember buffer numbers - let l:bufnumbers = l:bufnumbers . l:i . ':' + let l:bufnumbers .= l:i . ':' " remember the buffer that was active BEFORE showing the list if l:activebuf == l:i let l:activebufline = l:displayedbufs @@ -89,20 +125,20 @@ function! BufferList() " 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 . ' ' + let l:bufname .= ' ' endwhile " add the name to the list - let l:buflist = l:buflist . ' ' .l:bufname . "\n" + let 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:i = 0 | while l:i < l:width | let l:i += 1 let l:fill = ' ' . l:fill endwhile - + " now, create the buffer & set it up exec 'silent! ' . l:width . 'vne __BUFFERLIST__' setlocal noshowcmd @@ -128,31 +164,35 @@ function! BufferList() " 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 + "normal! Gdd$ + normal! 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 + let l:i = 0 | while l:i < winheight(0) | let l:i += 1 put! =l:fill endwhile - norm 0 + normal! 0 endif setlocal nomodifiable " set up the keymap - noremap :call LoadBuffer() - map q :bwipeout - map j :call BufferListMove("down") - map k :call BufferListMove("up") - map d :call BufferListDeleteBuffer() - map :call BufferListMove("up") - map :call BufferListMove("down") + noremap :call LoadBuffer() + noremap v :call LoadBuffer("vs") + noremap s :call LoadBuffer("sp") + noremap t :call LoadBuffer("tabnew") + map q :bwipeout + map j :call BufferListMove("down") + map k :call BufferListMove("up") + map d :call BufferListDeleteBuffer() + map D :call BufferListDeleteHiddenBuffers() + map :call BufferListMove("up") + map :call BufferListMove("down") map - map :call BufferListMove("mouse") - map <2-LeftMouse> :call BufferListMove("mouse") - \:call LoadBuffer() + map :call BufferListMove("mouse") + map <2-LeftMouse> :call BufferListMove("mouse") + \:call LoadBuffer() map j map k map h @@ -165,8 +205,14 @@ function! BufferList() map A map o map O - map :call BufferListMove(1) - map :call BufferListMove(line("$")) + map :call BufferListMove(1) + map :call BufferListMove(line("$")) + + if g:BufferListShowTabFriends + map a :call BufferListToggleTabFriends() + map f :call BufferListDetachTabFriend() + map F :call BufferListDeleteForeignBuffers() + endif " make the buffer count & the buffer numbers available " for our other functions @@ -174,13 +220,13 @@ function! BufferList() let b:bufcount = l:displayedbufs " go to the correct line - call BufferListMove(l:activebufline) + 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) +function! BufferListMove(where) if b:bufcount < 1 return endif @@ -194,7 +240,7 @@ function! BufferListMove(where) " and go back to the original location for now if a:where == "mouse" let l:newpos = line(".") - call BufferListGoto(b:lastline) + call BufferListGoto(b:lastline) endif " exchange the first char (>) with a space @@ -202,13 +248,13 @@ function! BufferListMove(where) " go where the user want's us to go if a:where == "up" - call BufferListGoto(line(".")-1) + call BufferListGoto(line(".")-1) elseif a:where == "down" - call BufferListGoto(line(".")+1) + call BufferListGoto(line(".")+1) elseif a:where == "mouse" - call BufferListGoto(l:newpos) + call BufferListGoto(l:newpos) else - call BufferListGoto(a:where) + call BufferListGoto(a:where) endif " and mark this line with a > @@ -222,7 +268,7 @@ function! BufferListMove(where) endfunction " tries to set the cursor to a line of the buffer list -function! BufferListGoto(line) +function! BufferListGoto(line) if b:bufcount < 1 | return | endif if a:line < 1 call cursor(1, 1) @@ -234,34 +280,74 @@ function! BufferListGoto(line) endfunction " loads the selected buffer -function! LoadBuffer() +function! LoadBuffer(...) " get the selected buffer - let l:str = BufferListGetSelectedBuffer() + let l:str = BufferListGetSelectedBuffer() " kill the buffer list bwipeout + + if !empty(a:000) + exec ":" . a:1 + endif + " ...and switch to the buffer number exec ":b " . l:str endfunction " deletes the selected buffer -function! BufferListDeleteBuffer() +function! BufferListDeleteBuffer() " get the selected buffer - let l:str = BufferListGetSelectedBuffer() - " kill the buffer list + let l:str = BufferListGetSelectedBuffer() + if !getbufvar(str2nr(l:str), '&modified') + " kill the buffer list + bwipeout + " delete the selected buffer + exec ":bdelete " . l:str + " and reopen the list + call BufferList(1) + endif +endfunction + +function! BufferListKeepBuffersForKeys(dict) + for b in range(1, bufnr('$')) + if buflisted(b) && !has_key(a:dict, b) && !getbufvar(b, '&modified') + exe ':bdelete ' . b + endif + endfor +endfunction + +" deletes all hidden buffers +" taken from: http://stackoverflow.com/a/3180886 +function! BufferListDeleteHiddenBuffers() + let l:visible = {} + for t in range(1, tabpagenr('$')) + for b in tabpagebuflist(t) + let l:visible[b] = 1 + endfor + endfor bwipeout - " delete the selected buffer - exec ":bdelete " . l:str - " and reopen the list - call BufferList() + call BufferListKeepBuffersForKeys(l:visible) + call BufferList(1) endfunction -function! BufferListGetSelectedBuffer() +" deletes all foreign (not tab friend) buffers +function! BufferListDeleteForeignBuffers() + let l:friends = {} + for t in range(1, tabpagenr('$')) + silent! call extend(l:friends, gettabvar(t, 'BufferListTabFriends')) + endfor + bwipeout + call BufferListKeepBuffersForKeys(l:friends) + call BufferList(1) +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:i = 1 | while l:i < line(".") | let l:i += 1 let l:str = strpart(l:str, stridx(l:str, ':') + 1) endwhile @@ -271,3 +357,40 @@ function! BufferListGetSelectedBuffer() return l:str endfunction +function! BufferListAddTabFriend() + if !exists('t:BufferListTabFriends') + let t:BufferListTabFriends = {} + endif + + let l:current = bufnr('%') + + if getbufvar(l:current, '&modifiable') && getbufvar(l:current, '&buflisted') && l:current != bufnr("__BUFFERLIST__") + let t:BufferListTabFriends[l:current] = 1 + endif +endfunction + +function! BufferListToggleTabFriends() + let s:tabfriendstoggle = !s:tabfriendstoggle + bwipeout + call BufferList(1) +endfunction + +function! BufferListDetachTabFriend() + let l:str = BufferListGetSelectedBuffer() + if exists('t:BufferListTabFriends[' . l:str . ']') + if bufwinnr(str2nr(l:str)) != -1 + call BufferListMove("down") + if BufferListGetSelectedBuffer() == l:str + call BufferListMove("up") + if BufferListGetSelectedBuffer() == l:str + return + endif + endif + call LoadBuffer() + else + bwipeout + endif + call remove(t:BufferListTabFriends, l:str) + call BufferList(1) + endif +endfunction