From a7d667b81bd381ff091e8ca0034a5b5e3660f1b2 Mon Sep 17 00:00:00 2001 From: Jason Franklin Date: Fri, 11 Aug 2017 08:07:23 -0400 Subject: [PATCH 01/10] Add spaces after comment leaders in "path.vim" Here, I applied the usual fix for the cramped comments I've found in our scripts. Use this command... :%s/^"\ze\S/" / to fix this problem elsewhere. --- lib/nerdtree/path.vim | 258 +++++++++++++++++++++--------------------- 1 file changed, 129 insertions(+), 129 deletions(-) diff --git a/lib/nerdtree/path.vim b/lib/nerdtree/path.vim index b884ec6..4d608c7 100644 --- a/lib/nerdtree/path.vim +++ b/lib/nerdtree/path.vim @@ -1,13 +1,13 @@ -"we need to use this number many times for sorting... so we calculate it only -"once here +" we need to use this number many times for sorting... so we calculate it only +" once here let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*') -"CLASS: Path -"============================================================ +" CLASS: Path +" ============================================================ let s:Path = {} let g:NERDTreePath = s:Path -"FUNCTION: Path.AbsolutePathFor(str) {{{1 +" FUNCTION: Path.AbsolutePathFor(str) {{{1 function! s:Path.AbsolutePathFor(str) let prependCWD = 0 if nerdtree#runningWindows() @@ -24,7 +24,7 @@ function! s:Path.AbsolutePathFor(str) return toReturn endfunction -"FUNCTION: Path.bookmarkNames() {{{1 +" FUNCTION: Path.bookmarkNames() {{{1 function! s:Path.bookmarkNames() if !exists("self._bookmarkNames") call self.cacheDisplayString() @@ -32,7 +32,7 @@ function! s:Path.bookmarkNames() return self._bookmarkNames endfunction -"FUNCTION: Path.cacheDisplayString() {{{1 +" FUNCTION: Path.cacheDisplayString() {{{1 function! s:Path.cacheDisplayString() abort let self.cachedDisplayString = self.getLastPathComponent(1) @@ -59,7 +59,7 @@ function! s:Path.cacheDisplayString() abort endif endfunction -"FUNCTION: Path.changeToDir() {{{1 +" FUNCTION: Path.changeToDir() {{{1 function! s:Path.changeToDir() let dir = self.str({'format': 'Cd'}) if self.isDirectory ==# 0 @@ -74,16 +74,16 @@ function! s:Path.changeToDir() endtry endfunction -"FUNCTION: Path.compareTo() {{{1 +" 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". +" 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 +" Args: +" path: the path object to compare this to " -"Return: -"1, -1 or 0 +" Return: +" 1, -1 or 0 function! s:Path.compareTo(path) let thisPath = self.getLastPathComponent(1) let thatPath = a:path.getLastPathComponent(1) @@ -118,16 +118,16 @@ function! s:Path.compareTo(path) endif endfunction -"FUNCTION: Path.Create(fullpath) {{{1 +" FUNCTION: Path.Create(fullpath) {{{1 " -"Factory method. +" Factory method. " -"Creates a path object with the given path. The path is also created on the -"filesystem. If the path already exists, a NERDTree.Path.Exists exception is -"thrown. If any other errors occur, a NERDTree.Path exception is thrown. +" Creates a path object with the given path. The path is also created on the +" filesystem. If the path already exists, a NERDTree.Path.Exists exception is +" thrown. If any other errors occur, a NERDTree.Path exception is thrown. " -"Args: -"fullpath: the full filesystem path to the file/dir to create +" Args: +" fullpath: the full filesystem path to the file/dir to create function! s:Path.Create(fullpath) "bail if the a:fullpath already exists if isdirectory(a:fullpath) || filereadable(a:fullpath) @@ -155,12 +155,12 @@ function! s:Path.Create(fullpath) return s:Path.New(a:fullpath) endfunction -"FUNCTION: Path.copy(dest) {{{1 +" FUNCTION: Path.copy(dest) {{{1 " -"Copies the file/dir represented by this Path to the given location +" Copies the file/dir represented by this Path to the given location " -"Args: -"dest: the location to copy this dir/file to +" Args: +" dest: the location to copy this dir/file to function! s:Path.copy(dest) if !s:Path.CopyingSupported() throw "NERDTree.CopyingNotSupportedError: Copying is not supported on this OS" @@ -181,20 +181,20 @@ function! s:Path.copy(dest) endif endfunction -"FUNCTION: Path.CopyingSupported() {{{1 +" FUNCTION: Path.CopyingSupported() {{{1 " -"returns 1 if copying is supported for this OS +" returns 1 if copying is supported for this OS function! s:Path.CopyingSupported() return exists('g:NERDTreeCopyCmd') || (exists('g:NERDTreeCopyDirCmd') && exists('g:NERDTreeCopyFileCmd')) endfunction -"FUNCTION: Path.copyingWillOverwrite(dest) {{{1 +" FUNCTION: Path.copyingWillOverwrite(dest) {{{1 " -"returns 1 if copy this path to the given location will cause files to -"overwritten +" returns 1 if copy this path to the given location will cause files to +" overwritten " -"Args: -"dest: the location this path will be copied to +" Args: +" dest: the location this path will be copied to function! s:Path.copyingWillOverwrite(dest) if filereadable(a:dest) return 1 @@ -208,13 +208,13 @@ function! s:Path.copyingWillOverwrite(dest) endif endfunction -"FUNCTION: Path.createParentDirectories(path) {{{1 +" FUNCTION: Path.createParentDirectories(path) {{{1 " -"create parent directories for this path if needed -"without throwing any errors if those directories already exist +" create parent directories for this path if needed +" without throwing any errors if those directories already exist " -"Args: -"path: full path of the node whose parent directories may need to be created +" Args: +" path: full path of the node whose parent directories may need to be created function! s:Path.createParentDirectories(path) let dir_path = fnamemodify(a:path, ':h') if !isdirectory(dir_path) @@ -222,11 +222,11 @@ function! s:Path.createParentDirectories(path) endif endfunction -"FUNCTION: Path.delete() {{{1 +" FUNCTION: Path.delete() {{{1 " -"Deletes the file or directory represented by this path. +" Deletes the file or directory represented by this path. " -"Throws NERDTree.Path.Deletion exceptions +" Throws NERDTree.Path.Deletion exceptions function! s:Path.delete() if self.isDirectory @@ -250,10 +250,10 @@ function! s:Path.delete() endfor endfunction -"FUNCTION: Path.displayString() {{{1 +" FUNCTION: Path.displayString() {{{1 " -"Returns a string that specifies how the path should be represented as a -"string +" Returns a string that specifies how the path should be represented as a +" string function! s:Path.displayString() if self.cachedDisplayString ==# "" call self.cacheDisplayString() @@ -262,14 +262,14 @@ function! s:Path.displayString() return self.cachedDisplayString endfunction -"FUNCTION: Path.edit() {{{1 +" FUNCTION: Path.edit() {{{1 function! s:Path.edit() exec "edit " . self.str({'format': 'Edit'}) endfunction -"FUNCTION: Path.extractDriveLetter(fullpath) {{{1 +" FUNCTION: Path.extractDriveLetter(fullpath) {{{1 " -"If running windows, cache the drive letter for this path +" If running windows, cache the drive letter for this path function! s:Path.extractDriveLetter(fullpath) if nerdtree#runningWindows() if a:fullpath =~ '^\(\\\\\|\/\/\)' @@ -285,14 +285,14 @@ function! s:Path.extractDriveLetter(fullpath) endfunction -"FUNCTION: Path.exists() {{{1 -"return 1 if this path points to a location that is readable or is a directory +" FUNCTION: Path.exists() {{{1 +" return 1 if this path points to a location that is readable or is a directory function! s:Path.exists() let p = self.str() return filereadable(p) || isdirectory(p) endfunction -"FUNCTION: Path._escChars() {{{1 +" FUNCTION: Path._escChars() {{{1 function! s:Path._escChars() if nerdtree#runningWindows() return " `\|\"#%&,?()\*^<>$" @@ -301,12 +301,12 @@ function! s:Path._escChars() return " \\`\|\"#%&,?()\*^<>[]$" endfunction -"FUNCTION: Path.getDir() {{{1 +" FUNCTION: Path.getDir() {{{1 " -"Returns this path if it is a directory, else this paths parent. +" Returns this path if it is a directory, else this paths parent. " -"Return: -"a Path object +" Return: +" a Path object function! s:Path.getDir() if self.isDirectory return self @@ -315,12 +315,12 @@ function! s:Path.getDir() endif endfunction -"FUNCTION: Path.getParent() {{{1 +" FUNCTION: Path.getParent() {{{1 " -"Returns a new path object for this paths parent +" Returns a new path object for this paths parent " -"Return: -"a new Path object +" Return: +" a new Path object function! s:Path.getParent() if nerdtree#runningWindows() let path = self.drive . '\' . join(self.pathSegments[0:-2], '\') @@ -331,13 +331,13 @@ function! s:Path.getParent() return s:Path.New(path) endfunction -"FUNCTION: Path.getLastPathComponent(dirSlash) {{{1 +" FUNCTION: Path.getLastPathComponent(dirSlash) {{{1 " -"Gets the last part of this path. +" 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. +" 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 '' @@ -349,8 +349,8 @@ function! s:Path.getLastPathComponent(dirSlash) return toReturn endfunction -"FUNCTION: Path.getSortOrderIndex() {{{1 -"returns the index of the pattern in g:NERDTreeSortOrder that this path matches +" 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) @@ -362,8 +362,8 @@ function! s:Path.getSortOrderIndex() return s:NERDTreeSortStarIndex endfunction -"FUNCTION: Path._splitChunks(path) {{{1 -"returns a list of path chunks +" FUNCTION: Path._splitChunks(path) {{{1 +" returns a list of path chunks function! s:Path._splitChunks(path) let chunks = split(a:path, '\(\D\+\|\d\+\)\zs') let i = 0 @@ -377,8 +377,8 @@ function! s:Path._splitChunks(path) return chunks endfunction -"FUNCTION: Path.getSortKey() {{{1 -"returns a key used in compare function for sorting +" FUNCTION: Path.getSortKey() {{{1 +" returns a key used in compare function for sorting function! s:Path.getSortKey() if !exists("self._sortKey") let path = self.getLastPathComponent(1) @@ -399,14 +399,14 @@ function! s:Path.getSortKey() endfunction -"FUNCTION: Path.isUnixHiddenFile() {{{1 -"check for unix hidden files +" 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: Path.isUnixHiddenPath() {{{1 +" check for unix path with hidden components function! s:Path.isUnixHiddenPath() if self.getLastPathComponent(0) =~# '^\.' return 1 @@ -420,8 +420,8 @@ function! s:Path.isUnixHiddenPath() endif endfunction -"FUNCTION: Path.ignore(nerdtree) {{{1 -"returns true if this path should be ignored +" 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() @@ -450,8 +450,8 @@ function! s:Path.ignore(nerdtree) return 0 endfunction -"FUNCTION: Path._ignorePatternMatches(pattern) {{{1 -"returns true if this path matches the given ignore pattern +" 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]]' @@ -469,10 +469,10 @@ function! s:Path._ignorePatternMatches(pattern) 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. +" 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 +" a:path should be a dir function! s:Path.isAncestor(path) if !self.isDirectory return 0 @@ -483,8 +483,8 @@ function! s:Path.isAncestor(path) 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: 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 @@ -495,7 +495,7 @@ function! s:Path.isUnder(path) return stridx(this, that . s:Path.Slash()) == 0 endfunction -"FUNCTION: Path.JoinPathStrings(...) {{{1 +" FUNCTION: Path.JoinPathStrings(...) {{{1 function! s:Path.JoinPathStrings(...) let components = [] for i in a:000 @@ -504,19 +504,19 @@ function! s:Path.JoinPathStrings(...) return '/' . join(components, '/') endfunction -"FUNCTION: Path.equals() {{{1 +" FUNCTION: Path.equals() {{{1 " -"Determines whether 2 path objects are "equal". -"They are equal if the paths they represent are the same +" 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 +" 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: Path.New() {{{1 +" The Constructor for the Path object function! s:Path.New(path) let newPath = copy(self) @@ -528,26 +528,26 @@ function! s:Path.New(path) return newPath endfunction -"FUNCTION: Path.Slash() {{{1 -"return the slash to use for the current OS +" 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: 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 +" FUNCTION: Path.readInfoFromDisk(fullpath) {{{1 " " -"Throws NERDTree.Path.InvalidArguments exception. +" Throws NERDTree.Path.InvalidArguments exception. function! s:Path.readInfoFromDisk(fullpath) call self.extractDriveLetter(a:fullpath) @@ -598,22 +598,22 @@ function! s:Path.readInfoFromDisk(fullpath) endif endfunction -"FUNCTION: Path.refresh(nerdtree) {{{1 +" 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: 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 +" FUNCTION: Path.rename() {{{1 " -"Renames this node on the filesystem +" Renames this node on the filesystem function! s:Path.rename(newPath) if a:newPath ==# '' throw "NERDTree.InvalidArgumentsError: Invalid newPath for renaming = ". a:newPath @@ -632,28 +632,28 @@ function! s:Path.rename(newPath) call g:NERDTreeBookmark.Write() endfunction -"FUNCTION: Path.str() {{{1 +" FUNCTION: Path.str() {{{1 " -"Returns a string representation of this Path +" Returns a string representation of this Path " -"Takes an optional dictionary param to specify how the output should be -"formatted. +" Takes an optional dictionary param to specify how the output should be +" formatted. " -"The dict may have the following keys: +" The dict may have the following keys: " 'format' " 'escape' " 'truncateTo' " -"The 'format' key may have a value of: +" 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 '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. +" 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 = "" @@ -688,7 +688,7 @@ function! s:Path.str(...) return toReturn endfunction -"FUNCTION: Path._strForUI() {{{1 +" FUNCTION: Path._strForUI() {{{1 function! s:Path._strForUI() let toReturn = '/' . join(self.pathSegments, '/') if self.isDirectory && toReturn != '/' @@ -697,17 +697,17 @@ function! s:Path._strForUI() return toReturn endfunction -"FUNCTION: Path._strForCd() {{{1 +" FUNCTION: Path._strForCd() {{{1 " " returns a string that can be used with :cd function! s:Path._strForCd() return escape(self.str(), self._escChars()) endfunction -"FUNCTION: Path._strForEdit() {{{1 +" FUNCTION: Path._strForEdit() {{{1 " -"Return: the string for this path that is suitable to be used with the :edit -"command +" Return: the string for this path that is suitable to be used with the :edit +" command function! s:Path._strForEdit() let p = escape(self.str(), self._escChars()) @@ -727,7 +727,7 @@ function! s:Path._strForEdit() return p endfunction -"FUNCTION: Path._strForGlob() {{{1 +" FUNCTION: Path._strForGlob() {{{1 function! s:Path._strForGlob() let lead = s:Path.Slash() @@ -744,10 +744,10 @@ function! s:Path._strForGlob() return toReturn endfunction -"FUNCTION: Path._str() {{{1 +" FUNCTION: Path._str() {{{1 " -"Gets the string path for this path object that is appropriate for the OS. -"EG, in windows c:\foo\bar +" Gets the string path for this path object that is appropriate for the OS. +" EG, in windows c:\foo\bar " in *nix /foo/bar function! s:Path._str() let lead = s:Path.Slash() @@ -760,8 +760,8 @@ function! s:Path._str() return lead . join(self.pathSegments, s:Path.Slash()) endfunction -"FUNCTION: Path.strTrunk() {{{1 -"Gets the path without the last segment on the end. +" FUNCTION: Path.strTrunk() {{{1 +" Gets the path without the last segment on the end. function! s:Path.strTrunk() return self.drive . '/' . join(self.pathSegments[0:-2], '/') endfunction @@ -782,13 +782,13 @@ function! s:Path.tabnr() return 0 endfunction -"FUNCTION: Path.WinToUnixPath(pathstr){{{1 -"Takes in a windows path and returns the unix equiv +" FUNCTION: Path.WinToUnixPath(pathstr){{{1 +" Takes in a windows path and returns the unix equiv " -"A class level method +" A class level method " -"Args: -"pathstr: the windows path to convert +" Args: +" pathstr: the windows path to convert function! s:Path.WinToUnixPath(pathstr) if !nerdtree#runningWindows() return a:pathstr From 1a121337dd1e8d7ec6c44c068cb147f4e9b896ef Mon Sep 17 00:00:00 2001 From: Jason Franklin Date: Fri, 11 Aug 2017 08:33:51 -0400 Subject: [PATCH 02/10] Clean up the script header in "path.vim" Some code was reorganized and comments were written/rewritten. --- lib/nerdtree/path.vim | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/nerdtree/path.vim b/lib/nerdtree/path.vim index 4d608c7..79dd483 100644 --- a/lib/nerdtree/path.vim +++ b/lib/nerdtree/path.vim @@ -1,9 +1,16 @@ -" we need to use this number many times for sorting... so we calculate it only -" once here -let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*') - +" ============================================================================ " CLASS: Path -" ============================================================ +" +" The Path class provides an abstracted representation of a file system +" pathname. Various operations on pathnames are provided and a number of +" representations of a given path name can be accessed here. +" ============================================================================ + + +" This constant is used throughout this script for sorting purposes. +let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*') +lockvar s:NERDTreeSortStarIndex + let s:Path = {} let g:NERDTreePath = s:Path From b5e54d255e8bc2369531e29b3eee46e4f9fb4f32 Mon Sep 17 00:00:00 2001 From: Jason Franklin Date: Fri, 11 Aug 2017 08:46:41 -0400 Subject: [PATCH 03/10] Rewrite the "Path._strForCd()" method This commit is the first in a series of commits that will rework some of the methods responsible for escaping pathnames. Some of these methods simply don't use the features that Vim has properly. The custom "Path._escChars()" method is far too rigid for our purposes, and better options have been available for some time. See ":h fnameescape()" for an especially helpful function in this effort. --- lib/nerdtree/path.vim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/nerdtree/path.vim b/lib/nerdtree/path.vim index 79dd483..9bd7793 100644 --- a/lib/nerdtree/path.vim +++ b/lib/nerdtree/path.vim @@ -705,10 +705,10 @@ function! s:Path._strForUI() endfunction " FUNCTION: Path._strForCd() {{{1 -" -" returns a string that can be used with :cd +" Return a string representation of this Path that is suitable for use as an +" argument to Vim's internal ":cd" command. function! s:Path._strForCd() - return escape(self.str(), self._escChars()) + return fnameescape(self.str()) endfunction " FUNCTION: Path._strForEdit() {{{1 From 72f9135d19cc4c4c4f9791176f93f76b0f182466 Mon Sep 17 00:00:00 2001 From: Jason Franklin Date: Fri, 11 Aug 2017 09:19:36 -0400 Subject: [PATCH 04/10] Clean up the commentary for two Path methods Especially note the improvements to the commentary on "Path.str()". This method does too much. However, it is used heavily, and changing its interface would be a major undertaking at this point. --- lib/nerdtree/path.vim | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/lib/nerdtree/path.vim b/lib/nerdtree/path.vim index 9bd7793..db40069 100644 --- a/lib/nerdtree/path.vim +++ b/lib/nerdtree/path.vim @@ -640,27 +640,27 @@ function! s:Path.rename(newPath) endfunction " FUNCTION: Path.str() {{{1 +" Return a string representation of this Path object. " -" Returns a string representation of this Path +" Args: +" This function takes a single dictionary (optional) with keys and values that +" specify how the returned pathname should be formatted. " -" Takes an optional dictionary param to specify how the output should be -" formatted. -" -" The dict may have the following keys: +" The dictionary 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 +" 'Cd' - a string to be used with ":cd" and similar commands +" 'Edit' - a string to be used with ":edit" and similar commands +" 'UI' - a string to be displayed in the NERDTree user interface " -" The 'escape' key, if specified will cause the output to be escaped with -" shellescape() +" The 'escape' key, if specified, will cause the output to be escaped with +" Vim's internal "shellescape()" function. " -" The 'truncateTo' key causes the resulting string to be truncated to the value -" 'truncateTo' maps to. A '<' char will be prepended. +" The 'truncateTo' key shortens the length of the path to that given by the +" value associated with 'truncateTo'. A '<' is prepended. function! s:Path.str(...) let options = a:0 ? a:1 : {} let toReturn = "" @@ -712,9 +712,8 @@ function! s:Path._strForCd() endfunction " FUNCTION: Path._strForEdit() {{{1 -" -" Return: the string for this path that is suitable to be used with the :edit -" command +" Return a string representation of this Path that is suitable for use as an +" argument to Vim's internal ":edit" command. function! s:Path._strForEdit() let p = escape(self.str(), self._escChars()) From 19b8dd7b60eb599d64e23c65f6aa6f9e50edbe18 Mon Sep 17 00:00:00 2001 From: Jason Franklin Date: Fri, 11 Aug 2017 09:32:01 -0400 Subject: [PATCH 05/10] Add a check for 'shellslash' in "Path.Slash()' Several issues (namely issue #733) report problems with using the NERDTree on Windows when 'shellslash' is set. This commit doesn't solve all of these problems, but it improves the NERDTree's recognition of this setting. --- lib/nerdtree/path.vim | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/nerdtree/path.vim b/lib/nerdtree/path.vim index db40069..1f33e65 100644 --- a/lib/nerdtree/path.vim +++ b/lib/nerdtree/path.vim @@ -536,9 +536,20 @@ function! s:Path.New(path) endfunction " FUNCTION: Path.Slash() {{{1 -" return the slash to use for the current OS +" Return the path separator used by the underlying file system. Special +" consideration is taken for the use of the 'shellslash' option on Windows +" systems. function! s:Path.Slash() - return nerdtree#runningWindows() ? '\' : '/' + + if nerdtree#runningWindows() + if exists('+shellslash') && &shellslash + return '/' + endif + + return '\' + endif + + return '/' endfunction " FUNCTION: Path.Resolve() {{{1 From 7a2fc6b6b94e8617a6f0ef14a5f1e789fc385213 Mon Sep 17 00:00:00 2001 From: Jason Franklin Date: Fri, 11 Aug 2017 09:43:57 -0400 Subject: [PATCH 06/10] Refactor the "Path._str()" method This method was using hardcoded values rather than provided abstractions to do its work. These improvements were necessary. --- lib/nerdtree/path.vim | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/nerdtree/path.vim b/lib/nerdtree/path.vim index 1f33e65..2082eb5 100644 --- a/lib/nerdtree/path.vim +++ b/lib/nerdtree/path.vim @@ -762,19 +762,17 @@ function! s:Path._strForGlob() endfunction " FUNCTION: Path._str() {{{1 -" -" Gets the string path for this path object that is appropriate for the OS. -" EG, in windows c:\foo\bar -" in *nix /foo/bar +" Return the absolute pathname associated with this Path object. The pathname +" returned is appropriate for the underlying file system. function! s:Path._str() - let lead = s:Path.Slash() + let l:separator = s:Path.Slash() + let l:leader = l:separator - "if we are running windows then slap a drive letter on the front if nerdtree#runningWindows() - let lead = self.drive . '\' + let l:leader = self.drive . l:separator endif - return lead . join(self.pathSegments, s:Path.Slash()) + return l:leader . join(self.pathSegments, l:separator) endfunction " FUNCTION: Path.strTrunk() {{{1 From a32a55e8d98413459aa309176501b97b3f8a350e Mon Sep 17 00:00:00 2001 From: Jason Franklin Date: Fri, 11 Aug 2017 10:09:18 -0400 Subject: [PATCH 07/10] Rewrite the "Path._strForEdit()" method This method used the brittle "Path._escChars()" method to do its work. This created problems when 'shellslash' was in use on Windows because excessive escape characters (i.e., backslashes!) are interpreted by Vim as additional path separators. The above problem made it impossible to edit files with weird names using the NERDTree on Windows with 'shellslash' set. For example, '+' should be escaped with ":edit", but '(' should not. So, when escaping '(', Vim on Windows correctly sees the start of a new directory in the path. This was reported in five issues which may be read for further details and commentary. Fixes #398, fixes #474, fixes #653, fixes #674, and fixes #733. --- lib/nerdtree/path.vim | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/nerdtree/path.vim b/lib/nerdtree/path.vim index 2082eb5..3e7c913 100644 --- a/lib/nerdtree/path.vim +++ b/lib/nerdtree/path.vim @@ -726,22 +726,23 @@ endfunction " Return a string representation of this Path that is suitable for use as an " argument to Vim's internal ":edit" command. function! s:Path._strForEdit() - let p = escape(self.str(), self._escChars()) - "make it relative - let p = fnamemodify(p, ':.') + " Make the path relative to the current working directory, if possible. + let l:result = fnamemodify(self.str(), ':.') - "handle the edge case where the file begins with a + (vim interprets - "the +foo in `:e +foo` as an option to :edit) - if p[0] == "+" - let p = '\' . p + " On Windows, the drive letter may be removed by "fnamemodify()". Add it + " back, if necessary. + if nerdtree#runningWindows() && l:result[0] == s:Path.Slash() + let l:result = self.drive . l:result endif - if p ==# '' - let p = '.' + let l:result = fnameescape(l:result) + + if empty(l:result) + let l:result = '.' endif - return p + return l:result endfunction " FUNCTION: Path._strForGlob() {{{1 From d7cf9a2a9802f580c988f69f129ab7b187debb4c Mon Sep 17 00:00:00 2001 From: Jason Franklin Date: Fri, 11 Aug 2017 10:13:12 -0400 Subject: [PATCH 08/10] Fix the drive check in "TreeDirNode._glob()" This check did not use the proper abstract method to check for a path separator. It now does. This fixes a problem with the 'u' macro that I noticed while working on the fix for using the NERDTree with 'shellslash'. --- lib/nerdtree/tree_dir_node.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nerdtree/tree_dir_node.vim b/lib/nerdtree/tree_dir_node.vim index 4a6d213..62bcf88 100644 --- a/lib/nerdtree/tree_dir_node.vim +++ b/lib/nerdtree/tree_dir_node.vim @@ -243,7 +243,7 @@ function! s:TreeDirNode._glob(pattern, all) let l:pathSpec = fnamemodify(self.path.str({'format': 'Glob'}), ':.') " On Windows, the drive letter may be removed by "fnamemodify()". - if nerdtree#runningWindows() && l:pathSpec[0] == '\' + if nerdtree#runningWindows() && l:pathSpec[0] == g:NERDTreePath.Slash() let l:pathSpec = self.path.drive . l:pathSpec endif endif From f4ff6dcf84bff73e6cc0e49410e28d0fb65ad73a Mon Sep 17 00:00:00 2001 From: Jason Franklin Date: Sat, 19 Aug 2017 08:58:57 -0400 Subject: [PATCH 09/10] Fix a menu command that breaks under 'shellslash' The (l) menu command breaks on Windows systems when 'shellslash' is set. This is due to the fact that the menu item uses a hard coded shell command, thus relying on the use of the default Windows shell without the 'shellslash' setting. The pattern used for the fix is localized to the problem function. However, this technique could easily be abstracted into its own function to execute Windows shell commands with the default shell throughout the NERDTree codebase. --- nerdtree_plugin/fs_menu.vim | 38 +++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/nerdtree_plugin/fs_menu.vim b/nerdtree_plugin/fs_menu.vim index e563a94..e42942c 100644 --- a/nerdtree_plugin/fs_menu.vim +++ b/nerdtree_plugin/fs_menu.vim @@ -212,14 +212,40 @@ endfunction " FUNCTION: NERDTreeListNodeWin32() {{{1 function! NERDTreeListNodeWin32() - let treenode = g:NERDTreeFileNode.GetSelected() - if treenode != {} - let metadata = split(system('DIR /Q ' . shellescape(treenode.path.str()) . ' | FINDSTR "^[012][0-9]/[0-3][0-9]/[12][0-9][0-9][0-9]"'), '\n') - call nerdtree#echo(metadata[0]) - else - call nerdtree#echo("No information avaialable") + let l:node = g:NERDTreeFileNode.GetSelected() + + if !empty(l:node) + + let l:save_shell = &shell + set shell& + + if exists('+shellslash') + let l:save_shellslash = &shellslash + set noshellslash + endif + + let l:command = 'DIR /Q ' + \ . shellescape(l:node.path.str()) + \ . ' | FINDSTR "^[012][0-9]/[0-3][0-9]/[12][0-9][0-9][0-9]"' + + let l:metadata = systemlist(l:command) + + if v:shell_error == 0 + call nerdtree#echo(l:metadata[0]) + else + call nerdtree#echoError('shell command failed') + endif + + let &shell = l:save_shell + + if exists('+shellslash') + let &shellslash = l:save_shellslash + endif + + return endif + call nerdtree#echo('node not recognized') endfunction " FUNCTION: NERDTreeCopyNode() {{{1 From 876283b07cadba4f607ae34430b3e08db7a42365 Mon Sep 17 00:00:00 2001 From: Jason Franklin Date: Sat, 19 Aug 2017 09:29:46 -0400 Subject: [PATCH 10/10] Improve display of shell output from menu command This small change reverts to the previous method of breaking shell output into lines. The reason for this is to avoid the printing of trailing carriage return characters on Windows. --- nerdtree_plugin/fs_menu.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nerdtree_plugin/fs_menu.vim b/nerdtree_plugin/fs_menu.vim index e42942c..bdb638e 100644 --- a/nerdtree_plugin/fs_menu.vim +++ b/nerdtree_plugin/fs_menu.vim @@ -228,7 +228,7 @@ function! NERDTreeListNodeWin32() \ . shellescape(l:node.path.str()) \ . ' | FINDSTR "^[012][0-9]/[0-3][0-9]/[12][0-9][0-9][0-9]"' - let l:metadata = systemlist(l:command) + let l:metadata = split(system(l:command), "\n") if v:shell_error == 0 call nerdtree#echo(l:metadata[0]) @@ -238,7 +238,7 @@ function! NERDTreeListNodeWin32() let &shell = l:save_shell - if exists('+shellslash') + if exists('l:save_shellslash') let &shellslash = l:save_shellslash endif