"we need to use this number many times for sorting... so we calculate it only "once here let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*') " used in formating sortKey, e.g. '%04d' if exists("log10") let s:sortKeyFormat = "%0" . float2nr(ceil(log10(len(g:NERDTreeSortOrder)))) . "d" else let s:sortKeyFormat = "%04d" endif "CLASS: Path "============================================================ let s:Path = {} let g:NERDTreePath = s:Path "FUNCTION: Path.AbsolutePathFor(str) {{{1 function! s:Path.AbsolutePathFor(str) let prependCWD = 0 if nerdtree#runningWindows() let prependCWD = a:str !~# '^.:\(\\\|\/\)' && a:str !~# '^\(\\\\\|\/\/\)' else let prependCWD = a:str !~# '^/' endif let toReturn = a:str if prependCWD let toReturn = getcwd() . s:Path.Slash() . a:str endif return toReturn endfunction "FUNCTION: Path.bookmarkNames() {{{1 function! s:Path.bookmarkNames() if !exists("self._bookmarkNames") call self.cacheDisplayString() endif return self._bookmarkNames endfunction "FUNCTION: Path.cacheDisplayString() {{{1 function! s:Path.cacheDisplayString() abort let self.cachedDisplayString = self.getLastPathComponent(1) if self.isExecutable let self.cachedDisplayString = self.cachedDisplayString . '*' endif let self._bookmarkNames = [] for i in g:NERDTreeBookmark.Bookmarks() if i.path.equals(self) call add(self._bookmarkNames, i.name) endif endfor if !empty(self._bookmarkNames) let self.cachedDisplayString .= ' {' . join(self._bookmarkNames) . '}' endif if self.isSymLink let self.cachedDisplayString .= ' -> ' . self.symLinkDest endif if self.isReadOnly let self.cachedDisplayString .= ' ['.g:NERDTreeGlyphReadOnly.']' endif endfunction "FUNCTION: Path.changeToDir() {{{1 function! s:Path.changeToDir() let dir = self.str({'format': 'Cd'}) if self.isDirectory ==# 0 let dir = self.getParent().str({'format': 'Cd'}) endif try execute "cd " . dir call nerdtree#echo("CWD is now: " . getcwd()) catch throw "NERDTree.PathChangeError: cannot change CWD to " . dir endtry endfunction "FUNCTION: Path.compareTo() {{{1 " "Compares this Path to the given path and returns 0 if they are equal, -1 if "this Path is "less than" the given path, or 1 if it is "greater". " "Args: "path: the path object to compare this to " "Return: "1, -1 or 0 function! s:Path.compareTo(path) let thisPath = self.getLastPathComponent(1) let thatPath = a:path.getLastPathComponent(1) "if the paths are the same then clearly we return 0 if thisPath ==# thatPath return 0 endif let thisSS = self.getSortOrderIndex() let thatSS = a:path.getSortOrderIndex() "compare the sort sequences, if they are different then the return "value is easy if thisSS < thatSS return -1 elseif thisSS > thatSS return 1 else if !g:NERDTreeSortHiddenFirst let thisPath = substitute(thisPath, '^[._]', '', '') let thatPath = substitute(thatPath, '^[._]', '', '') endif "if the sort sequences are the same then compare the paths "alphabetically let pathCompare = g:NERDTreeCaseSensitiveSort ? thisPath <# thatPath : thisPath " endif return " \\`\|\"#%&,?()\*^<>[]" endfunction "FUNCTION: Path.getDir() {{{1 " "Returns this path if it is a directory, else this paths parent. " "Return: "a Path object function! s:Path.getDir() if self.isDirectory return self else return self.getParent() endif endfunction "FUNCTION: Path.getParent() {{{1 " "Returns a new path object for this paths parent " "Return: "a new Path object function! s:Path.getParent() if nerdtree#runningWindows() let path = self.drive . '\' . join(self.pathSegments[0:-2], '\') else let path = '/'. join(self.pathSegments[0:-2], '/') endif return s:Path.New(path) endfunction "FUNCTION: Path.getLastPathComponent(dirSlash) {{{1 " "Gets the last part of this path. " "Args: "dirSlash: if 1 then a trailing slash will be added to the returned value for "directory nodes. function! s:Path.getLastPathComponent(dirSlash) if empty(self.pathSegments) return '' endif let toReturn = self.pathSegments[-1] if a:dirSlash && self.isDirectory let toReturn = toReturn . '/' endif return toReturn endfunction "FUNCTION: Path.getSortOrderIndex() {{{1 "returns the index of the pattern in g:NERDTreeSortOrder that this path matches function! s:Path.getSortOrderIndex() let i = 0 while i < len(g:NERDTreeSortOrder) if self.getLastPathComponent(1) =~# g:NERDTreeSortOrder[i] return i endif let i = i + 1 endwhile return s:NERDTreeSortStarIndex endfunction "FUNCTION: Path.getSortKey() {{{1 "returns a string used in compare function for sorting function! s:Path.getSortKey() if !exists("self._sortKey") let path = self.getLastPathComponent(1) if !g:NERDTreeSortHiddenFirst let path = substitute(path, '^[._]', '', '') endif if !g:NERDTreeCaseSensitiveSort let path = tolower(path) endif let self._sortKey = printf(s:sortKeyFormat, self.getSortOrderIndex()) . path endif return self._sortKey endfunction "FUNCTION: Path.isUnixHiddenFile() {{{1 "check for unix hidden files function! s:Path.isUnixHiddenFile() return self.getLastPathComponent(0) =~# '^\.' endfunction "FUNCTION: Path.isUnixHiddenPath() {{{1 "check for unix path with hidden components function! s:Path.isUnixHiddenPath() if self.getLastPathComponent(0) =~# '^\.' return 1 else for segment in self.pathSegments if segment =~# '^\.' return 1 endif endfor return 0 endif endfunction "FUNCTION: Path.ignore(nerdtree) {{{1 "returns true if this path should be ignored function! s:Path.ignore(nerdtree) "filter out the user specified paths to ignore if a:nerdtree.ui.isIgnoreFilterEnabled() for i in g:NERDTreeIgnore if self._ignorePatternMatches(i) return 1 endif endfor for callback in g:NERDTree.PathFilters() if {callback}({'path': self, 'nerdtree': a:nerdtree}) return 1 endif endfor endif "dont show hidden files unless instructed to if !a:nerdtree.ui.getShowHidden() && self.isUnixHiddenFile() return 1 endif if a:nerdtree.ui.getShowFiles() ==# 0 && self.isDirectory ==# 0 return 1 endif return 0 endfunction "FUNCTION: Path._ignorePatternMatches(pattern) {{{1 "returns true if this path matches the given ignore pattern function! s:Path._ignorePatternMatches(pattern) let pat = a:pattern if strpart(pat,len(pat)-7) == '[[dir]]' if !self.isDirectory return 0 endif let pat = strpart(pat,0, len(pat)-7) elseif strpart(pat,len(pat)-8) == '[[file]]' if self.isDirectory return 0 endif let pat = strpart(pat,0, len(pat)-8) endif return self.getLastPathComponent(0) =~# pat endfunction "FUNCTION: Path.isAncestor(path) {{{1 "return 1 if this path is somewhere above the given path in the filesystem. " "a:path should be a dir function! s:Path.isAncestor(path) if !self.isDirectory return 0 endif let this = self.str() let that = a:path.str() return stridx(that, this) == 0 endfunction "FUNCTION: Path.isUnder(path) {{{1 "return 1 if this path is somewhere under the given path in the filesystem. function! s:Path.isUnder(path) if a:path.isDirectory == 0 return 0 endif let this = self.str() let that = a:path.str() return stridx(this, that . s:Path.Slash()) == 0 endfunction "FUNCTION: Path.JoinPathStrings(...) {{{1 function! s:Path.JoinPathStrings(...) let components = [] for i in a:000 let components = extend(components, split(i, '/')) endfor return '/' . join(components, '/') endfunction "FUNCTION: Path.equals() {{{1 " "Determines whether 2 path objects are "equal". "They are equal if the paths they represent are the same " "Args: "path: the other path obj to compare this with function! s:Path.equals(path) return self.str() ==# a:path.str() endfunction "FUNCTION: Path.New() {{{1 "The Constructor for the Path object function! s:Path.New(path) let newPath = copy(self) call newPath.readInfoFromDisk(s:Path.AbsolutePathFor(a:path)) let newPath.cachedDisplayString = "" let newPath.flagSet = g:NERDTreeFlagSet.New() return newPath endfunction "FUNCTION: Path.Slash() {{{1 "return the slash to use for the current OS function! s:Path.Slash() return nerdtree#runningWindows() ? '\' : '/' endfunction "FUNCTION: Path.Resolve() {{{1 "Invoke the vim resolve() function and return the result "This is necessary because in some versions of vim resolve() removes trailing "slashes while in other versions it doesn't. This always removes the trailing "slash function! s:Path.Resolve(path) let tmp = resolve(a:path) return tmp =~# '.\+/$' ? substitute(tmp, '/$', '', '') : tmp endfunction "FUNCTION: Path.readInfoFromDisk(fullpath) {{{1 " " "Throws NERDTree.Path.InvalidArguments exception. function! s:Path.readInfoFromDisk(fullpath) call self.extractDriveLetter(a:fullpath) let fullpath = s:Path.WinToUnixPath(a:fullpath) if getftype(fullpath) ==# "fifo" throw "NERDTree.InvalidFiletypeError: Cant handle FIFO files: " . a:fullpath endif let self.pathSegments = split(fullpath, '/') let self.isReadOnly = 0 if isdirectory(a:fullpath) let self.isDirectory = 1 elseif filereadable(a:fullpath) let self.isDirectory = 0 let self.isReadOnly = filewritable(a:fullpath) ==# 0 else throw "NERDTree.InvalidArgumentsError: Invalid path = " . a:fullpath endif let self.isExecutable = 0 if !self.isDirectory let self.isExecutable = getfperm(a:fullpath) =~# 'x' endif "grab the last part of the path (minus the trailing slash) let lastPathComponent = self.getLastPathComponent(0) "get the path to the new node with the parent dir fully resolved let hardPath = s:Path.Resolve(self.strTrunk()) . '/' . lastPathComponent "if the last part of the path is a symlink then flag it as such let self.isSymLink = (s:Path.Resolve(hardPath) != hardPath) if self.isSymLink let self.symLinkDest = s:Path.Resolve(fullpath) "if the link is a dir then slap a / on the end of its dest if isdirectory(self.symLinkDest) "we always wanna treat MS windows shortcuts as files for "simplicity if hardPath !~# '\.lnk$' let self.symLinkDest = self.symLinkDest . '/' endif endif endif endfunction "FUNCTION: Path.refresh(nerdtree) {{{1 function! s:Path.refresh(nerdtree) call self.readInfoFromDisk(self.str()) call g:NERDTreePathNotifier.NotifyListeners('refresh', self, a:nerdtree, {}) call self.cacheDisplayString() endfunction "FUNCTION: Path.refreshFlags(nerdtree) {{{1 function! s:Path.refreshFlags(nerdtree) call g:NERDTreePathNotifier.NotifyListeners('refreshFlags', self, a:nerdtree, {}) call self.cacheDisplayString() endfunction "FUNCTION: Path.rename() {{{1 " "Renames this node on the filesystem function! s:Path.rename(newPath) if a:newPath ==# '' throw "NERDTree.InvalidArgumentsError: Invalid newPath for renaming = ". a:newPath endif let success = rename(self.str(), a:newPath) if success != 0 throw "NERDTree.PathRenameError: Could not rename: '" . self.str() . "'" . 'to:' . a:newPath endif call self.readInfoFromDisk(a:newPath) for i in self.bookmarkNames() let b = g:NERDTreeBookmark.BookmarkFor(i) call b.setPath(copy(self)) endfor call g:NERDTreeBookmark.Write() endfunction "FUNCTION: Path.str() {{{1 " "Returns a string representation of this Path " "Takes an optional dictionary param to specify how the output should be "formatted. " "The dict may have the following keys: " 'format' " 'escape' " 'truncateTo' " "The 'format' key may have a value of: " 'Cd' - a string to be used with the :cd command " 'Edit' - a string to be used with :e :sp :new :tabedit etc " 'UI' - a string used in the NERD tree UI " "The 'escape' key, if specified will cause the output to be escaped with "shellescape() " "The 'truncateTo' key causes the resulting string to be truncated to the value "'truncateTo' maps to. A '<' char will be prepended. function! s:Path.str(...) let options = a:0 ? a:1 : {} let toReturn = "" if has_key(options, 'format') let format = options['format'] if has_key(self, '_strFor' . format) exec 'let toReturn = self._strFor' . format . '()' else throw 'NERDTree.UnknownFormatError: unknown format "'. format .'"' endif else let toReturn = self._str() endif if nerdtree#has_opt(options, 'escape') let toReturn = shellescape(toReturn) endif if has_key(options, 'truncateTo') let limit = options['truncateTo'] if len(toReturn) > limit-1 let toReturn = toReturn[(len(toReturn)-limit+1):] if len(split(toReturn, '/')) > 1 let toReturn = '