diff --git a/plugin/NERD_tree.vim b/plugin/NERD_tree.vim index 405f981..f86e378 100644 --- 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 :call KeyMap_Invoke('". g:NERDTreeMapActivateNode ."')" @@ -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