"============================================================================= " Copyright: Copyright (C) 2001-2012 Jeff Lanzarotta " Permission is hereby granted to use and distribute this code, " with or without modifications, provided that this copyright " notice is copied with it. Like anything else that's free, " bufexplorer.vim is provided *as is* and comes with no " warranty of any kind, either expressed or implied. In no " event will the copyright holder be liable for any damages " resulting from the use of this software. " Name Of File: bufexplorer.vim " Description: Buffer Explorer Vim Plugin " Maintainer: Jeff Lanzarotta (delux256-vim at yahoo dot com) " Last Changed: Sunday, 23 Dec 2012 " Version: See g:bufexplorer_version for version number. " Usage: This file should reside in the plugin directory and be " automatically sourced. " " You may use the default keymappings of " " be - Opens BufExplorer " bs - Opens horizontally split window BufExplorer " bv - Opens vertically split window BufExplorer " " Or you can override the defaults and define your own mapping " in your vimrc file, for example: " " noremap :BufExplorer " noremap :BufExplorerHorizontalSplit " noremap :BufExplorerVerticalSplit " " Or you can use " " ":BufExplorer" - Opens BufExplorer " ":BufExplorerHorizontalSplit" - Opens horizontally window BufExplorer " ":BufExplorerVerticalSplit" - Opens vertically split window BufExplorer " " For more help see supplied documentation. " History: See supplied documentation. " Issues: 'D' and 'd' remove the buffer from the list but the list is not " displayed correctly. " - Add ability to open a buffer in a new split when \be is used. "============================================================================= " Plugin Code {{{1 " Exit quickly if already running or when 'compatible' is set. {{{2 if exists("g:bufexplorer_version") || &cp finish endif "2}}} " Version number let g:bufexplorer_version = "7.3.2" " Check for Vim version {{{2 if v:version < 700 echohl WarningMsg echo "Sorry, bufexplorer ".g:bufexplorer_version." required Vim 7.0 and greater." echohl None finish endif " Create commands {{{2 command! BufExplorer :call BufExplorer(has ("gui") ? "drop" : "hide edit") command! BufExplorerHorizontalSplit :call BufExplorerHorizontalSplit() command! BufExplorerVerticalSplit :call BufExplorerVerticalSplit() " Set {{{2 function! s:Set(var, default) if !exists(a:var) if type(a:default) exec "let" a:var "=" string(a:default) else exec "let" a:var "=" a:default endif return 1 endif return 0 endfunction " Script variables {{{2 let s:MRU_Exclude_List = ["[BufExplorer]","__MRU_Files__"] let s:MRUList = [] let s:name = '[BufExplorer]' let s:originBuffer = 0 let s:running = 0 let s:sort_by = ["number", "name", "fullpath", "mru", "extension"] let s:splitMode = "" let s:tabSpace = [] let s:types = {"fullname": ':p', "path": ':p:h', "relativename": ':~:.', "relativepath": ':~:.:h', "shortname": ':t'} " Setup the autocommands that handle the MRUList and other stuff. {{{2 autocmd VimEnter * call s:Setup() " Setup {{{2 function! s:Setup() call s:Reset() " Now that the MRUList is created, add the other autocmds. augroup BufExplorer autocmd! autocmd BufEnter,BufNew * call s:ActivateBuffer() autocmd BufWipeOut * call s:DeactivateBuffer(1) autocmd BufDelete * call s:DeactivateBuffer(0) autocmd BufWinEnter \[BufExplorer\] call s:Initialize() autocmd BufWinLeave \[BufExplorer\] call s:Cleanup() autocmd TabEnter * call s:TabEnter() autocmd SessionLoadPost * call s:Reset() augroup END endfunction " Reset {{{2 function! s:Reset() " Build initial MRUList. This makes sure all the files specified on the " command line are picked up correctly. let s:MRUList = range(1, bufnr('$')) " Initialize one tab space array, ignore zero-based tabpagenr " since all tabpagenr's start at 1. " -1 signifies this is the first time we are referencing this " tabpagenr. " If Vim has been loaded with mksession, then it is possible for " more tabs to exist. So use tabpagenr() to determine how large " to make the array. If there are 4 tabs, there should be 5 " elements in this array. " Each element will hold a CSV list of buffers viewed in " that tab. So on the 3rd tab, if there user has viewed " 4 different buffers in that tab, the value would be: " echo s:tabSpace[3] " [4, 9, 1, 10] " echo s:tabSpace " [[-1], [-1], [-1], [4, 9, 1, 10], [-1]] let s:tabSpace = [] let i = 0 while( tabpagenr('$') > 0 && i <= tabpagenr('$') ) call add(s:tabSpace, [-1]) let i = i + 1 endwhile endfunction " ActivateBuffer {{{2 function! s:ActivateBuffer() " Verify the current tabpage exists in the " current s:tabSpace array. This can be missing " entries when restoring sessions. let i = 0 while( tabpagenr('$') > 0 && i <= tabpagenr() ) " Number: 0 " String: 1 " Funcref: 2 " List: 3 " Dictionary: 4 " Float: 5 if type(get(s:tabSpace, i)) == 0 call add(s:tabSpace, [-1]) endif let i = i + 1 endwhile let _bufnr = bufnr("%") let list = get(s:tabSpace, tabpagenr(), [-1]) if !empty(list) && list[0] == '-1' " The first time we add a tab, Vim uses the current buffer " as it's starting page. Even though we are about to " edit a new page (BufEnter is triggered after), so " remove the -1 entry indicating we have covered this case. let list = [] call add(list, _bufnr) let s:tabSpace[tabpagenr()] = list elseif empty(list) || index(list, _bufnr) == -1 " Add new buffer to this tab's buffer list. call add(list, _bufnr) let s:tabSpace[tabpagenr()] = list if g:bufExplorerOnlyOneTab == 1 " If a buffer can only be available in 1 tab page ensure this " buffer is not present in any other tabs let tabidx = 1 while tabidx < len(s:tabSpace) if tabidx != tabpagenr() let bufidx = index(s:tabSpace[tabidx], _bufnr) if bufidx != -1 call remove(s:tabSpace[tabidx], bufidx) endif endif let tabidx = tabidx + 1 endwhile endif endif call s:MRUPush(_bufnr) endfunction " DeactivateBuffer {{{2 function! s:DeactivateBuffer(remove) let _bufnr = str2nr(expand("")) call s:MRUPop(_bufnr) endfunction " TabEnter {{{2 function! s:TabEnter() " Make s:tabSpace 1-based if empty(s:tabSpace) || len(s:tabSpace) < (tabpagenr() + 1) call add(s:tabSpace, [-1]) endif endfunction " MRUPop {{{2 function! s:MRUPop(bufnr) call filter(s:MRUList, 'v:val != '.a:bufnr) endfunction " MRUPush {{{2 function! s:MRUPush(buf) " Skip temporary buffer with buftype set. Don't add the BufExplorer window to the " list. if s:ShouldIgnore(a:buf) == 1 return endif " Remove the buffer number from the list if it already exists. call s:MRUPop(a:buf) " Add the buffer number to the head of the list. call insert(s:MRUList, a:buf) endfunction " ShouldIgnore {{{2 function! s:ShouldIgnore(buf) " Ignore temporary buffers with buftype set. if empty(getbufvar(a:buf, "&buftype") == 0) return 1 endif " Ignore unlisted buffers. if buflisted(a:buf) == 0 return 1 endif " Ignore buffers with no name. if empty(bufname(a:buf)) == 1 return 1 endif " Ignore the BufExplorer buffer. if fnamemodify(bufname(a:buf), ":t") == s:name return 1 endif " Ignore any buffers in the exclude list. if index(s:MRU_Exclude_List, bufname(a:buf)) >= 0 return 1 endif " Else return 0 to indicate that the buffer was not ignored. return 0 endfunction " Initialize {{{2 function! s:Initialize() let s:_insertmode = &insertmode set noinsertmode let s:_showcmd = &showcmd set noshowcmd let s:_cpo = &cpo set cpo&vim let s:_report = &report let &report = 10000 let s:_list = &list set nolist setlocal nonumber setlocal foldcolumn=0 setlocal nofoldenable setlocal cursorline setlocal nospell setlocal nobuflisted let s:running = 1 endfunction " Cleanup {{{2 function! s:Cleanup() if exists("s:_insertmode") let &insertmode = s:_insertmode endif if exists("s:_showcmd") let &showcmd = s:_showcmd endif if exists("s:_cpo") let &cpo = s:_cpo endif if exists("s:_report") let &report = s:_report endif if exists("s:_list") let &list = s:_list endif let s:running = 0 let s:splitMode = "" delmarks! endfunction " BufExplorerHorizontalSplit {{{2 function! BufExplorerHorizontalSplit() let s:splitMode = "sp" exec "BufExplorer" endfunction " BufExplorerVerticalSplit {{{2 function! BufExplorerVerticalSplit() let s:splitMode = "vsp" exec "BufExplorer" endfunction " BufExplorer {{{2 function! BufExplorer(open) let name = s:name if !has("win32") " On non-Windows boxes, escape the name so that is shows up correctly. let name = escape(name, "[]") endif " Make sure there is only one explorer open at a time. if s:running == 1 " Go to the open buffer. if has("gui") exec "drop" name endif return endif " Add zero to ensure the variable is treated as a number. let s:originBuffer = bufnr("%") + 0 silent let s:raw_buffer_listing = s:GetBufferInfo(0) let buffer_listing_copy = copy(s:raw_buffer_listing) if (g:bufExplorerShowUnlisted == 0) call filter(buffer_listing_copy, 'v:val.attributes !~ "u"') endif if (!empty(buffer_listing_copy)) call filter(buffer_listing_copy, 'v:val.shortname !~ "\\\[No Name\\\]"') endif " if len(buffer_listing_copy) <= 1 " call s:Warning("Sorry, there are no more buffers to explore") " return " endif " We may have to split the current window. if (s:splitMode != "") " Save off the original settings. let [_splitbelow, _splitright] = [&splitbelow, &splitright] " Set the setting to ours. let [&splitbelow, &splitright] = [g:bufExplorerSplitBelow, g:bufExplorerSplitRight] " Do it. exe 'keepalt '.s:splitMode " Restore the original settings. let [&splitbelow, &splitright] = [_splitbelow, _splitright] endif if !exists("b:displayMode") || b:displayMode != "winmanager" " Do not use keepalt when opening bufexplorer to allow the buffer that " we are leaving to become the new alternate buffer exec "silent keepjumps ".a:open." ".name endif call s:DisplayBufferList() " Position the cursor in the newly displayed list on the line representing " the active buffer. The active buffer is the line with the '%' character " in it. execute search("%") endfunction " DisplayBufferList {{{2 function! s:DisplayBufferList() " Do not set bufhidden since it wipes out the data if we switch away from " the buffer using CTRL-^. setlocal buftype=nofile setlocal modifiable setlocal noswapfile setlocal nowrap call s:SetupSyntax() call s:MapKeys() call setline(1, s:CreateHelp()) call s:BuildBufferList() call cursor(s:firstBufferLine, 1) if !g:bufExplorerResize normal! zz endif setlocal nomodifiable endfunction " MapKeys {{{2 function! s:MapKeys() if exists("b:displayMode") && b:displayMode == "winmanager" nnoremap :call SelectBuffer() endif nnoremap