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 <dir>` 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.
This commit is contained in:
Zefei Xuan 2018-05-14 15:25:23 -07:00
parent 6188c5ea5f
commit be15e4dace
6 changed files with 150 additions and 51 deletions

View File

@ -16,36 +16,12 @@ 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)

View File

@ -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('<args>')
command! -n=? -complete=dir -bar NERDTreeToggle :call g:NERDTreeCreator.ToggleTabTree('<args>')
command! -n=0 -bar NERDTreeClose :call g:NERDTree.Close()
command! -n=1 -complete=customlist,nerdtree#completeBookmarks -bar NERDTreeFromBookmark call g:NERDTreeCreator.CreateTabTree('<args>')
command! -n=? -complete=dir -bar NERDTree :call <SID>createTree('<args>')
command! -n=? -complete=dir -bar NERDTreeToggle :call <SID>toggleTree('<args>')
command! -n=0 -bar NERDTreeClose :call <SID>closeTree()
command! -n=1 -complete=customlist,nerdtree#completeBookmarks -bar NERDTreeFromBookmark call <SID>createTree('<args>')
command! -n=0 -bar NERDTreeMirror call g:NERDTreeCreator.CreateMirror()
command! -n=? -complete=file -bar NERDTreeFind call s:findAndRevealPath('<args>')
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")

View File

@ -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.

View File

@ -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)

View File

@ -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"

View File

@ -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