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: Tuesday, 16 Feb 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.7"
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
306 if index(s:MRU_Exclude_List, bufname(a:buf)) >= 0
314 function! s:BECleanup()
315 let &insertmode = s:_insertmode
316 let &showcmd = s:_showcmd
318 let &report = s:_report
326 " BufExplorerHorizontalSplit {{{1
327 function! BufExplorerHorizontalSplit()
328 let s:splitMode = "sp"
332 " BufExplorerVerticalSplit {{{1
333 function! BufExplorerVerticalSplit()
334 let s:splitMode = "vsp"
338 " StartBufExplorer {{{1
339 function! StartBufExplorer(open)
343 " On non-Windows boxes, escape the name so that is shows up correctly.
344 let name = escape(name, "[]")
347 " Make sure there is only one explorer open at a time.
349 " Go to the open buffer.
357 " Add zero to ensure the variable is treated as a Number.
358 let s:originBuffer = bufnr("%") + 0
360 " Create or rebuild the raw buffer list if necessary.
361 if !exists('s:raw_buffer_listing') ||
362 \ empty(s:raw_buffer_listing) ||
363 \ s:refreshBufferList == 1
364 silent let s:raw_buffer_listing = s:BEGetBufferInfo(0)
367 let copy = copy(s:raw_buffer_listing)
369 if (g:bufExplorerShowUnlisted == 0)
370 call filter(copy, 'v:val.attributes !~ "u"')
373 " We may have to split the current window.
374 if (s:splitMode != "")
375 " Save off the original settings.
376 let [_splitbelow, _splitright] = [&splitbelow, &splitright]
378 " Set the setting to ours.
379 let [&splitbelow, &splitright] = [g:bufExplorerSplitBelow, g:bufExplorerSplitRight]
382 exe 'keepalt '.s:splitMode
384 " Restore the original settings.
385 let [&splitbelow, &splitright] = [_splitbelow, _splitright]
388 if !exists("b:displayMode") || b:displayMode != "winmanager"
389 " Do not use keepalt when opening bufexplorer to allow the buffer that we are
390 " leaving to become the new alternate buffer
391 exec "silent keepjumps ".a:open." ".name
394 call s:BEDisplayBufferList()
397 " BEDisplayBufferList {{{1
398 function! s:BEDisplayBufferList()
399 " Do not set bufhidden since it wipes out
400 " the data if we switch away from the buffer
402 setlocal buftype=nofile
407 " Delete all previous lines to the black hole register
409 exec 'silent! normal! "_dG'
411 call s:BESetupSyntax()
413 call setline(1, s:BECreateHelp())
414 call s:BEBuildBufferList()
415 call cursor(s:firstBufferLine, 1)
417 if !g:bufExplorerResize
421 setlocal nomodifiable
425 function! s:BEMapKeys()
426 if exists("b:displayMode") && b:displayMode == "winmanager"
427 nnoremap <buffer> <silent> <tab> :call <SID>BESelectBuffer("tab")<cr>
430 nnoremap <buffer> <silent> <F1> :call <SID>BEToggleHelp()<cr>
431 nnoremap <buffer> <silent> <2-leftmouse> :call <SID>BESelectBuffer()<cr>
432 nnoremap <buffer> <silent> <cr> :call <SID>BESelectBuffer()<cr>
433 nnoremap <buffer> <silent> o :call <SID>BESelectBuffer()<cr>
434 nnoremap <buffer> <silent> t :call <SID>BESelectBuffer("tab")<cr>
435 nnoremap <buffer> <silent> <s-cr> :call <SID>BESelectBuffer("tab")<cr>
437 nnoremap <buffer> <silent> d :call <SID>BERemoveBuffer("delete", "n")<cr>
438 xnoremap <buffer> <silent> d :call <SID>BERemoveBuffer("delete", "v")<cr>
439 nnoremap <buffer> <silent> D :call <SID>BERemoveBuffer("wipe", "n")<cr>
440 xnoremap <buffer> <silent> D :call <SID>BERemoveBuffer("wipe", "v")<cr>
442 nnoremap <buffer> <silent> m :call <SID>BEMRUListShow()<cr>
443 nnoremap <buffer> <silent> p :call <SID>BEToggleSplitOutPathName()<cr>
444 nnoremap <buffer> <silent> q :call <SID>BEClose("quit")<cr>
445 nnoremap <buffer> <silent> r :call <SID>BESortReverse()<cr>
446 nnoremap <buffer> <silent> R :call <SID>BEToggleShowRelativePath()<cr>
447 nnoremap <buffer> <silent> s :call <SID>BESortSelect()<cr>
448 nnoremap <buffer> <silent> S :call <SID>BEReverseSortSelect()<cr>
449 nnoremap <buffer> <silent> u :call <SID>BEToggleShowUnlisted()<cr>
450 nnoremap <buffer> <silent> f :call <SID>BEToggleFindActive()<cr>
451 nnoremap <buffer> <silent> T :call <SID>BEToggleShowTabBuffer()<cr>
452 nnoremap <buffer> <silent> B :call <SID>BEToggleOnlyOneTab()<cr>
454 for k in ["G", "n", "N", "L", "M", "H"]
455 exec "nnoremap <buffer> <silent>" k ":keepjumps normal!" k."<cr>"
460 function! s:BESetupSyntax()
462 syn match bufExplorerHelp "^\".*" contains=bufExplorerSortBy,bufExplorerMapping,bufExplorerTitle,bufExplorerSortType,bufExplorerToggleSplit,bufExplorerToggleOpen
463 syn match bufExplorerOpenIn "Open in \w\+ window" contained
464 syn match bufExplorerSplit "\w\+ split" contained
465 syn match bufExplorerSortBy "Sorted by .*" contained contains=bufExplorerOpenIn,bufExplorerSplit
466 syn match bufExplorerMapping "\" \zs.\+\ze :" contained
467 syn match bufExplorerTitle "Buffer Explorer.*" contained
468 syn match bufExplorerSortType "'\w\{-}'" contained
469 syn match bufExplorerBufNbr /^\s*\d\+/
470 syn match bufExplorerToggleSplit "toggle split type" contained
471 syn match bufExplorerToggleOpen "toggle open mode" contained
472 syn match bufExplorerModBuf /^\s*\d\+.\{4}+.*/
473 syn match bufExplorerLockedBuf /^\s*\d\+.\{3}[\-=].*/
474 syn match bufExplorerHidBuf /^\s*\d\+.\{2}h.*/
475 syn match bufExplorerActBuf /^\s*\d\+.\{2}a.*/
476 syn match bufExplorerCurBuf /^\s*\d\+.%.*/
477 syn match bufExplorerAltBuf /^\s*\d\+.#.*/
478 syn match bufExplorerUnlBuf /^\s*\d\+u.*/
480 hi def link bufExplorerBufNbr Number
481 hi def link bufExplorerMapping NonText
482 hi def link bufExplorerHelp Special
483 hi def link bufExplorerOpenIn Identifier
484 hi def link bufExplorerSortBy String
485 hi def link bufExplorerSplit NonText
486 hi def link bufExplorerTitle NonText
487 hi def link bufExplorerSortType bufExplorerSortBy
488 hi def link bufExplorerToggleSplit bufExplorerSplit
489 hi def link bufExplorerToggleOpen bufExplorerOpenIn
491 hi def link bufExplorerActBuf Identifier
492 hi def link bufExplorerAltBuf String
493 hi def link bufExplorerCurBuf Type
494 hi def link bufExplorerHidBuf Constant
495 hi def link bufExplorerLockedBuf Special
496 hi def link bufExplorerModBuf Exception
497 hi def link bufExplorerUnlBuf Comment
502 function! s:BEToggleHelp()
503 let g:bufExplorerDetailedHelp = !g:bufExplorerDetailedHelp
511 if (s:firstBufferLine > 1)
512 exec "keepjumps 1,".(s:firstBufferLine - 1) "d _"
515 call append(0, s:BECreateHelp())
520 setlocal nomodifiable
522 if exists("b:displayMode") && b:displayMode == "winmanager"
523 call WinManagerForceReSize("BufExplorer")
527 " BEGetHelpStatus {{{1
528 function! s:BEGetHelpStatus()
529 let ret = '" Sorted by '.((g:bufExplorerReverseSort == 1) ? "reverse " : "").g:bufExplorerSortBy
530 let ret .= ' | '.((g:bufExplorerFindActive == 0) ? "Don't " : "")."Locate buffer"
531 let ret .= ((g:bufExplorerShowUnlisted == 0) ? "" : " | Show unlisted")
532 let ret .= ((g:bufExplorerShowTabBuffer == 0) ? "" : " | Show buffers/tab")
533 let ret .= ((g:bufExplorerOnlyOneTab == 1) ? "" : " | One tab / buffer")
534 let ret .= ' | '.((g:bufExplorerShowRelativePath == 0) ? "Absolute" : "Relative")
535 let ret .= ' '.((g:bufExplorerSplitOutPathName == 0) ? "Full" : "Split")." path"
541 function! s:BECreateHelp()
542 if g:bufExplorerDefaultHelp == 0 && g:bufExplorerDetailedHelp == 0
543 let s:firstBufferLine = 1
549 if g:bufExplorerDetailedHelp == 1
550 call add(header, '" Buffer Explorer ('.g:bufexplorer_version.')')
551 call add(header, '" --------------------------')
552 call add(header, '" <F1> : toggle this help')
553 call add(header, '" <enter> or o or Mouse-Double-Click : open buffer under cursor')
554 call add(header, '" <shift-enter> or t : open buffer in another tab')
555 call add(header, '" d : delete buffer')
556 call add(header, '" D : wipe buffer')
557 call add(header, '" f : toggle find active buffer')
558 call add(header, '" p : toggle spliting of file and path name')
559 call add(header, '" q : quit')
560 call add(header, '" r : reverse sort')
561 call add(header, '" R : toggle showing relative or full paths')
562 call add(header, '" s : cycle thru "sort by" fields '.string(s:sort_by).'')
563 call add(header, '" S : reverse cycle thru "sort by" fields')
564 call add(header, '" T : toggle if to show only buffers for this tab or not')
565 call add(header, '" u : toggle showing unlisted buffers')
567 call add(header, '" Press <F1> for Help')
570 if (!exists("b:displayMode") || b:displayMode != "winmanager") || (b:displayMode == "winmanager" && g:bufExplorerDetailedHelp == 1)
571 call add(header, s:BEGetHelpStatus())
572 call add(header, '"=')
575 let s:firstBufferLine = len(header) + 1
580 " BEGetBufferInfo {{{1
581 function! s:BEGetBufferInfo(bufnr)
587 " Since we are only interested in this specified buffer
588 " remove the other buffers listed
589 let bufoutput = substitute(bufoutput."\n", '^.*\n\(\s*'.a:bufnr.'\>.\{-}\)\n.*', '\1', '')
592 let [all, allwidths, listedwidths] = [[], {}, {}]
594 for n in keys(s:types)
595 let allwidths[n] = []
596 let listedwidths[n] = []
599 for buf in split(bufoutput, '\n')
600 let bits = split(buf, '"')
601 let b = {"attributes": bits[0], "line": substitute(bits[2], '\s*', '', '')}
603 for [key, val] in items(s:types)
604 let b[key] = fnamemodify(bits[1], val)
607 if getftype(b.fullname) == "dir" && g:bufExplorerShowDirectories == 1
608 let b.shortname = "<DIRECTORY>"
613 for n in keys(s:types)
614 call add(allwidths[n], len(b[n]))
616 if b.attributes !~ "u"
617 call add(listedwidths[n], len(b[n]))
622 let [s:allpads, s:listedpads] = [{}, {}]
624 for n in keys(s:types)
625 let s:allpads[n] = repeat(' ', max(allwidths[n]))
626 let s:listedpads[n] = repeat(' ', max(listedwidths[n]))
629 let s:refreshBufferList = 1
634 " BEBuildBufferList {{{1
635 function! s:BEBuildBufferList()
638 " Loop through every buffer.
639 for buf in s:raw_buffer_listing
640 if (!g:bufExplorerShowUnlisted && buf.attributes =~ "u")
641 " Skip unlisted buffers if we are not to show them.
645 if (g:bufExplorerShowTabBuffer)
648 for bufnr in s:tabSpace[tabpagenr()]
649 if (buf.attributes =~ '^\s*'.bufnr.'\>')
650 " Only buffers shown on the current tabpagenr
661 let line = buf.attributes." "
663 if g:bufExplorerSplitOutPathName
664 let type = (g:bufExplorerShowRelativePath) ? "relativepath" : "path"
666 let pad = (g:bufExplorerShowUnlisted) ? s:allpads.shortname : s:listedpads.shortname
667 let line .= buf.shortname." ".strpart(pad.path, len(buf.shortname))
669 let type = (g:bufExplorerShowRelativePath) ? "relativename" : "fullname"
674 let pads = (g:bufExplorerShowUnlisted) ? s:allpads : s:listedpads
676 if !empty(pads[type])
677 let line .= strpart(pads[type], len(path))." "
682 call add(lines, line)
685 call setline(s:firstBufferLine, lines)
687 call s:BESortListing()
690 " BESelectBuffer {{{1
691 function! s:BESelectBuffer(...)
692 " Sometimes messages are not cleared when we get here so it looks like an error has
693 " occurred when it really has not.
696 " Are we on a line with a file name?
697 if line('.') < s:firstBufferLine
702 let _bufNbr = str2nr(getline('.'))
704 " Check and see if we are running BE via WinManager.
705 if exists("b:displayMode") && b:displayMode == "winmanager"
706 let bufname = expand("#"._bufNbr.":p")
708 if (a:0 == 1) && (a:1 == "tab")
709 call WinManagerFileEdit(bufname, 1)
711 call WinManagerFileEdit(bufname, 0)
717 if bufexists(_bufNbr)
718 if bufnr("#") == _bufNbr
722 " Are we suppose to open the selected buffer in a tab?
723 if (a:0 == 1) && (a:1 == "tab")
724 " Yes, we are to open the selected buffer in a tab.
726 " Restore [BufExplorer] buffer.
727 exec "keepjumps silent buffer!".s:originBuffer
729 " Get the tab number where this buffer is located at.
730 let tabNbr = s:BEGetTabNbr(_bufNbr)
734 " _bufNbr is not opened in any tabs. Open a new tab with the selected buffer in it.
735 exec "999tab split +buffer" . _bufNbr
737 " The _bufNbr is already opened in tab, go to that tab.
738 exec tabNbr . "tabnext"
741 exec s:BEGetWinNbr(tabNbr, _bufNbr) . "wincmd w"
744 "No, the use did not ask to open the selected buffer in a tab.
746 " Are we suppose to move to the tab where this active buffer is?
747 if bufloaded(_bufNbr) && g:bufExplorerFindActive
748 " Close the BE window.
751 " Get the tab number where this buffer is located at.
752 let tabNbr = s:BEGetTabNbr(_bufNbr)
756 " The buffer is located in a tab. Go to that tab number.
757 exec tabNbr . "tabnext"
759 " Nope, the buffer is not in a tab, simple switch to that buffer.
760 let bufname = expand("#"._bufNbr.":p")
761 exec bufname ? "drop ".escape(bufname, " ") : "buffer "._bufNbr
765 " Switch to the buffer.
766 exec "keepalt keepjumps silent b!" _bufNbr
769 " Make the buffer 'listed' again.
770 call setbufvar(_bufNbr, "&buflisted", "1")
772 call s:BEError("Sorry, that buffer no longer exists, please select another")
773 call s:BEDeleteBuffer(_bufNbr, "wipe")
777 " BEDeleteBufferListing {{{1
778 function! s:BEDeleteBufferListing(buf)
779 if exists('s:raw_buffer_listing') && !empty(s:raw_buffer_listing)
780 " Delete the buffer from the raw buffer list.
781 " Careful use of ' and " so we do not have to escape all the \'s
782 " Regex: ^\s*\(10\|20\)\>
783 " ^ - Starting at the beginning of the string
784 " \s* - optional whitespace
785 " \(10\|20\) - either a 10 or a 20
786 " \> - end of word (so it can't make 100 or 201)
787 call filter(s:raw_buffer_listing, "v:val.attributes !~ '".'^\s*\('.substitute(a:buf, ' ', '\\|', 'g').'\)\>'."'")
791 " BERemoveBuffer {{{1
792 function! s:BERemoveBuffer(type, mode) range
793 " Are we on a line with a file name?
794 if line('.') < s:firstBufferLine
798 " These commands are to temporarily suspend the activity of winmanager.
799 if exists("b:displayMode") && b:displayMode == "winmanager"
800 call WinManagerSuspendAUs()
805 for lineNum in range(a:firstline, a:lastline)
806 let line = getline(lineNum)
808 if line =~ '^\s*\(\d\+\)'
809 " Regex: ^\s*\(10\|20\)\>
810 " ^ - Starting at the beginning of the string
811 " \s* - optional whitespace
812 " \zs - start the match here
814 " \> - end of word (so it can't make 100 or 201)
815 let bufNbr = matchstr(line, '^\s*\zs\d\+\>')
817 " Add 0 to bufNbr to ensure Vim treats it as a Number
818 " for use with the getbufvar() function
819 if bufNbr !~ '^\d\+$' || getbufvar(bufNbr+0, '&modified') != 0
820 call s:BEError("Sorry, no write since last change for buffer ".bufNbr.", unable to delete")
822 let _bufNbrs = _bufNbrs . (_bufNbrs==''?'':' '). bufNbr
827 " Okay, everything is good, delete or wipe the buffers.
828 call s:BEDeleteBuffer(_bufNbrs, a:type)
830 " Reactivate winmanager autocommand activity.
831 if exists("b:displayMode") && b:displayMode == "winmanager"
832 call WinManagerForceReSize("BufExplorer")
833 call WinManagerResumeAUs()
837 " BEDeleteBuffer {{{1
838 function! s:BEDeleteBuffer(bufNbr, mode)
839 " This routine assumes that the buffer to be removed is on the current line.
844 exe "bdelete" a:bufNbr
849 " Remove each of the lines beginning with the buffer numbers we are removing
850 " Regex: ^\s*\(10\|20\)\>
851 " ^ - Starting at the beginning of the string
852 " \s* - optional whitespace
853 " \(10\|20\) - either a 10 or a 20
854 " \> - end of word (so it can't make 100 or 201)
855 exec 'silent! g/^\s*\('.substitute(a:bufNbr, ' ', '\\|', 'g').'\)\>/d_'
857 setlocal nomodifiable
859 call s:BEDeleteBufferListing(a:bufNbr)
861 call s:BEError(v:exception)
866 function! s:BEClose(mode)
867 " Get only the listed buffers.
868 let listed = filter(copy(s:MRUList), "buflisted(v:val)")
870 " If we needed to split the main window, close the split one.
872 if (s:splitMode != "" && a:mode == "quit")
879 for b in reverse(listed[0:1])
880 exec "keepjumps silent b ".b
885 " BEToggleSplitOutPathName {{{1
886 function! s:BEToggleSplitOutPathName()
887 let g:bufExplorerSplitOutPathName = !g:bufExplorerSplitOutPathName
888 call s:BERebuildBufferList()
889 call s:BEUpdateHelpStatus()
892 " BEToggleShowRelativePath {{{1
893 function! s:BEToggleShowRelativePath()
894 let g:bufExplorerShowRelativePath = !g:bufExplorerShowRelativePath
895 call s:BERebuildBufferList()
896 call s:BEUpdateHelpStatus()
899 " BEToggleShowUnlisted {{{1
900 function! s:BEToggleShowUnlisted()
901 let g:bufExplorerShowUnlisted = !g:bufExplorerShowUnlisted
902 let num_bufs = s:BERebuildBufferList(g:bufExplorerShowUnlisted == 0)
903 call s:BEUpdateHelpStatus()
906 " BEToggleFindActive {{{1
907 function! s:BEToggleFindActive()
908 let g:bufExplorerFindActive = !g:bufExplorerFindActive
909 call s:BEUpdateHelpStatus()
912 " BEToggleShowTabBuffer {{{1
913 function! s:BEToggleShowTabBuffer()
914 let g:bufExplorerShowTabBuffer = !g:bufExplorerShowTabBuffer
915 call s:BEDisplayBufferList()
918 " BEToggleOnlyOneTab {{{1
919 function! s:BEToggleOnlyOneTab()
920 let g:bufExplorerOnlyOneTab = !g:bufExplorerOnlyOneTab
921 call s:BEDisplayBufferList()
924 " BERebuildBufferList {{{1
925 function! s:BERebuildBufferList(...)
928 let curPos = getpos('.')
931 " Clear the list first.
932 exec "keepjumps ".s:firstBufferLine.',$d "_'
935 let num_bufs = s:BEBuildBufferList()
937 call setpos('.', curPos)
939 setlocal nomodifiable
944 " BEUpdateHelpStatus {{{1
945 function! s:BEUpdateHelpStatus()
948 let text = s:BEGetHelpStatus()
949 call setline(s:firstBufferLine - 2, text)
951 setlocal nomodifiable
955 function! s:BEMRUCmp(line1, line2)
956 return index(s:MRUList, str2nr(a:line1)) - index(s:MRUList, str2nr(a:line2))
960 function! s:BESortReverse()
961 let g:bufExplorerReverseSort = !g:bufExplorerReverseSort
963 call s:BEReSortListing()
967 function! s:BESortSelect()
968 let g:bufExplorerSortBy = get(s:sort_by, index(s:sort_by, g:bufExplorerSortBy) + 1, s:sort_by[0])
970 call s:BEReSortListing()
973 " BEReverseSortSelect {{{1
974 function! s:BEReverseSortSelect()
975 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])
977 call s:BEReSortListing()
980 " BEReSortListing {{{1
981 function! s:BEReSortListing()
984 let curPos = getpos('.')
986 call s:BESortListing()
987 call s:BEUpdateHelpStatus()
989 call setpos('.', curPos)
991 setlocal nomodifiable
995 function! s:BESortListing()
996 let sort = s:firstBufferLine.",$sort".((g:bufExplorerReverseSort == 1) ? "!": "")
998 if g:bufExplorerSortBy == "number"
1001 elseif g:bufExplorerSortBy == "name"
1002 if g:bufExplorerSplitOutPathName
1003 exec sort 'ir /\d.\{7}\zs\f\+\ze/'
1005 exec sort 'ir /\zs[^\/\\]\+\ze\s*line/'
1007 elseif g:bufExplorerSortBy == "fullpath"
1008 if g:bufExplorerSplitOutPathName
1009 " Sort twice - first on the file name then on the path.
1010 exec sort 'ir /\d.\{7}\zs\f\+\ze/'
1013 exec sort 'ir /\zs\f\+\ze\s\+line/'
1014 elseif g:bufExplorerSortBy == "extension"
1015 exec sort 'ir /\.\zs\w\+\ze\s/'
1016 elseif g:bufExplorerSortBy == "mru"
1017 let l = getline(s:firstBufferLine, "$")
1019 call sort(l, "<SID>BEMRUCmp")
1021 if g:bufExplorerReverseSort
1025 call setline(s:firstBufferLine, l)
1029 " BEMRUListShow {{{1
1030 function! s:BEMRUListShow()
1031 echomsg "MRUList=".string(s:MRUList)
1035 function! s:BEError(msg)
1036 echohl ErrorMsg | echo a:msg | echohl none
1040 function! s:BEWarning(msg)
1041 echohl WarningMsg | echo a:msg | echohl none
1045 function! s:BEGetTabNbr(bufNbr)
1046 " Searching buffer bufno, in tabs.
1047 for i in range(tabpagenr("$"))
1048 if index(tabpagebuflist(i + 1), a:bufNbr) != -1
1057 function! s:BEGetWinNbr(tabNbr, bufNbr)
1058 " window number in tabpage.
1059 return index(tabpagebuflist(a:tabNbr), a:bufNbr) + 1
1062 " Winmanager Integration {{{1
1063 let g:BufExplorer_title = "\[Buf\ List\]"
1064 call s:BESet("g:bufExplorerResize", 1)
1065 call s:BESet("g:bufExplorerMaxHeight", 25) " Handles dynamic resizing of the window.
1067 " Function to start display. Set the mode to 'winmanager' for this buffer.
1068 " This is to figure out how this plugin was called. In a standalone fashion
1070 function! BufExplorer_Start()
1071 let b:displayMode = "winmanager"
1072 call StartBufExplorer("e")
1075 " Returns whether the display is okay or not.
1076 function! BufExplorer_IsValid()
1080 " Handles dynamic refreshing of the window.
1081 function! BufExplorer_Refresh()
1082 let b:displayMode = "winmanager"
1083 call StartBufExplorer("e")
1086 function! BufExplorer_ReSize()
1087 if !g:bufExplorerResize
1091 let nlines = min([line("$"), g:bufExplorerMaxHeight])
1093 exe nlines." wincmd _"
1095 " The following lines restore the layout so that the last file line is also
1096 " the last window line. Sometimes, when a line is deleted, although the
1097 " window size is exactly equal to the number of lines in the file, some of
1098 " the lines are pushed up and we see some lagging '~'s.
1099 let pres = getpos(".")
1103 let _scr = &scrolloff
1108 let &scrolloff = _scr
1110 call setpos(".", pres)
1113 " Default values {{{1
1114 call s:BESet("g:bufExplorerDefaultHelp", 1) " Show default help?
1115 call s:BESet("g:bufExplorerDetailedHelp", 0) " Show detailed help?
1116 call s:BESet("g:bufExplorerFindActive", 1) " When selecting an active buffer, take you to the window where it is active?
1117 call s:BESet("g:bufExplorerReverseSort", 0) " sort reverse?
1118 call s:BESet("g:bufExplorerShowDirectories", 1) " (Dir's are added by commands like ':e .')
1119 call s:BESet("g:bufExplorerShowRelativePath", 0) " Show listings with relative or absolute paths?
1120 call s:BESet("g:bufExplorerShowUnlisted", 0) " Show unlisted buffers?
1121 call s:BESet("g:bufExplorerSortBy", "mru") " Sorting methods are in s:sort_by:
1122 call s:BESet("g:bufExplorerSplitOutPathName", 1) " Split out path and file name?
1123 call s:BESet("g:bufExplorerSplitRight", &splitright) " Should vertical splits be on the right or left of current window?
1124 call s:BESet("g:bufExplorerSplitBelow", &splitbelow) " Should horizontal splits be below or above current window?
1125 call s:BESet("g:bufExplorerShowTabBuffer", 0) " Show only buffer(s) for this tab?
1126 call s:BESet("g:bufExplorerOnlyOneTab", 1) " If ShowTabBuffer = 1, only store the most recent tab for this buffer.
1128 " Global variables {{{1
1131 let s:sort_by = ["number", "name", "fullpath", "mru", "extension"]
1132 let s:types = {"fullname": ':p', "path": ':p:h', "relativename": ':~:.', "relativepath": ':~:.:h', "shortname": ':t'}
1133 let s:originBuffer = 0
1134 let s:splitMode = ""
1135 let s:name = '[BufExplorer]'
1136 let s:refreshBufferList = 1
1137 let s:MRU_Exclude_List = ["[BufExplorer]","__MRU_Files__"]
1140 " vim:ft=vim foldmethod=marker sw=2