Răsfoiți Sursa

Merge pull request #129 from drmikehenry/open-close-toggle

Flexibly open, close, and toggle BufExplorer windows and splits
jlanzarotta 9 luni în urmă
părinte
comite
87ac3de521
2 a modificat fișierele cu 209 adăugiri și 45 ștergeri
  1. 84 4
      doc/bufexplorer.txt
  2. 125 41
      plugin/bufexplorer.vim

+ 84 - 4
doc/bufexplorer.txt

@@ -8,6 +8,7 @@ Plugin for easily exploring (or browsing) Vim|:buffers|.
 |bufexplorer-installation|   Installation
 |bufexplorer-installation|   Installation
 |bufexplorer-usage|          Usage
 |bufexplorer-usage|          Usage
 |bufexplorer-windowlayout|   Window Layout
 |bufexplorer-windowlayout|   Window Layout
+|bufexplorer-commands|       Commands
 |bufexplorer-customization|  Customization
 |bufexplorer-customization|  Customization
 |bufexplorer-changelog|      Change Log
 |bufexplorer-changelog|      Change Log
 |bufexplorer-todo|           Todo
 |bufexplorer-todo|           Todo
@@ -49,6 +50,8 @@ To start exploring in a newly split horizontal window, use: >
 To start exploring in a newly split vertical window, use: >
 To start exploring in a newly split vertical window, use: >
  <Leader>bv   or   :BufExplorerVerticalSplit   or   Your custom key mapping
  <Leader>bv   or   :BufExplorerVerticalSplit   or   Your custom key mapping
 
 
+For full information on these flexible commands, see |bufexplorer-commands|.
+
 If you would like to use something other than the default leader key - '\' -
 If you would like to use something other than the default leader key - '\' -
 you may simply change the leader (see |mapleader|).
 you may simply change the leader (see |mapleader|).
 
 
@@ -60,10 +63,6 @@ windows) in the newly split window.  When <Leader>be is issued, bufexplorer
 opens the bufexplorer contents in the current window and the buffer the user
 opens the bufexplorer contents in the current window and the buffer the user
 selects is opened in the current window.
 selects is opened in the current window.
 
 
-Note: If the current buffer is modified when bufexplorer started, the current
-      window is always split and the new bufexplorer is displayed in that new
-      window.
-
 Commands to use once exploring:
 Commands to use once exploring:
 
 
  <F1>          Toggle help information.
  <F1>          Toggle help information.
@@ -114,6 +113,74 @@ wanting to act upon. Once you have selected the buffer you would like,
 you can then either open it, close it (delete), resort the list, reverse
 you can then either open it, close it (delete), resort the list, reverse
 the sort, quit exploring and so on...
 the sort, quit exploring and so on...
 
 
+===============================================================================
+COMMANDS                                            *bufexplorer-commands*
+
+:BufExplorer [action]                               *:BufExplorer*
+                Open or close BufExplorer.
+
+`:BufExplorer` accepts an optional "action" argument as follows:
+
+  current   Open BufExplorer in the current window
+  split     Open BufExplorer in a new horizontal split
+  vsplit    Open BufExplorer in a new vertical split
+  above     Open BufExplorer in a new horizontal split above the current window
+  below     Open BufExplorer in a new horizontal split below the current window
+  left      Open BufExplorer in a new vertical split left of the current window
+  right     Open BufExplorer in a new vertical split right of the current window
+  close     Close BufExplorer
+
+If the action argument is not provided, then the value of
+|g:bufExplorerDefaultAction| will be used; by default, this variable contains
+`current` and thus `:Bufexplorer` is the same as `:BufExplorer current`.
+
+Note that this means the behavior of the default mapping <Leader>be (which maps
+to `:BufExplorer`) is determined by |g:bufExplorerDefaultAction|.
+
+The `close` action will close BufExplorer regardless of the tab page or window
+where it was left running.
+
+For actions other than `close`, the `:BufExplorer` command will switch to any
+existing BufExplorer window instead of launching a new instance of BufExplorer.
+
+The actions `above`, `below`, `left`, and `right` specify the type of split
+(horizontal or vertical) to create and where the new window should be placed
+relative to the current window.
+
+The `split` action makes a horizontal split; the position of the split is
+controlled by |g:bufExplorerSplitBelow| (true means `below`, false means
+`above`).
+
+The `vsplit` action makes a vertical split; the position of the split is
+controlled by |g:bufExplorerSplitRight| (true means `right`, false means
+`left`).
+
+Tab completion is provided.  For example, typing `:BufExplorer v` and then
+pressing the <Tab> key will complete the action argument to become `vsplit`.
+
+:ToggleBufExplorer [action]                         *:ToggleBufExplorer*
+                Toggle open/closed BufExplorer.
+
+In most ways, this command is identical to |:BufExplorer|, and the invocation
+`:ToggleBufExplorer action` is equivalent to `:BufExplorer action`; however, if
+BufExplorer is already running in the current window, `action` is converted to
+`close` before chaining to `:BufExplorer action`.  If BufExplorer is running in
+a different window and the action is not `close`, switch to that already-running
+BufExplorer window.
+
+Note that the behavior of the default mapping <Leader>bt (which maps to
+`:ToggleBufExplorer`) is determined by |g:bufExplorerDefaultAction|.
+
+:BufExplorerHorizontalSplit                         *:BufExplorerHorizontalSplit*
+                Open BufExplorer in a new horizontal split.
+
+This is equivalent to `:BufExplorer split`.
+
+:BufExplorerVerticalSplit                           *:BufExplorerVerticalSplit*
+                Open BufExplorer in a new vertical split.
+
+This is equivalent to `:BufExplorer vsplit`.
+
 ===============================================================================
 ===============================================================================
 WINDOW LAYOUT                                       *bufexplorer-windowlayout*
 WINDOW LAYOUT                                       *bufexplorer-windowlayout*
 
 
