commit 4f1a205c8358c97ab9a7199fdb7e6b5e22c46db4
parent 3620029ae0c82d4ad83f2ddfe26e55235c975933
Author: Martin Grenfell <martin.grenfell@gmail.com>
Date: Mon, 9 Jan 2012 15:59:21 +0000
add Opener class to handle opening nodes/bookmarks
Move the code to split windows and open nodes and bookmarks out into a
dedicated class. This will remove duplication and remove and centralise
a concern from the other classes.
Diffstat:
| M | plugin/NERD_tree.vim | | | 505 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
1 file changed, 269 insertions(+), 236 deletions(-)
diff --git a/plugin/NERD_tree.vim b/plugin/NERD_tree.vim
@@ -392,34 +392,18 @@ endfunction
function! s:Bookmark.open(...)
let opts = a:0 ? a:1 : {}
- if self.path.isDirectory
- if has_key(opts, 'split')
- let n = s:TreeDirNode.New(self.path)
- call n.open(opts)
- else
- call self.toRoot()
- endif
+ if self.path.isDirectory && !has_key(opts, 'split')
+ call self.toRoot()
else
- if self.validate()
- let n = s:TreeFileNode.New(self.path)
- call n.open(opts)
- endif
+ let opener = s:Opener.New(self.path, opts)
+ call opener.open(self)
endif
endfunction
" FUNCTION: Bookmark.openInNewTab(options) {{{3
" Create a new bookmark object with the given name and path object
function! s:Bookmark.openInNewTab(options)
- let currentTab = tabpagenr()
- if self.path.isDirectory
- tabnew
- call s:initNerdTree(self.name)
- else
- exec "tabedit " . self.path.str({'format': 'Edit'})
- endif
-
- if s:has_opt(a:options, 'stayInCurrentTab')
- exec "tabnext " . currentTab
- endif
+ call s:deprecated('Bookmark.openInNewTab', 'is deprecated, use open() instead')
+ call self.open(a:options)
endfunction
" Function: Bookmark.setPath(path) {{{3
" makes this bookmark point to the given path
@@ -1232,210 +1216,30 @@ function! s:TreeFileNode.New(path)
endfunction
"FUNCTION: TreeFileNode.open() {{{3
-"Args:
-"A dictionary containing the following keys (all optional):
-" 'split': Specifies whether the node should be opened in new split/tab or in
-" the previous window. Can be either 'v' or 'h' or 't' (for open in
-" new tab)
-" 'reuse': if a window is displaying the file then jump the cursor there
-" 'keepopen': dont close the tree window
-" 'stay': open the file, but keep the cursor in the tree win
-"
function! s:TreeFileNode.open(...)
+ echomsg self.path.str()
let opts = a:0 ? a:1 : {}
-
- let currentBuf = bufnr("")
- let currentTab = tabpagenr()
-
- if s:has_opt(opts, 'reuse') && self._putCursorInBufWin()
- return
- endif
-
- if has_key(opts, 'split')
- if opts['split'] == 'v'
- call self._openVSplit()
- elseif opts['split'] == 'h'
- call self._openSplit()
- else
- call self._openInNewTab(opts)
- endif
- else
- call self._open()
- endif
-
- if !s:has_opt(opts, 'keepopen')
- call s:closeTreeIfQuitOnOpen()
- endif
-
- if s:has_opt(opts, 'stay')
- call s:exec('normal ' . currentTab . 'gt')
- call s:exec(bufwinnr(currentBuf) . 'wincmd w')
- endif
+ let opener = s:Opener.New(self.path, opts)
+ call opener.open(self)
endfunction
-"FUNCTION: TreeFileNode._open() {{{3
-function! s:TreeFileNode._open()
-
- if b:NERDTreeType ==# "secondary"
- exec 'edit ' . self.path.str({'format': 'Edit'})
- return
- endif
-
- if !s:isWindowUsable(winnr("#")) && s:firstUsableWindow() ==# -1
- call self._openSplit()
- else
- try
- if !s:isWindowUsable(winnr("#"))
- call s:exec(s:firstUsableWindow() . "wincmd w")
- else
- call s:exec('wincmd p')
- endif
- exec ("edit " . self.path.str({'format': 'Edit'}))
- catch /^Vim\%((\a\+)\)\=:E37/
- call s:putCursorInTreeWin()
- throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self.path.str() ." is already open and modified."
- catch /^Vim\%((\a\+)\)\=:/
- echo v:exception
- endtry
- endif
-endfunction
"FUNCTION: TreeFileNode.openSplit() {{{3
"Open this node in a new window
function! s:TreeFileNode.openSplit()
call s:deprecated('TreeFileNode.openSplit', 'is deprecated, use .open() instead.')
call self.open({'split': 'h'})
endfunction
-"FUNCTION: TreeFileNode._openSplit() {{{3
-"Open this node in a new window
-function! s:TreeFileNode._openSplit()
-
- if b:NERDTreeType ==# "secondary"
- exec "split " . self.path.str({'format': 'Edit'})
- return
- endif
-
- " 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 s: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 " . self.path.str({'format': 'Edit'}))
- catch /^Vim\%((\a\+)\)\=:E37/
- call s:putCursorInTreeWin()
- 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 s:exec(there)
- exec("silent ". splitMode ." resize ". size)
- call s:exec('wincmd p')
- endif
-
- " Restore splitmode settings
- let &splitbelow=savesplitbelow
- let &splitright=savesplitright
-endfunction
"FUNCTION: TreeFileNode.openVSplit() {{{3
"Open this node in a new vertical window
function! s:TreeFileNode.openVSplit()
call s:deprecated('TreeFileNode.openVSplit', 'is deprecated, use .open() instead.')
call self.open({'split': 'v'})
endfunction
-"FUNCTION: TreeFileNode._openVSplit() {{{3
-"Open this node in a new vertical window
-function! s:TreeFileNode._openVSplit()
- if b:NERDTreeType ==# "secondary"
- exec "vnew " . self.path.str({'format': 'Edit'})
- return
- endif
-
- let winwidth = winwidth(".")
- if winnr("$")==#1
- let winwidth = g:NERDTreeWinSize
- endif
-
- call s:exec("wincmd p")
- exec "vnew " . self.path.str({'format': 'Edit'})
-
- "resize the nerd tree back to the original size
- call s:putCursorInTreeWin()
- exec("silent vertical resize ". winwidth)
- call s:exec('wincmd p')
-endfunction
"FUNCTION: TreeFileNode.openInNewTab(options) {{{3
function! s:TreeFileNode.openInNewTab(options)
echomsg 'TreeFileNode.openInNewTab is deprecated'
call self.open(extend({'split': 't'}, a:options))
endfunction
-"FUNCTION: TreeFileNode._openInNewTab(options) {{{3
-function! s:TreeFileNode._openInNewTab(options)
- let currentTab = tabpagenr()
- exec "tabedit " . self.path.str({'format': 'Edit'})
-
- if s:has_opt(a:options, 'stayInCurrentTab')
- exec "tabnext " . currentTab
- endif
-endfunction
-"FUNCTION: TreeFileNode._putCursorInBufWin(){{{3
-"put the cursor in the first window we find for this file
-"
-"return 1 if we were successful
-function! s:TreeFileNode._putCursorInBufWin(...)
- "check the current tab for the window
- let winnr = bufwinnr('^' . self.path.str() . '$')
- if winnr != -1
- call s:exec(winnr . "wincmd w")
- return 1
- else
- "check other tabs
- let tabnr = self.path.tabnr()
- if tabnr
- call s:exec('normal! ' . tabnr . 'gt')
- let winnr = bufwinnr('^' . self.path.str() . '$')
- call s:exec(winnr . "wincmd w")
- return 1
- endif
- endif
- return 0
-endfunction
-
-
"FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{3
"Places the cursor on the line number this node is rendered on
"
@@ -1870,21 +1674,9 @@ unlet s:TreeDirNode.open
function! s:TreeDirNode.open(...)
let opts = a:0 ? a:1 : {}
- if has_key(opts, 'split') && opts['split'] == 't'
- let currentBuf = bufnr("")
- let currentTab = tabpagenr()
-
- call self._openInNewTab()
-
- if s:has_opt(opts, 'stay')
- call s:exec('normal ' . currentTab . 'gt')
- call s:exec(bufwinnr(currentBuf) . 'wincmd w')
- endif
-
- if !s:has_opt(opts, 'keepopen')
- call s:closeTreeIfQuitOnOpen()
- endif
-
+ if has_key(opts, 'split') && !empty(opts['split'])
+ let opener = s:Opener.New(self.path, opts)
+ call opener.open(self)
else
let self.isOpen = 1
if self.children ==# []
@@ -1899,23 +1691,14 @@ endfunction
" opens an explorer window for this node in the previous window (could be a
" nerd tree or a netrw)
function! s:TreeDirNode.openExplorer()
- let oldwin = winnr()
- call s:exec('wincmd p')
- if oldwin ==# winnr() || (&modified && s:bufInWindows(winbufnr(winnr())) < 2)
- call s:exec('wincmd p')
- call self.openSplit()
- else
- exec ("silent edit " . self.path.str({'format': 'Edit'}))
- endif
+ call self.open({'split': 'p'})
endfunction
"FUNCTION: TreeDirNode.openInNewTab(options) {{{3
-unlet s:TreeDirNode.openInNewTab
function! s:TreeDirNode.openInNewTab(options)
call s:deprecated('TreeDirNode.openInNewTab', 'is deprecated, use open() instead')
call self.open({'split': 't'})
endfunction
"FUNCTION: TreeDirNode._openInNewTab() {{{3
-unlet s:TreeDirNode._openInNewTab
function! s:TreeDirNode._openInNewTab()
tabnew
call s:initNerdTree(self.path.str())
@@ -2086,6 +1869,243 @@ function! s:TreeDirNode.transplantChild(newNode)
endfor
endfunction
"============================================================
+"CLASS: Opener {{{2
+"============================================================
+let s:Opener = {}
+"FUNCTION: Opener._gotoTargetWin() {{{3
+function! s:Opener._gotoTargetWin()
+ if b:NERDTreeType ==# "secondary"
+ if self._split == 'v'
+ vsplit
+ elseif self._split == 'h'
+ split
+ elseif self._split == 't'
+ tabnew
+ endif
+ else
+
+ if self._split == 'v'
+ call self._newVSplit()
+ elseif self._split == 'h'
+ call self._newSplit()
+ elseif self._split == 't'
+ tabnew
+ elseif self._split == 'p'
+ call self._previousWindow()
+ endif
+ endif
+endfunction
+
+"FUNCTION: Opener.New(path, opts) {{{3
+"Args:
+"
+"a:path: The path object that is to be opened.
+"
+"a:opts:
+"
+"A dictionary containing the following keys (all optional):
+" 'split': Specifies whether the node should be opened in new split/tab or in
+" the previous window. Can be either 'v' or 'h' or 't' (for open in
+" new tab)
+" 'reuse': if a window is displaying the file then jump the cursor there
+" 'keepopen': dont close the tree window
+" 'stay': open the file, but keep the cursor in the tree win
+function! s:Opener.New(path, opts)
+ let newObj = copy(self)
+
+ let newObj._path = a:path
+ let newObj._stay = s:has_opt(a:opts, 'stay')
+ let newObj._reuse = s:has_opt(a:opts, 'reuse')
+ let newObj._keepopen = s:has_opt(a:opts, 'keepopen')
+ let newObj._split = has_key(a:opts, 'split') ? a:opts['split'] : ''
+ call newObj._saveCursorPos()
+
+ return newObj
+endfunction
+
+"FUNCTION: Opener._newSplit() {{{3
+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 s: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 s:putCursorInTreeWin()
+ 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 s:exec(there)
+ exec("silent ". splitMode ." resize ". size)
+ call s:exec('wincmd p')
+ endif
+
+ " Restore splitmode settings
+ let &splitbelow=savesplitbelow
+ let &splitright=savesplitright
+endfunction
+
+"FUNCTION: Opener._newVSplit() {{{3
+function! s:Opener._newVSplit()
+ let winwidth = winwidth(".")
+ if winnr("$")==#1
+ let winwidth = g:NERDTreeWinSize
+ endif
+
+ call s:exec("wincmd p")
+ vnew
+
+ "resize the nerd tree back to the original size
+ call s:putCursorInTreeWin()
+ exec("silent vertical resize ". winwidth)
+ call s:exec('wincmd p')
+endfunction
+
+"FUNCTION: Opener.open(target) {{{3
+function! s:Opener.open(target)
+ if self._path.isDirectory
+ call self._openDirectory(a:target)
+ else
+ call self._openFile()
+ endif
+endfunction
+
+"FUNCTION: Opener._openFile() {{{3
+function! s:Opener._openFile()
+ if self._reuse && self._reuseWindow()
+ return
+ endif
+
+ if b:NERDTreeType ==# "secondary"
+ call self._gotoTargetWin()
+ call self._path.edit()
+ else
+ call self._gotoTargetWin()
+ call self._path.edit()
+
+ if self._keepopen
+ call s:closeTreeIfQuitOnOpen()
+ endif
+
+ if self._stay
+ call self._restoreCursorPos()
+ endif
+ endif
+endfunction
+
+"FUNCTION: Opener._openDirectory(node) {{{3
+function! s:Opener._openDirectory(node)
+ if b:NERDTreeType ==# "secondary"
+ call self._gotoTargetWin()
+ call s:initNerdTreeInPlace(a:node.path.str())
+ else
+ call self._gotoTargetWin()
+ if empty(self._split)
+ call a:node.makeRoot()
+ call s:renderView()
+ call a:node.putCursorHere(0, 0)
+ elseif self._split == 't'
+ call s:initNerdTree(a:node.path.str())
+ else
+ call s:initNerdTreeInPlace(a:node.path.str())
+ endif
+ endif
+endfunction
+
+"FUNCTION: Opener._previousWindow() {{{3
+function! s:Opener._previousWindow()
+ if !s:isWindowUsable(winnr("#")) && s:firstUsableWindow() ==# -1
+ call self._newSplit()
+ else
+ try
+ if !s:isWindowUsable(winnr("#"))
+ call s:exec(s:firstUsableWindow() . "wincmd w")
+ else
+ call s:exec('wincmd p')
+ endif
+ exec ("edit " . self._path.str({'format': 'Edit'}))
+ catch /^Vim\%((\a\+)\)\=:E37/
+ call s:putCursorInTreeWin()
+ throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self._path.str() ." is already open and modified."
+ catch /^Vim\%((\a\+)\)\=:/
+ echo v:exception
+ endtry
+ endif
+endfunction
+
+"FUNCTION: Opener._restoreCursorPos(){{{3
+function! s:Opener._restoreCursorPos()
+ call s:exec('normal ' . self._tabnr . 'gt')
+ call s:exec(bufwinnr(self._bufnr) . 'wincmd w')
+endfunction
+
+"FUNCTION: Opener._reuseWindow(){{{3
+"put the cursor in the first window we find for this file
+"
+"return 1 if we were successful
+function! s:Opener._reuseWindow()
+ "check the current tab for the window
+ let winnr = bufwinnr('^' . self._path.str() . '$')
+ if winnr != -1
+ call s:exec(winnr . "wincmd w")
+ return 1
+ else
+ "check other tabs
+ let tabnr = self._path.tabnr()
+ if tabnr
+ call s:exec('normal! ' . tabnr . 'gt')
+ let winnr = bufwinnr('^' . self._path.str() . '$')
+ call s:exec(winnr . "wincmd w")
+ return 1
+ endif
+ endif
+ return 0
+endfunction
+
+"FUNCTION: Opener._saveCursorPos(){{{3
+function! s:Opener._saveCursorPos()
+ let self._bufnr = bufnr("")
+ let self._tabnr = tabpagenr()
+endfunction
+
"CLASS: Path {{{2
"============================================================
let s:Path = {}
@@ -2317,6 +2337,10 @@ function! s:Path.displayString()
return self.cachedDisplayString
endfunction
+"FUNCTION: Path.edit() {{{3
+function! s:Path.edit()
+ exec "edit " . self.str({'format': 'Edit'})
+endfunction
"FUNCTION: Path.extractDriveLetter(fullpath) {{{3
"
"If running windows, cache the drive letter for this path
@@ -3803,16 +3827,22 @@ function! s:activateAll()
endif
endfunction
-"FUNCTION: s:activateNode() {{{2
+"FUNCTION: s:activateDirNode() {{{2
"handle the user activating a tree node
-function! s:activateNode(node)
+function! s:activateDirNode(node)
call a:node.activate({'reuse': 1})
endfunction
+"FUNCTION: s:activateFileNode() {{{2
+"handle the user activating a tree node
+function! s:activateFileNode(node)
+ call a:node.activate({'reuse': 1, 'split': 'p'})
+endfunction
+
"FUNCTION: s:activateBookmark() {{{2
"handle the user activating a bookmark
function! s:activateBookmark(bm)
- call a:bm.activate()
+ call a:bm.activate(!a:bm.path.isDirectory ? {'split': 'p'} : {})
endfunction
"FUNCTION: s:bindMappings() {{{2
@@ -3821,12 +3851,15 @@ function! s:bindMappings()
call NERDTreeAddKeyMap({ 'key': 'middlerelease', 'scope': "all", 'callback': s."handleMiddleMouse" })
call NERDTreeAddKeyMap({ 'key': 'leftrelease', 'scope': "all", 'callback': s."handleLeftClick" })
- call NERDTreeAddKeyMap({ 'key': '2-leftmouse', 'scope': "Node", 'callback': s."activateNode" })
+ call NERDTreeAddKeyMap({ 'key': '2-leftmouse', 'scope': "DirNode", 'callback': s."activateDirNode" })
+ call NERDTreeAddKeyMap({ 'key': '2-leftmouse', 'scope': "FileNode", 'callback': s."activateFileNode" })
call NERDTreeAddKeyMap({ 'key': '2-leftmouse', 'scope': "Bookmark", 'callback': s."activateBookmark" })
call NERDTreeAddKeyMap({ 'key': '2-leftmouse', 'scope': "all", 'callback': s."activateAll" })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "Node", 'callback': s."activateNode" })
+ call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "DirNode", 'callback': s."activateDirNode" })
+ call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "FileNode", 'callback': s."activateFileNode" })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "Bookmark", 'callback': s."activateBookmark" })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "all", 'callback': s."activateAll" })
exec "nnoremap <silent> <buffer> <cr> :call <SID>KeyMap_Invoke('". g:NERDTreeMapActivateNode ."')<cr>"
@@ -4108,7 +4141,7 @@ function! s:openBookmark(name)
if targetNode.path.isDirectory
call targetNode.openExplorer()
else
- call targetNode.open()
+ call targetNode.open({'split': 'p'})
endif
endfunction
@@ -4148,7 +4181,7 @@ endfunction
"FUNCTION: s:previewNodeCurrent(node) {{{2
function! s:previewNodeCurrent(node)
- call a:node.open({'stay': 1})
+ call a:node.open({'stay': 1, 'split': 'p'})
endfunction
"FUNCTION: s:previewNodeHSplit(node) {{{2