Merge pull request #795 from lifecrisis/empty-line

Fix unstable behaviour in the "NERDTreeUI.getPath()" method.
This commit is contained in:
Jason Franklin 2018-01-07 08:33:01 -05:00 committed by GitHub
commit 183bb53485
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 196 additions and 187 deletions

View File

@ -14,21 +14,23 @@ lockvar s:NERDTreeSortStarIndex
let s:Path = {} let s:Path = {}
let g:NERDTreePath = s:Path let g:NERDTreePath = s:Path
" FUNCTION: Path.AbsolutePathFor(str) {{{1 " FUNCTION: Path.AbsolutePathFor(pathStr) {{{1
function! s:Path.AbsolutePathFor(str) function! s:Path.AbsolutePathFor(pathStr)
let prependCWD = 0 let l:prependWorkingDir = 0
if nerdtree#runningWindows() if nerdtree#runningWindows()
let prependCWD = a:str !~# '^.:\(\\\|\/\)' && a:str !~# '^\(\\\\\|\/\/\)' let l:prependWorkingDir = a:pathStr !~# '^.:\(\\\|\/\)' && a:pathStr !~# '^\(\\\\\|\/\/\)'
else else
let prependCWD = a:str !~# '^/' let l:prependWorkingDir = a:pathStr !~# '^/'
endif endif
let toReturn = a:str let l:result = a:pathStr
if prependCWD
let toReturn = getcwd() . s:Path.Slash() . a:str if l:prependWorkingDir
let l:result = getcwd() . s:Path.Slash() . a:pathStr
endif endif
return toReturn return l:result
endfunction endfunction
" FUNCTION: Path.bookmarkNames() {{{1 " FUNCTION: Path.bookmarkNames() {{{1
@ -541,17 +543,16 @@ function! s:Path.equals(path)
return self.str() ==# a:path.str() return self.str() ==# a:path.str()
endfunction endfunction
" FUNCTION: Path.New() {{{1 " FUNCTION: Path.New(pathStr) {{{1
" The Constructor for the Path object function! s:Path.New(pathStr)
function! s:Path.New(path) let l:newPath = copy(self)
let newPath = copy(self)
call newPath.readInfoFromDisk(s:Path.AbsolutePathFor(a:path)) call l:newPath.readInfoFromDisk(s:Path.AbsolutePathFor(a:pathStr))
let newPath.cachedDisplayString = "" let l:newPath.cachedDisplayString = ''
let newPath.flagSet = g:NERDTreeFlagSet.New() let l:newPath.flagSet = g:NERDTreeFlagSet.New()
return newPath return l:newPath
endfunction endfunction
" FUNCTION: Path.Slash() {{{1 " FUNCTION: Path.Slash() {{{1

View File

@ -1,22 +1,25 @@
"CLASS: TreeFileNode " ============================================================================
"This class is the parent of the TreeDirNode class and is the " CLASS: TreeFileNode
"'Component' part of the composite design pattern between the treenode "
"classes. " This class is the parent of the "TreeDirNode" class and is the "Component"
"============================================================ " part of the composite design pattern between the NERDTree node classes.
" ============================================================================
let s:TreeFileNode = {} let s:TreeFileNode = {}
let g:NERDTreeFileNode = s:TreeFileNode let g:NERDTreeFileNode = s:TreeFileNode
"FUNCTION: TreeFileNode.activate(...) {{{1 " FUNCTION: TreeFileNode.activate(...) {{{1
function! s:TreeFileNode.activate(...) function! s:TreeFileNode.activate(...)
call self.open(a:0 ? a:1 : {}) call self.open(a:0 ? a:1 : {})
endfunction endfunction
"FUNCTION: TreeFileNode.bookmark(name) {{{1 " FUNCTION: TreeFileNode.bookmark(name) {{{1
"bookmark this node with a:name " bookmark this node with a:name
function! s:TreeFileNode.bookmark(name) function! s:TreeFileNode.bookmark(name)
"if a bookmark exists with the same name and the node is cached then save " if a bookmark exists with the same name and the node is cached then save
"it so we can update its display string " it so we can update its display string
let oldMarkedNode = {} let oldMarkedNode = {}
try try
let oldMarkedNode = g:NERDTreeBookmark.GetNodeForName(a:name, 1, self.getNerdtree()) let oldMarkedNode = g:NERDTreeBookmark.GetNodeForName(a:name, 1, self.getNerdtree())
@ -33,8 +36,8 @@ function! s:TreeFileNode.bookmark(name)
endif endif
endfunction endfunction
"FUNCTION: TreeFileNode.cacheParent() {{{1 " FUNCTION: TreeFileNode.cacheParent() {{{1
"initializes self.parent if it isnt already " initializes self.parent if it isnt already
function! s:TreeFileNode.cacheParent() function! s:TreeFileNode.cacheParent()
if empty(self.parent) if empty(self.parent)
let parentPath = self.path.getParent() let parentPath = self.path.getParent()
@ -45,7 +48,7 @@ function! s:TreeFileNode.cacheParent()
endif endif
endfunction endfunction
"FUNCTION: TreeFileNode.clearBookmarks() {{{1 " FUNCTION: TreeFileNode.clearBookmarks() {{{1
function! s:TreeFileNode.clearBookmarks() function! s:TreeFileNode.clearBookmarks()
for i in g:NERDTreeBookmark.Bookmarks() for i in g:NERDTreeBookmark.Bookmarks()
if i.path.equals(self.path) if i.path.equals(self.path)
@ -55,7 +58,7 @@ function! s:TreeFileNode.clearBookmarks()
call self.path.cacheDisplayString() call self.path.cacheDisplayString()
endfunction endfunction
"FUNCTION: TreeFileNode.copy(dest) {{{1 " FUNCTION: TreeFileNode.copy(dest) {{{1
function! s:TreeFileNode.copy(dest) function! s:TreeFileNode.copy(dest)
call self.path.copy(a:dest) call self.path.copy(a:dest)
let newPath = g:NERDTreePath.New(a:dest) let newPath = g:NERDTreePath.New(a:dest)
@ -68,44 +71,44 @@ function! s:TreeFileNode.copy(dest)
endif endif
endfunction endfunction
"FUNCTION: TreeFileNode.delete {{{1 " FUNCTION: TreeFileNode.delete {{{1
"Removes this node from the tree and calls the Delete method for its path obj " Removes this node from the tree and calls the Delete method for its path obj
function! s:TreeFileNode.delete() function! s:TreeFileNode.delete()
call self.path.delete() call self.path.delete()
call self.parent.removeChild(self) call self.parent.removeChild(self)
endfunction endfunction
"FUNCTION: TreeFileNode.displayString() {{{1 " FUNCTION: TreeFileNode.displayString() {{{1
" "
"Returns a string that specifies how the node should be represented as a " Returns a string that specifies how the node should be represented as a
"string " string
" "
"Return: " Return:
"a string that can be used in the view to represent this node " a string that can be used in the view to represent this node
function! s:TreeFileNode.displayString() function! s:TreeFileNode.displayString()
return self.path.flagSet.renderToString() . self.path.displayString() return self.path.flagSet.renderToString() . self.path.displayString()
endfunction endfunction
"FUNCTION: TreeFileNode.equals(treenode) {{{1 " FUNCTION: TreeFileNode.equals(treenode) {{{1
" "
"Compares this treenode to the input treenode and returns 1 if they are the " Compares this treenode to the input treenode and returns 1 if they are the
"same node. " same node.
" "
"Use this method instead of == because sometimes when the treenodes contain " Use this method instead of == because sometimes when the treenodes contain
"many children, vim seg faults when doing == " many children, vim seg faults when doing ==
" "
"Args: " Args:
"treenode: the other treenode to compare to " treenode: the other treenode to compare to
function! s:TreeFileNode.equals(treenode) function! s:TreeFileNode.equals(treenode)
return self.path.str() ==# a:treenode.path.str() return self.path.str() ==# a:treenode.path.str()
endfunction endfunction
"FUNCTION: TreeFileNode.findNode(path) {{{1 " FUNCTION: TreeFileNode.findNode(path) {{{1
"Returns self if this node.path.Equals the given path. " Returns self if this node.path.Equals the given path.
"Returns {} if not equal. " Returns {} if not equal.
" "
"Args: " Args:
"path: the path object to compare against " path: the path object to compare against
function! s:TreeFileNode.findNode(path) function! s:TreeFileNode.findNode(path)
if a:path.equals(self.path) if a:path.equals(self.path)
return self return self
@ -113,18 +116,18 @@ function! s:TreeFileNode.findNode(path)
return {} return {}
endfunction endfunction
"FUNCTION: TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) {{{1 " FUNCTION: TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) {{{1
" "
"Finds the next sibling for this node in the indicated direction. This sibling " Finds the next sibling for this node in the indicated direction. This sibling
"must be a directory and may/may not have children as specified. " must be a directory and may/may not have children as specified.
" "
"Args: " Args:
"direction: 0 if you want to find the previous sibling, 1 for the next sibling " direction: 0 if you want to find the previous sibling, 1 for the next sibling
" "
"Return: " Return:
"a treenode object or {} if no appropriate sibling could be found " a treenode object or {} if no appropriate sibling could be found
function! s:TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) function! s:TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction)
"if we have no parent then we can have no siblings " if we have no parent then we can have no siblings
if self.parent != {} if self.parent != {}
let nextSibling = self.findSibling(a:direction) let nextSibling = self.findSibling(a:direction)
@ -139,37 +142,37 @@ function! s:TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction)
return {} return {}
endfunction endfunction
"FUNCTION: TreeFileNode.findSibling(direction) {{{1 " FUNCTION: TreeFileNode.findSibling(direction) {{{1
" "
"Finds the next sibling for this node in the indicated direction " Finds the next sibling for this node in the indicated direction
" "
"Args: " Args:
"direction: 0 if you want to find the previous sibling, 1 for the next sibling " direction: 0 if you want to find the previous sibling, 1 for the next sibling
" "
"Return: " Return:
"a treenode object or {} if no sibling could be found " a treenode object or {} if no sibling could be found
function! s:TreeFileNode.findSibling(direction) function! s:TreeFileNode.findSibling(direction)
"if we have no parent then we can have no siblings " if we have no parent then we can have no siblings
if self.parent != {} if self.parent != {}
"get the index of this node in its parents children " get the index of this node in its parents children
let siblingIndx = self.parent.getChildIndex(self.path) let siblingIndx = self.parent.getChildIndex(self.path)
if siblingIndx != -1 if siblingIndx != -1
"move a long to the next potential sibling node " move a long to the next potential sibling node
let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1 let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1
"keep moving along to the next sibling till we find one that is valid " keep moving along to the next sibling till we find one that is valid
let numSiblings = self.parent.getChildCount() let numSiblings = self.parent.getChildCount()
while siblingIndx >= 0 && siblingIndx < numSiblings while siblingIndx >= 0 && siblingIndx < numSiblings
"if the next node is not an ignored node (i.e. wont show up in the " if the next node is not an ignored node (i.e. wont show up in the
"view) then return it " view) then return it
if self.parent.children[siblingIndx].path.ignore(self.getNerdtree()) ==# 0 if self.parent.children[siblingIndx].path.ignore(self.getNerdtree()) ==# 0
return self.parent.children[siblingIndx] return self.parent.children[siblingIndx]
endif endif
"go to next node " go to next node
let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1 let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1
endwhile endwhile
endif endif
@ -178,13 +181,13 @@ function! s:TreeFileNode.findSibling(direction)
return {} return {}
endfunction endfunction
"FUNCTION: TreeFileNode.getNerdtree(){{{1 " FUNCTION: TreeFileNode.getNerdtree(){{{1
function! s:TreeFileNode.getNerdtree() function! s:TreeFileNode.getNerdtree()
return self._nerdtree return self._nerdtree
endfunction endfunction
"FUNCTION: TreeFileNode.GetRootForTab(){{{1 " FUNCTION: TreeFileNode.GetRootForTab(){{{1
"get the root node for this tab " get the root node for this tab
function! s:TreeFileNode.GetRootForTab() function! s:TreeFileNode.GetRootForTab()
if g:NERDTree.ExistsForTab() if g:NERDTree.ExistsForTab()
return getbufvar(t:NERDTreeBufName, 'NERDTree').root return getbufvar(t:NERDTreeBufName, 'NERDTree').root
@ -192,28 +195,32 @@ function! s:TreeFileNode.GetRootForTab()
return {} return {}
endfunction endfunction
"FUNCTION: TreeFileNode.GetSelected() {{{1 " FUNCTION: TreeFileNode.GetSelected() {{{1
"gets the treenode that the cursor is currently over " If the cursor is currently positioned on a tree node, return the node.
" Otherwise, return the empty dictionary.
function! s:TreeFileNode.GetSelected() function! s:TreeFileNode.GetSelected()
try try
let path = b:NERDTree.ui.getPath(line(".")) let l:path = b:NERDTree.ui.getPath(line('.'))
if path ==# {}
if empty(l:path)
return {} return {}
endif endif
return b:NERDTree.root.findNode(path)
return b:NERDTree.root.findNode(l:path)
catch /^NERDTree/ catch /^NERDTree/
return {} return {}
endtry endtry
endfunction endfunction
"FUNCTION: TreeFileNode.isVisible() {{{1 " FUNCTION: TreeFileNode.isVisible() {{{1
"returns 1 if this node should be visible according to the tree filters and " returns 1 if this node should be visible according to the tree filters and
"hidden file filters (and their on/off status) " hidden file filters (and their on/off status)
function! s:TreeFileNode.isVisible() function! s:TreeFileNode.isVisible()
return !self.path.ignore(self.getNerdtree()) return !self.path.ignore(self.getNerdtree())
endfunction endfunction
"FUNCTION: TreeFileNode.isRoot() {{{1 " FUNCTION: TreeFileNode.isRoot() {{{1
function! s:TreeFileNode.isRoot() function! s:TreeFileNode.isRoot()
if !g:NERDTree.ExistsForBuf() if !g:NERDTree.ExistsForBuf()
throw "NERDTree.NoTreeError: No tree exists for the current buffer" throw "NERDTree.NoTreeError: No tree exists for the current buffer"
@ -222,12 +229,12 @@ function! s:TreeFileNode.isRoot()
return self.equals(self.getNerdtree().root) return self.equals(self.getNerdtree().root)
endfunction endfunction
"FUNCTION: TreeFileNode.New(path, nerdtree) {{{1 " FUNCTION: TreeFileNode.New(path, nerdtree) {{{1
"Returns a new TreeNode object with the given path and parent " Returns a new TreeNode object with the given path and parent
" "
"Args: " Args:
"path: file/dir that the node represents " path: file/dir that the node represents
"nerdtree: the tree the node belongs to " nerdtree: the tree the node belongs to
function! s:TreeFileNode.New(path, nerdtree) function! s:TreeFileNode.New(path, nerdtree)
if a:path.isDirectory if a:path.isDirectory
return g:NERDTreeDirNode.New(a:path, a:nerdtree) return g:NERDTreeDirNode.New(a:path, a:nerdtree)
@ -240,40 +247,40 @@ function! s:TreeFileNode.New(path, nerdtree)
endif endif
endfunction endfunction
"FUNCTION: TreeFileNode.open() {{{1 " FUNCTION: TreeFileNode.open() {{{1
function! s:TreeFileNode.open(...) function! s:TreeFileNode.open(...)
let opts = a:0 ? a:1 : {} let opts = a:0 ? a:1 : {}
let opener = g:NERDTreeOpener.New(self.path, opts) let opener = g:NERDTreeOpener.New(self.path, opts)
call opener.open(self) call opener.open(self)
endfunction endfunction
"FUNCTION: TreeFileNode.openSplit() {{{1 " FUNCTION: TreeFileNode.openSplit() {{{1
"Open this node in a new window " Open this node in a new window
function! s:TreeFileNode.openSplit() function! s:TreeFileNode.openSplit()
call nerdtree#deprecated('TreeFileNode.openSplit', 'is deprecated, use .open() instead.') call nerdtree#deprecated('TreeFileNode.openSplit', 'is deprecated, use .open() instead.')
call self.open({'where': 'h'}) call self.open({'where': 'h'})
endfunction endfunction
"FUNCTION: TreeFileNode.openVSplit() {{{1 " FUNCTION: TreeFileNode.openVSplit() {{{1
"Open this node in a new vertical window " Open this node in a new vertical window
function! s:TreeFileNode.openVSplit() function! s:TreeFileNode.openVSplit()
call nerdtree#deprecated('TreeFileNode.openVSplit', 'is deprecated, use .open() instead.') call nerdtree#deprecated('TreeFileNode.openVSplit', 'is deprecated, use .open() instead.')
call self.open({'where': 'v'}) call self.open({'where': 'v'})
endfunction endfunction
"FUNCTION: TreeFileNode.openInNewTab(options) {{{1 " FUNCTION: TreeFileNode.openInNewTab(options) {{{1
function! s:TreeFileNode.openInNewTab(options) function! s:TreeFileNode.openInNewTab(options)
echomsg 'TreeFileNode.openInNewTab is deprecated' echomsg 'TreeFileNode.openInNewTab is deprecated'
call self.open(extend({'where': 't'}, a:options)) call self.open(extend({'where': 't'}, a:options))
endfunction endfunction
"FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{1 " FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{1
"Places the cursor on the line number this node is rendered on " Places the cursor on the line number this node is rendered on
" "
"Args: " Args:
"isJump: 1 if this cursor movement should be counted as a jump by vim " isJump: 1 if this cursor movement should be counted as a jump by vim
"recurseUpward: try to put the cursor on the parent if the this node isnt " recurseUpward: try to put the cursor on the parent if the this node isnt
"visible " visible
function! s:TreeFileNode.putCursorHere(isJump, recurseUpward) function! s:TreeFileNode.putCursorHere(isJump, recurseUpward)
let ln = self.getNerdtree().ui.getLineNum(self) let ln = self.getNerdtree().ui.getLineNum(self)
if ln != -1 if ln != -1
@ -294,18 +301,18 @@ function! s:TreeFileNode.putCursorHere(isJump, recurseUpward)
endif endif
endfunction endfunction
"FUNCTION: TreeFileNode.refresh() {{{1 " FUNCTION: TreeFileNode.refresh() {{{1
function! s:TreeFileNode.refresh() function! s:TreeFileNode.refresh()
call self.path.refresh(self.getNerdtree()) call self.path.refresh(self.getNerdtree())
endfunction endfunction
"FUNCTION: TreeFileNode.refreshFlags() {{{1 " FUNCTION: TreeFileNode.refreshFlags() {{{1
function! s:TreeFileNode.refreshFlags() function! s:TreeFileNode.refreshFlags()
call self.path.refreshFlags(self.getNerdtree()) call self.path.refreshFlags(self.getNerdtree())
endfunction endfunction
"FUNCTION: TreeFileNode.rename() {{{1 " FUNCTION: TreeFileNode.rename() {{{1
"Calls the rename method for this nodes path obj " Calls the rename method for this nodes path obj
function! s:TreeFileNode.rename(newName) function! s:TreeFileNode.rename(newName)
let newName = substitute(a:newName, '\(\\\|\/\)$', '', '') let newName = substitute(a:newName, '\(\\\|\/\)$', '', '')
call self.path.rename(newName) call self.path.rename(newName)
@ -320,17 +327,17 @@ function! s:TreeFileNode.rename(newName)
endif endif
endfunction endfunction
"FUNCTION: TreeFileNode.renderToString {{{1 " FUNCTION: TreeFileNode.renderToString {{{1
"returns a string representation for this tree to be rendered in the view " returns a string representation for this tree to be rendered in the view
function! s:TreeFileNode.renderToString() function! s:TreeFileNode.renderToString()
return self._renderToString(0, 0) return self._renderToString(0, 0)
endfunction endfunction
"Args: " Args:
"depth: the current depth in the tree for this call " depth: the current depth in the tree for this call
"drawText: 1 if we should actually draw the line for this node (if 0 then the " drawText: 1 if we should actually draw the line for this node (if 0 then the
"child nodes are rendered only) " child nodes are rendered only)
"for each depth in the tree " for each depth in the tree
function! s:TreeFileNode._renderToString(depth, drawText) function! s:TreeFileNode._renderToString(depth, drawText)
let output = "" let output = ""
if a:drawText ==# 1 if a:drawText ==# 1
@ -346,7 +353,7 @@ function! s:TreeFileNode._renderToString(depth, drawText)
let output = output . line . "\n" let output = output . line . "\n"
endif endif
"if the node is an open dir, draw its children " if the node is an open dir, draw its children
if self.path.isDirectory ==# 1 && self.isOpen ==# 1 if self.path.isDirectory ==# 1 && self.isOpen ==# 1
let childNodesToDraw = self.getVisibleChildren() let childNodesToDraw = self.getVisibleChildren()

View File

@ -1,11 +1,14 @@
"CLASS: UI " ============================================================================
"============================================================ " CLASS: UI
" ============================================================================
let s:UI = {} let s:UI = {}
let g:NERDTreeUI = s:UI let g:NERDTreeUI = s:UI
"FUNCTION: s:UI.centerView() {{{2 " FUNCTION: s:UI.centerView() {{{2
"centers the nerd tree window around the cursor (provided the nerd tree " centers the nerd tree window around the cursor (provided the nerd tree
"options permit) " options permit)
function! s:UI.centerView() function! s:UI.centerView()
if g:NERDTreeAutoCenter if g:NERDTreeAutoCenter
let current_line = winline() let current_line = winline()
@ -17,8 +20,8 @@ function! s:UI.centerView()
endif endif
endfunction endfunction
"FUNCTION: s:UI._dumpHelp {{{1 " FUNCTION: s:UI._dumpHelp {{{1
"prints out the quick help " prints out the quick help
function! s:UI._dumpHelp() function! s:UI._dumpHelp()
if self.getShowHelp() if self.getShowHelp()
let help = "\" NERDTree (" . nerdtree#version() . ") quickhelp~\n" let help = "\" NERDTree (" . nerdtree#version() . ") quickhelp~\n"
@ -93,7 +96,7 @@ function! s:UI._dumpHelp()
let help .= "\" ". g:NERDTreeMapToggleFiles .": files (" . (self.getShowFiles() ? "on" : "off") . ")\n" let help .= "\" ". g:NERDTreeMapToggleFiles .": files (" . (self.getShowFiles() ? "on" : "off") . ")\n"
let help .= "\" ". g:NERDTreeMapToggleBookmarks .": bookmarks (" . (self.getShowBookmarks() ? "on" : "off") . ")\n" let help .= "\" ". g:NERDTreeMapToggleBookmarks .": bookmarks (" . (self.getShowBookmarks() ? "on" : "off") . ")\n"
"add quickhelp entries for each custom key map " add quickhelp entries for each custom key map
let help .= "\"\n\" ----------------------------\n" let help .= "\"\n\" ----------------------------\n"
let help .= "\" Custom mappings~\n" let help .= "\" Custom mappings~\n"
for i in g:NERDTreeKeyMap.All() for i in g:NERDTreeKeyMap.All()
@ -124,7 +127,7 @@ function! s:UI._dumpHelp()
endfunction endfunction
"FUNCTION: s:UI.new(nerdtree) {{{1 " FUNCTION: s:UI.new(nerdtree) {{{1
function! s:UI.New(nerdtree) function! s:UI.New(nerdtree)
let newObj = copy(self) let newObj = copy(self)
let newObj.nerdtree = a:nerdtree let newObj.nerdtree = a:nerdtree
@ -137,22 +140,16 @@ function! s:UI.New(nerdtree)
return newObj return newObj
endfunction endfunction
"FUNCTION: s:UI.getPath(ln) {{{1 " FUNCTION: s:UI.getPath(ln) {{{1
"Gets the full path to the node that is rendered on the given line number " Return the "Path" object for the node that is rendered on the given line
" " number. If the "up a dir" line is selected, return the "Path" object for
"Args: " the parent of the root. Return the empty dictionary if the given line
"ln: the line number to get the path for " does not reference a tree node.
"
"Return:
"A path if a node was selected, {} if nothing is selected.
"If the 'up a dir' line was selected then the path to the parent of the
"current root is returned
function! s:UI.getPath(ln) function! s:UI.getPath(ln)
let line = getline(a:ln) let line = getline(a:ln)
let rootLine = self.getRootLineNum() let rootLine = self.getRootLineNum()
"check to see if we have the root node
if a:ln == rootLine if a:ln == rootLine
return self.nerdtree.root.path return self.nerdtree.root.path
endif endif
@ -161,9 +158,13 @@ function! s:UI.getPath(ln)
return self.nerdtree.root.path.getParent() return self.nerdtree.root.path.getParent()
endif endif
if a:ln < rootLine
return {}
endif
let indent = self._indentLevelFor(line) let indent = self._indentLevelFor(line)
"remove the tree parts and the leading space " remove the tree parts and the leading space
let curFile = self._stripMarkup(line) let curFile = self._stripMarkup(line)
let dir = "" let dir = ""
@ -173,7 +174,7 @@ function! s:UI.getPath(ln)
let curLine = getline(lnum) let curLine = getline(lnum)
let curLineStripped = self._stripMarkup(curLine) let curLineStripped = self._stripMarkup(curLine)
"have we reached the top of the tree? " have we reached the top of the tree?
if lnum == rootLine if lnum == rootLine
let dir = self.nerdtree.root.path.str({'format': 'UI'}) . dir let dir = self.nerdtree.root.path.str({'format': 'UI'}) . dir
break break
@ -193,19 +194,19 @@ function! s:UI.getPath(ln)
return toReturn return toReturn
endfunction endfunction
"FUNCTION: s:UI.getLineNum(file_node){{{1 " FUNCTION: s:UI.getLineNum(file_node){{{1
"returns the line number this node is rendered on, or -1 if it isnt rendered " returns the line number this node is rendered on, or -1 if it isnt rendered
function! s:UI.getLineNum(file_node) function! s:UI.getLineNum(file_node)
"if the node is the root then return the root line no. " if the node is the root then return the root line no.
if a:file_node.isRoot() if a:file_node.isRoot()
return self.getRootLineNum() return self.getRootLineNum()
endif endif
let totalLines = line("$") let totalLines = line("$")
"the path components we have matched so far " the path components we have matched so far
let pathcomponents = [substitute(self.nerdtree.root.path.str({'format': 'UI'}), '/ *$', '', '')] let pathcomponents = [substitute(self.nerdtree.root.path.str({'format': 'UI'}), '/ *$', '', '')]
"the index of the component we are searching for " the index of the component we are searching for
let curPathComponent = 1 let curPathComponent = 1
let fullpath = a:file_node.path.str({'format': 'UI'}) let fullpath = a:file_node.path.str({'format': 'UI'})
@ -213,7 +214,7 @@ function! s:UI.getLineNum(file_node)
let lnum = self.getRootLineNum() let lnum = self.getRootLineNum()
while lnum > 0 while lnum > 0
let lnum = lnum + 1 let lnum = lnum + 1
"have we reached the bottom of the tree? " have we reached the bottom of the tree?
if lnum ==# totalLines+1 if lnum ==# totalLines+1
return -1 return -1
endif endif
@ -241,8 +242,8 @@ function! s:UI.getLineNum(file_node)
return -1 return -1
endfunction endfunction
"FUNCTION: s:UI.getRootLineNum(){{{1 " FUNCTION: s:UI.getRootLineNum(){{{1
"gets the line number of the root node " gets the line number of the root node
function! s:UI.getRootLineNum() function! s:UI.getRootLineNum()
let rootLine = 1 let rootLine = 1
while getline(rootLine) !~# '^\(/\|<\)' while getline(rootLine) !~# '^\(/\|<\)'
@ -251,29 +252,29 @@ function! s:UI.getRootLineNum()
return rootLine return rootLine
endfunction endfunction
"FUNCTION: s:UI.getShowBookmarks() {{{1 " FUNCTION: s:UI.getShowBookmarks() {{{1
function! s:UI.getShowBookmarks() function! s:UI.getShowBookmarks()
return self._showBookmarks return self._showBookmarks
endfunction endfunction
"FUNCTION: s:UI.getShowFiles() {{{1 " FUNCTION: s:UI.getShowFiles() {{{1
function! s:UI.getShowFiles() function! s:UI.getShowFiles()
return self._showFiles return self._showFiles
endfunction endfunction
"FUNCTION: s:UI.getShowHelp() {{{1 " FUNCTION: s:UI.getShowHelp() {{{1
function! s:UI.getShowHelp() function! s:UI.getShowHelp()
return self._showHelp return self._showHelp
endfunction endfunction
"FUNCTION: s:UI.getShowHidden() {{{1 " FUNCTION: s:UI.getShowHidden() {{{1
function! s:UI.getShowHidden() function! s:UI.getShowHidden()
return self._showHidden return self._showHidden
endfunction endfunction
"FUNCTION: s:UI._indentLevelFor(line) {{{1 " FUNCTION: s:UI._indentLevelFor(line) {{{1
function! s:UI._indentLevelFor(line) function! s:UI._indentLevelFor(line)
"have to do this work around because match() returns bytes, not chars " have to do this work around because match() returns bytes, not chars
let numLeadBytes = match(a:line, '\M\[^ '.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.']') let numLeadBytes = match(a:line, '\M\[^ '.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.']')
" The next line is a backward-compatible workaround for strchars(a:line(0:numLeadBytes-1]). strchars() is in 7.3+ " The next line is a backward-compatible workaround for strchars(a:line(0:numLeadBytes-1]). strchars() is in 7.3+
let leadChars = len(split(a:line[0:numLeadBytes-1], '\zs')) let leadChars = len(split(a:line[0:numLeadBytes-1], '\zs'))
@ -281,27 +282,27 @@ function! s:UI._indentLevelFor(line)
return leadChars / s:UI.IndentWid() return leadChars / s:UI.IndentWid()
endfunction endfunction
"FUNCTION: s:UI.IndentWid() {{{1 " FUNCTION: s:UI.IndentWid() {{{1
function! s:UI.IndentWid() function! s:UI.IndentWid()
return 2 return 2
endfunction endfunction
"FUNCTION: s:UI.isIgnoreFilterEnabled() {{{1 " FUNCTION: s:UI.isIgnoreFilterEnabled() {{{1
function! s:UI.isIgnoreFilterEnabled() function! s:UI.isIgnoreFilterEnabled()
return self._ignoreEnabled == 1 return self._ignoreEnabled == 1
endfunction endfunction
"FUNCTION: s:UI.isMinimal() {{{1 " FUNCTION: s:UI.isMinimal() {{{1
function! s:UI.isMinimal() function! s:UI.isMinimal()
return g:NERDTreeMinimalUI return g:NERDTreeMinimalUI
endfunction endfunction
"FUNCTION: s:UI.MarkupReg() {{{1 " FUNCTION: s:UI.MarkupReg() {{{1
function! s:UI.MarkupReg() function! s:UI.MarkupReg()
return '^\(['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'] \| \+['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'] \| \+\)' return '^\(['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'] \| \+['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'] \| \+\)'
endfunction endfunction
"FUNCTION: s:UI._renderBookmarks {{{1 " FUNCTION: s:UI._renderBookmarks {{{1
function! s:UI._renderBookmarks() function! s:UI._renderBookmarks()
if !self.isMinimal() if !self.isMinimal()
@ -322,12 +323,12 @@ function! s:UI._renderBookmarks()
call cursor(line(".")+1, col(".")) call cursor(line(".")+1, col("."))
endfunction endfunction
"FUNCTION: s:UI.restoreScreenState() {{{1 " FUNCTION: s:UI.restoreScreenState() {{{1
" "
"Sets the screen state back to what it was when nerdtree#saveScreenState was last " Sets the screen state back to what it was when nerdtree#saveScreenState was last
"called. " called.
" "
"Assumes the cursor is in the NERDTree window " Assumes the cursor is in the NERDTree window
function! s:UI.restoreScreenState() function! s:UI.restoreScreenState()
if !has_key(self, '_screenState') if !has_key(self, '_screenState')
return return
@ -342,9 +343,9 @@ function! s:UI.restoreScreenState()
let &scrolloff=old_scrolloff let &scrolloff=old_scrolloff
endfunction endfunction
"FUNCTION: s:UI.saveScreenState() {{{1 " FUNCTION: s:UI.saveScreenState() {{{1
"Saves the current cursor position in the current buffer and the window " Saves the current cursor position in the current buffer and the window
"scroll position " scroll position
function! s:UI.saveScreenState() function! s:UI.saveScreenState()
let win = winnr() let win = winnr()
call g:NERDTree.CursorToTreeWin() call g:NERDTree.CursorToTreeWin()
@ -355,31 +356,31 @@ function! s:UI.saveScreenState()
call nerdtree#exec(win . "wincmd w") call nerdtree#exec(win . "wincmd w")
endfunction endfunction
"FUNCTION: s:UI.setShowHidden(val) {{{1 " FUNCTION: s:UI.setShowHidden(val) {{{1
function! s:UI.setShowHidden(val) function! s:UI.setShowHidden(val)
let self._showHidden = a:val let self._showHidden = a:val
endfunction endfunction
"FUNCTION: s:UI._stripMarkup(line){{{1 " FUNCTION: s:UI._stripMarkup(line){{{1
"returns the given line with all the tree parts stripped off " returns the given line with all the tree parts stripped off
" "
"Args: " Args:
"line: the subject line " line: the subject line
function! s:UI._stripMarkup(line) function! s:UI._stripMarkup(line)
let line = a:line let line = a:line
"remove the tree parts and the leading space " remove the tree parts and the leading space
let line = substitute (line, g:NERDTreeUI.MarkupReg(),"","") let line = substitute (line, g:NERDTreeUI.MarkupReg(),"","")
"strip off any read only flag " strip off any read only flag
let line = substitute (line, ' \['.g:NERDTreeGlyphReadOnly.'\]', "","") let line = substitute (line, ' \['.g:NERDTreeGlyphReadOnly.'\]', "","")
"strip off any bookmark flags " strip off any bookmark flags
let line = substitute (line, ' {[^}]*}', "","") let line = substitute (line, ' {[^}]*}', "","")
"strip off any executable flags " strip off any executable flags
let line = substitute (line, '*\ze\($\| \)', "","") let line = substitute (line, '*\ze\($\| \)', "","")
"strip off any generic flags " strip off any generic flags
let line = substitute (line, '\[[^]]*\]', "","") let line = substitute (line, '\[[^]]*\]', "","")
let line = substitute (line,' -> .*',"","") " remove link to let line = substitute (line,' -> .*',"","") " remove link to
@ -387,22 +388,22 @@ function! s:UI._stripMarkup(line)
return line return line
endfunction endfunction
"FUNCTION: s:UI.render() {{{1 " FUNCTION: s:UI.render() {{{1
function! s:UI.render() function! s:UI.render()
setlocal modifiable setlocal modifiable
"remember the top line of the buffer and the current line so we can " remember the top line of the buffer and the current line so we can
"restore the view exactly how it was " restore the view exactly how it was
let curLine = line(".") let curLine = line(".")
let curCol = col(".") let curCol = col(".")
let topLine = line("w0") let topLine = line("w0")
"delete all lines in the buffer (being careful not to clobber a register) " delete all lines in the buffer (being careful not to clobber a register)
silent 1,$delete _ silent 1,$delete _
call self._dumpHelp() call self._dumpHelp()
"delete the blank line before the help and add one after it " delete the blank line before the help and add one after it
if !self.isMinimal() if !self.isMinimal()
call setline(line(".")+1, "") call setline(line(".")+1, "")
call cursor(line(".")+1, col(".")) call cursor(line(".")+1, col("."))
@ -412,24 +413,24 @@ function! s:UI.render()
call self._renderBookmarks() call self._renderBookmarks()
endif endif
"add the 'up a dir' line " add the 'up a dir' line
if !self.isMinimal() if !self.isMinimal()
call setline(line(".")+1, s:UI.UpDirLine()) call setline(line(".")+1, s:UI.UpDirLine())
call cursor(line(".")+1, col(".")) call cursor(line(".")+1, col("."))
endif endif
"draw the header line " draw the header line
let header = self.nerdtree.root.path.str({'format': 'UI', 'truncateTo': winwidth(0)}) let header = self.nerdtree.root.path.str({'format': 'UI', 'truncateTo': winwidth(0)})
call setline(line(".")+1, header) call setline(line(".")+1, header)
call cursor(line(".")+1, col(".")) call cursor(line(".")+1, col("."))
"draw the tree " draw the tree
silent put =self.nerdtree.root.renderToString() silent put =self.nerdtree.root.renderToString()
"delete the blank line at the top of the buffer " delete the blank line at the top of the buffer
silent 1,1delete _ silent 1,1delete _
"restore the view " restore the view
let old_scrolloff=&scrolloff let old_scrolloff=&scrolloff
let &scrolloff=0 let &scrolloff=0
call cursor(topLine, 1) call cursor(topLine, 1)
@ -441,14 +442,14 @@ function! s:UI.render()
endfunction endfunction
"FUNCTION: UI.renderViewSavingPosition {{{1 " FUNCTION: UI.renderViewSavingPosition {{{1
"Renders the tree and ensures the cursor stays on the current node or the " Renders the tree and ensures the cursor stays on the current node or the
"current nodes parent if it is no longer available upon re-rendering " current nodes parent if it is no longer available upon re-rendering
function! s:UI.renderViewSavingPosition() function! s:UI.renderViewSavingPosition()
let currentNode = g:NERDTreeFileNode.GetSelected() let currentNode = g:NERDTreeFileNode.GetSelected()
"go up the tree till we find a node that will be visible or till we run " go up the tree till we find a node that will be visible or till we run
"out of nodes " out of nodes
while currentNode != {} && !currentNode.isVisible() && !currentNode.isRoot() while currentNode != {} && !currentNode.isVisible() && !currentNode.isRoot()
let currentNode = currentNode.parent let currentNode = currentNode.parent
endwhile endwhile
@ -460,7 +461,7 @@ function! s:UI.renderViewSavingPosition()
endif endif
endfunction endfunction
"FUNCTION: s:UI.toggleHelp() {{{1 " FUNCTION: s:UI.toggleHelp() {{{1
function! s:UI.toggleHelp() function! s:UI.toggleHelp()
let self._showHelp = !self._showHelp let self._showHelp = !self._showHelp
endfunction endfunction
@ -515,7 +516,7 @@ function! s:UI.toggleZoom()
endif endif
endfunction endfunction
"FUNCTION: s:UI.UpDirLine() {{{1 " FUNCTION: s:UI.UpDirLine() {{{1
function! s:UI.UpDirLine() function! s:UI.UpDirLine()
return '.. (up a dir)' return '.. (up a dir)'
endfunction endfunction