From be15e4dace3696f90243f44be982e35ee7bf0939 Mon Sep 17 00:00:00 2001 From: Zefei Xuan Date: Mon, 14 May 2018 15:25:23 -0700 Subject: [PATCH] Add an option to open NERDTree in current window In a multi-window workflow, it's often desirable to make NERDTree to work in the current window instead of its side window. See issue #244 for brief discussion. Currently it's possible to use `:e ` to achieve this for `:NERDTree` command; but there are no workarounds for other functions like opening bookmark, toggling nerdtree, finding current file, etc. This commit adds an option to render NERDTree in current window instead of side window, and modifies all relevant commands to respect the option. --- autoload/nerdtree.vim | 34 ++------------ autoload/nerdtree/ui_glue.vim | 37 +++++++++++++-- doc/NERDTree.txt | 11 +++++ lib/nerdtree/creator.vim | 88 ++++++++++++++++++++++++++++------- lib/nerdtree/nerdtree.vim | 24 ++++++++++ plugin/NERD_tree.vim | 7 +++ 6 files changed, 150 insertions(+), 51 deletions(-) diff --git a/autoload/nerdtree.vim b/autoload/nerdtree.vim index b138c21..103b873 100644 --- a/autoload/nerdtree.vim +++ b/autoload/nerdtree.vim @@ -10,42 +10,18 @@ endfunction " SECTION: General Functions {{{1 "============================================================ -"FUNCTION: nerdtree#checkForBrowse(dir) {{{2 -"inits a window tree in the current buffer if appropriate +" FUNCTION: nerdtree#checkForBrowse(dir) {{{2 +" inits a window tree in the current buffer if appropriate function! nerdtree#checkForBrowse(dir) if !isdirectory(a:dir) return endif - - if s:reuseWin(a:dir) - return - endif - + " wipe current directory buffer before opening NERDTree buffer + setlocal bufhidden=wipe + buffer # call g:NERDTreeCreator.CreateWindowTree(a:dir) endfunction -"FUNCTION: s:reuseWin(dir) {{{2 -"finds a NERDTree buffer with root of dir, and opens it. -function! s:reuseWin(dir) abort - let path = g:NERDTreePath.New(fnamemodify(a:dir, ":p")) - - for i in range(1, bufnr("$")) - unlet! nt - let nt = getbufvar(i, "NERDTree") - if empty(nt) - continue - endif - - if nt.isWinTree() && nt.root.path.equals(path) - call nt.setPreviousBuf(bufnr("#")) - exec "buffer " . i - return 1 - endif - endfor - - return 0 -endfunction - " FUNCTION: nerdtree#completeBookmarks(A,L,P) {{{2 " completion function for the bookmark commands function! nerdtree#completeBookmarks(A,L,P) diff --git a/autoload/nerdtree/ui_glue.vim b/autoload/nerdtree/ui_glue.vim index 6ba9ee6..51e7be5 100644 --- a/autoload/nerdtree/ui_glue.vim +++ b/autoload/nerdtree/ui_glue.vim @@ -270,7 +270,7 @@ function! s:findAndRevealPath(pathStr) return endtry - if !g:NERDTree.ExistsForTab() + if !g:NERDTree.ExistsForTab() && !g:NERDTreeUseCurrentWindow try let l:cwd = g:NERDTreePath.New(getcwd()) catch /^NERDTree.InvalidArgumentsError/ @@ -569,16 +569,43 @@ endfunction " FUNCTION: nerdtree#ui_glue#setupCommands() {{{1 function! nerdtree#ui_glue#setupCommands() - command! -n=? -complete=dir -bar NERDTree :call g:NERDTreeCreator.CreateTabTree('') - command! -n=? -complete=dir -bar NERDTreeToggle :call g:NERDTreeCreator.ToggleTabTree('') - command! -n=0 -bar NERDTreeClose :call g:NERDTree.Close() - command! -n=1 -complete=customlist,nerdtree#completeBookmarks -bar NERDTreeFromBookmark call g:NERDTreeCreator.CreateTabTree('') + command! -n=? -complete=dir -bar NERDTree :call createTree('') + command! -n=? -complete=dir -bar NERDTreeToggle :call toggleTree('') + command! -n=0 -bar NERDTreeClose :call closeTree() + command! -n=1 -complete=customlist,nerdtree#completeBookmarks -bar NERDTreeFromBookmark call createTree('') command! -n=0 -bar NERDTreeMirror call g:NERDTreeCreator.CreateMirror() command! -n=? -complete=file -bar NERDTreeFind call s:findAndRevealPath('') command! -n=0 -bar NERDTreeFocus call NERDTreeFocus() command! -n=0 -bar NERDTreeCWD call NERDTreeCWD() endfunction +" Function: s:createTree(name) {{{1 +function s:createTree(name) + if g:NERDTreeUseCurrentWindow + call g:NERDTreeCreator.CreateWindowTree(a:name) + else + call g:NERDTreeCreator.CreateTabTree(a:name) + endif +endfunction + +" Function: s:toggleTree(name) {{{1 +function s:toggleTree(name) + if g:NERDTreeUseCurrentWindow + call g:NERDTreeCreator.ToggleWindowTree(a:name) + else + call g:NERDTreeCreator.ToggleTabTree(a:name) + endif +endfunction + +" Function: s:closeTree() {{{1 +function s:closeTree() + if g:NERDTreeUseCurrentWindow + call g:NERDTree.CloseWindowTree() + else + call g:NERDTree.Close() + endif +endfunction + " Function: s:SID() {{{1 function s:SID() if !exists("s:sid") diff --git a/doc/NERDTree.txt b/doc/NERDTree.txt index a83c4e1..4241aaa 100644 --- a/doc/NERDTree.txt +++ b/doc/NERDTree.txt @@ -639,6 +639,9 @@ NERD tree. These options should be set in your vimrc. |'NERDTreeHijackNetrw'| Tell the NERD tree whether to replace the netrw autocommands for exploring local directories. +|'NERDTreeUseCurrentWindow'| Tells the NERD tree whether to render in side + window or current window. + |'NERDTreeIgnore'| Tells the NERD tree which files to ignore. |'NERDTreeRespectWildIgnore'| Tells the NERD tree to respect |'wildignore'|. @@ -833,6 +836,14 @@ following respects: replacing it. 2. you can have one tree per window - instead of per tab. +------------------------------------------------------------------------------ + *'NERDTreeUseCurrentWindow'* +Values: 0 or 1. +Default: 0. + +If set to 1, NERD tree will open in the current window instead of a side window. +This option affects all NERD tree commands except |:NERDTreeMirror|. + ------------------------------------------------------------------------------ *'NERDTreeIgnore'* Values: a list of regular expressions. diff --git a/lib/nerdtree/creator.vim b/lib/nerdtree/creator.vim index fb5adfd..53d6f68 100644 --- a/lib/nerdtree/creator.vim +++ b/lib/nerdtree/creator.vim @@ -73,32 +73,35 @@ function! s:Creator.createTabTree(name) call self._broadcastInitEvent() endfunction -" FUNCTION: s:Creator.CreateWindowTree(dir) {{{1 -function! s:Creator.CreateWindowTree(dir) +" FUNCTION: s:Creator.CreateWindowTree(name) {{{1 +function! s:Creator.CreateWindowTree(name) let creator = s:Creator.New() - call creator.createWindowTree(a:dir) + call creator.createWindowTree(a:name) endfunction -" FUNCTION: s:Creator.createWindowTree(dir) {{{1 -function! s:Creator.createWindowTree(dir) - try - let path = g:NERDTreePath.New(a:dir) - catch /^NERDTree.InvalidArgumentsError/ - call nerdtree#echo("Invalid directory name:" . a:name) +" FUNCTION: s:Creator.createWindowTree(name) {{{1 +function! s:Creator.createWindowTree(name) + let l:path = self._pathForString(a:name) + + " Abort if an exception was thrown (i.e., if the bookmark or directory + " does not exist). + if empty(l:path) return - endtry + endif - "we want the directory buffer to disappear when we do the :edit below - setlocal bufhidden=wipe + if (self._reuseWin(l:path)) + return + endif - let previousBuf = expand("#") + let previousBuf = bufnr("%") - "we need a unique name for each window tree buffer to ensure they are - "all independent + " We need a unique name for each window tree buffer to ensure they are all + " independent exec g:NERDTreeCreatePrefix . " edit " . self._nextBufferName() - call self._createNERDTree(path, "window") - let b:NERDTree._previousBuf = bufnr(previousBuf) + call self._createNERDTree(l:path, "window") + call b:NERDTree.setPreviousBuf(previousBuf) + let w:NERDTreeBufName = bufname("%") call self._setCommonBufOptions() call b:NERDTree.render() @@ -106,6 +109,29 @@ function! s:Creator.createWindowTree(dir) call self._broadcastInitEvent() endfunction +" FUNCTION: s:Creator._reuseWin(path) {{{1 +" finds a NERDTree buffer with root of dir, and opens it. +function! s:Creator._reuseWin(path) abort + for i in range(1, bufnr("$")) + unlet! nt + let nt = getbufvar(i, "NERDTree") + if empty(nt) + continue + endif + + if nt.isWinTree() && nt.root.path.equals(a:path) + if i != bufnr("%") + call nt.setPreviousBuf(bufnr("%")) + exec "buffer " . i + let w:NERDTreeBufName = bufname("%") + endif + return 1 + endif + endfor + + return 0 +endfunction + " FUNCTION: s:Creator._createNERDTree(path) {{{1 function! s:Creator._createNERDTree(path, type) let b:NERDTree = g:NERDTree.New(a:path, a:type) @@ -364,6 +390,34 @@ function! s:Creator.toggleTabTree(dir) endif endfunction +" FUNCTION: s:Creator.ToggleWindowTree(dir) {{{1 +function! s:Creator.ToggleWindowTree(dir) + let creator = s:Creator.New() + call creator.toggleWindowTree(a:dir) +endfunction + +" FUNCTION: s:Creator.toggleWindowTree(dir) {{{1 +" Toggles the NERD tree in current window. I.e the NERD tree is open in the +" current window, it is closed, if it is closed it is restored or initialized +" (if it doesnt exist) +" +" Args: +" dir: the full path for the root node (is only used if the NERD tree is being +" initialized. +function! s:Creator.toggleWindowTree(dir) + if g:NERDTree.IsWindowTreeOpen() + call g:NERDTree.CloseWindowTree() + return + endif + if g:NERDTree.ExistsForWindow() + let previousBuf = bufnr("%") + exec 'buffer ' . w:NERDTreeBufName + call b:NERDTree.setPreviousBuf(previousBuf) + else + call self.createWindowTree(a:dir) + endif +endfunction + " Function: s:Creator._uniq(list) {{{1 " returns a:list without duplicates function! s:Creator._uniq(list) diff --git a/lib/nerdtree/nerdtree.vim b/lib/nerdtree/nerdtree.vim index fcabcb9..5af3ba8 100644 --- a/lib/nerdtree/nerdtree.vim +++ b/lib/nerdtree/nerdtree.vim @@ -71,6 +71,13 @@ function! s:NERDTree.CloseIfQuitOnOpen() endif endfunction +" FUNCTION: s:NERDTree.CloseWindowTree() {{{1 +function! s:NERDTree.CloseWindowTree() + if s:NERDTree.IsWindowTreeOpen() + exec "buffer " . b:NERDTree.previousBuf() + endif +endfunction + "FUNCTION: s:NERDTree.CursorToBookmarkTable(){{{1 "Places the cursor at the top of the bookmarks table function! s:NERDTree.CursorToBookmarkTable() @@ -118,6 +125,17 @@ function! s:NERDTree.ExistsForTab() return !empty(getbufvar(bufnr(t:NERDTreeBufName), 'NERDTree')) endfunction +" Function: s:NERDTree.ExistsForWindow() {{{1 +" Returns 1 if a nerd tree root exists in the current window +function! s:NERDTree.ExistsForWindow() + if !exists("w:NERDTreeBufName") + return + end + + " check b:NERDTree is still there and hasn't been e.g. :bdeleted + return !empty(getbufvar(bufnr(w:NERDTreeBufName), 'NERDTree')) +endfunction + function! s:NERDTree.ForCurrentBuf() if s:NERDTree.ExistsForBuf() return b:NERDTree @@ -156,6 +174,12 @@ function! s:NERDTree.IsOpen() return s:NERDTree.GetWinNum() != -1 endfunction +"FUNCTION: s:NERDTree.IsWindowTreeOpen() {{{1 +function! s:NERDTree.IsWindowTreeOpen() + let nerdtree = s:NERDTree.ForCurrentBuf() + return !empty(nerdtree) && nerdtree.isWinTree() +endfunction + "FUNCTION: s:NERDTree.isTabTree() {{{1 function! s:NERDTree.isTabTree() return self._type == "tab" diff --git a/plugin/NERD_tree.vim b/plugin/NERD_tree.vim index 35b47c3..6c0f7b0 100644 --- a/plugin/NERD_tree.vim +++ b/plugin/NERD_tree.vim @@ -68,6 +68,7 @@ call s:initVariable("g:NERDTreeShowFiles", 1) call s:initVariable("g:NERDTreeShowHidden", 0) call s:initVariable("g:NERDTreeShowLineNumbers", 0) call s:initVariable("g:NERDTreeSortDirs", 1) +call s:initVariable("g:NERDTreeUseCurrentWindow", 0) if !nerdtree#runningWindows() && !nerdtree#runningCygwin() call s:initVariable("g:NERDTreeDirArrowExpandable", "▸") @@ -198,6 +199,12 @@ function! NERDTreeRender() endfunction function! NERDTreeFocus() + if g:NERDTreeUseCurrentWindow + if !g:NERDTree.IsWindowTreeOpen() + call g:NERDTreeCreator.ToggleWindowTree("") + endif + return + endif if g:NERDTree.IsOpen() call g:NERDTree.CursorToTreeWin() else