@@ -246,6 +313,19 @@ be called to adjust BufExplorer's mappings: >
 If set, bufexplorer will bring up the selected buffer in the window specified
 If set, bufexplorer will bring up the selected buffer in the window specified
 by g:bufExplorerChgWin.
 by g:bufExplorerChgWin.
 
 
+                                                   *g:bufExplorerDefaultAction*
+Specify the default action for |:BufExplorer| and |:ToggleBufExplorer|.  For
+example: >
+  let g:bufExplorerDefaultAction = 'current'  " Open in current window.
+  let g:bufExplorerDefaultAction = 'split'    " Open in new horizontal split.
+  let g:bufExplorerDefaultAction = 'vsplit'   " Open in new vertical split.
+  let g:bufExplorerDefaultAction = 'above'    " Open in horizontal split above.
+  let g:bufExplorerDefaultAction = 'below'    " Open in horizontal split below.
+  let g:bufExplorerDefaultAction = 'left'     " Open in vertical split to left.
+  let g:bufExplorerDefaultAction = 'right'    " Open in vertical split to right.
+The default is `current` (open in current window). See |:BufExplorer| for more
+details.
+
                                                      *g:bufExplorerDefaultHelp*
                                                      *g:bufExplorerDefaultHelp*
 To control whether the default help is displayed or not, use: >
 To control whether the default help is displayed or not, use: >
   let g:bufExplorerDefaultHelp=0       " Do not show default help.
   let g:bufExplorerDefaultHelp=0       " Do not show default help.

+ 125 - 41
plugin/bufexplorer.vim

@@ -93,9 +93,28 @@ if v:version < 704
     finish
     finish
 endif
 endif
 
 
+" Command actions {{{2
+let s:actions = [
+        \ 'current',
+        \ 'close',
+        \ 'split',
+        \ 'vsplit',
+        \ 'above',
+        \ 'below',
+        \ 'left',
+        \ 'right',
+        \ ]
+
+" Command-line completion function for `s:actions`.
+function! s:ActionArgs(ArgLead, CmdLine, CursorPos)
+    return join(s:actions, "\n")
+endfunction
+
 " Create commands {{{2
 " Create commands {{{2
-command! BufExplorer :call BufExplorer()
-command! ToggleBufExplorer :call ToggleBufExplorer()
+command! -nargs=? -complete=custom,<SID>ActionArgs
+        \ BufExplorer :call BufExplorer(<f-args>)
+command! -nargs=? -complete=custom,<SID>ActionArgs
+        \ ToggleBufExplorer :call ToggleBufExplorer(<f-args>)
 command! BufExplorerHorizontalSplit :call BufExplorerHorizontalSplit()
 command! BufExplorerHorizontalSplit :call BufExplorerHorizontalSplit()
 command! BufExplorerVerticalSplit :call BufExplorerVerticalSplit()
 command! BufExplorerVerticalSplit :call BufExplorerVerticalSplit()
 
 
@@ -121,7 +140,6 @@ let s:name = '[BufExplorer]'
 let s:bufExplorerBuffer = 0
 let s:bufExplorerBuffer = 0
 let s:running = 0
 let s:running = 0
 let s:sort_by = ["number", "name", "fullpath", "mru", "extension"]
 let s:sort_by = ["number", "name", "fullpath", "mru", "extension"]
