1 "==============================================================================
2 " Copyright: Copyright (C) 2001-2010 Jeff Lanzarotta
3 " Permission is hereby granted to use and distribute this code,
4 " with or without modifications, provided that this copyright
5 " notice is copied with it. Like anything else that's free,
6 " bufexplorer.vim is provided *as is* and comes with no
7 " warranty of any kind, either expressed or implied. In no
8 " event will the copyright holder be liable for any damages
9 " resulting from the use of this software.
10 " Name Of File: bufexplorer.vim
11 " Description: Buffer Explorer Vim Plugin
12 " Maintainer: Jeff Lanzarotta (delux256-vim at yahoo dot com)
13 " Last Changed: Friday, 22 October 2010
14 " Version: See g:bufexplorer_version for version number.
15 " Usage: This file should reside in the plugin directory and be
16 " automatically sourced.
18 " You may use the default keymappings of
20 " <Leader>be - Opens BE.
21 " <Leader>bs - Opens horizontally window BE.
22 " <Leader>bv - Opens vertically window BE.
26 " ":BufExplorer" - Opens BE.
27 " ":BufExplorerHorizontalSplit" - Opens horizontally window BE.
28 " ":BufExplorerVerticalSplit" - Opens vertically window BE.
30 " For more help see supplied documentation.
31 " History: See supplied documentation.
32 "==============================================================================
34 " Exit quickly if already running or when 'compatible' is set. {{{1
35 if exists("g:bufexplorer_version") || &cp
41 let g:bufexplorer_version = "7.2.8"
43 " Check for Vim version 700 or greater {{{1
45 "echo "Sorry, bufexplorer ".g:bufexplorer_version."\nONLY runs with Vim 7.0 and greater."
49 " Public Interface {{{1
50 if maparg("<Leader>be") =~ 'BufExplorer'
54 if maparg("<Leader>bs") =~ 'BufExplorerHorizontalSplit'
58 if maparg("<Leader>bv") =~ 'BufExplorerVerticalSplit'
62 nmap <script> <silent> <unique> <Leader>be :BufExplorer<CR>
63 nmap <script> <silent> <unique> <Leader>bs :BufExplorerHorizontalSplit<CR>
64 nmap <script> <silent> <unique> <Leader>bv :BufExplorerVerticalSplit<CR>
66 " Create commands {{{1
67 command! BufExplorer :call StartBufExplorer(has ("gui") ? "drop" : "hide edit")
68 command! BufExplorerHorizontalSplit :call BufExplorerHorizontalSplit()
69 command! BufExplorerVerticalSplit :call BufExplorerVerticalSplit()
72 function! s:BESet(var, default)
75 exec "let" a:var "=" string(a:default)
77 exec "let" a:var "=" a:default
88 " Build initial MRUList. This makes sure all the files specified on the
89 " command line are picked up correctly.
90 let s:MRUList = range(1, bufnr('$'))
92 " Initialize one tab space array, ignore zero-based tabpagenr
93 " since all tabpagenr's start at 1.
94 " -1 signifies this is the first time we are referencing this
96 let s:tabSpace = [ [-1], [-1] ]
99 " Setup the autocommands that handle the MRUList and other stuff. {{{1
100 " This is only done once when Vim starts up.
101 augroup BufExplorerVimEnter
103 autocmd VimEnter * call s:BESetup()
107 function! s:BESetup()
110 " Now that the MRUList is created, add the other autocmds.
112 " Deleting autocommands in case the script is reloaded
114 autocmd TabEnter * call s:BETabEnter()
115 autocmd BufNew * call s:BEAddBuffer()
116 autocmd BufEnter * call s:BEActivateBuffer()
118 autocmd BufWipeOut * call s:BEDeactivateBuffer(1)
119 autocmd BufDelete * call s:BEDeactivateBuffer(0)
121 autocmd BufWinEnter \[BufExplorer\] call s:BEInitialize()
122 autocmd BufWinLeave \[BufExplorer\] call s:BECleanup()
123 autocmd SessionLoadPost * call s:BEReset()
126 " Remove the VimEnter event as it is no longer needed
127 augroup SelectBufVimEnter
133 function! s:BETabEnter()
134 " Make s:tabSpace 1-based
135 if empty(s:tabSpace) || len(s:tabSpace) < (tabpagenr() + 1)
136 call add(s:tabSpace, [-1])
141 function! s:BEAddBuffer()
142 if !exists('s:raw_buffer_listing') || empty(s:raw_buffer_listing)
143 silent let s:raw_buffer_listing = s:BEGetBufferInfo(0)
145 " We cannot use :buffers! or :ls! to gather information
146 " about this buffer since it was only just added.
147 " Any changes to the buffer (setlocal buftype, ...)
148 " happens after this event fires.
150 " So we will indicate the :buffers! command must be re-run.
151 " This should help with the performance of the plugin.
153 " There are some checks which can be performed
154 " before deciding to refresh the buffer list.
155 let bufnr = expand('<abuf>') + 0
157 if s:BEIgnoreBuffer(bufnr) == 1
160 let s:refreshBufferList = 1
164 call s:BEActivateBuffer()
167 " ActivateBuffer {{{1
168 function! s:BEActivateBuffer()
170 let l = get(s:tabSpace, tabpagenr(), [])
172 if s:BEIgnoreBuffer(b) == 1
176 if !empty(l) && l[0] == '-1'
177 " The first time we add a tab Vim uses the current
178 " buffer as it's starting page, even though we are about
179 " to edit a new page (BufEnter triggers after), so
180 " remove the -1 entry indicating we have covered this case.
182 let s:tabSpace[tabpagenr()] = l
183 elseif empty(l) || index(l, b) == -1
184 " Add new buffer to this tab buffer list
186 let s:tabSpace[tabpagenr()] = l
188 if g:bufExplorerOnlyOneTab == 1
189 " If a buffer can only be available in 1 tab page
190 " ensure this buffer is not present in any other tabs
192 while tabidx < len(s:tabSpace)
193 if tabidx != tabpagenr()
194 let bufidx = index(s:tabSpace[tabidx], b)
196 call remove(s:tabSpace[tabidx], bufidx)
199 let tabidx = tabidx + 1
206 if exists('s:raw_buffer_listing') && !empty(s:raw_buffer_listing)
207 " Check if the buffer exists, but was deleted previously
208 " Careful use of ' and " so we do not have to escape all the \'s
210 " ^ - Starting at the beginning of the string
211 " \s* - optional whitespace
212 " b - Vim's buffer number
213 " u\> - the buffer must be unlisted
214 let shortlist = filter(copy(s:raw_buffer_listing), "v:val.attributes =~ '".'^\s*'.b.'u\>'."'")
217 " If it is unlisted (ie deleted), but now we editing it again
218 " rebuild the buffer list.
219 let s:refreshBufferList = 1
224 " BEDeactivateBuffer {{{1
225 function! s:BEDeactivateBuffer(remove)
226 let _bufnr = str2nr(expand("<abuf>"))
228 call s:BEMRUPop(_bufnr)
231 call s:BEDeleteBufferListing(_bufnr)
233 let s:refreshBufferList = 1
238 function! s:BEMRUPop(buf)
239 call filter(s:MRUList, 'v:val != '.a:buf)
243 function! s:BEMRUPush(buf)
244 if s:BEIgnoreBuffer(a:buf) == 1
248 " Remove the buffer number from the list if it already exists.
249 call s:BEMRUPop(a:buf)
251 " Add the buffer number to the head of the list.
252 call insert(s:MRUList,a:buf)
256 function! s:BEInitialize()
257 let s:_insertmode = &insertmode
260 let s:_showcmd = &showcmd
266 let s:_report = &report
273 setlocal foldcolumn=0
274 setlocal nofoldenable
283 function! s:BEIgnoreBuffer(buf)
284 " Check to see if this buffer should be ignore by BufExplorer.
286 " Skip temporary buffers with buftype set.
287 if empty(getbufvar(a:buf, "&buftype") == 0)
291 " Skip unlisted buffers.
292 if buflisted(a:buf) == 0
296 " Skip buffers with no name.
297 if empty(bufname(a:buf)) == 1
301 " Do not add the BufExplorer window to the list.
302 if fnamemodify(bufname(a:buf), ":t") == s:name
303 call s:BEError("The buffer name was [".s:name."] so it was skipped.")
307 if index(s:MRU_Exclude_List, bufname(a:buf)) >= 0
315 function! s:BECleanup()
316 if exists("s:_insertmode")|let &insertmode = s:_insertmode|endif
317 if exists("s:_showcmd") |let &showcmd = s:_showcmd |endif
318 if exists("s:_cpo") |let &cpo = s:_cpo |endif
319 if exists("s:_report") |let &report = s:_report |endif
320 if exists("s:_list") |let &list = s:_list |endif
327 " BufExplorerHorizontalSplit {{{1
328 function! BufExplorerHorizontalSplit()
329 let s:splitMode = "sp"
333 " BufExplorerVerticalSplit {{{1
334 function! BufExplorerVerticalSplit()
335 let s:splitMode = "vsp"
339 " StartBufExplorer {{{1
340 function! StartBufExplorer(open)
344 " On non-Windows boxes, escape the name so that is shows up correctly.
345 let name = escape(name, "[]")
346 call s:BEError("Escaped")
349 " Make sure there is only one explorer open at a time.
351 call s:BEError("WHAT THE 1")
352 " Go to the open buffer.
354 call s:BEError("WHAT THE 2")
362 " Add zero to ensure the variable is treated as a Number.
363 let s:originBuffer = bufnr("%") + 0
365 " Create or rebuild the raw buffer list if necessary.
366 if !exists('s:raw_buffer_listing') ||
367 \ empty(s:raw_buffer_listing) ||
368 \ s:refreshBufferList == 1
369 silent let s:raw_buffer_listing = s:BEGetBufferInfo(0)
372 let copy = copy(s:raw_buffer_listing)
374 if (g:bufExplorerShowUnlisted == 0)
375 call filter(copy, 'v:val.attributes !~ "u"')
378 " We may have to split the current window.
379 if (s:splitMode != "")
380 " Save off the original settings.
381 let [_splitbelow, _splitright] = [&splitbelow, &splitright]
383 " Set the setting to ours.
384 let [&splitbelow, &splitright] = [g:bufExplorerSplitBelow, g:bufExplorerSplitRight]
387 exe 'keepalt '.s:splitMode
389 " Restore the original settings.
390 let [&splitbelow, &splitright] = [_splitbelow, _splitright]
393 if !exists("b:displayMode") || b:displayMode != "winmanager"
394 " Do not use keepalt when opening bufexplorer to allow the buffer that we are
395 " leaving to become the new alternate buffer
396 exec "silent keepjumps ".a:open." ".name
399 call s:BEDisplayBufferList()
402 " BEDisplayBufferList {{{1
403 function! s:BEDisplayBufferList()
404 " Do not set bufhidden since it wipes out
405 " the data if we switch away from the buffer
407 setlocal buftype=nofile
412 " Delete all previous lines to the black hole register
414 exec 'silent! normal! "_dG'
416 call s:BESetupSyntax()
418 call setline(1, s:BECreateHelp())
419 call s:BEBuildBufferList()
420 call cursor(s:firstBufferLine, 1)
422 if !g:bufExplorerResize
426 setlocal nomodifiable
430 function! s:BEMapKeys()
431 if exists("b:displayMode") && b:displayMode == "winmanager"
432 nnoremap <buffer> <silent> <tab> :call <SID>BESelectBuffer("tab")<cr>
435 nnoremap <buffer> <silent> <F1> :call <SID>BEToggleHelp()<cr>
436 nnoremap <buffer> <silent> <2-leftmouse> :call <SID>BESelectBuffer()<cr>
437 nnoremap <buffer> <silent> <cr> :call <SID>BESelectBuffer()<cr>
438 nnoremap <buffer> <silent> o :call <SID>BESelectBuffer()<cr>
439 nnoremap <buffer> <silent> t :call <SID>BESelectBuffer("tab")<cr>
440 nnoremap <buffer> <silent> <s-cr> :call <SID>BESelectBuffer("tab")<cr>
442 nnoremap <buffer> <silent> d :call <SID>BERemoveBuffer("delete", "n")<cr>
443 xnoremap <buffer> <silent> d :call <SID>BERemoveBuffer("delete", "v")<cr>
444 nnoremap <buffer> <silent> D :call <SID>BERemoveBuffer("wipe", "n")<cr>
445 xnoremap <buffer> <silent> D :call <SID>BERemoveBuffer("wipe", "v")<cr>
447 nnoremap <buffer> <silent> m :call <SID>BEMRUListShow()<cr>
448 nnoremap <buffer> <silent> p :call <SID>BEToggleSplitOutPathName()<cr>
449 nnoremap <buffer> <silent> q :call <SID>BEClose("quit")<cr>
450 nnoremap <buffer> <silent> r :call <SID>BESortReverse()<cr>
451 nnoremap <buffer> <silent> R :call <SID>BEToggleShowRelativePath()<cr>
452 nnoremap <buffer> <silent> s :call <SID>BESortSelect()<cr>
453 nnoremap <buffer> <silent> S :call <SID>BEReverseSortSelect()<cr>
454 nnoremap <buffer> <silent> u :call <SID>BEToggleShowUnlisted()<cr>
455 nnoremap <buffer> <silent> f :call <SID>BEToggleFindActive()<cr>
456 nnoremap <buffer> <silent> T :call <SID>BEToggleShowTabBuffer()<cr>
457 nnoremap <buffer> <silent> B :call <SID>BEToggleOnlyOneTab()<cr>
459 for k in ["G", "n", "N", "L", "M", "H"]
460 exec "nnoremap <buffer> <silent>" k ":keepjumps normal!" k."<cr>"
465 function! s:BESetupSyntax()
467 syn match bufExplorerHelp "^\".*" contains=bufExplorerSortBy,bufExplorerMapping,bufExplorerTitle,bufExplorerSortType,bufExplorerToggleSplit,bufExplorerToggleOpen
468 syn match bufExplorerOpenIn "Open in \w\+ window" contained
469 syn match bufExplorerSplit "\w\+ split" contained
470 syn match bufExplorerSortBy "Sorted by .*" contained contains=bufExplorerOpenIn,bufExplorerSplit
471 syn match bufExplorerMapping "\" \zs.\+\ze :" contained
472 syn match bufExplorerTitle "Buffer Explorer.*" contained
473 syn match bufExplorerSortType "'\w\{-}'" contained
474 syn match bufExplorerBufNbr /^\s*\d\+/
475 syn match bufExplorerToggleSplit "toggle split type" contained
476 syn match bufExplorerToggleOpen "toggle open mode" contained
477 syn match bufExplorerModBuf /^\s*\d\+.\{4}+.*/
478 syn match bufExplorerLockedBuf /^\s*\d\+.\{3}[\-=].*/
479 syn match bufExplorerHidBuf /^\s*\d\+.\{2}h.*/
480 syn match bufExplorerActBuf /^\s*\d\+.\{2}a.*/
481 syn match bufExplorerCurBuf /^\s*\d\+.%.*/
482 syn match bufExplorerAltBuf /^\s*\d\+.#.*/
483 syn match bufExplorerUnlBuf /^\s*\d\+u.*/
485 hi def link bufExplorerBufNbr Number
486 hi def link bufExplorerMapping NonText
487 hi def link bufExplorerHelp Special
488 hi def link bufExplorerOpenIn Identifier
489 hi def link bufExplorerSortBy String
490 hi def link bufExplorerSplit NonText
491 hi def link bufExplorerTitle NonText
492 hi def link bufExplorerSortType bufExplorerSortBy
493 hi def link bufExplorerToggleSplit bufExplorerSplit
494 hi def link bufExplorerToggleOpen bufExplorerOpenIn
496 hi def link bufExplorerActBuf Identifier
497 hi def link bufExplorerAltBuf String
498 hi def link bufExplorerCurBuf Type
499 hi def link bufExplorerHidBuf Constant
500 hi def link bufExplorerLockedBuf Special
501 hi def link bufExplorerModBuf Exception
502 hi def link bufExplorerUnlBuf Comment
507 function! s:BEToggleHelp()
508 let g:bufExplorerDetailedHelp = !g:bufExplorerDetailedHelp
516 if (s:firstBufferLine > 1)
517 exec "keepjumps 1,".(s:firstBufferLine - 1) "d _"
520 call append(0, s:BECreateHelp())
525 setlocal nomodifiable
527 if exists("b:displayMode") && b:displayMode == "winmanager"
528 call WinManagerForceReSize("BufExplorer")
532 " BEGetHelpStatus {{{1
533 function! s:BEGetHelpStatus()
534 let ret = '" Sorted by '.((g:bufExplorerReverseSort == 1) ? "reverse " : "").g:bufExplorerSortBy
535 let ret .= ' | '.((g:bufExplorerFindActive == 0) ? "Don't " : "")."Locate buffer"
536 let ret .= ((g:bufExplorerShowUnlisted == 0) ? "" : " | Show unlisted")
537 let ret .= ((g:bufExplorerShowTabBuffer == 0) ? "" : " | Show buffers/tab")
538 let ret .= ((g:bufExplorerOnlyOneTab == 1) ? "" : " | One tab / buffer")
539 let ret .= ' | '.((g:bufExplorerShowRelativePath == 0) ? "Absolute" : "Relative")
540 let ret .= ' '.((g:bufExplorerSplitOutPathName == 0) ? "Full" : "Split")." path"
546 function! s:BECreateHelp()
547 if g:bufExplorerDefaultHelp == 0 && g:bufExplorerDetailedHelp == 0
548 let s:firstBufferLine = 1
554 if g:bufExplorerDetailedHelp == 1
555 call add(header, '" Buffer Explorer ('.g:bufexplorer_version.')')
556 call add(header, '" --------------------------')
557 call add(header, '" <F1> : toggle this help')
558 call add(header, '" <enter> or o or Mouse-Double-Click : open buffer under cursor')
559 call add(header, '" <shift-enter> or t : open buffer in another tab')
560 call add(header, '" d : delete buffer')
561 call add(header, '" D : wipe buffer')
562 call add(header, '" f : toggle find active buffer')
563 call add(header, '" p : toggle spliting of file and path name')
564 call add(header, '" q : quit')
565 call add(header, '" r : reverse sort')
566 call add(header, '" R : toggle showing relative or full paths')
567 call add(header, '" s : cycle thru "sort by" fields '.string(s:sort_by).'')
568 call add(header, '" S : reverse cycle thru "sort by" fields')
569 call add(header, '" T : toggle if to show only buffers for this tab or not')
570 call add(header, '" u : toggle showing unlisted buffers')
572 call add(header, '" Press <F1> for Help')
575 if (!exists("b:displayMode") || b:displayMode != "winmanager") || (b:displayMode == "winmanager" && g:bufExplorerDetailedHelp == 1)
576 call add(header, s:BEGetHelpStatus())
577 call add(header, '"=')
580 let s:firstBufferLine = len(header) + 1
585 " BEGetBufferInfo {{{1
586 function! s:BEGetBufferInfo(bufnr)
592 " Since we are only interested in this specified buffer
593 " remove the other buffers listed
594 let bufoutput = substitute(bufoutput."\n", '^.*\n\(\s*'.a:bufnr.'\>.\{-}\)\n.*', '\1', '')
597 let [all, allwidths, listedwidths] = [[], {}, {}]
599 for n in keys(s:types)
600 let allwidths[n] = []
601 let listedwidths[n] = []
604 for buf in split(bufoutput, '\n')
605 let bits = split(buf, '"')
606 let b = {"attributes": bits[0], "line": substitute(bits[2], '\s*', '', '')}
608 for [key, val] in items(s:types)
609 let b[key] = fnamemodify(bits[1], val)
612 if getftype(b.fullname) == "dir" && g:bufExplorerShowDirectories == 1
613 let b.shortname = "<DIRECTORY>"
618 for n in keys(s:types)
619 call add(allwidths[n], len(b[n]))
621 if b.attributes !~ "u"
622 call add(listedwidths[n], len(b[n]))
627 let [s:allpads, s:listedpads] = [{}, {}]
629 for n in keys(s:types)
630 let s:allpads[n] = repeat(' ', max(allwidths[n]))
631 let s:listedpads[n] = repeat(' ', max(listedwidths[n]))
634 let s:refreshBufferList = 1
639 " BEBuildBufferList {{{1
640 function! s:BEBuildBufferList()
643 " Loop through every buffer.
644 for buf in s:raw_buffer_listing
645 " Skip unlisted buffers if we are not to show them.
646 if (!g:bufExplorerShowUnlisted && buf.attributes =~ "u")
650 if (g:bufExplorerShowTabBuffer)
653 for bufnr in s:tabSpace[tabpagenr()]
654 if (buf.attributes =~ '^\s*'.bufnr.'\>')
655 " Only buffers shown on the current tabpagenr
666 let line = buf.attributes." "
668 if g:bufExplorerSplitOutPathName
669 let type = (g:bufExplorerShowRelativePath) ? "relativepath" : "path"
671 let pad = (g:bufExplorerShowUnlisted) ? s:allpads.shortname : s:listedpads.shortname
672 let line .= buf.shortname." ".strpart(pad.path, len(buf.shortname))
674 let type = (g:bufExplorerShowRelativePath) ? "relativename" : "fullname"
679 let pads = (g:bufExplorerShowUnlisted) ? s:allpads : s:listedpads
681 if !empty(pads[type])
682 let line .= strpart(pads[type], len(path))." "
687 call add(lines, line)
690 call setline(s:firstBufferLine, lines)
692 call s:BESortListing()
695 " BESelectBuffer {{{1
696 function! s:BESelectBuffer(...)
697 " Sometimes messages are not cleared when we get here so it looks like an error has
698 " occurred when it really has not.
701 " Are we on a line with a file name?
702 if line('.') < s:firstBufferLine
707 let _bufNbr = str2nr(getline('.'))
709 " Check and see if we are running BE via WinManager.
710 if exists("b:displayMode") && b:displayMode == "winmanager"
711 let bufname = expand("#"._bufNbr.":p")
713 if (a:0 == 1) && (a:1 == "tab")
714 call WinManagerFileEdit(bufname, 1)
716 call WinManagerFileEdit(bufname, 0)
722 if bufexists(_bufNbr)
723 if bufnr("#") == _bufNbr && !exists("g:bufExplorerChgWin")
727 " Are we suppose to open the selected buffer in a tab?
728 if (a:0 == 1) && (a:1 == "tab")
729 " Yes, we are to open the selected buffer in a tab.
731 " Restore [BufExplorer] buffer.
732 exec "keepjumps silent buffer!".s:originBuffer
734 " Get the tab number where this buffer is located at.
735 let tabNbr = s:BEGetTabNbr(_bufNbr)
739 " _bufNbr is not opened in any tabs. Open a new tab with the selected buffer in it.
740 exec "999tab split +buffer" . _bufNbr
742 " The _bufNbr is already opened in tab, go to that tab.
743 exec tabNbr . "tabnext"
746 exec s:BEGetWinNbr(tabNbr, _bufNbr) . "wincmd w"
749 "No, the use did not ask to open the selected buffer in a tab.
751 " Are we suppose to move to the tab where this active buffer is?
752 if exists("g:bufExplorerChgWin")
753 exe g:bufExplorerChgWin."wincmd w"
754 elseif bufloaded(_bufNbr) && g:bufExplorerFindActive
755 " Close the BE window.
758 " Get the tab number where this buffer is located at.
759 let tabNbr = s:BEGetTabNbr(_bufNbr)
763 " The buffer is located in a tab. Go to that tab number.
764 exec tabNbr . "tabnext"
766 " Nope, the buffer is not in a tab, simple switch to that buffer.
767 let bufname = expand("#"._bufNbr.":p")
768 exec bufname ? "drop ".escape(bufname, " ") : "buffer "._bufNbr
772 " Switch to the buffer.
773 exec "keepalt keepjumps silent b!" _bufNbr
776 " Make the buffer 'listed' again.
777 call setbufvar(_bufNbr, "&buflisted", "1")
779 " call any associated function references
780 " g:bufExplorerFuncRef may be an individual function reference
781 " or it may be a list containing function references.
782 " It will ignore anything that's not a function reference.
783 " See :help FuncRef for more on function references.
784 if exists("g:BufExplorerFuncRef")
785 if type(g:BufExplorerFuncRef) == 2
786 keepj call g:BufExplorerFuncRef()
787 elseif type(g:BufExplorerFuncRef) == 3
788 for FncRef in g:BufExplorerFuncRef
796 call s:BEError("Sorry, that buffer no longer exists, please select another")
797 call s:BEDeleteBuffer(_bufNbr, "wipe")
801 " BEDeleteBufferListing {{{1
802 function! s:BEDeleteBufferListing(buf)
803 if exists('s:raw_buffer_listing') && !empty(s:raw_buffer_listing)
804 " Delete the buffer from the raw buffer list.
805 " Careful use of ' and " so we do not have to escape all the \'s
806 " Regex: ^\s*\(10\|20\)\>
807 " ^ - Starting at the beginning of the string
808 " \s* - optional whitespace
809 " \(10\|20\) - either a 10 or a 20
810 " \> - end of word (so it can't make 100 or 201)
811 call filter(s:raw_buffer_listing, "v:val.attributes !~ '".'^\s*\('.substitute(a:buf, ' ', '\\|', 'g').'\)\>'."'")
815 " BERemoveBuffer {{{1
816 function! s:BERemoveBuffer(type, mode) range
817 " Are we on a line with a file name?
818 if line('.') < s:firstBufferLine
822 " These commands are to temporarily suspend the activity of winmanager.
823 if exists("b:displayMode") && b:displayMode == "winmanager"
824 call WinManagerSuspendAUs()
829 for lineNum in range(a:firstline, a:lastline)
830 let line = getline(lineNum)
832 if line =~ '^\s*\(\d\+\)'
833 " Regex: ^\s*\(10\|20\)\>
834 " ^ - Starting at the beginning of the string
835 " \s* - optional whitespace
836 " \zs - start the match here
838 " \> - end of word (so it can't make 100 or 201)
839 let bufNbr = matchstr(line, '^\s*\zs\d\+\>')
841 " Add 0 to bufNbr to ensure Vim treats it as a Number
842 " for use with the getbufvar() function
843 if bufNbr !~ '^\d\+$' || getbufvar(bufNbr+0, '&modified') != 0
844 call s:BEError("Sorry, no write since last change for buffer ".bufNbr.", unable to delete")
846 let _bufNbrs = _bufNbrs . (_bufNbrs==''?'':' '). bufNbr
851 " Okay, everything is good, delete or wipe the buffers.
852 call s:BEDeleteBuffer(_bufNbrs, a:type)
854 " Reactivate winmanager autocommand activity.
855 if exists("b:displayMode") && b:displayMode == "winmanager"
856 call WinManagerForceReSize("BufExplorer")
857 call WinManagerResumeAUs()
861 " BEDeleteBuffer {{{1
862 function! s:BEDeleteBuffer(bufNbr, mode)
863 " This routine assumes that the buffer to be removed is on the current line.
868 exe "bdelete" a:bufNbr
873 " Remove each of the lines beginning with the buffer numbers we are removing
874 " Regex: ^\s*\(10\|20\)\>
875 " ^ - Starting at the beginning of the string
876 " \s* - optional whitespace
877 " \(10\|20\) - either a 10 or a 20
878 " \> - end of word (so it can't make 100 or 201)
879 exec 'silent! g/^\s*\('.substitute(a:bufNbr, ' ', '\\|', 'g').'\)\>/d_'
881 setlocal nomodifiable
883 call s:BEDeleteBufferListing(a:bufNbr)
885 call s:BEError(v:exception)
890 function! s:BEClose(mode)
891 " Get only the listed buffers.
892 let listed = filter(copy(s:MRUList), "buflisted(v:val)")
894 " If we needed to split the main window, close the split one.
896 " if (s:splitMode != "")
897 if (s:splitMode != "" && a:mode == "quit")
904 for b in reverse(listed[0:1])
905 exec "keepjumps silent b ".b
910 " BEToggleSplitOutPathName {{{1
911 function! s:BEToggleSplitOutPathName()
912 let g:bufExplorerSplitOutPathName = !g:bufExplorerSplitOutPathName
913 call s:BERebuildBufferList()
914 call s:BEUpdateHelpStatus()
917 " BEToggleShowRelativePath {{{1
918 function! s:BEToggleShowRelativePath()
919 let g:bufExplorerShowRelativePath = !g:bufExplorerShowRelativePath
920 call s:BERebuildBufferList()
921 call s:BEUpdateHelpStatus()
924 " BEToggleShowUnlisted {{{1
925 function! s:BEToggleShowUnlisted()
926 let g:bufExplorerShowUnlisted = !g:bufExplorerShowUnlisted
927 let num_bufs = s:BERebuildBufferList(g:bufExplorerShowUnlisted == 0)
928 call s:BEUpdateHelpStatus()
931 " BEToggleFindActive {{{1
932 function! s:BEToggleFindActive()
933 let g:bufExplorerFindActive = !g:bufExplorerFindActive
934 call s:BEUpdateHelpStatus()
937 " BEToggleShowTabBuffer {{{1
938 function! s:BEToggleShowTabBuffer()
939 let g:bufExplorerShowTabBuffer = !g:bufExplorerShowTabBuffer
940 call s:BEDisplayBufferList()
943 " BEToggleOnlyOneTab {{{1
944 function! s:BEToggleOnlyOneTab()
945 let g:bufExplorerOnlyOneTab = !g:bufExplorerOnlyOneTab
946 call s:BEDisplayBufferList()
949 " BERebuildBufferList {{{1
950 function! s:BERebuildBufferList(...)
953 let curPos = getpos('.')
956 " Clear the list first.
957 exec "keepjumps ".s:firstBufferLine.',$d "_'
960 let num_bufs = s:BEBuildBufferList()
962 call setpos('.', curPos)
964 setlocal nomodifiable
969 " BEUpdateHelpStatus {{{1
970 function! s:BEUpdateHelpStatus()
973 let text = s:BEGetHelpStatus()
974 call setline(s:firstBufferLine - 2, text)
976 setlocal nomodifiable
980 function! s:BEMRUCmp(line1, line2)
981 return index(s:MRUList, str2nr(a:line1)) - index(s:MRUList, str2nr(a:line2))
985 function! s:BESortReverse()
986 let g:bufExplorerReverseSort = !g:bufExplorerReverseSort
987 call s:BEReSortListing()
991 function! s:BESortSelect()
992 let g:bufExplorerSortBy = get(s:sort_by, index(s:sort_by, g:bufExplorerSortBy) + 1, s:sort_by[0])
993 call s:BEReSortListing()
996 " BEReverseSortSelect {{{1
997 function! s:BEReverseSortSelect()
998 let g:bufExplorerSortBy = get(s:sort_by, (index(s:sort_by, g:bufExplorerSortBy) + len(s:sort_by) - 1) % len(s:sort_by), s:sort_by[0])
999 call s:BEReSortListing()
1002 " BEReSortListing {{{1
1003 function! s:BEReSortListing()
1006 let curPos = getpos('.')
1008 call s:BESortListing()
1009 call s:BEUpdateHelpStatus()
1011 call setpos('.', curPos)
1013 setlocal nomodifiable
1016 " BESortListing {{{1
1017 function! s:BESortListing()
1018 let sort = s:firstBufferLine.",$sort".((g:bufExplorerReverseSort == 1) ? "!": "")
1020 if g:bufExplorerSortBy == "number"
1023 elseif g:bufExplorerSortBy == "name"
1024 if g:bufExplorerSplitOutPathName
1025 exec sort 'ir /\d.\{7}\zs\f\+\ze/'
1027 exec sort 'ir /\zs[^\/\\]\+\ze\s*line/'
1029 elseif g:bufExplorerSortBy == "fullpath"
1030 if g:bufExplorerSplitOutPathName
1031 " Sort twice - first on the file name then on the path.
1032 exec sort 'ir /\d.\{7}\zs\f\+\ze/'
1035 exec sort 'ir /\zs\f\+\ze\s\+line/'
1036 elseif g:bufExplorerSortBy == "extension"
1037 exec sort 'ir /\.\zs\w\+\ze\s/'
1038 elseif g:bufExplorerSortBy == "mru"
1039 let l = getline(s:firstBufferLine, "$")
1041 call sort(l, "<SID>BEMRUCmp")
1043 if g:bufExplorerReverseSort
1047 call setline(s:firstBufferLine, l)
1051 " BEMRUListShow {{{1
1052 function! s:BEMRUListShow()
1053 echomsg "MRUList=".string(s:MRUList)
1057 function! s:BEError(msg)
1058 echohl ErrorMsg | echo a:msg | echohl none
1062 function! s:BEWarning(msg)
1063 echohl WarningMsg | echo a:msg | echohl none
1067 function! s:BEGetTabNbr(bufNbr)
1068 " Searching buffer bufno, in tabs.
1069 for i in range(tabpagenr("$"))
1070 if index(tabpagebuflist(i + 1), a:bufNbr) != -1
1079 function! s:BEGetWinNbr(tabNbr, bufNbr)
1080 " window number in tabpage.
1081 return index(tabpagebuflist(a:tabNbr), a:bufNbr) + 1
1084 " Winmanager Integration {{{1
1085 let g:BufExplorer_title = "\[Buf\ List\]"
1086 call s:BESet("g:bufExplorerResize", 1)
1087 call s:BESet("g:bufExplorerMaxHeight", 25) " Handles dynamic resizing of the window.
1089 " Function to start display. Set the mode to 'winmanager' for this buffer.
1090 " This is to figure out how this plugin was called. In a standalone fashion
1092 function! BufExplorer_Start()
1093 let b:displayMode = "winmanager"
1094 call StartBufExplorer("e")
1097 " Returns whether the display is okay or not.
1098 function! BufExplorer_IsValid()
1102 " Handles dynamic refreshing of the window.
1103 function! BufExplorer_Refresh()
1104 let b:displayMode = "winmanager"
1105 call StartBufExplorer("e")
1108 function! BufExplorer_ReSize()
1109 if !g:bufExplorerResize
1113 let nlines = min([line("$"), g:bufExplorerMaxHeight])
1115 exe nlines." wincmd _"
1117 " The following lines restore the layout so that the last file line is also
1118 " the last window line. Sometimes, when a line is deleted, although the
1119 " window size is exactly equal to the number of lines in the file, some of
1120 " the lines are pushed up and we see some lagging '~'s.
1121 let pres = getpos(".")
1125 let _scr = &scrolloff
1130 let &scrolloff = _scr
1132 call setpos(".", pres)
1135 " Default values {{{1
1136 call s:BESet("g:bufExplorerDefaultHelp", 1) " Show default help?
1137 call s:BESet("g:bufExplorerDetailedHelp", 0) " Show detailed help?
1138 call s:BESet("g:bufExplorerFindActive", 1) " When selecting an active buffer, take you to the window where it is active?
1139 call s:BESet("g:bufExplorerReverseSort", 0) " sort reverse?
1140 call s:BESet("g:bufExplorerShowDirectories", 1) " (Dir's are added by commands like ':e .')
1141 call s:BESet("g:bufExplorerShowRelativePath", 0) " Show listings with relative or absolute paths?
1142 call s:BESet("g:bufExplorerShowUnlisted", 0) " Show unlisted buffers?
1143 call s:BESet("g:bufExplorerSortBy", "mru") " Sorting methods are in s:sort_by:
1144 call s:BESet("g:bufExplorerSplitOutPathName", 1) " Split out path and file name?
1145 call s:BESet("g:bufExplorerSplitRight", &splitright) " Should vertical splits be on the right or left of current window?
1146 call s:BESet("g:bufExplorerSplitBelow", &splitbelow) " Should horizontal splits be below or above current window?
1147 call s:BESet("g:bufExplorerShowTabBuffer", 0) " Show only buffer(s) for this tab?
1148 call s:BESet("g:bufExplorerOnlyOneTab", 1) " If ShowTabBuffer = 1, only store the most recent tab for this buffer.
1150 " Global variables {{{1
1153 let s:sort_by = ["number", "name", "fullpath", "mru", "extension"]
1154 let s:types = {"fullname": ':p', "path": ':p:h', "relativename": ':~:.', "relativepath": ':~:.:h', "shortname": ':t'}
1155 let s:originBuffer = 0
1156 let s:splitMode = ""
1157 let s:name = '[BufExplorer]'
1158 let s:refreshBufferList = 1
1159 let s:MRU_Exclude_List = ["[BufExplorer]","__MRU_Files__"]
1162 " vim:ft=vim foldmethod=marker sw=2