From 0ce14bf5b5862fbdebbdfb3526b58e52511dd2a3 Mon Sep 17 00:00:00 2001 From: Johannes Stolp Date: Thu, 26 May 2016 18:54:32 +0200 Subject: Added Buffer Explorer Addons --- .../minibufexpl/plugin/minibufexpl.vim | 2467 ++++++++++++++++++++ 1 file changed, 2467 insertions(+) create mode 100755 .vim/available_plugins/minibufexpl/plugin/minibufexpl.vim (limited to '.vim/available_plugins/minibufexpl/plugin') diff --git a/.vim/available_plugins/minibufexpl/plugin/minibufexpl.vim b/.vim/available_plugins/minibufexpl/plugin/minibufexpl.vim new file mode 100755 index 0000000..e2b3348 --- /dev/null +++ b/.vim/available_plugins/minibufexpl/plugin/minibufexpl.vim @@ -0,0 +1,2467 @@ +" Mini Buffer Explorer +" +" HINT: Type zR if you don't know how to use folds +" +" Script Info and Documentation {{{ +"============================================================================= +" Copyright: Copyright (C) 2002 & 2003 Bindu Wavell +" Copyright (C) 2010 Oliver Uvman +" Copyright (C) 2010 Danielle Church +" Copyright (C) 2010 Stephan Sokolow +" Copyright (C) 2010 & 2011 Federico Holgado +" 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, +" minibufexpl.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 damamges +" resulting from the use of this software. +" +" Name Of File: minibufexpl.vim +" Description: Mini Buffer Explorer Vim Plugin +" Documentation: See minibufexpl.txt +" +"============================================================================= +" }}} +" +" Startup Check +" +" Has this plugin already been loaded? {{{ +" +if exists('loaded_minibufexplorer') + finish +endif +let loaded_minibufexplorer = 1 + +" }}} +" +" Mappings and Commands +" +" MBE commands {{{ +" +if !exists(':MiniBufExplorer') + command! MiniBufExplorer echoe 'MiniBufExplorer is depreciated, please use MBEOpen instead.' +endif +if !exists(':CMiniBufExplorer') + command! CMiniBufExplorer echoe 'CMiniBufExplorer is depreciated, please use MBEClose instead.' +endif +if !exists(':TMiniBufExplorer') + command! TMiniBufExplorer echoe 'TMiniBufExplorer is depreciated, please use MBEToggle instead.' +endif +if !exists(':MBEFocus') + command! MBEFocus call FocusExplorer() +endif +if !exists(':MBEFocusAll') + command! MBEFocusAll tabdo call FocusExplorer() +endif +if !exists(':MBEOpen') + command! -bang MBEOpen let t:skipEligibleBuffersCheck = 1 | if '' == '!' | call StopExplorer(0) | endif | call StartExplorer(bufnr("%")) +endif +if !exists(':MBEOpenAll') + command! -bang MBEOpenAll tabdo let t:skipEligibleBuffersCheck = 1 | if '' == '!' | call StopExplorer(0) | endif | call StartExplorer(bufnr("%")) | let s:TabsMBEState = 1 +endif +if !exists(':MBEClose') + command! -bang MBEClose let t:skipEligibleBuffersCheck = 0 | call StopExplorer('' == '!') +endif +if !exists(':MBECloseAll') + command! -bang MBECloseAll tabdo let t:skipEligibleBuffersCheck = 0 | call StopExplorer('' == '!') | let s:TabsMBEState = 0 +endif +if !exists(':MBEToggle') + command! -bang MBEToggle call ToggleExplorer(0,''=='!') +endif +if !exists(':MBEToggleAll') + command! -bang MBEToggleAll call ToggleExplorer(1,''=='!') +endif +if !exists(':MBEToggleMRU') + command! -bang MBEToggleMRU call ToggleMRU() +endif +if !exists(':MBEToggleMRUAll') + command! -bang MBEToggleMRUAll tabdo call ToggleMRU() +endif +if !exists(':MBEbn') + command! MBEbn call CycleBuffer(1) +endif +if !exists(':MBEbp') + command! MBEbp call CycleBuffer(0) +endif +if !exists(':MBEbf') + command! MBEbf call CycleBuffer(1,1) +endif +if !exists(':MBEbb') + command! MBEbb call CycleBuffer(0,1) +endif +if !exists(':MBEbd') + command! -bang -nargs=* MBEbd call DeleteBuffer(0,''=='!',) +endif +if !exists(':MBEbw') + command! -bang -nargs=* MBEbw call DeleteBuffer(1,''=='!',) +endif +if !exists(':MBEbun') + command! -bang -nargs=* MBEbun call DeleteBuffer(2,''=='!',) +endif + +" }}} +" +" Global Configuration Variables - Depreciated +" +" {{{ +if exists('g:miniBufExplSplitBelow') + let g:miniBufExplBRSplit = g:miniBufExplSplitBelow +endif + +if exists('g:miniBufExplMaxHeight') + let g:miniBufExplMaxSize = g:miniBufExplMaxHeight +endif + +if exists('g:miniBufExplMinHeight') + let g:miniBufExplMinSize = g:miniBufExplMinHeight +endif + +if exists('g:miniBufExplorerMoreThanOne') + let g:miniBufExplBuffersNeeded = g:miniBufExplorerMoreThanOne +endif + +if exists('g:miniBufExplorerAutoStart') + let g:miniBufExplAutoStart = g:miniBufExplorerAutoStart +endif + +if exists('g:miniBufExplorerDebugMode') + let g:miniBufExplDebugMode = g:miniBufExplorerDebugMode +endif + +if exists('g:miniBufExplorerDebugLevel') + let g:miniBufExplDebugLevel = g:miniBufExplorerDebugLevel +endif + +if exists('g:miniBufExplorerDebugOutput') + let g:miniBufExplDebugOutput = g:miniBufExplorerDebugOutput +endif + +if exists('g:miniBufExplorerHideWhenDiff') + let g:miniBufExplHideWhenDiff = g:miniBufExplorerHideWhenDiff +endif + +" }}} +" +" Global Configuration Variables +" +" Start MBE automatically ? {{{ +" +if !exists('g:miniBufExplAutoStart') + let g:miniBufExplAutoStart = 1 +endif + +" }}} +" Debug Mode {{{ +" +" 0 = debug to a window +" 1 = use vim's echo facility +" 2 = write to a file named MiniBufExplorer.DBG +" in the directory where vim was started +" THIS IS VERY SLOW +" 3 = Write into g:miniBufExplDebugOutput +" global variable [This is the default] +if !exists('g:miniBufExplDebugMode') + let g:miniBufExplDebugMode = 3 +endif + +" }}} +" Debug Level {{{ +" +" 0 = no logging +" 1=5 = errors ; 1 is the most important +" 5-9 = info ; 5 is the most important +" 10 = Entry/Exit +if !exists('g:miniBufExplDebugLevel') + let g:miniBufExplDebugLevel = 1 +endif + +" }}} +" Stop auto starting MBE in diff mode? {{{ +if !exists('g:miniBufExplHideWhenDiff') + let g:miniBufExplHideWhenDiff = 0 +endif + +" }}} +" MoreThanOne? {{{ +" Display Mini Buf Explorer when there are 'More Than One' eligible buffers +" +if !exists('g:miniBufExplBuffersNeeded') + let g:miniBufExplBuffersNeeded = 2 +endif + +" }}} +" Set the updatetime? {{{ +if !exists('g:miniBufExplSetUT') + let g:miniBufExplSetUT = 1 +endif + +" }}} +" Horizontal or Vertical explorer? {{{ +" For folks that like vertical explorers, I'm caving in and providing for +" veritcal splits. If this is set to 0 then the current horizontal +" splitting logic will be run. If however you want a vertical split, +" assign the width (in characters) you wish to assign to the MBE window. +" +if !exists('g:miniBufExplVSplit') + let g:miniBufExplVSplit = 0 +endif + +" }}} +" Split below/above/left/right? {{{ +" When opening a new -MiniBufExplorer- window, split the new windows below or +" above the current window? 1 = below, 0 = above. +" +if !exists('g:miniBufExplBRSplit') + let g:miniBufExplBRSplit = g:miniBufExplVSplit ? &splitright : &splitbelow +endif + +" }}} +" Split to edge? {{{ +" When opening a new -MiniBufExplorer- window, split the new windows to the +" full edge? 1 = yes, 0 = no. +" +if !exists('g:miniBufExplSplitToEdge') + let g:miniBufExplSplitToEdge = 1 +endif + +" }}} +" MaxSize {{{ +" Same as MaxHeight but also works for vertical splits if specified with a +" vertical split then vertical resizing will be performed. If left at 0 +" then the number of columns in g:miniBufExplVSplit will be used as a +" static window width. +if !exists('g:miniBufExplMaxSize') + let g:miniBufExplMaxSize = 0 +endif + +" }}} +" MinSize {{{ +" Same as MinHeight but also works for vertical splits. For vertical splits, +" this is ignored unless g:miniBufExplMax(Size|Height) are specified. +if !exists('g:miniBufExplMinSize') + let g:miniBufExplMinSize = 1 +endif + +" }}} +" TabWrap? {{{ +" By default line wrap is used (possibly breaking a tab name between two +" lines.) Turning this option on (setting it to 1) can take more screen +" space, but will make sure that each tab is on one and only one line. +" +if !exists('g:miniBufExplTabWrap') + let g:miniBufExplTabWrap = 0 +endif + +" }}} +" ShowBufNumber? {{{ +" By default buffers' numbers are shown in MiniBufExplorer. You can turn it off +" by setting this option to 0. +" +if !exists('g:miniBufExplShowBufNumbers') + let g:miniBufExplShowBufNumbers = 1 +endif + +" }}} +" Single/Double Click? {{{ +" flag that can be set to 1 in a users .vimrc to allow +" single click switching of tabs. By default we use +" double click for tab selection. +" +if !exists('g:miniBufExplUseSingleClick') + let g:miniBufExplUseSingleClick = 0 +endif + +" }}} +" Close on Select? {{{ +" Flag that can be set to 1 in a users .vimrc to hide +" the explorer when a user selects a buffer. +" +if !exists('g:miniBufExplCloseOnSelect') + let g:miniBufExplCloseOnSelect = 0 +endif + +" }}} +" Status Line Text for MBE window {{{ +" +if !exists('g:miniBufExplStatusLineText') + let g:miniBufExplStatusLineText = "-MiniBufExplorer-" +endif + +" }}} +" How to sort the buffers in MBE window {{{ +" +if !exists('g:miniBufExplSortBy') + let g:miniBufExplSortBy = "number" +endif + +" }}} +" Should buffer be cycled arround if hits the begining or the end while {{{ +" using MBE's buffer movement commands. +" +if !exists('g:miniBufExplCycleArround') + let g:miniBufExplCycleArround = 0 +endif + +" }}} +" +" Variables used internally +" +" Script/Global variables {{{ +" In debug mode 3 this variable will hold the debug output +let g:miniBufExplDebugOutput = '' + +" check to see what platform we are in +if (has('unix')) + let s:PathSeparator = '/' +else + let s:PathSeparator = '\' +endif + +" Variable used to count debug output lines +let s:debugIndex = 0 + +" Variable used to pass maxTabWidth info between functions +let s:maxTabWidth = 0 + +" Variable used as a mutex to indicate the current state of MBEToggleAll +let s:TabsMBEState = 0 + +" List for all eligible buffers +let s:BufList = [] + +" List for tracking order of the buffer entering +let s:MRUList = [] + +" Whether MRU List should be updated. +let s:MRUEnable = 1 + +" Dictionary used to keep track of the modification state of buffers +let s:bufStateDict = {} + +" Global used to store the buffer list so that we don't update the MBE +" unless the list has changed. +let s:miniBufExplBufList = '' + +" Variable used as a mutex so that AutoUpdates would not get nested. +let s:miniBufExplInAutoUpdate = 0 + +" Dictionary used to keep track of the names we have seen. +let s:bufNameDict = {} + +" Dictionary used to map buffer numbers to names when the buffer +" names are not unique. +let s:bufUniqNameDict = {} + +" Dictionary used to hold the path parts for each buffer +let s:bufPathDict = {} + +" Dictionary used to hold the path signature index for each buffer +let s:bufPathSignDict = {} + +" We start out with this off for startup, but once vim is running we +" turn this on. This prevent any BufEnter event from being triggered +" before VimEnter event. +let t:miniBufExplAutoUpdate = 0 + +" If MBE was opened manually, then we should skip eligible buffers checking, +" open MBE window no matter what value 'g:miniBufExplBuffersNeeded' is set. +let t:skipEligibleBuffersCheck = 0 + +" The order of buffer listing in MBE window is tab dependently. +let t:miniBufExplSortBy = g:miniBufExplSortBy + +" }}} +" +" Auto Commands +" +" Setup an autocommand group and some autocommands {{{ +" that keep our explorer updated automatically. +" + +" Set a lower value to 'updatetime' for the CursorHold/CursorHoldI event, so +" that the MBE could be updated in time. It can not be set too low, otherwise +" might breaks many things, 1500ms should be a reasonable value. +" We only change it if we are allowed to and it has not been changed yet. +if g:miniBufExplSetUT && &ut == 4000 + set updatetime=1500 +endif + +augroup MiniBufExpl + autocmd! + autocmd VimEnter * nested call VimEnterHandler() + autocmd TabEnter * nested call TabEnterHandler() + autocmd BufAdd * call BufAddHandler() + autocmd BufEnter * nested call BufEnterHandler() + autocmd BufDelete * call BufDeleteHandler() + autocmd CursorHold,CursorHoldI,BufWritePost * + \ call DEBUG('Entering UpdateBufferStateDict AutoCmd', 10) | + \ call UpdateBufferStateDict(bufnr("%"),0) | + \ call DEBUG('Leaving UpdateBufferStateDict AutoCmd', 10) +if exists('##QuitPre') + autocmd QuitPre * + \ if NextNormalWindow() == -1 | call StopExplorer(0) | endif +else + autocmd BufEnter * nested call QuitIfLastOpen() +endif + autocmd FileType minibufexpl call RenderSyntax() +augroup END + +function! VimEnterHandler() + call DEBUG('Entering VimEnter Handler', 10) + + " Build initial MRUList. + " This makes sure all the files specified on the command + " line are picked up correctly. + let s:BufList = range(1, bufnr('$')) + let s:MRUList = range(1, bufnr('$')) + + for l:i in s:BufList + if IsBufferIgnored(l:i) + call ListPop(s:BufList,l:i) + endif + endfor + + for l:i in s:MRUList + if IsBufferIgnored(l:i) + call ListPop(s:MRUList,l:i) + endif + endfor + + if g:miniBufExplHideWhenDiff!=1 || !&diff + let t:miniBufExplAutoUpdate = 1 + endif + + if g:miniBufExplAutoStart && t:miniBufExplAutoUpdate == 1 + \ && (t:skipEligibleBuffersCheck == 1 || HasEligibleBuffers() == 1) + call StartExplorer(bufnr("%")) + + " Let the MBE open in the new tab + let s:TabsMBEState = 1 + endif + + call DEBUG('Leaving VimEnter Handler', 10) +endfunction + +function! TabEnterHandler() + call DEBUG('Entering TabEnter Handler', 10) + + if !exists('t:miniBufExplSortBy') + let t:miniBufExplSortBy = g:miniBufExplSortBy + endif + + if !exists('t:miniBufExplAutoUpdate') + let t:miniBufExplAutoUpdate = s:TabsMBEState + endif + + if !exists('t:skipEligibleBuffersCheck') + let t:skipEligibleBuffersCheck = 0 + endif + + if g:miniBufExplAutoStart && t:miniBufExplAutoUpdate == 1 + \ && (t:skipEligibleBuffersCheck == 1 || HasEligibleBuffers() == 1) + call StartExplorer(bufnr("%")) + endif + + call DEBUG('Leaving TabEnter Handler', 10) +endfunction + +function! BufAddHandler() + call DEBUG('Entering BufAdd Handler', 10) + + call ListAdd(s:BufList,str2nr(expand(""))) + call ListAdd(s:MRUList,str2nr(expand(""))) + + call UpdateAllBufferDicts(expand(""),0) + + call AutoUpdate(bufnr("%"),0) + + call DEBUG('Leaving BufAdd Handler', 10) +endfunction + +function! BufEnterHandler() abort + call DEBUG('Entering BufEnter Handler', 10) + + for l:i in s:BufList + if IsBufferIgnored(l:i) + call ListPop(s:BufList,l:i) + endif + endfor + + for l:i in s:MRUList + if IsBufferIgnored(l:i) + call ListPop(s:MRUList,l:i) + endif + endfor + + call AutoUpdate(bufnr("%"),0) + + call DEBUG('Leaving BufEnter Handler', 10) +endfunction + +function! BufDeleteHandler() + call DEBUG('Entering BufDelete Handler', 10) + + call ListPop(s:BufList,str2nr(expand(""))) + call ListPop(s:MRUList,str2nr(expand(""))) + + call UpdateAllBufferDicts(expand(""),1) + + " Handle ':bd' command correctly + if (bufname('%') == '-MiniBufExplorer-' && NextNormalWindow() == -1 && len(s:BufList) > 0) + if(tabpagenr('$') == 1) + setlocal modifiable + resize + exec 'noautocmd sb'.s:BufList[0] + call StopExplorer(0) + call StartExplorer(bufnr("%")) + else + close + endif + endif + + call AutoUpdate(bufnr("%"),1) + + call DEBUG('Leaving BufDelete Handler', 10) +endfunction +" }}} +" +" Functions +" +" RenderSyntax {{{ +" +function! RenderSyntax() + if has("syntax") + syn clear + syn match MBENormal '\[[^\]]*\]' + syn match MBEChanged '\[[^\]]*\]+' + syn match MBEVisibleNormal '\[[^\]]*\]\*' + syn match MBEVisibleChanged '\[[^\]]*\]\*+' + syn match MBEVisibleActiveNormal '\[[^\]]*\]\*!' + syn match MBEVisibleActiveChanged '\[[^\]]*\]\*+!' + + "MiniBufExpl Color Examples + " hi MBENormal guifg=#808080 guibg=fg + " hi MBEChanged guifg=#CD5907 guibg=fg + " hi MBEVisibleNormal guifg=#5DC2D6 guibg=fg + " hi MBEVisibleChanged guifg=#F1266F guibg=fg + " hi MBEVisibleActiveNormal guifg=#A6DB29 guibg=fg + " hi MBEVisibleActiveChanged guifg=#F1266F guibg=fg + + if !exists("g:did_minibufexplorer_syntax_inits") + let g:did_minibufexplorer_syntax_inits = 1 + hi def link MBENormal Comment + hi def link MBEChanged String + hi def link MBEVisibleNormal Special + hi def link MBEVisibleChanged Special + hi def link MBEVisibleActiveNormal Underlined + hi def link MBEVisibleActiveChanged Error + endif + + let b:current_syntax = "minibufexpl" + endif +endfunction + +" }}} +" StartExplorer - Sets up our explorer and causes it to be displayed {{{ +" +function! StartExplorer(curBufNum) + call DEBUG('Entering StartExplorer('.a:curBufNum.')',10) + + call DEBUG('Current state: '.winnr().' : '.bufnr('%').' : '.bufname('%'),10) + + call BuildAllBufferDicts() + + let t:miniBufExplAutoUpdate = 1 + + let l:winNum = FindWindow('-MiniBufExplorer-', 1) + + if l:winNum != -1 + call DEBUG('There is already a MBE window, aborting...',1) + call DEBUG('Leaving StartExplorer()',10) + return + endif + + call CreateWindow('-MiniBufExplorer-', g:miniBufExplVSplit, g:miniBufExplBRSplit, g:miniBufExplSplitToEdge, 1, 1) + + let l:winNum = FindWindow('-MiniBufExplorer-', 1) + + if l:winNum == -1 + call DEBUG('Failed to create the MBE window, aborting...',1) + call DEBUG('Leaving StartExplorer()',10) + return + endif + + " Save current window number and switch to previous + " window before entering MBE window so that the later + " `wincmd p` command will get into this window, then + " we can preserve a one level window movement history. + let l:currWin = winnr() + call s:SwitchWindow('p',1) + + " Switch into MBE allowing autocmd to run will + " make the syntax highlight in MBE window working + call s:SwitchWindow('w',0,l:winNum) + + " Make sure we are in our window + if bufname('%') != '-MiniBufExplorer-' + call DEBUG('StartExplorer called in invalid window',1) + call DEBUG('Leaving StartExplorer()',10) + return + endif + + " Set filetype for MBE buffer + set filetype=minibufexpl + + " !!! We may want to make the following optional -- Bindu + " New windows don't cause all windows to be resized to equal sizes + set noequalalways + + " !!! We may want to make the following optional -- Bindu + " We don't want the mouse to change focus without a click + set nomousefocus + + if g:miniBufExplVSplit == 0 + setlocal wrap + else + setlocal nowrap + exec 'setlocal winwidth='.g:miniBufExplMinSize + endif + + " If folks turn numbering and columns on by default we will turn + " them off for the MBE window + setlocal foldcolumn=0 + setlocal nonumber + if exists("&norelativenumber") + " relativenumber was introduced in Vim 7.3 - this provides compatibility + " for older versions of Vim + setlocal norelativenumber + endif + "don't highlight matching parentheses, etc. + setlocal matchpairs= + "Depending on what type of split, make sure the MBE buffer is not + "automatically rezised by CTRL + W =, etc... + setlocal winfixheight + setlocal winfixwidth + + " Set the text of the statusline for the MBE buffer. See help:stl for + " many options + exec 'setlocal statusline='.g:miniBufExplStatusLineText + + " No spell check + setlocal nospell + + " Restore colorcolumn for VIM >= 7.3 + if exists("+colorcolumn") + setlocal colorcolumn& + end + + " If you press return, o or e in the -MiniBufExplorer- then try + " to open the selected buffer in the previous window. + nnoremap o :call MBESelectBuffer(0): + nnoremap e :call MBESelectBuffer(0): + nnoremap :call MBESelectBuffer(0): + " If you press s in the -MiniBufExplorer- then try + " to open the selected buffer in a split in the previous window. + nnoremap s :call MBESelectBuffer(1): + " If you press j in the -MiniBufExplorer- then try + " to open the selected buffer in a vertical split in the previous window. + nnoremap v :call MBESelectBuffer(2): + " If you press d in the -MiniBufExplorer- then try to + " delete the selected buffer. + nnoremap d :call MBEDeleteBuffer(): + " The following allow us to use regular movement keys to + " scroll in a wrapped single line buffer + nnoremap k gk + nnoremap j gj + nnoremap gk + nnoremap gj + " The following allows for quicker moving between buffer + " names in the [MBE] window it also saves the last-pattern + " and restores it. + if !g:miniBufExplShowBufNumbers + nnoremap l :call search('\[[^\]]*\]'): + nnoremap h :call search('\[[^\]]*\]','b'): + nnoremap :call search('\[[^\]]*\]'): + nnoremap :call search('\[[^\]]*\]','b'): + else + nnoremap l :call search('\[[0-9]*:[^\]]*\]'): + nnoremap h :call search('\[[0-9]*:[^\]]*\]','b'): + nnoremap :call search('\[[0-9]*:[^\]]*\]'): + nnoremap :call search('\[[0-9]*:[^\]]*\]','b'): + endif + + " Attempt to perform single click mapping + " It would be much nicer if we could 'nnoremap ...', however + " vim does not fire the ' ' when you use the mouse + " to enter a buffer. + if g:miniBufExplUseSingleClick == 1 + let l:mapcmd = ':nnoremap ' + let l:clickcmd = ':if bufname("%") == "-MiniBufExplorer-" call MBESelectBuffer(0) endif ' + " no mapping for leftmouse + if maparg('', 'n') == '' + exec l:mapcmd . l:clickcmd + " we have a mapping + else + let l:mapcmd = l:mapcmd . substitute(substitute(maparg('', 'n'), '|', '', 'g'), '\c^', '', '') + let l:mapcmd = l:mapcmd . l:clickcmd + exec l:mapcmd + endif + " If you DoubleClick in the MBE window then try to open the selected + " buffer in the previous window. + else + nnoremap <2-LEFTMOUSE> :call MBESelectBuffer(0): + endif + + call BuildBufferList(a:curBufNum) + + call DisplayBuffers(a:curBufNum) + + " Switch away from MBE allowing autocmd to run which will + " trigger PowerLine's BufLeave event handler + call s:SwitchWindow('p',0) + + " Now we are in the previous window, let's enter + " the window current window, this will preserve + " one-level backwards window movement history. + call s:SwitchWindow('w',1,l:currWin) + + call DEBUG('Leaving StartExplorer()',10) +endfunction + +" }}} +" StopExplorer - Looks for our explorer and closes the window if it is open {{{ +" +function! StopExplorer(force) + call DEBUG('Entering StopExplorer()',10) + + if a:force || HasEligibleBuffers() + let t:miniBufExplAutoUpdate = 0 + endif + + let l:winNum = FindWindow('-MiniBufExplorer-', 1) + + if l:winNum == -1 + call DEBUG('There is no MBE window, aborting...',1) + call DEBUG('Leaving StopExplorer()',10) + return + endif + + call s:SwitchWindow('w',1,l:winNum) + silent! close + call s:SwitchWindow('p',1) + + " Work around a redraw bug in gVim (Confirmed present in 7.3.50) + if has('gui_gtk') && has('gui_running') + redraw! + endif + + call DEBUG('Leaving StopExplorer()',10) +endfunction + +" }}} +" FocusExplorer {{{ +" +function! FocusExplorer() + call DEBUG('Entering FocusExplorer()',10) + + let t:miniBufExplAutoUpdate = 1 + + let l:winNum = FindWindow('-MiniBufExplorer-', 1) + + if l:winNum == -1 + call DEBUG('There is no MBE window, aborting...',1) + call DEBUG('Leaving FocusExplorer()',10) + return + endif + + call s:SwitchWindow('w',0,l:winNum) + + call DEBUG('Leaving FocusExplorer()',10) +endfunction + +" }}} +" ToggleMRU - Switch the order of buffer listing in MBE window {{{ +" between its default and most recently used. +" +function! ToggleMRU() + call DEBUG('Entering ToggleMRU()',10) + + if t:miniBufExplSortBy == 'number' + let t:miniBufExplSortBy = 'mru' + else + let t:miniBufExplSortBy = 'number' + endif + + let l:winnr = FindWindow('-MiniBufExplorer-', 1) + + if (l:winnr == -1) + call DEBUG('MiniBufExplorer was not running, starting...', 9) + call StartExplorer(bufnr('%')) + else + call DEBUG('Updating MiniBufExplorer...', 9) + call UpdateExplorer(bufnr('%')) + endif + + call DEBUG('Leaving ToggleMRU()',10) +endfunction + +" }}} +" ToggleExplorer - Looks for our explorer and opens/closes the window {{{ +" +" a:tabs, 0 no, 1 yes +" toggle MBE in all tabs +" a:force, 0 no, 1 yes +" reopen MBE when it is already open +" close MBE with auto-updating disabled +" +function! ToggleExplorer(tabs,force) + call DEBUG('Entering ToggleExplorer()',10) + + if a:tabs + if s:TabsMBEState + tabdo let t:skipEligibleBuffersCheck = 0 | call StopExplorer(a:force) + else + tabdo let t:skipEligibleBuffersCheck = 1 | if a:force | call StopExplorer(0) | endif | call StartExplorer(bufnr("%")) + endif + let s:TabsMBEState = !s:TabsMBEState + else + let l:winNum = FindWindow('-MiniBufExplorer-', 1) + + if l:winNum != -1 + let t:skipEligibleBuffersCheck = 0 + call StopExplorer(a:force) + else + let t:skipEligibleBuffersCheck = 1 + call StartExplorer(bufnr("%")) + endif + endif + + call DEBUG('Leaving ToggleExplorer()',10) +endfunction + +" }}} +" UpdateExplorer {{{ +" +function! UpdateExplorer(curBufNum) + call DEBUG('Entering UpdateExplorer('.a:curBufNum.')',10) + + call DEBUG('Current state: '.winnr().' : '.bufnr('%').' : '.bufname('%'),10) + + if !BuildBufferList(a:curBufNum) + call DEBUG('Buffer List have not changed, aborting...',10) + call DEBUG('Leaving UpdateExplorer()',10) + return + endif + + let l:winNum = FindWindow('-MiniBufExplorer-', 1) + + if l:winNum == -1 + call DEBUG('Found no MBE window, aborting...',1) + call DEBUG('Leaving UpdateExplorer()',10) + return + endif + + if l:winNum != winnr() + let l:winChanged = 1 + + " Save current window number and switch to previous + " window before entering MBE window so that the later + " `wincmd p` command will get into this window, then + " we can preserve a one level window movement history. + let l:currWin = winnr() + call s:SwitchWindow('p',1) + + " Switch into MBE allowing autocmd to run will + " make the syntax highlight in MBE window working + call s:SwitchWindow('w',0,l:winNum) + endif + + call DisplayBuffers(a:curBufNum) + + if exists('l:winChanged') + " Switch away from MBE allowing autocmd to run which will + " trigger PowerLine's BufLeave event handler + call s:SwitchWindow('p',0) + + " Now we are in the previous window, let's enter + " the window current window, this will preserve + " one-level backwards window movement history. + call s:SwitchWindow('w',1,l:currWin) + endif + + call DEBUG('Leaving UpdateExplorer()',10) +endfunction + +" }}} +" FindWindow - Return the window number of a named buffer {{{ +" If none is found then returns -1. +" +function! FindWindow(bufName, doDebug) + if a:doDebug + call DEBUG('Entering FindWindow('.a:bufName.','.a:doDebug.')',10) + endif + + " Try to find an existing window that contains + " our buffer. + let l:winnr = bufwinnr(a:bufName) + + if l:winnr != -1 + if a:doDebug + call DEBUG('Found window '.l:winnr.' with buffer ('.winbufnr(l:winnr).' : '.bufname(winbufnr(l:winnr)).')',9) + endif + else + if a:doDebug + call DEBUG('Can not find window with buffer ('.a:bufName.')',9) + endif + endif + + if a:doDebug + call DEBUG('Leaving FindWindow()',10) + endif + + return l:winnr +endfunction + +" }}} +" CreateWindow {{{ +" +" vSplit, 0 no, 1 yes +" split vertically or horizontally +" brSplit, 0 no, 1 yes +" split the window below/right to current window +" forceEdge, 0 no, 1 yes +" split the window at the edege of the editor +" isPluginWindow, 0 no, 1 yes +" if it is a plugin window +" doDebug, 0 no, 1 yes +" show debugging message or not +" +function! CreateWindow(bufName, vSplit, brSplit, forceEdge, isPluginWindow, doDebug) + if a:doDebug + call DEBUG('Entering CreateWindow('.a:bufName.','.a:vSplit.','.a:brSplit.','.a:forceEdge.','.a:isPluginWindow.','.a:doDebug.')',10) + endif + + " Window number will change after creating a new window, + " we need to save both current and previous window number + " so that we can canculate theire correct window number + " after the new window creating. + let l:currWin = winnr() + call s:SwitchWindow('p',1) + let l:prevWin = winnr() + call s:SwitchWindow('p',1) + + " Save the user's split setting. + let l:saveSplitBelow = &splitbelow + let l:saveSplitRight = &splitright + + " Set to our new values. + let &splitbelow = a:brSplit + let &splitright = a:brSplit + + let l:bufNum = bufnr(a:bufName) + + if l:bufNum == -1 + let l:spCmd = 'sp' + else + let l:spCmd = 'sb' + endif + + if a:forceEdge == 1 + let l:edge = a:vSplit ? &splitright : &splitbelow + + if l:edge + if a:vSplit == 0 + silent exec 'noautocmd bo '.l:spCmd.' '.a:bufName + else + silent exec 'noautocmd bo vert '.l:spCmd.' '.a:bufName + endif + else + if a:vSplit == 0 + silent exec 'noautocmd to '.l:spCmd.' '.a:bufName + else + silent exec 'noautocmd to vert '.l:spCmd.' '.a:bufName + endif + endif + else + if a:vSplit == 0 + silent exec 'noautocmd '.l:spCmd.' '.a:bufName + else + silent exec 'noautocmd vert '.l:spCmd.' '.a:bufName + endif + endif + + " Restore the user's split setting. + let &splitbelow = l:saveSplitBelow + let &splitright = l:saveSplitRight + + " Turn off the swapfile, set the buftype and bufhidden option, so that it + " won't get written and will be deleted when it gets hidden. + if a:isPluginWindow + setlocal noswapfile + setlocal nobuflisted + setlocal buftype=nofile + setlocal bufhidden=delete + endif + + " Canculate the correct window number, for those whose window + " number before the creating is greater than or equal to the + " number of the newly created window, their window number should + " increase by one. + let l:prevWin = l:prevWin >= winnr() ? l:prevWin + 1 : l:prevWin + let l:currWin = l:currWin >= winnr() ? l:currWin + 1 : l:currWin + " This will preserve one-level backwards window movement history. + call s:SwitchWindow('w',1,l:prevWin) + call s:SwitchWindow('w',1,l:currWin) + + if a:doDebug + call DEBUG('Leaving CreateWindow()',10) + endif +endfunction + +" }}} +" FindCreateWindow - Attempts to find a window for a named buffer. {{{ +" +" If it is found then moves there. Otherwise creates a new window and +" configures it and moves there. +" +" vSplit, 0 no, 1 yes +" split vertically or horizontally +" brSplit, 0 no, 1 yes +" split the window below/right to current window +" forceEdge, 0 no, 1 yes +" split the window at the edege of the editor +" isPluginWindow, 0 no, 1 yes +" if it is a plugin window +" doDebug, 0 no, 1 yes +" show debugging message or not +" +function! FindCreateWindow(bufName, vSplit, brSplit, forceEdge, isPluginWindow, doDebug) + if a:doDebug + call DEBUG('Entering FindCreateWindow('.a:bufName.','.a:vSplit.','.a:brSplit.','.a:forceEdge.','.a:isPluginWindow.','.a:doDebug.')',10) + endif + + " Try to find an existing explorer window + let l:winNum = FindWindow(a:bufName, a:doDebug) + + " If found goto the existing window, otherwise + " split open a new window. + if l:winNum == -1 + if a:doDebug + call DEBUG('Creating a new window with buffer ('.a:bufName.')',9) + endif + + call CreateWindow(a:bufName, a:vSplit, a:brSplit, a:forceEdge, a:isPluginWindow, a:doDebug) + + " Try to find an existing explorer window + let l:winNum = FindWindow(a:bufName, 0) + + if l:winNum != -1 + if a:doDebug + call DEBUG('Created window '.l:winNum.' with buffer ('.a:bufName.')',9) + endif + else + if a:doDebug + call DEBUG('Failed to create window with buffer ('.a:bufName.').',1) + endif + endif + endif + + if a:doDebug + call DEBUG('Leaving FindCreateWindow()',10) + endif + + return l:winNum +endfunction + +" }}} +" DisplayBuffers - Wrapper for getting MBE window shown {{{ +" +" Makes sure we are in our explorer, then erases the current buffer and turns +" it into a mini buffer explorer window. +" +function! DisplayBuffers(curBufNum) + call DEBUG('Entering DisplayExplorer('.a:curBufNum.')',10) + + " Make sure we are in our window + if bufname('%') != '-MiniBufExplorer-' + call DEBUG('DisplayBuffers called in invalid window',1) + return + endif + + call ShowBuffers() + call ResizeWindow() + + " Place cursor at current buffer in MBE + if !IsBufferIgnored(a:curBufNum) + if !g:miniBufExplShowBufNumbers + call search('\V['.s:bufUniqNameDict[a:curBufNum].']', 'w') + else + call search('\V['.a:curBufNum.':'.s:bufUniqNameDict[a:curBufNum].']', 'w') + endif + endif + + call DEBUG('Leaving DisplayExplorer()',10) +endfunction + +" }}} +" Resize Window - Set width/height of MBE window {{{ +" +" Makes sure we are in our explorer, then sets the height/width for our explorer +" window so that we can fit all of our information without taking extra lines. +" +function! ResizeWindow() + call DEBUG('Entering ResizeWindow()',10) + + " Make sure we are in our window + if bufname('%') != '-MiniBufExplorer-' + call DEBUG('ResizeWindow called in invalid window',1) + call DEBUG('Leaving ResizeWindow()',10) + return + endif + + " Prevent a report of our actions from showing up. + let l:save_rep = &report + let l:save_sc = &showcmd + let &report = 10000 + set noshowcmd + + let l:width = winwidth('.') + + " Horizontal Resize + if g:miniBufExplVSplit == 0 + + if g:miniBufExplTabWrap == 0 + let l:length = strlen(getline('.')) + let l:height = 0 + if (l:width == 0) + let l:height = winheight('.') + else + let l:height = (l:length / l:width) + " handle truncation from div + if (l:length % l:width) != 0 + let l:height = l:height + 1 + endif + endif + else + " We need to be able to modify the buffer + setlocal modifiable + + exec "setlocal textwidth=".l:width + normal gg + normal gq} + normal G + let l:height = line('.') + normal gg + + " Prevent the buffer from being modified. + setlocal nomodifiable + endif + + " enforce max window height + if g:miniBufExplMaxSize != 0 + if g:miniBufExplMaxSize < l:height + let l:height = g:miniBufExplMaxSize + endif + endif + + " enfore min window height + if l:height < g:miniBufExplMinSize || l:height == 0 + let l:height = g:miniBufExplMinSize + endif + + call DEBUG('ResizeWindow to '.l:height.' lines',9) + + if &winminheight > l:height + let l:saved_winminheight = &winminheight + let &winminheight = 1 + exec 'resize '.l:height + let &winminheight = l:saved_winminheight + else + exec 'resize '.l:height + endif + + let saved_ead = &ead + let &ead = 'ver' + set equalalways + let &ead = saved_ead + set noequalalways + + " Vertical Resize + else + + if g:miniBufExplMaxSize != 0 + let l:newWidth = s:maxTabWidth + if l:newWidth > g:miniBufExplMaxSize + let l:newWidth = g:miniBufExplMaxSize + endif + if l:newWidth < g:miniBufExplMinSize + let l:newWidth = g:miniBufExplMinSize + endif + else + let l:newWidth = g:miniBufExplVSplit + endif + + if l:width != l:newWidth + call DEBUG('ResizeWindow to '.l:newWidth.' columns',9) + exec 'vertical resize '.l:newWidth + endif + + let saved_ead = &ead + let &ead = 'hor' + set equalalways + let &ead = saved_ead + set noequalalways + + endif + + normal! zz + + let &report = l:save_rep + let &showcmd = l:save_sc + + call DEBUG('Leaving ResizeWindow()',10) +endfunction + +" }}} +" ShowBuffers - Clear current buffer and put the MBE text into it {{{ +" +" Makes sure we are in our explorer, then adds a list of all modifiable +" buffers to the current buffer. Special marks are added for buffers that +" are in one or more windows (*) and buffers that have been modified (+) +" +function! ShowBuffers() + call DEBUG('Entering ShowExplorer()',10) + + " Make sure we are in our window + if bufname('%') != '-MiniBufExplorer-' + call DEBUG('ShowBuffers called in invalid window',1) + call DEBUG('Leaving ShowBuffers()',10) + return + endif + + let l:save_rep = &report + let l:save_sc = &showcmd + let &report = 10000 + set noshowcmd + + " We need to be able to modify the buffer + setlocal modifiable + + " Delete all lines in buffer. + silent 1,$d _ + + " Goto the end of the buffer put the buffer list + " and then delete the extra trailing blank line + $ + put! =s:miniBufExplBufList + silent $ d _ + + " Prevent the buffer from being modified. + setlocal nomodifiable + + let &report = l:save_rep + let &showcmd = l:save_sc + + call DEBUG('Leaving ShowBuffers()',10) +endfunction + +" }}} +" CycleBuffer - Cycle Through Buffers {{{ +" +" Move to next or previous buffer in the current window. If there +" are no more modifiable buffers then stay on the current buffer. +" can be called with no parameters in which case the buffers are +" cycled forward. Otherwise a single argument is accepted, if +" it's 0 then the buffers are cycled backwards, otherwise they +" are cycled forward. +" +function! CycleBuffer(forward,...) + if IsBufferIgnored(bufnr('%')) == 1 + return + endif + + let curBufNum = bufnr('%') + + if exists('a:1') && a:1 == 1 + call DEBUG('MRUList is '.string(s:MRUList),1) + let curBufIndex = index(s:MRUList, l:curBufNum) + call DEBUG('curBufIndex is '.l:curBufIndex,1) + let forBufIndex = l:curBufIndex - 1 < 0 ? len(s:MRUList) - 1 : l:curBufIndex - 1 + call DEBUG('forBufIndex is '.l:forBufIndex,1) + let bacBufIndex = l:curBufIndex + 1 >= len(s:MRUList) ? 0 : l:curBufIndex + 1 + call DEBUG('bacBufIndex is '.l:bacBufIndex,1) + + if a:forward + if !g:miniBufExplCycleArround && l:curBufIndex < l:forBufIndex + echo "You have reached the most recent buffer!" + return + endif + let l:moveCmd = 'b! '.s:MRUList[l:forBufIndex] + else + if !g:miniBufExplCycleArround && l:curBufIndex > l:bacBufIndex + echo "You have reached the least recent buffer!" + return + endif + let l:moveCmd = 'b! '.s:MRUList[l:bacBufIndex] + endif + + let s:MRUEnable = 0 + else + call DEBUG('BufList is '.string(s:BufList),1) + let curBufIndex = index(s:BufList, l:curBufNum) + call DEBUG('curBufIndex is '.l:curBufIndex,1) + let forBufIndex = l:curBufIndex + 1 >= len(s:BufList) ? 0 : l:curBufIndex + 1 + call DEBUG('forBufIndex is '.l:forBufIndex,1) + let bacBufIndex = l:curBufIndex - 1 < 0 ? len(s:BufList) - 1 : l:curBufIndex - 1 + call DEBUG('bacBufIndex is '.l:bacBufIndex,1) + + if a:forward + if !g:miniBufExplCycleArround && l:curBufIndex > l:forBufIndex + echo "You have reached the last buffer!" + return + endif + let l:moveCmd = 'b! '.s:BufList[l:forBufIndex] + else + if !g:miniBufExplCycleArround && l:curBufIndex < l:bacBufIndex + echo "You have reached the first buffer!" + return + endif + let l:moveCmd = 'b! '.s:BufList[l:bacBufIndex] + endif + + let s:MRUEnable = 1 + endif + + call DEBUG('===============move cmd is '.l:moveCmd,1) + + " Change buffer (keeping track of before and after buffers) + exec l:moveCmd + + let s:MRUEnable = 1 +endfunction + +" }}} +" DeleteBuffer {{{ +" +" Delete/Unload/Wipeout a buffer but preserve the window it was in +" +" a:action 0 bd, 1 bw, 2 bun +" delete/wipeout/unload a buffer +" a:bufNum +" number of the buffer to be deleted +" +function! DeleteBuffer(action,bang,...) + call DEBUG('Entering DeleteBuffer('.a:action.','.a:bang.')',10) + + if a:0 == 0 + call DEBUG('No buffer is given, use current buffer',5) + let l:bufNums = [ bufnr('%') ] + else + call DEBUG('Given buffers are '.string(a:000),5) + let l:bufNums = map(copy(a:000),'v:val =~ ''\d\+'' ? bufnr(v:val + 0) : bufnr(v:val)') + endif + + call DEBUG('Buffers to be deleted are '.string(l:bufNums),5) + + for l:bufNum in l:bufNums + if IsBufferIgnored(l:bufNum) + call DEBUG('Buffer '.l:bufNum.'is not a normal buffer, skip it',5) + continue + endif + + let l:bufName = bufname(l:bufNum) + call DEBUG('Buffer to be deleted is <'.l:bufName.'>['.l:bufNum.']',5) + + " Don't want auto updates while we are processing a delete + " request. + let l:saveAutoUpdate = t:miniBufExplAutoUpdate + let t:miniBufExplAutoUpdate = 0 + + " Get the currently active buffer, so we can update the MBE + " correctly. If that is the buffer to be deleted, then get + " the window for that buffer, so we can find which buffer + " is in that window after the detaching. + let l:actBuf = GetActiveBuffer() + if l:actBuf == l:bufNum + let l:actBufWin = bufwinnr(l:actBuf) + endif + + " Detach the buffer from all the windows that holding it + " in every tab page. + tabdo call DetachBuffer(l:bufNum) + + " Find which buffer is in the active window now + if l:actBuf == l:bufNum + let l:actBuf = winbufnr(l:actBufWin) + endif + + " Delete the buffer selected. + call DEBUG('About to delete buffer: '.l:bufNum,5) + + if a:action == 2 + let l:cmd = 'bun' + elseif a:action == 1 + let l:cmd = 'bw' + else + let l:cmd = 'bd' + endif + + if a:bang + let l:cmd = l:cmd.'!' + endif + + let l:cmd = 'silent! '.l:cmd.' '.l:bufNum + call DEBUG('About to execute the command "'.l:cmd.'"',5) + + exec l:cmd + + let t:miniBufExplAutoUpdate = l:saveAutoUpdate + + call UpdateExplorer(l:actBuf) + endfor + + call DEBUG('Leaving DeleteBuffer()',10) +endfunction + +" }}} +" DetachBuffer {{{ +" +" Detach a buffer from all the windows in which it is displayed. +" +function! DetachBuffer(bufNum) + call DEBUG('Entering DetachBuffer('.a:bufNum.')',10) + + call DEBUG('We are currently in tab page '.tabpagenr(),10) + + let l:bufNum = a:bufNum + 0 + + let l:winNum = bufwinnr(l:bufNum) + " while we have windows that contain our buffer + while l:winNum != -1 + call DEBUG('Buffer '.l:bufNum.' is being displayed in window: '.l:winNum,5) + + " move to window that contains our selected buffer + call s:SwitchWindow('w',1,l:winNum) + + call DEBUG('We are now in window: '.winnr(),5) + + call DEBUG('Window contains buffer: '.bufnr('%').' which should be: '.l:bufNum,5) + let l:origBuf = bufnr('%') + call CycleBuffer(0,1) + let l:currBuf = bufnr('%') + call DEBUG('Window now contains buffer: '.bufnr('%').' which should not be: '.l:bufNum,5) + + if l:origBuf == l:currBuf + " we wrapped so we are going to have to delete a buffer + " that is in an open window. + let l:winNum = -1 + else + " see if we have anymore windows with our selected buffer + let l:winNum = bufwinnr(l:bufNum) + endif + endwhile + + call DEBUG('Leaving DetachBuffer()',10) +endfunction + +" }}} +" IsBufferIgnored - check to see if buffer should be ignored {{{ +" +" Returns 0 if this buffer should be displayed in the list, 1 otherwise. +" +function! IsBufferIgnored(buf) + call DEBUG('Entering IsBufferIgnored('.a:buf.')',10) + + " Skip unlisted buffers. + if buflisted(a:buf) == 0 || index(s:BufList,a:buf) == -1 + call DEBUG('Buffer '.a:buf.' is unlisted, ignoring...',5) + call DEBUG('Leaving IsBufferIgnored()',10) + return 1 + endif + + " Skip non normal buffers. + if getbufvar(a:buf, "&buftype") != '' + call DEBUG('Buffer '.a:buf.' is not normal, ignoring...',5) + call DEBUG('Leaving IsBufferIgnored()',10) + return 1 + endif + + call DEBUG('Leaving IsBufferIgnored()',10) + return 0 +endfunction + +" }}} +" BuildBufferList - Build the text for the MBE window {{{ +" +" Creates the buffer list string and returns 1 if it is different than +" last time this was called and 0 otherwise. +" +function! BuildBufferList(curBufNum) + call DEBUG('Entering BuildBufferList('.a:curBufNum.')',10) + + let l:CurBufNum = a:curBufNum + + " Get the number of the last buffer. + let l:NBuffers = bufnr('$') + + let l:tabList = [] + let l:maxTabWidth = 0 + + " Loop through every buffer less than the total number of buffers. + for l:i in s:BufList + let l:BufName = expand( "#" . l:i . ":p:t") + + " Establish the tab's content, including the differentiating root + " dir if neccessary + let l:tab = '[' + if g:miniBufExplShowBufNumbers == 1 + let l:tab .= l:i.':' + endif + let l:tab .= s:bufUniqNameDict[l:i] + let l:tab .= ']' + + " If the buffer is open in a window mark it + if bufwinnr(l:i) != -1 + let l:tab .= '*' + endif + + " If the buffer is modified then mark it + if(getbufvar(l:i, '&modified') == 1) + let l:tab .= '+' + endif + + " If the buffer matches the)current buffer name, then mark it + call DEBUG('l:i is '.l:i.' and l:CurBufNum is '.l:CurBufNum,10) + if(l:i == l:CurBufNum) + let l:tab .= '!' + endif + + let l:maxTabWidth = strlen(l:tab) > l:maxTabWidth ? strlen(l:tab) : l:maxTabWidth + + call add(l:tabList, l:tab) + endfor + + if t:miniBufExplSortBy == "name" + call sort(l:tabList, "NameCmp") + elseif t:miniBufExplSortBy == "mru" + call sort(l:tabList, "MRUCmp") + endif + + let l:miniBufExplBufList = '' + for l:tab in l:tabList + let l:miniBufExplBufList = l:miniBufExplBufList.l:tab + + " If horizontal and tab wrap is turned on we need to add spaces + if g:miniBufExplVSplit == 0 + if g:miniBufExplTabWrap != 0 + let l:miniBufExplBufList = l:miniBufExplBufList.' ' + endif + " If not horizontal we need a newline + else + let l:miniBufExplBufList = l:miniBufExplBufList . "\n" + endif + endfor + + if (s:miniBufExplBufList != l:miniBufExplBufList) + let s:maxTabWidth = l:maxTabWidth + let s:miniBufExplBufList = l:miniBufExplBufList + call DEBUG('Leaving BuildBufferList()',10) + return 1 + else + call DEBUG('Leaving BuildBufferList()',10) + return 0 + endif +endfunction + +" }}} +" CreateBufferUniqName {{{ +" +" Construct a unique buffer name using the parts from the signature index of +" the path. +" +function! CreateBufferUniqName(bufNum) + call DEBUG('Entering CreateBufferUniqName('.a:bufNum.')',10) + + let l:bufNum = 0 + a:bufNum + let l:bufName = expand( "#" . l:bufNum . ":p:t") + " Remove []'s & ()'s, these chars are preserved for buffer name locating + let l:bufName = substitute(l:bufName, '[][()]', '', 'g') + + " Create a unique name for unamed buffer + if empty(l:bufName) + call DEBUG('Leaving CreateBufferUniqName()',10) + return '--NO NAME--'.localtime() + endif + + let l:bufPathPrefix = "" + + if(!has_key(s:bufPathSignDict, l:bufNum)) + call DEBUG(l:bufNum . ' is not in s:bufPathSignDict, aborting...',5) + call DEBUG('Leaving CreateBufferUniqName()',10) + return l:bufName + endif + + let l:signs = s:bufPathSignDict[l:bufNum] + if(empty(l:signs)) + call DEBUG('Signs for ' . l:bufNum . ' is empty, aborting...',5) + call DEBUG('Leaving CreateBufferUniqName()',10) + return l:bufName + endif + + for l:sign in l:signs + call DEBUG('l:sign is ' . l:sign,5) + if empty(get(s:bufPathDict[l:bufNum],l:sign)) + continue + endif + let l:bufPathSignPart = get(s:bufPathDict[l:bufNum],l:sign).'/' + " If the index is not right after the previous one and it is also not the + " last one, then put a '-' before it + if exists('l:last') && l:last + 1 != l:sign + let l:bufPathSignPart = '-/'.l:bufPathSignPart + endif + let l:bufPathPrefix = l:bufPathPrefix.l:bufPathSignPart + let l:last = l:sign + endfor + " If the last signature index is not the last index of the path, then put + " a '-' after it + if l:sign < len(s:bufPathDict[l:bufNum]) - 1 + let l:bufPathPrefix = l:bufPathPrefix.'-/' + endif + + call DEBUG('Uniq name for ' . l:bufNum . ' is ' . l:bufPathPrefix.l:bufName,5) + + call DEBUG('Leaving CreateBufferUniqName()',10) + + return l:bufPathPrefix.l:bufName +endfunction + +" }}} +" UpdateBufferNameDict {{{ +" +function! UpdateBufferNameDict(bufNum,deleted) + call DEBUG('Entering UpdateBufferNameDict('.a:bufNum.','.a:deleted.')',10) + + let l:bufNum = 0 + a:bufNum + + let l:bufName = expand( "#" . l:bufNum . ":p:t") + + " Identify buffers with no name + if empty(l:bufName) + let l:bufName = '--NO NAME--' + endif + + " Remove a deleted buffer from the buffer name dictionary + if a:deleted + if has_key(s:bufNameDict, l:bufName) + call DEBUG('Found entry for deleted buffer '.l:bufNum,5) + let l:bufnrs = s:bufNameDict[l:bufName] + call filter(l:bufnrs, 'v:val != '.l:bufNum) + let s:bufNameDict[l:bufName] = l:bufnrs + call DEBUG('Delete entry for deleted buffer '.l:bufNum,5) + endif + call DEBUG('Leaving UpdateBufferNameDict()',10) + return + endif + + if(!has_key(s:bufNameDict, l:bufName)) + call DEBUG('Adding empty list for ' . l:bufName,5) + let s:bufNameDict[l:bufName] = [] + endif + + if index(s:bufNameDict[l:bufName],l:bufNum) == -1 + call add(s:bufNameDict[l:bufName], l:bufNum) + endif + + call DEBUG('Leaving UpdateBufferNameDict()',10) +endfunction + +" }}} +" UpdateBufferPathDict {{{ +" +function! UpdateBufferPathDict(bufNum,deleted) + call DEBUG('Entering UpdateBufferPathDict('.a:bufNum.','.a:deleted.')',10) + + let l:bufNum = 0 + a:bufNum + let l:bufPath = expand( "#" . l:bufNum . ":p:h") + let l:bufName = expand( "#" . l:bufNum . ":p:t") + + " Identify buffers with no name + if empty(l:bufName) + let l:bufName = '--NO NAME--' + endif + + " Remove a deleted buffer from the buffer path dictionary + if a:deleted + if has_key(s:bufNameDict, l:bufName) + call DEBUG('Found entry for deleted buffer '.l:bufNum,5) + let l:bufnrs = s:bufNameDict[l:bufName] + call filter(s:bufPathDict, 'v:key != '.l:bufNum) + call DEBUG('Delete entry for deleted buffer '.l:bufNum,5) + endif + call DEBUG('Leaving UpdateBufferPathDict()',10) + return + endif + + let s:bufPathDict[l:bufNum] = split(l:bufPath,s:PathSeparator,0) + + call DEBUG('Leaving UpdateBufferPathDict()',10) +endfunction + +" }}} +" BuildBufferPathSignDict {{{ +" +" Compare the parts from the same index of all the buffer's paths, if there +" are differences, it means this index is a signature index for all the +" buffer's paths, mark it. At this point, the buffers are splited into several +" subsets. Then, doing the same check for each subset on the next index. We +" should finally get a set of signature locations which will uniquely identify +" the path. We could then construct a string with these locaitons using as +" less characters as possible. +" +function! BuildBufferPathSignDict(bufnrs, ...) + if a:0 == 0 + let index = 0 + else + let index = a:1 + endif + + call DEBUG('Entering BuildBufferPathSignDict('.string(a:bufnrs).','.index.')',10) + + let bufnrs = a:bufnrs + + " Temporary dictionary to see if there is any different part + let partDict = {} + + " Marker to see if there are more avaliable parts + let moreParts = 0 + + " Group the buffers by this part of the buffer's path + for bufnr in bufnrs + " Make sure each buffer has an entry in 's:bufPathSignDict' + " If index is zero, we force re-initialize the entry + if index == 0 || !has_key(s:bufPathSignDict, bufnr) + let s:bufPathSignDict[bufnr] = [] + endif + + " If some buffers' path does not have this index, we skip it + if len(s:bufPathDict[bufnr]) < index + continue + endif + + " Mark that there are still available paths + let moreParts = 1 + + " Get requested part of the path + let part = get(s:bufPathDict[bufnr],index) + + if empty(part) + let part = '--EMPTY--' + endif + + " Group the buffers using dictionary by this part + if(!has_key(partDict, part)) + let partDict[part] = [] + endif + call add(partDict[part],bufnr) + endfor + + " All the paths have been walked to the end + if !moreParts + call DEBUG('Leaving BuildBufferPathSignDict() '.index,10) + return + endif + + " We only need the buffer subsets from now on + let subsets = values(partDict) + + " If the buffers have been splited into more than one subset, or all the + " remaining buffers are still in the same subset but some buffers' path + " have hit the end, then mark this index as signature index. + if len(partDict) > 1 || ( len(partDict) == 1 && len(subsets[0]) < len(bufnrs) ) + " Store the signature index in the 's:bufPathSignDict' variable + for bufnr in bufnrs + call add(s:bufPathSignDict[bufnr],index) + endfor + " For all buffer subsets, increase the index by one, run again. + for subset in subsets + " If we only have one buffer left in the subset, it means there are + " already enough signature index sufficient to identify the buffer + if len(subset) <= 1 + continue + endif + call BuildBufferPathSignDict(subset, index + 1) + endfor + " If all the buffers are in the same subset, then this index is not a + " signature index, increase the index by one, run again. + else + call BuildBufferPathSignDict(bufnrs, index + 1) + endif + + call DEBUG('Leaving BuildBufferPathSignDict() '.index,10) +endfunction + +" }}} +" UpdateBufferPathSignDict {{{ +" +function! UpdateBufferPathSignDict(bufNum,deleted) + call DEBUG('Entering UpdateBufferPathSignDict('.a:bufNum.','.a:deleted.')',10) + + let l:bufNum = 0 + a:bufNum + + " Remove a deleted buffer from the buffer path signature dictionary + if a:deleted + if has_key(s:bufPathSignDict, l:bufNum) + call DEBUG('Found entry for deleted buffer '.l:bufNum,5) + call filter(s:bufPathSignDict, 'v:key != '.l:bufNum) + call DEBUG('Delete entry for deleted buffer '.l:bufNum,5) + endif + call DEBUG('Leaving UpdateBufferPathSignDict()',10) + return + endif + + call DEBUG('Leaving UpdateBufferPathSignDict()',10) +endfunction + +" }}} +" BuildBufferFinalDict {{{ +" +function! BuildBufferFinalDict(arg,deleted) + call DEBUG('Entering BuildBufferFinalDict('.string(a:arg).','.a:deleted.')',10) + + if type(a:arg) == 3 + let l:bufnrs = a:arg + else + let l:bufNum = 0 + a:arg + let l:bufName = expand( "#" . l:bufNum . ":p:t") + + " Identify buffers with no name + if empty(l:bufName) + let l:bufName = '--NO NAME--' + endif + + if(!has_key(s:bufNameDict, l:bufName)) + call DEBUG(l:bufName . ' is not in s:bufNameDict, aborting...',5) + call DEBUG('Leaving BuildBufferFinalDict()',10) + return + endif + + let l:bufnrs = s:bufNameDict[l:bufName] + + " Remove a deleted buffer from the buffer unique name dictionary + if a:deleted + call UpdateBufferPathSignDict(l:bufNum, a:deleted) + call UpdateBufferUniqNameDict(l:bufNum, a:deleted) + endif + endif + + call BuildBufferPathSignDict(l:bufnrs) + + call BuildBufferUniqNameDict(l:bufnrs) + + call DEBUG('Leaving BuildBufferFinalDict()',10) +endfunction + +" }}} +" BuildBufferUniqNameDict {{{ +" +function! BuildBufferUniqNameDict(bufnrs) + call DEBUG('Entering BuildBufferUniqNameDict('.string(a:bufnrs).')',10) + + let l:bufnrs = a:bufnrs + + for bufnr in l:bufnrs + call UpdateBufferUniqNameDict(bufnr,0) + endfor + + call DEBUG('Leaving BuildBufferUniqNameDict()',10) +endfunction + +" }}} +" UpdateBufferUniqNameDict {{{ +" +function! UpdateBufferUniqNameDict(bufNum,deleted) + call DEBUG('Entering UpdateBufferUniqNameDict('.a:bufNum.','.a:deleted.')',10) + + let l:bufNum = 0 + a:bufNum + + " Remove a deleted buffer from the buffer path dictionary + if a:deleted + if has_key(s:bufUniqNameDict, l:bufNum) + call DEBUG('Found entry for deleted buffer '.l:bufNum,5) + call filter(s:bufUniqNameDict, 'v:key != '.l:bufNum) + call DEBUG('Delete entry for deleted buffer '.l:bufNum,5) + endif + call DEBUG('Leaving UpdateBufferUniqNameDict()',10) + return + endif + + call DEBUG('Creating buffer name for ' . l:bufNum,5) + let l:bufUniqName = CreateBufferUniqName(l:bufNum) + + call DEBUG('Setting ' . l:bufNum . ' to ' . l:bufUniqName,5) + let s:bufUniqNameDict[l:bufNum] = l:bufUniqName + + call DEBUG('Leaving UpdateBufferUniqNameDict()',10) +endfunction + +" }}} +" BuildAllBufferDicts {{{ +" +function! BuildAllBufferDicts() + call DEBUG('Entering BuildAllBuffersDicts()',10) + + " Get the number of the last buffer. + let l:NBuffers = bufnr('$') + + " Loop through every buffer less than the total number of buffers. + let l:i = 0 + while(l:i <= l:NBuffers) + if IsBufferIgnored(l:i) + let l:i = l:i + 1 + continue + endif + + call UpdateBufferNameDict(l:i,0) + call UpdateBufferPathDict(l:i,0) + call UpdateBufferStateDict(l:i,0) + + let l:i = l:i + 1 + endwhile + + for bufnrs in values(s:bufNameDict) + call BuildBufferFinalDict(bufnrs,0) + endfor + + call DEBUG('Leaving BuildAllBuffersDicts()',10) +endfunction + +" }}} +" UpdateAllBufferDicts {{{ +" +function! UpdateAllBufferDicts(bufNum,deleted) + call DEBUG('Entering UpdateAllBuffersDicts('.a:bufNum.','.a:deleted.')',10) + + call UpdateBufferNameDict(a:bufNum,a:deleted) + call UpdateBufferPathDict(a:bufNum,a:deleted) + call UpdateBufferStateDict(a:bufNum,a:deleted) + + call BuildBufferFinalDict(a:bufNum,a:deleted) + + call DEBUG('Leaving UpdateAllBuffersDicts()',10) +endfunction + +" }}} +" UpdateBufferStateDict {{{ +function! UpdateBufferStateDict(bufNum,deleted) + call DEBUG('Entering UpdateBufferStateDict('.a:bufNum.','.a:deleted.')',10) + + let l:bufNum = 0 + a:bufNum + + if a:deleted && has_key(s:bufStateDict, l:bufNum) + call filter(s:bufStateDict, 'v:key != '.l:bufNum) + call DEBUG('Leaving UpdateBufferStateDict()',10) + return + endif + + if has_key(s:bufStateDict, l:bufNum) + if s:bufStateDict[l:bufNum] != getbufvar(a:bufNum, '&modified') + let s:bufStateDict[l:bufNum] = getbufvar(a:bufNum, '&modified') + call AutoUpdate(bufnr(a:bufNum),0) + endif + else + let s:bufStateDict[l:bufNum] = getbufvar(a:bufNum, '&modified') + endif + + call DEBUG('Leaving UpdateBufferStateDict()',10) +endfunction + +" }}} +" NameCmp - compares tabs based on filename {{{ +" +function! NameCmp(tab1, tab2) + let l:name1 = matchstr(a:tab1, ":.*") + let l:name2 = matchstr(a:tab2, ":.*") + if l:name1 < l:name2 + return -1 + elseif l:name1 > l:name2 + return 1 + else + return 0 + endif +endfunction + +" }}} +" MRUCmp - compares tabs based on MRU order {{{ +" +function! MRUCmp(tab1, tab2) + let l:buf1 = str2nr(matchstr(a:tab1, '[0-9]\+')) + let l:buf2 = str2nr(matchstr(a:tab2, '[0-9]\+')) + return index(s:MRUList, l:buf1) - index(s:MRUList, l:buf2) +endfunction + +" }}} +" HasEligibleBuffers - Are there enough MBE eligible buffers to open the MBE window? {{{ +" +" Returns 1 if there are any buffers that can be displayed in a +" mini buffer explorer. Otherwise returns 0. +" +function! HasEligibleBuffers() + call DEBUG('Entering HasEligibleBuffers()',10) + + let l:found = len(s:BufList) + let l:needed = g:miniBufExplBuffersNeeded + + call DEBUG('Eligible buffers are '.string(s:BufList),6) + call DEBUG('Found '.l:found.' eligible buffers of '.l:needed.' needed',6) + + call DEBUG('Leaving HasEligibleBuffers()',10) + return (l:found >= l:needed) +endfunction + +" }}} +" Auto Update - Function called by auto commands for auto updating the MBE {{{ +" +" IF auto update is turned on AND +" we are in a real buffer AND +" we have enough eligible buffers THEN +" Update our explorer and get back to the current window +" +" If we get a buffer number for a buffer that +" is being deleted, we need to make sure and +" remove the buffer from the list of eligible +" buffers in case we are down to one eligible +" buffer, in which case we will want to close +" the MBE window. +" +function! AutoUpdate(curBufNum,force) + call DEBUG('Entering AutoUpdate('.a:curBufNum.')',10) + + call DEBUG('Current state: '.winnr().' : '.bufnr('%').' : '.bufname('%'),10) + + if (s:miniBufExplInAutoUpdate == 1) + call DEBUG('AutoUpdate recursion stopped',9) + call DEBUG('Leaving AutoUpdate()',10) + return + else + let s:miniBufExplInAutoUpdate = 1 + endif + + " Skip windows holding ignored buffer + if !a:force && IsBufferIgnored(a:curBufNum) == 1 + call DEBUG('Leaving AutoUpdate()',10) + + let s:miniBufExplInAutoUpdate = 0 + return + endif + + if s:MRUEnable == 1 + call ListPush(s:MRUList,a:curBufNum) + endif + + " Only allow updates when the AutoUpdate flag is set + " this allows us to stop updates on startup. + if exists('t:miniBufExplAutoUpdate') && t:miniBufExplAutoUpdate == 1 + " if we don't have a window then create one + let l:winnr = FindWindow('-MiniBufExplorer-', 1) + + if (exists('t:skipEligibleBuffersCheck') && t:skipEligibleBuffersCheck == 1) || HasEligibleBuffers() == 1 + if (l:winnr == -1) + if g:miniBufExplAutoStart == 1 + call DEBUG('MiniBufExplorer was not running, starting...', 9) + call StartExplorer(a:curBufNum) + else + call DEBUG('MiniBufExplorer was not running, aborting...', 9) + call DEBUG('Leaving AutoUpdate()',10) + let s:miniBufExplInAutoUpdate = 0 + return + endif + else + call DEBUG('Updating MiniBufExplorer...', 9) + call UpdateExplorer(a:curBufNum) + endif + else + if (l:winnr == -1) + call DEBUG('MiniBufExplorer was not running, aborting...', 9) + call DEBUG('Leaving AutoUpdate()',10) + let s:miniBufExplInAutoUpdate = 0 + return + else + call DEBUG('Failed in eligible check', 9) + call StopExplorer(0) + " we do not want to turn auto-updating off + let t:miniBufExplAutoUpdate = 1 + endif + endif + else + call DEBUG('AutoUpdates are turned off, terminating',9) + endif + + call DEBUG('Leaving AutoUpdate()',10) + + let s:miniBufExplInAutoUpdate = 0 +endfunction + +" }}} +" QuitIfLastOpen {{{ +" +function! QuitIfLastOpen() abort + " Quit MBE if no more mormal window left + if (bufname('%') == '-MiniBufExplorer-') && (NextNormalWindow() == -1) + call DEBUG('MBE is the last open window, quit it', 9) + if tabpagenr('$') == 1 + " Before quitting Vim, delete the MBE buffer so that + " the '0 mark is correctly set to the previous buffer. + " Also disable autocmd on this command to avoid unnecessary + " autocmd nesting. + if winnr('$') == 1 + noautocmd bdelete + endif + quit + else + close + endif + endif +endfunction + +" }}} +" GetActiveBuffer {{{ +" +function! GetActiveBuffer() + call DEBUG('Entering GetActiveBuffer()',10) + let l:bufNum = substitute(s:miniBufExplBufList,'\[\([0-9]*\):[^\]]*\][^\!]*!', '\1', '') + 0 + call DEBUG('Currently active buffer is '.l:bufNum,10) + call DEBUG('Leaving GetActiveBuffer()',10) + return l:bufNum +endfunction + +" }}} +" GetSelectedBuffer - From the MBE window, return the bufnum for buf under cursor {{{ +" +" If we are in our explorer window then return the buffer number +" for the buffer under the cursor. +" +function! GetSelectedBuffer() + call DEBUG('Entering GetSelectedBuffer()',10) + + " Make sure we are in our window + if bufname('%') != '-MiniBufExplorer-' + call DEBUG('GetSelectedBuffer called in invalid window',1) + call DEBUG('Leaving GetSelectedBuffer()',10) + return -1 + endif + + let l:save_rep = &report + let l:save_sc = &showcmd + let &report = 10000 + set noshowcmd + + let l:save_reg = @" + let @" = "" + normal ""yi[ + if @" != "" + if !g:miniBufExplShowBufNumbers + " This is a bit ugly, but it works, unless we come up with a + " better way to get the key for a dictionary by its value. + let l:bufUniqNameDictKeys = keys(s:bufUniqNameDict) + let l:bufUniqNameDictValues = values(s:bufUniqNameDict) + let l:retv = l:bufUniqNameDictKeys[match(l:bufUniqNameDictValues,substitute(@",'[0-9]*:\(.*\)', '\1', ''))] + else + let l:retv = substitute(@",'\([0-9]*\):.*', '\1', '') + 0 + endif + let @" = l:save_reg + call DEBUG('Leaving GetSelectedBuffer()',10) + return l:retv + else + let @" = l:save_reg + call DEBUG('Leaving GetSelectedBuffer()',10) + return -1 + endif + + let &report = l:save_rep + let &showcmd = l:save_sc +endfunction + +" }}} +" MBESelectBuffer - From the MBE window, open buffer under the cursor {{{ +" +" If we are in our explorer, then we attempt to open the buffer under the +" cursor in the previous window. +" +" Split indicates whether to open with split, 0 no split, 1 split horizontally +" +function! MBESelectBuffer(split) + call DEBUG('Entering MBESelectBuffer()',10) + + " Make sure we are in our window + if bufname('%') != '-MiniBufExplorer-' + call DEBUG('MBESelectBuffer called in invalid window',1) + call DEBUG('Leaving MBESelectBuffer()',10) + return + endif + + let l:bufnr = GetSelectedBuffer() + + if(l:bufnr != -1) " If the buffer exists. + let l:saveAutoUpdate = t:miniBufExplAutoUpdate + let t:miniBufExplAutoUpdate = 0 + + call s:SwitchWindow('p',1) + + if IsBufferIgnored(bufnr('%')) + let l:winNum = NextNormalWindow() + if l:winNum != -1 + call s:SwitchWindow('w',1,l:winNum) + else + call DEBUG('No elegible window avaliable',1) + call DEBUG('Leaving MBESelectBuffer()',10) + return + endif + endif + + if a:split == 0 + exec 'b! '.l:bufnr + elseif a:split == 1 + exec 'sb! '.l:bufnr + elseif a:split == 2 + exec 'vertical sb! '.l:bufnr + endif + + let t:miniBufExplAutoUpdate = l:saveAutoUpdate + + call AutoUpdate(bufnr("%"),0) + endif + + if g:miniBufExplCloseOnSelect == 1 + call StopExplorer(0) + endif + + call DEBUG('Leaving MBESelectBuffer()',10) +endfunction + +" }}} +" MBEDeleteBuffer - From the MBE window, delete selected buffer from list {{{ +" +" After making sure that we are in our explorer, This will delete the buffer +" under the cursor. If the buffer under the cursor is being displayed in a +" window, this routine will attempt to get different buffers into the +" windows that will be affected so that windows don't get removed. +" +function! MBEDeleteBuffer() + call DEBUG('Entering MBEDeleteBuffer()',10) + + " Make sure we are in our window + if bufname('%') != '-MiniBufExplorer-' + call DEBUG('MBEDeleteBuffer called in invalid window',1) + call DEBUG('Leaving MBEDeleteBuffer()',10) + return + endif + + let l:selBuf = GetSelectedBuffer() + + if l:selBuf != -1 + call DeleteBuffer(0,0,l:selBuf) + endif + + call DEBUG('Leaving MBEDeleteBuffer()',10) +endfunction + +" }}} +" NextNormalWindow {{{ +" +function! NextNormalWindow() + call DEBUG('Entering NextNormalWindow()',10) + + let l:winSum = winnr('$') + call DEBUG('Total number of open windows are '.l:winSum,9) + + let l:i = 1 + while(l:i <= l:winSum) + call DEBUG('window: '.l:i.', buffer: ('.winbufnr(l:i).':'.bufname(winbufnr(l:i)).')',9) + if !IsBufferIgnored(winbufnr(l:i)) && l:i != winnr() + call DEBUG('Found window '.l:i,8) + call DEBUG('Leaving NextNormalWindow()',10) + return l:i + endif + let l:i = l:i + 1 + endwhile + + call DEBUG('Found no window',8) + call DEBUG('Leaving NextNormalWindow()',10) + return -1 +endfunction + +" }}} +" ListAdd {{{ +" +function! ListAdd(list,val) + call DEBUG('Entering ListAdd('.string(a:list).','.a:val.')',10) + call add(a:list, a:val) + call DEBUG('Leaving ListAdd()',10) +endfunction + +" }}} +" ListPop {{{ +" +function! ListPop(list,val) + call DEBUG('Entering ListPop('.string(a:list).','.a:val.')',10) + call filter(a:list, 'v:val != '.a:val) + call DEBUG('Leaving ListPop()',10) +endfunction + +" }}} +" ListPush {{{ +" +function! ListPush(list,val) + call DEBUG('Entering ListPush('.string(a:list).','.a:val.')',10) + " Remove the buffer number from the list if it already exists. + call ListPop(a:list,a:val) + + " Add the buffer number to the head of the list. + call insert(a:list,a:val) + call DEBUG('Leaving ListPush()',10) +endfunction + +" }}} +" DEBUG - Display debug output when debugging is turned on {{{ +" +" Thanks to Charles E. Campbell, Jr. PhD +" for Decho.vim which was the inspiration for this enhanced debugging +" capability. +" +let g:miniBufExplFuncCallDepth = 0 +function! DEBUG(msg, level) + if g:miniBufExplDebugLevel >= a:level + + if a:level == 10 && a:msg =~ '^Entering' + let g:miniBufExplFuncCallDepth += 1 + endif + + if a:msg =~ '^Entering' + let l:msg = repeat('│ ',g:miniBufExplFuncCallDepth - 1).'┌ '.a:msg + elseif a:msg =~ '^Leaving' + let l:msg = repeat('│ ',g:miniBufExplFuncCallDepth - 1).'└ '.a:msg + else + let l:msg = repeat('│ ',g:miniBufExplFuncCallDepth).a:msg + endif + + " Prevent a report of our actions from showing up. + let l:save_rep = &report + let l:save_sc = &showcmd + let &report = 10000 + set noshowcmd + + " Debug output to a buffer + if g:miniBufExplDebugMode == 0 + if bufname('%') == 'MiniBufExplorer.DBG' + return + endif + + " Get into the debug window or create it if needed + let l:winNum = FindCreateWindow('MiniBufExplorer.DBG', 0, 1, 1, 1, 0) + + if l:winNum == -1 + let g:miniBufExplDebugMode == 3 + call DEBUG('Failed to get the MBE debugging window, reset debugging mode to 3.',1) + call DEBUG('Forwarding message...',1) + call DEBUG(a:msg,1) + call DEBUG('Forwarding message end.',1) + return + endif + + " Save the current window number so we can come back here + let l:currWin = winnr() + call s:SwitchWindow('p',1) + + " Change to debug window + call s:SwitchWindow('w',1,l:winNum) + + " Make sure we really got to our window, if not we + " will display a confirm dialog and turn debugging + " off so that we won't break things even more. + if bufname('%') != 'MiniBufExplorer.DBG' + call confirm('Error in window debugging code. Dissabling MiniBufExplorer debugging.', 'OK') + let g:miniBufExplDebugLevel = 0 + return + endif + + set modified + + " Write Message to DBG buffer + let res=append("$",s:debugIndex.':'.a:level.':'.a:msg) + + set nomodified + + norm G + + " Return to original window + call s:SwitchWindow('p',1) + call s:SwitchWindow('w',1,l:currWin) + " Debug output using VIM's echo facility + elseif g:miniBufExplDebugMode == 1 + echo s:debugIndex.':'.a:level.':'.a:msg + " Debug output to a file -- VERY SLOW!!! + " should be OK on UNIX and Win32 (not the 95/98 variants) + elseif g:miniBufExplDebugMode == 2 + if has('system') || has('fork') + if has('win32') && !has('win95') + let l:result = system("cmd /c 'echo ".s:debugIndex.':'.a:level.':'.a:msg." >> MiniBufExplorer.DBG'") + endif + if has('unix') + let l:result = system("echo '".s:debugIndex.':'.a:level.':'.a:msg." >> MiniBufExplorer.DBG'") + endif + else + call confirm('Error in file writing version of the debugging code, vim not compiled with system or fork. Dissabling MiniBufExplorer debugging.', 'OK') + let g:miniBufExplDebugLevel = 0 + endif + elseif g:miniBufExplDebugMode == 3 + let g:miniBufExplDebugOutput = g:miniBufExplDebugOutput."\n".s:debugIndex."\t".':'.a:level."\t".':'.l:msg + endif + + let s:debugIndex = s:debugIndex + 1 + + if a:level == 10 && a:msg =~ '^Leaving' + let g:miniBufExplFuncCallDepth -= 1 + endif + + let &report = l:save_rep + let &showcmd = l:save_sc + endif +endfunc + +" }}} +" SwitchWindow {{{ +" +function! s:SwitchWindow(action, ...) + call DEBUG('Entering SwitchWindow('.a:action.','.string(a:000).')',10) + + if a:action !~ '[hjkltbwWpP]' + call DEBUG('invalid window action : '.a:action,10) + call DEBUG('Leaving SwitchWindow()',10) + return + endif + + if exists('a:1') && a:1 == 1 + let l:aucmd = 'noautocmd ' + else + let l:aucmd = '' + endif + + if exists('a:2') + let l:winnr = a:2 + else + let l:winnr = '' + endif + + call DEBUG('previous window is: '.winnr(),10) + let l:wincmd = l:aucmd.l:winnr.'wincmd '.a:action + call DEBUG('window switching command is: '.l:wincmd,10) + exec l:wincmd + call DEBUG('current window is: '.winnr(),10) + + call DEBUG('Leaving SwitchWindow()',10) +endfunction + +" }}} + +" vim:ft=vim:fdm=marker:ff=unix:nowrap:tabstop=2:shiftwidth=2:softtabstop=2:smarttab:shiftround:expandtab -- cgit v1.2.3