-let s:splitMode = ""
 let s:didSplit = 0
 let s:didSplit = 0
 let s:types = ["fullname", "homename", "path", "relativename", "relativepath", "shortname"]
 let s:types = ["fullname", "homename", "path", "relativename", "relativepath", "shortname"]
 
 
@@ -528,7 +546,6 @@ function! s:Cleanup()
     endif
     endif
 
 
     let s:running = 0
     let s:running = 0
-    let s:splitMode = ""
     let s:didSplit = 0
     let s:didSplit = 0
 
 
     delmarks!
     delmarks!
@@ -559,46 +576,80 @@ endfunction
 
 
 " BufExplorerHorizontalSplit {{{2
 " BufExplorerHorizontalSplit {{{2
 function! BufExplorerHorizontalSplit()
 function! BufExplorerHorizontalSplit()
-    let s:splitMode = "sp"
-    execute "BufExplorer"
-    let s:splitMode = ""
+    call BufExplorer('split')
 endfunction
 endfunction
 
 
 " BufExplorerVerticalSplit {{{2
 " BufExplorerVerticalSplit {{{2
 function! BufExplorerVerticalSplit()
 function! BufExplorerVerticalSplit()
-    let s:splitMode = "vsp"
-    execute "BufExplorer"
-    let s:splitMode = ""
+    call BufExplorer('vsplit')
 endfunction
 endfunction
 
 
 " ToggleBufExplorer {{{2
 " ToggleBufExplorer {{{2
-function! ToggleBufExplorer()
-    if exists("s:running") && s:running == 1 && bufname(winbufnr(0)) == s:name
-        call s:Close()
+" Args: `([action])`
+" Optional `action` argument must be taken from `s:actions`.  If not present,
+" `action` defaults to `g:bufExplorerDefaultAction`.
+function! ToggleBufExplorer(...)
+    if a:0 >= 1
+        let action = a:1
     else
     else
-        call BufExplorer()
+        let action = g:bufExplorerDefaultAction
+    endif
+    if a:0 >= 2
+        echoerr 'Too many arguments'
+        return
+    endif
+
+    if index(s:actions, action) < 0
+        echoerr 'Invalid action ' . action
+        return
+    endif
+
+    if s:running && bufnr('%') == s:bufExplorerBuffer
+        let action = 'close'
     endif
     endif
+
+    call BufExplorer(action)
 endfunction
 endfunction
 
 
 " BufExplorer {{{2
 " BufExplorer {{{2
-function! BufExplorer()
-    let name = s:name
+" Args: `([action])`
+" Optional `action` argument must be taken from `s:actions`.  If not present,
+" `action` defaults to `g:bufExplorerDefaultAction`.
+function! BufExplorer(...)
+    if a:0 >= 1
+        let action = a:1
+    else
+        let action = g:bufExplorerDefaultAction
+    endif
+    if a:0 >= 2
+        echoerr 'Too many arguments'
+        return
+    endif
 
 
-    if !has("win32")
-        " On non-Windows boxes, escape the name so that is shows up correctly.
-        let name = escape(name, "[]")
+    if index(s:actions, action) < 0
+        echoerr 'Invalid action ' . action
+        return
     endif
     endif
 
 
-    " Make sure there is only one explorer open at a time.
-    if s:running == 1
-        " Go to the open buffer.
-        if has("gui")
-            execute "drop" name
-        endif
+    if action == 'close'
+        call s:Close()
+        return
+    endif
 
 
+    let [tabNbr, winNbr] = s:FindBufExplorer()
+    if tabNbr > 0
+        execute 'keepjumps ' . tabNbr . 'tabnext'
+        execute 'keepjumps ' . winNbr . 'wincmd w'
         return
         return
     endif
     endif
 
 
+    let name = s:name
+
+    if !has("win32")
+        " On non-Windows boxes, escape the name so that is shows up correctly.
+        let name = escape(name, "[]")
+    endif
+
     let s:tabIdAtLaunch = s:MRUEnsureTabId(tabpagenr())
     let s:tabIdAtLaunch = s:MRUEnsureTabId(tabpagenr())
     let s:windowAtLaunch = winnr()
     let s:windowAtLaunch = winnr()
 
 
@@ -610,24 +661,27 @@ function! BufExplorer()
     call s:MRUGarbageCollectBufs()
     call s:MRUGarbageCollectBufs()
     call s:MRUGarbageCollectTabs()
     call s:MRUGarbageCollectTabs()
 
 
