70c8cb9bfa
Previously the "t" and "T" mappings were altered to open new tabs at the end of the tab line. This commit reverts that change.
351 lines
9.9 KiB
VimL
351 lines
9.9 KiB
VimL
" ============================================================================
|
|
" CLASS: Opener
|
|
"
|
|
" The Opener class defines an API for "opening" operations.
|
|
" ============================================================================
|
|
|
|
|
|
let s:Opener = {}
|
|
let g:NERDTreeOpener = s:Opener
|
|
|
|
" FUNCTION: s:Opener._bufInWindows(bnum) {{{1
|
|
" [[STOLEN FROM VTREEEXPLORER.VIM]]
|
|
" Determine the number of windows open to this buffer number.
|
|
" Care of Yegappan Lakshman. Thanks!
|
|
"
|
|
" Args:
|
|
" bnum: the subject buffers buffer number
|
|
function! s:Opener._bufInWindows(bnum)
|
|
let cnt = 0
|
|
let winnum = 1
|
|
while 1
|
|
let bufnum = winbufnr(winnum)
|
|
if bufnum < 0
|
|
break
|
|
endif
|
|
if bufnum ==# a:bnum
|
|
let cnt = cnt + 1
|
|
endif
|
|
let winnum = winnum + 1
|
|
endwhile
|
|
|
|
return cnt
|
|
endfunction
|
|
|
|
" FUNCTION: Opener._checkToCloseTree(newtab) {{{1
|
|
" Check the class options and global options (i.e. NERDTreeQuitOnOpen) to see
|
|
" if the tree should be closed now.
|
|
"
|
|
" Args:
|
|
" a:newtab - boolean. If set, only close the tree now if we are opening the
|
|
" target in a new tab. This is needed because we have to close tree before we
|
|
" leave the tab
|
|
function! s:Opener._checkToCloseTree(newtab)
|
|
if self._keepopen
|
|
return
|
|
endif
|
|
|
|
if (a:newtab && self._where == 't') || !a:newtab
|
|
call g:NERDTree.CloseIfQuitOnOpen()
|
|
endif
|
|
endfunction
|
|
|
|
" FUNCTION: s:Opener._firstUsableWindow() {{{1
|
|
" find the window number of the first normal window
|
|
function! s:Opener._firstUsableWindow()
|
|
let i = 1
|
|
while i <= winnr("$")
|
|
let bnum = winbufnr(i)
|
|
if bnum != -1 && getbufvar(bnum, '&buftype') ==# ''
|
|
\ && !getwinvar(i, '&previewwindow')
|
|
\ && (!getbufvar(bnum, '&modified') || &hidden)
|
|
return i
|
|
endif
|
|
|
|
let i += 1
|
|
endwhile
|
|
return -1
|
|
endfunction
|
|
|
|
" FUNCTION: Opener._gotoTargetWin() {{{1
|
|
function! s:Opener._gotoTargetWin()
|
|
if b:NERDTree.isWinTree()
|
|
if self._where == 'v'
|
|
vsplit
|
|
elseif self._where == 'h'
|
|
split
|
|
elseif self._where == 't'
|
|
tabnew
|
|
endif
|
|
else
|
|
call self._checkToCloseTree(1)
|
|
|
|
if self._where == 'v'
|
|
call self._newVSplit()
|
|
elseif self._where == 'h'
|
|
call self._newSplit()
|
|
elseif self._where == 't'
|
|
tabnew
|
|
elseif self._where == 'p'
|
|
call self._previousWindow()
|
|
endif
|
|
|
|
call self._checkToCloseTree(0)
|
|
endif
|
|
endfunction
|
|
|
|
" FUNCTION: s:Opener._isWindowUsable(winnumber) {{{1
|
|
" Returns 0 if opening a file from the tree in the given window requires it to
|
|
" be split, 1 otherwise
|
|
"
|
|
" Args:
|
|
" winnumber: the number of the window in question
|
|
function! s:Opener._isWindowUsable(winnumber)
|
|
"gotta split if theres only one window (i.e. the NERD tree)
|
|
if winnr("$") ==# 1
|
|
return 0
|
|
endif
|
|
|
|
let oldwinnr = winnr()
|
|
call nerdtree#exec(a:winnumber . "wincmd p")
|
|
let specialWindow = getbufvar("%", '&buftype') != '' || getwinvar('%', '&previewwindow')
|
|
let modified = &modified
|
|
call nerdtree#exec(oldwinnr . "wincmd p")
|
|
|
|
"if its a special window e.g. quickfix or another explorer plugin then we
|
|
"have to split
|
|
if specialWindow
|
|
return 0
|
|
endif
|
|
|
|
if &hidden
|
|
return 1
|
|
endif
|
|
|
|
return !modified || self._bufInWindows(winbufnr(a:winnumber)) >= 2
|
|
endfunction
|
|
|
|
" FUNCTION: Opener.New(path, opts) {{{1
|
|
" Instantiate a new NERDTreeOpener object.
|
|
" Args:
|
|
" a:path: the path object that is to be opened
|
|
" a:opts: a dictionary containing the following optional keys...
|
|
" 'where': specifies whether the node should be opened in new split, in
|
|
" a new tab or, in the last window; takes values "v", "h", or "t"
|
|
" 'reuse': if file is already shown in a window, jump there; takes values
|
|
" "all", "currenttab", or empty
|
|
" 'keepopen': boolean (0 or 1); if true, the tree window will not be closed
|
|
" 'stay': boolean (0 or 1); if true, remain in tree window after opening
|
|
function! s:Opener.New(path, opts)
|
|
let l:newOpener = copy(self)
|
|
|
|
let l:newOpener._keepopen = nerdtree#has_opt(a:opts, 'keepopen')
|
|
let l:newOpener._nerdtree = b:NERDTree
|
|
let l:newOpener._path = a:path
|
|
let l:newOpener._reuse = has_key(a:opts, 'reuse') ? a:opts['reuse'] : ''
|
|
let l:newOpener._stay = nerdtree#has_opt(a:opts, 'stay')
|
|
let l:newOpener._where = has_key(a:opts, 'where') ? a:opts['where'] : ''
|
|
|
|
call l:newOpener._saveCursorPos()
|
|
|
|
return l:newOpener
|
|
endfunction
|
|
|
|
" FUNCTION: Opener._newSplit() {{{1
|
|
function! s:Opener._newSplit()
|
|
" Save the user's settings for splitbelow and splitright
|
|
let savesplitbelow=&splitbelow
|
|
let savesplitright=&splitright
|
|
|
|
" 'there' will be set to a command to move from the split window
|
|
" back to the explorer window
|
|
"
|
|
" 'back' will be set to a command to move from the explorer window
|
|
" back to the newly split window
|
|
"
|
|
" 'right' and 'below' will be set to the settings needed for
|
|
" splitbelow and splitright IF the explorer is the only window.
|
|
"
|
|
let there= g:NERDTreeWinPos ==# "left" ? "wincmd h" : "wincmd l"
|
|
let back = g:NERDTreeWinPos ==# "left" ? "wincmd l" : "wincmd h"
|
|
let right= g:NERDTreeWinPos ==# "left"
|
|
let below=0
|
|
|
|
" Attempt to go to adjacent window
|
|
call nerdtree#exec(back)
|
|
|
|
let onlyOneWin = (winnr("$") ==# 1)
|
|
|
|
" If no adjacent window, set splitright and splitbelow appropriately
|
|
if onlyOneWin
|
|
let &splitright=right
|
|
let &splitbelow=below
|
|
else
|
|
" found adjacent window - invert split direction
|
|
let &splitright=!right
|
|
let &splitbelow=!below
|
|
endif
|
|
|
|
let splitMode = onlyOneWin ? "vertical" : ""
|
|
|
|
" Open the new window
|
|
try
|
|
exec(splitMode." sp ")
|
|
catch /^Vim\%((\a\+)\)\=:E37/
|
|
call g:NERDTree.CursorToTreeWin()
|
|
throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self._path.str() ." is already open and modified."
|
|
catch /^Vim\%((\a\+)\)\=:/
|
|
"do nothing
|
|
endtry
|
|
|
|
"resize the tree window if no other window was open before
|
|
if onlyOneWin
|
|
let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize
|
|
call nerdtree#exec(there)
|
|
exec("silent ". splitMode ." resize ". size)
|
|
call nerdtree#exec('wincmd p')
|
|
endif
|
|
|
|
" Restore splitmode settings
|
|
let &splitbelow=savesplitbelow
|
|
let &splitright=savesplitright
|
|
endfunction
|
|
|
|
" FUNCTION: Opener._newVSplit() {{{1
|
|
function! s:Opener._newVSplit()
|
|
let l:winwidth = winwidth('.')
|
|
|
|
if winnr('$') == 1
|
|
let l:winwidth = g:NERDTreeWinSize
|
|
endif
|
|
|
|
call nerdtree#exec('wincmd p')
|
|
vnew
|
|
|
|
let l:currentWindowNumber = winnr()
|
|
|
|
" Restore the NERDTree to its original width.
|
|
call g:NERDTree.CursorToTreeWin()
|
|
execute 'silent vertical resize ' . l:winwidth
|
|
|
|
call nerdtree#exec(l:currentWindowNumber . 'wincmd w')
|
|
endfunction
|
|
|
|
" FUNCTION: Opener.open(target) {{{1
|
|
function! s:Opener.open(target)
|
|
|
|
if self._path.isDirectory
|
|
call self._openDirectory(a:target)
|
|
return
|
|
endif
|
|
|
|
call self._openFile()
|
|
endfunction
|
|
|
|
" FUNCTION: Opener._openFile() {{{1
|
|
function! s:Opener._openFile()
|
|
|
|
if self._reuseWindow()
|
|
return
|
|
endif
|
|
|
|
call self._gotoTargetWin()
|
|
|
|
if self._stay
|
|
silent call self._path.edit()
|
|
call self._restoreCursorPos()
|
|
return
|
|
endif
|
|
|
|
call self._path.edit()
|
|
endfunction
|
|
|
|
" FUNCTION: Opener._openDirectory(node) {{{1
|
|
function! s:Opener._openDirectory(node)
|
|
call self._gotoTargetWin()
|
|
|
|
if self._nerdtree.isWinTree()
|
|
call g:NERDTreeCreator.CreateWindowTree(a:node.path.str())
|
|
else
|
|
if empty(self._where)
|
|
call b:NERDTree.changeRoot(a:node)
|
|
elseif self._where == 't'
|
|
call g:NERDTreeCreator.CreateTabTree(a:node.path.str())
|
|
else
|
|
call g:NERDTreeCreator.CreateWindowTree(a:node.path.str())
|
|
endif
|
|
endif
|
|
|
|
if self._stay
|
|
call self._restoreCursorPos()
|
|
endif
|
|
endfunction
|
|
|
|
" FUNCTION: Opener._previousWindow() {{{1
|
|
function! s:Opener._previousWindow()
|
|
if !self._isWindowUsable(winnr("#")) && self._firstUsableWindow() ==# -1
|
|
call self._newSplit()
|
|
else
|
|
try
|
|
if !self._isWindowUsable(winnr("#"))
|
|
call nerdtree#exec(self._firstUsableWindow() . "wincmd w")
|
|
else
|
|
call nerdtree#exec('wincmd p')
|
|
endif
|
|
catch /^Vim\%((\a\+)\)\=:E37/
|
|
call g:NERDTree.CursorToTreeWin()
|
|
throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self._path.str() ." is already open and modified."
|
|
catch /^Vim\%((\a\+)\)\=:/
|
|
echo v:exception
|
|
endtry
|
|
endif
|
|
endfunction
|
|
|
|
" FUNCTION: Opener._restoreCursorPos() {{{1
|
|
function! s:Opener._restoreCursorPos()
|
|
call nerdtree#exec('normal ' . self._tabnr . 'gt')
|
|
call nerdtree#exec(bufwinnr(self._bufnr) . 'wincmd w')
|
|
endfunction
|
|
|
|
" FUNCTION: Opener._reuseWindow() {{{1
|
|
" put the cursor in the first window we find for this file
|
|
"
|
|
" return 1 if we were successful
|
|
function! s:Opener._reuseWindow()
|
|
if empty(self._reuse)
|
|
return 0
|
|
endif
|
|
|
|
"check the current tab for the window
|
|
let winnr = bufwinnr('^' . self._path.str() . '$')
|
|
if winnr != -1
|
|
call nerdtree#exec(winnr . "wincmd w")
|
|
call self._checkToCloseTree(0)
|
|
return 1
|
|
endif
|
|
|
|
if self._reuse == 'currenttab'
|
|
return 0
|
|
endif
|
|
|
|
"check other tabs
|
|
let tabnr = self._path.tabnr()
|
|
if tabnr
|
|
call self._checkToCloseTree(1)
|
|
call nerdtree#exec('normal! ' . tabnr . 'gt')
|
|
let winnr = bufwinnr('^' . self._path.str() . '$')
|
|
call nerdtree#exec(winnr . "wincmd w")
|
|
return 1
|
|
endif
|
|
|
|
return 0
|
|
endfunction
|
|
|
|
" FUNCTION: Opener._saveCursorPos() {{{1
|
|
function! s:Opener._saveCursorPos()
|
|
let self._bufnr = bufnr("")
|
|
let self._tabnr = tabpagenr()
|
|
endfunction
|
|
|
|
" vim: set sw=4 sts=4 et fdm=marker:
|