-    " We may have to split the current window.
-    if s:splitMode != ""
-        " Save off the original settings.
-        let [_splitbelow, _splitright] = [&splitbelow, &splitright]
+    " `{ action: [splitMode, botRight] }`.
+    let actionMap = {
+            \ 'split'   : ['split', g:bufExplorerSplitBelow],
+            \ 'vsplit'  : ['vsplit', g:bufExplorerSplitRight],
+            \ 'above'   : ['split', 0],
+            \ 'below'   : ['split', 1],
+            \ 'left'    : ['vsplit', 0],
+            \ 'right'   : ['vsplit', 1],
+            \ 'current' : ['', 0],
+            \}
+    let [splitMode, botRight] = actionMap[action]
 
 
-        " Set the setting to ours.
-        let [&splitbelow, &splitright] = [g:bufExplorerSplitBelow, g:bufExplorerSplitRight]
-        let _size = (s:splitMode == "sp") ? g:bufExplorerSplitHorzSize : g:bufExplorerSplitVertSize
-
-        " Split the window either horizontally or vertically.
-        if _size <= 0
-            execute 'keepalt ' . s:splitMode
-        else
-            execute 'keepalt ' . _size . s:splitMode
+    " We may have to split the current window.
+    if splitMode != ''
+        let size = splitMode == 'split' ? g:bufExplorerSplitHorzSize : g:bufExplorerSplitVertSize
+        let cmd = 'keepalt ' . (botRight ? 'botright ' : 'topleft ')
+        if size > 0
+            let cmd .= size
         endif
         endif
-
-        " Restore the original settings.
-        let [&splitbelow, &splitright] = [_splitbelow, _splitright]
+        let cmd .= splitMode
+        execute cmd
 
 
         " Remember that a split was triggered
         " Remember that a split was triggered
         let s:didSplit = 1
         let s:didSplit = 1
@@ -1352,6 +1406,18 @@ endfunction
 
 
 " Close {{{2
 " Close {{{2
 function! s:Close()
 function! s:Close()
+    let [tabNbr, winNbr] = s:FindBufExplorer()
+    if tabNbr == 0
+        return
+    endif
+    let [curTabNbr, curWinNbr] = [tabpagenr(), winnr()]
+    if [tabNbr, winNbr] != [curTabNbr, curWinNbr]
+        " User has switched away from the original BufExplorer window.
+        " It's unclear how to do better than simply wiping out the
+        " BufExplorer buffer.
+        execute 'bwipeout ' . s:bufExplorerBuffer
+        return
+    endif
     " Get only the listed buffers associated with the current tab (up to 2).
     " Get only the listed buffers associated with the current tab (up to 2).
     let listed = s:MRUListedBuffersForTab(s:tabIdAtLaunch, 2)
     let listed = s:MRUListedBuffersForTab(s:tabIdAtLaunch, 2)
 
 
@@ -1377,6 +1443,23 @@ function! s:Close()
     echo
     echo
 endfunction
 endfunction
 
 
+" FindBufExplorer {{{2
+" Return `[tabNbr, winNbr]`; both numbers will be zero if not found.
+function! s:FindBufExplorer()
+    let result = [0, 0]
+    if s:running
+        let numTabs = tabpagenr('$')
+        for tabNbr in range(1, numTabs)
+            let winNbr = index(tabpagebuflist(tabNbr), s:bufExplorerBuffer) + 1
+            if winNbr > 0
+                let result = [tabNbr, winNbr]
+                break
+            endif
+        endfor
+    endif
+    return result
+endfunction
+
 " ToggleShowTerminal {{{2
 " ToggleShowTerminal {{{2
 function! s:ToggleShowTerminal()
 function! s:ToggleShowTerminal()
     let g:bufExplorerShowTerminal = !g:bufExplorerShowTerminal
     let g:bufExplorerShowTerminal = !g:bufExplorerShowTerminal
@@ -1677,6 +1760,7 @@ endfunction
 
 
 " Default values {{{2
 " Default values {{{2
 call s:Set("g:bufExplorerDisableDefaultKeyMapping", 0)  " Do not disable default key mappings.
 call s:Set("g:bufExplorerDisableDefaultKeyMapping", 0)  " Do not disable default key mappings.
+call s:Set("g:bufExplorerDefaultAction", 'current')     " Default action for `:BufExplorer` with no args.
 call s:Set("g:bufExplorerDefaultHelp", 1)               " Show default help?
 call s:Set("g:bufExplorerDefaultHelp", 1)               " Show default help?
 call s:Set("g:bufExplorerDetailedHelp", 0)              " Show detailed help?
 call s:Set("g:bufExplorerDetailedHelp", 0)              " Show detailed help?
 call s:Set("g:bufExplorerFindActive", 1)                " When selecting an active buffer, take you to the window where it is active?
 call s:Set("g:bufExplorerFindActive", 1)                " When selecting an active buffer, take you to the window where it is active?