summaryrefslogtreecommitdiff
path: root/.vim/pack/vendor/start/nerdtree/lib
diff options
context:
space:
mode:
authorSam Chudnick <sam@chudnick.com>2023-06-11 07:54:59 -0400
committerSam Chudnick <sam@chudnick.com>2023-06-11 07:54:59 -0400
commit3adcf542289a0883924ae9b9be8b898c36702c95 (patch)
treef02166ef4c95161ffa994eb1a3e5729c93c2c66b /.vim/pack/vendor/start/nerdtree/lib
parentdfcc303e7cc284a45f55bae81ed888dc256432b8 (diff)
Add some Vim plugins
Diffstat (limited to '.vim/pack/vendor/start/nerdtree/lib')
-rw-r--r--.vim/pack/vendor/start/nerdtree/lib/nerdtree/bookmark.vim365
-rw-r--r--.vim/pack/vendor/start/nerdtree/lib/nerdtree/creator.vim402
-rw-r--r--.vim/pack/vendor/start/nerdtree/lib/nerdtree/event.vim13
-rw-r--r--.vim/pack/vendor/start/nerdtree/lib/nerdtree/flag_set.vim58
-rw-r--r--.vim/pack/vendor/start/nerdtree/lib/nerdtree/key_map.vim164
-rw-r--r--.vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_controller.vim211
-rw-r--r--.vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_item.vim118
-rw-r--r--.vim/pack/vendor/start/nerdtree/lib/nerdtree/nerdtree.vim209
-rw-r--r--.vim/pack/vendor/start/nerdtree/lib/nerdtree/notifier.vim35
-rw-r--r--.vim/pack/vendor/start/nerdtree/lib/nerdtree/opener.vim326
-rw-r--r--.vim/pack/vendor/start/nerdtree/lib/nerdtree/path.vim852
-rw-r--r--.vim/pack/vendor/start/nerdtree/lib/nerdtree/tree_dir_node.vim706
-rw-r--r--.vim/pack/vendor/start/nerdtree/lib/nerdtree/tree_file_node.vim349
-rw-r--r--.vim/pack/vendor/start/nerdtree/lib/nerdtree/ui.vim532
14 files changed, 4340 insertions, 0 deletions
diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/bookmark.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/bookmark.vim
new file mode 100644
index 0000000..37be451
--- /dev/null
+++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/bookmark.vim
@@ -0,0 +1,365 @@
1" ============================================================================
2" CLASS: Bookmark
3"
4" The Bookmark class serves two purposes:
5" (1) It is the top-level prototype for new, concrete Bookmark objects.
6" (2) It provides an interface for client code to query and manipulate the
7" global list of Bookmark objects within the current Vim session.
8" ============================================================================
9
10
11let s:Bookmark = {}
12let g:NERDTreeBookmark = s:Bookmark
13
14" FUNCTION: Bookmark.activate(nerdtree) {{{1
15function! s:Bookmark.activate(nerdtree, ...)
16 call self.open(a:nerdtree, a:0 ? a:1 : {})
17endfunction
18
19" FUNCTION: Bookmark.AddBookmark(name, path) {{{1
20" Class method to add a new bookmark to the list, if a previous bookmark exists
21" with the same name, just update the path for that bookmark
22function! s:Bookmark.AddBookmark(name, path)
23 for i in s:Bookmark.Bookmarks()
24 if i.name ==# a:name
25 let i.path = a:path
26 return
27 endif
28 endfor
29 call add(s:Bookmark.Bookmarks(), s:Bookmark.New(a:name, a:path))
30endfunction
31
32" FUNCTION: Bookmark.Bookmarks() {{{1
33" Class method to get all bookmarks. Lazily initializes the bookmarks global
34" variable
35function! s:Bookmark.Bookmarks()
36 if !exists('g:NERDTreeBookmarks')
37 let g:NERDTreeBookmarks = []
38 endif
39 return g:NERDTreeBookmarks
40endfunction
41
42" FUNCTION: Bookmark.BookmarkExistsFor(name) {{{1
43" class method that returns 1 if a bookmark with the given name is found, 0
44" otherwise
45function! s:Bookmark.BookmarkExistsFor(name)
46 try
47 call s:Bookmark.BookmarkFor(a:name)
48 return 1
49 catch /^NERDTree.BookmarkNotFoundError/
50 return 0
51 endtry
52endfunction
53
54" FUNCTION: Bookmark.BookmarkFor(name) {{{1
55" Class method that returns the Bookmark object having the specified name.
56" Throws NERDTree.BookmarkNotFoundError if no Bookmark is found.
57function! s:Bookmark.BookmarkFor(name)
58 let l:result = {}
59 for l:bookmark in s:Bookmark.Bookmarks()
60 if l:bookmark.name ==# a:name
61 let l:result = l:bookmark
62 break
63 endif
64 endfor
65 if empty(l:result)
66 throw 'NERDTree.BookmarkNotFoundError: "' . a:name . '" not found'
67 endif
68 return l:result
69endfunction
70
71" FUNCTION: Bookmark.BookmarkNames() {{{1
72" Class method to return an array of all bookmark names
73function! s:Bookmark.BookmarkNames()
74 let names = []
75 for i in s:Bookmark.Bookmarks()
76 call add(names, i.name)
77 endfor
78 return names
79endfunction
80
81" FUNCTION: Bookmark.CacheBookmarks(silent) {{{1
82" Class method to read all bookmarks from the bookmarks file initialize
83" bookmark objects for each one.
84"
85" Args:
86" silent - dont echo an error msg if invalid bookmarks are found
87function! s:Bookmark.CacheBookmarks(silent)
88 if filereadable(g:NERDTreeBookmarksFile)
89 let g:NERDTreeBookmarks = []
90 let g:NERDTreeInvalidBookmarks = []
91 let bookmarkStrings = readfile(g:NERDTreeBookmarksFile)
92 let invalidBookmarksFound = 0
93 for i in bookmarkStrings
94
95 "ignore blank lines
96 if i !=# ''
97
98 let name = substitute(i, '^\(.\{-}\) .*$', '\1', '')
99 let path = substitute(i, '^.\{-} \(.*\)$', '\1', '')
100 let path = fnamemodify(path, ':p')
101
102 try
103 let bookmark = s:Bookmark.New(name, g:NERDTreePath.New(path))
104 call add(g:NERDTreeBookmarks, bookmark)
105 catch /^NERDTree.InvalidArgumentsError/
106 call add(g:NERDTreeInvalidBookmarks, i)
107 let invalidBookmarksFound += 1
108 endtry
109 endif
110 endfor
111 if invalidBookmarksFound
112 call s:Bookmark.Write()
113 if !a:silent
114 call nerdtree#echo(invalidBookmarksFound . ' invalid bookmarks were read. See :help NERDTreeInvalidBookmarks for info.')
115 endif
116 endif
117 endif
118endfunction
119
120" FUNCTION: Bookmark.CompareBookmarksByName(firstBookmark, secondBookmark) {{{1
121" Class method that indicates the relative position of two bookmarks when
122" placed in alphabetical order by name. Case-sensitivity is determined by an
123" option. Supports the s:Bookmark.SortBookmarksList() method.
124function! s:Bookmark.CompareBookmarksByName(firstBookmark, secondBookmark)
125 let l:result = 0
126 if g:NERDTreeBookmarksSort ==# 1
127 if a:firstBookmark.name <? a:secondBookmark.name
128 let l:result = -1
129 elseif a:firstBookmark.name >? a:secondBookmark.name
130 let l:result = 1
131 endif
132 elseif g:NERDTreeBookmarksSort ==# 2
133 if a:firstBookmark.name <# a:secondBookmark.name
134 let l:result = -1
135 elseif a:firstBookmark.name ># a:secondBookmark.name
136 let l:result = 1
137 endif
138 endif
139 return l:result
140endfunction
141
142" FUNCTION: Bookmark.ClearAll() {{{1
143" Class method to delete all bookmarks.
144function! s:Bookmark.ClearAll()
145 for i in s:Bookmark.Bookmarks()
146 call i.delete()
147 endfor
148 call s:Bookmark.Write()
149endfunction
150
151" FUNCTION: Bookmark.delete() {{{1
152" Delete this bookmark. If the node for this bookmark is under the current
153" root, then recache bookmarks for its Path object
154function! s:Bookmark.delete()
155 call remove(s:Bookmark.Bookmarks(), index(s:Bookmark.Bookmarks(), self))
156 call s:Bookmark.Write()
157endfunction
158
159" FUNCTION: s:Edit() {{{1
160" opens the NERDTreeBookmarks file for manual editing
161function! s:Bookmark.Edit()
162 call nerdtree#exec('wincmd w', 1)
163 call nerdtree#exec('edit '.g:NERDTreeBookmarksFile, 1)
164endfunction
165
166" FUNCTION: Bookmark.getNode(nerdtree, searchFromAbsoluteRoot) {{{1
167" Returns the tree node object associated with this Bookmark.
168" Throws NERDTree.BookmarkedNodeNotFoundError if the node is not found.
169"
170" Args:
171" searchFromAbsoluteRoot: boolean flag, search from the highest cached node
172" if true and from the current tree root if false
173function! s:Bookmark.getNode(nerdtree, searchFromAbsoluteRoot)
174 if a:searchFromAbsoluteRoot
175 let l:searchRoot = a:nerdtree.root.AbsoluteTreeRoot()
176 else
177 let l:searchRoot = a:nerdtree.root
178 endif
179 let l:targetNode = l:searchRoot.findNode(self.path)
180 if empty(l:targetNode)
181 throw 'NERDTree.BookmarkedNodeNotFoundError: node for bookmark "' . self.name . '" not found'
182 endif
183 return l:targetNode
184endfunction
185
186" FUNCTION: Bookmark.GetNodeForName(name, searchFromAbsoluteRoot, nerdtree) {{{1
187" Class method that returns the tree node object for the Bookmark with the
188" given name. Throws NERDTree.BookmarkNotFoundError if a Bookmark with the
189" name does not exist. Throws NERDTree.BookmarkedNodeNotFoundError if a
190" tree node for the named Bookmark could not be found.
191function! s:Bookmark.GetNodeForName(name, searchFromAbsoluteRoot, nerdtree)
192 let l:bookmark = s:Bookmark.BookmarkFor(a:name)
193 return l:bookmark.getNode(a:nerdtree, a:searchFromAbsoluteRoot)
194endfunction
195
196" FUNCTION: Bookmark.GetSelected() {{{1
197" returns the Bookmark the cursor is over, or {}
198function! s:Bookmark.GetSelected()
199 let line = getline('.')
200 let name = substitute(line, '^>\(.\{-}\) .\+$', '\1', '')
201 if name !=# line
202 try
203 return s:Bookmark.BookmarkFor(name)
204 catch /^NERDTree.BookmarkNotFoundError/
205 return {}
206 endtry
207 endif
208 return {}
209endfunction
210
211" FUNCTION: Bookmark.InvalidBookmarks() {{{1
212" Class method to get all invalid bookmark strings read from the bookmarks
213" file
214function! s:Bookmark.InvalidBookmarks()
215 if !exists('g:NERDTreeInvalidBookmarks')
216 let g:NERDTreeInvalidBookmarks = []
217 endif
218 return g:NERDTreeInvalidBookmarks
219endfunction
220
221" FUNCTION: Bookmark.mustExist() {{{1
222function! s:Bookmark.mustExist()
223 if !self.path.exists()
224 call s:Bookmark.CacheBookmarks(1)
225 throw 'NERDTree.BookmarkPointsToInvalidLocationError: the bookmark "'.
226 \ self.name .'" points to a non existing location: "'. self.path.str()
227 endif
228endfunction
229
230" FUNCTION: Bookmark.New(name, path) {{{1
231" Create a new bookmark object with the given name and path object
232function! s:Bookmark.New(name, path)
233 if a:name =~# ' '
234 throw 'NERDTree.IllegalBookmarkNameError: illegal name:' . a:name
235 endif
236
237 let newBookmark = copy(self)
238 let newBookmark.name = a:name
239 let newBookmark.path = a:path
240 return newBookmark
241endfunction
242
243" FUNCTION: Bookmark.open(nerdtree, [options]) {{{1
244"Args:
245"
246"nerdtree: the tree to load open the bookmark in
247"
248"A dictionary containing the following keys (all optional):
249" 'where': Specifies whether the node should be opened in new split/tab or in
250" the previous window. Can be either 'v' (vertical split), 'h'
251" (horizontal split), 't' (new tab) or 'p' (previous window).
252" 'reuse': if a window is displaying the file then jump the cursor there
253" 'keepopen': dont close the tree window
254" 'stay': open the file, but keep the cursor in the tree win
255"
256function! s:Bookmark.open(nerdtree, ...)
257 let opts = a:0 ? a:1 : {}
258
259 if nerdtree#closeBookmarksOnOpen()
260 call a:nerdtree.ui.toggleShowBookmarks()
261 endif
262
263 if self.path.isDirectory && !has_key(opts, 'where')
264 call self.toRoot(a:nerdtree)
265 else
266 let opener = g:NERDTreeOpener.New(self.path, opts)
267 call opener.open(self)
268 endif
269endfunction
270
271" FUNCTION: Bookmark.openInNewTab(options) {{{1
272" Create a new bookmark object with the given name and path object
273function! s:Bookmark.openInNewTab(options)
274 call nerdtree#deprecated('Bookmark.openInNewTab', 'is deprecated, use open() instead')
275 call self.open(a:options)
276endfunction
277
278" FUNCTION: Bookmark.setPath(path) {{{1
279" makes this bookmark point to the given path
280function! s:Bookmark.setPath(path)
281 let self.path = a:path
282endfunction
283
284" FUNCTION: Bookmark.SortBookmarksList() {{{1
285" Class method that sorts the global list of bookmarks alphabetically by name.
286" Note that case-sensitivity is determined by a user option.
287function! s:Bookmark.SortBookmarksList()
288 call sort(s:Bookmark.Bookmarks(), s:Bookmark.CompareBookmarksByName, s:Bookmark)
289endfunction
290
291" FUNCTION: Bookmark.str() {{{1
292" Get the string that should be rendered in the view for this bookmark
293function! s:Bookmark.str()
294 let pathStrMaxLen = winwidth(g:NERDTree.GetWinNum()) - 4 - strdisplaywidth(self.name)
295 if &number
296 let pathStrMaxLen = pathStrMaxLen - &numberwidth
297 endif
298
299 let pathStr = self.path.str({'format': 'UI'})
300 if strdisplaywidth(pathStr) > pathStrMaxLen
301 while strdisplaywidth(pathStr) > pathStrMaxLen && strchars(pathStr) > 0
302 let pathStr = substitute(pathStr, '^.', '', '')
303 endwhile
304 let pathStr = '<' . pathStr
305 endif
306 return '>' . self.name . ' ' . pathStr
307endfunction
308
309" FUNCTION: Bookmark.toRoot(nerdtree) {{{1
310" Set the root of the given NERDTree to the node for this Bookmark. If a node
311" for this Bookmark does not exist, a new one is initialized.
312function! s:Bookmark.toRoot(nerdtree)
313 if self.validate()
314 try
315 let l:targetNode = self.getNode(a:nerdtree, 1)
316 call l:targetNode.closeChildren()
317 catch /^NERDTree.BookmarkedNodeNotFoundError/
318 let l:targetNode = g:NERDTreeFileNode.New(s:Bookmark.BookmarkFor(self.name).path, a:nerdtree)
319 endtry
320 call a:nerdtree.changeRoot(l:targetNode)
321 endif
322endfunction
323
324" FUNCTION: Bookmark.ToRoot(name, nerdtree) {{{1
325" Class method that makes the Bookmark with the given name the root of
326" specified NERDTree.
327function! s:Bookmark.ToRoot(name, nerdtree)
328 let l:bookmark = s:Bookmark.BookmarkFor(a:name)
329 call l:bookmark.toRoot(a:nerdtree)
330endfunction
331
332" FUNCTION: Bookmark.validate() {{{1
333function! s:Bookmark.validate()
334 if self.path.exists()
335 return 1
336 else
337 call s:Bookmark.CacheBookmarks(1)
338 call nerdtree#echo(self.name . 'now points to an invalid location. See :help NERDTreeInvalidBookmarks for info.')
339 return 0
340 endif
341endfunction
342
343" FUNCTION: Bookmark.Write() {{{1
344" Class method to write all bookmarks to the bookmarks file
345function! s:Bookmark.Write()
346 let bookmarkStrings = []
347 for i in s:Bookmark.Bookmarks()
348 call add(bookmarkStrings, i.name . ' ' . fnamemodify(i.path.str(), ':~'))
349 endfor
350
351 "add a blank line before the invalid ones
352 call add(bookmarkStrings, '')
353
354 for j in s:Bookmark.InvalidBookmarks()
355 call add(bookmarkStrings, j)
356 endfor
357
358 try
359 call writefile(bookmarkStrings, g:NERDTreeBookmarksFile)
360 catch
361 call nerdtree#echoError('Failed to write bookmarks file. Make sure g:NERDTreeBookmarksFile points to a valid location.')
362 endtry
363endfunction
364
365" vim: set sw=4 sts=4 et fdm=marker:
diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/creator.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/creator.vim
new file mode 100644
index 0000000..b9d45dc
--- /dev/null
+++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/creator.vim
@@ -0,0 +1,402 @@
1" ============================================================================
2" CLASS: Creator
3"
4" This class is responsible for creating NERDTree instances. The new NERDTree
5" may be a tab tree, a window tree, or a mirrored tree. In the process of
6" creating a NERDTree, it sets up all of the window and buffer options and key
7" mappings etc.
8" ============================================================================
9
10
11let s:Creator = {}
12let g:NERDTreeCreator = s:Creator
13
14" FUNCTION: s:Creator._bindMappings() {{{1
15function! s:Creator._bindMappings()
16 call g:NERDTreeKeyMap.BindAll()
17
18 command! -buffer -nargs=? Bookmark :call nerdtree#ui_glue#bookmarkNode('<args>')
19 command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=1 RevealBookmark :call nerdtree#ui_glue#revealBookmark('<args>')
20 command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=1 OpenBookmark call nerdtree#ui_glue#openBookmark('<args>')
21 command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=* ClearBookmarks call nerdtree#ui_glue#clearBookmarks('<args>')
22 command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=+ BookmarkToRoot call g:NERDTreeBookmark.ToRoot('<args>', b:NERDTree)
23 command! -buffer -nargs=0 ClearAllBookmarks call g:NERDTreeBookmark.ClearAll() <bar> call b:NERDTree.render()
24 command! -buffer -nargs=0 ReadBookmarks call g:NERDTreeBookmark.CacheBookmarks(0) <bar> call b:NERDTree.render()
25 command! -buffer -nargs=0 WriteBookmarks call g:NERDTreeBookmark.Write()
26 command! -buffer -nargs=0 EditBookmarks call g:NERDTreeBookmark.Edit()
27endfunction
28
29" FUNCTION: s:Creator._broadcastInitEvent() {{{1
30function! s:Creator._broadcastInitEvent()
31 if exists('#User#NERDTreeInit')
32 doautocmd User NERDTreeInit
33 endif
34endfunction
35
36" FUNCTION: s:Creator.BufNamePrefix() {{{1
37function! s:Creator.BufNamePrefix()
38 return 'NERD_tree_'
39endfunction
40
41" FUNCTION: s:Creator.CreateTabTree(a:name) {{{1
42function! s:Creator.CreateTabTree(name)
43 let creator = s:Creator.New()
44 call creator.createTabTree(a:name)
45endfunction
46
47" FUNCTION: s:Creator.createTabTree(a:name) {{{1
48" name: the name of a bookmark or a directory
49function! s:Creator.createTabTree(name)
50 let l:path = self._pathForString(a:name)
51
52 " Abort if an exception was thrown (i.e., if the bookmark or directory
53 " does not exist).
54 if empty(l:path)
55 return
56 endif
57
58 " Obey the user's preferences for changing the working directory.
59 if g:NERDTreeChDirMode != 0
60 call l:path.changeToDir()
61 endif
62
63 if g:NERDTree.ExistsForTab()
64 call g:NERDTree.Close()
65 call self._removeTreeBufForTab()
66 endif
67
68 call self._createTreeWin()
69 call self._createNERDTree(l:path, 'tab')
70 call b:NERDTree.render()
71 call b:NERDTree.root.putCursorHere(0, 0)
72
73 call self._broadcastInitEvent()
74endfunction
75
76" FUNCTION: s:Creator.CreateWindowTree(dir) {{{1
77function! s:Creator.CreateWindowTree(dir)
78 let creator = s:Creator.New()
79 call creator.createWindowTree(a:dir)
80endfunction
81
82" FUNCTION: s:Creator.createWindowTree(dir) {{{1
83function! s:Creator.createWindowTree(dir)
84 try
85 let path = g:NERDTreePath.New(a:dir)
86 catch /^NERDTree.InvalidArgumentsError/
87 call nerdtree#echo('Invalid directory name:' . a:dir)
88 return
89 endtry
90
91 "we want the directory buffer to disappear when we do the :edit below
92 setlocal bufhidden=wipe
93
94 let previousBuf = expand('#')
95
96 "we need a unique name for each window tree buffer to ensure they are
97 "all independent
98 exec g:NERDTreeCreatePrefix . ' edit ' . self._nextBufferName()
99
100 call self._createNERDTree(path, 'window')
101 let b:NERDTree._previousBuf = bufnr(previousBuf)
102 call self._setCommonBufOptions()
103
104 call b:NERDTree.render()
105
106 call self._broadcastInitEvent()
107endfunction
108
109" FUNCTION: s:Creator._createNERDTree(path) {{{1
110function! s:Creator._createNERDTree(path, type)
111 let b:NERDTree = g:NERDTree.New(a:path, a:type)
112
113 " TODO: This assignment is kept for compatibility reasons. Many other
114 " plugins use b:NERDTreeRoot instead of b:NERDTree.root. Remove this
115 " assignment in the future.
116 let b:NERDTreeRoot = b:NERDTree.root
117
118 call b:NERDTree.root.open()
119endfunction
120
121" FUNCTION: s:Creator.CreateMirror() {{{1
122function! s:Creator.CreateMirror()
123 let creator = s:Creator.New()
124 call creator.createMirror()
125endfunction
126
127" FUNCTION: s:Creator.createMirror() {{{1
128function! s:Creator.createMirror()
129 "get the names off all the nerd tree buffers
130 let treeBufNames = []
131 for i in range(1, tabpagenr('$'))
132 let nextName = self._tabpagevar(i, 'NERDTreeBufName')
133 if nextName != -1 && (!exists('t:NERDTreeBufName') || nextName != t:NERDTreeBufName)
134 call add(treeBufNames, nextName)
135 endif
136 endfor
137 let treeBufNames = self._uniq(treeBufNames)
138
139 "map the option names (that the user will be prompted with) to the nerd
140 "tree buffer names
141 let options = {}
142 let i = 0
143 while i < len(treeBufNames)
144 let bufName = treeBufNames[i]
145 let treeRoot = getbufvar(bufName, 'NERDTree').root
146 let options[i+1 . '. ' . treeRoot.path.str() . ' (buf name: ' . bufName . ')'] = bufName
147 let i = i + 1
148 endwhile
149
150 "work out which tree to mirror, if there is more than 1 then ask the user
151 let bufferName = ''
152 if len(keys(options)) > 1
153 let choices = ['Choose a tree to mirror']
154 let choices = extend(choices, sort(keys(options)))
155 let choice = inputlist(choices)
156 if choice < 1 || choice > len(options) || choice ==# ''
157 return
158 endif
159
160 let bufferName = options[sort(keys(options))[choice-1]]
161 elseif len(keys(options)) ==# 1
162 let bufferName = values(options)[0]
163 else
164 call nerdtree#echo('No trees to mirror')
165 return
166 endif
167
168 if g:NERDTree.ExistsForTab() && g:NERDTree.IsOpen()
169 call g:NERDTree.Close()
170 endif
171
172 let t:NERDTreeBufName = bufferName
173 call self._createTreeWin()
174 exec 'buffer ' . bufferName
175 call b:NERDTree.ui.restoreScreenState()
176 if !&hidden
177 call b:NERDTree.render()
178 endif
179endfunction
180
181" FUNCTION: s:Creator._createTreeWin() {{{1
182" Initialize the NERDTree window. Open the window, size it properly, set all
183" local options, etc.
184function! s:Creator._createTreeWin()
185 let l:splitLocation = g:NERDTreeWinPos ==# 'left' ? 'topleft ' : 'botright '
186 let l:splitSize = g:NERDTreeWinSize
187
188 if !g:NERDTree.ExistsForTab()
189 let t:NERDTreeBufName = self._nextBufferName()
190 silent! execute l:splitLocation . 'vertical ' . l:splitSize . ' new'
191 silent! execute 'edit ' . t:NERDTreeBufName
192 silent! execute 'vertical resize '. l:splitSize
193 else
194 silent! execute l:splitLocation . 'vertical ' . l:splitSize . ' split'
195 silent! execute 'buffer ' . t:NERDTreeBufName
196 endif
197
198 setlocal winfixwidth
199
200 call self._setCommonBufOptions()
201
202 if has('patch-7.4.1925')
203 clearjumps
204 endif
205
206endfunction
207
208" FUNCTION: s:Creator._isBufHidden(nr) {{{1
209function! s:Creator._isBufHidden(nr)
210 redir => bufs
211 silent ls!
212 redir END
213
214 return bufs =~ a:nr . '..h'
215endfunction
216
217" FUNCTION: s:Creator.New() {{{1
218function! s:Creator.New()
219 let newCreator = copy(self)
220 return newCreator
221endfunction
222
223" FUNCTION: s:Creator._nextBufferName() {{{1
224" returns the buffer name for the next nerd tree
225function! s:Creator._nextBufferName()
226 let name = s:Creator.BufNamePrefix() . self._nextBufferNumber()
227 return name
228endfunction
229
230" FUNCTION: s:Creator._nextBufferNumber() {{{1
231" the number to add to the nerd tree buffer name to make the buf name unique
232function! s:Creator._nextBufferNumber()
233 if !exists('s:Creator._NextBufNum')
234 let s:Creator._NextBufNum = 1
235 else
236 let s:Creator._NextBufNum += 1
237 endif
238
239 return s:Creator._NextBufNum
240endfunction
241
242" FUNCTION: s:Creator._pathForString(str) {{{1
243" find a bookmark or adirectory for the given string
244function! s:Creator._pathForString(str)
245 let path = {}
246 if g:NERDTreeBookmark.BookmarkExistsFor(a:str)
247 let path = g:NERDTreeBookmark.BookmarkFor(a:str).path
248 else
249 let dir = a:str ==# '' ? getcwd() : a:str
250
251 "hack to get an absolute path if a relative path is given
252 if dir =~# '^\.'
253 let dir = getcwd() . nerdtree#slash() . dir
254 endif
255
256 "hack to prevent removing slash if dir is the root of the file system.
257 if dir !=# '/'
258 let dir = g:NERDTreePath.Resolve(dir)
259 endif
260
261 try
262 let path = g:NERDTreePath.New(dir)
263 catch /^NERDTree.InvalidArgumentsError/
264 call nerdtree#echo('No bookmark or directory found for: ' . a:str)
265 return {}
266 endtry
267 endif
268 if !path.isDirectory
269 let path = path.getParent()
270 endif
271
272 return path
273endfunction
274
275" Function: s:Creator._removeTreeBufForTab() {{{1
276function! s:Creator._removeTreeBufForTab()
277 let buf = bufnr(t:NERDTreeBufName)
278
279 "if &hidden is not set then it will already be gone
280 if buf != -1
281
282 "nerdtree buf may be mirrored/displayed elsewhere
283 if self._isBufHidden(buf)
284 exec 'bwipeout ' . buf
285 endif
286
287 endif
288
289 unlet t:NERDTreeBufName
290endfunction
291
292" FUNCTION: s:Creator._setCommonBufOptions() {{{1
293function! s:Creator._setCommonBufOptions()
294
295 " Options for a non-file/control buffer.
296 setlocal bufhidden=hide
297 setlocal buftype=nofile
298 setlocal noswapfile
299
300 " Options for controlling buffer/window appearance.
301 setlocal foldcolumn=0
302 setlocal foldmethod=manual
303 setlocal nobuflisted
304 setlocal nofoldenable
305 setlocal nolist
306 setlocal nospell
307 setlocal nowrap
308
309 if g:NERDTreeShowLineNumbers
310 setlocal number
311 else
312 setlocal nonumber
313 if v:version >= 703
314 setlocal norelativenumber
315 endif
316 endif
317
318 iabc <buffer>
319
320 if g:NERDTreeHighlightCursorline
321 setlocal cursorline
322 endif
323
324 call self._setupStatusline()
325 call self._bindMappings()
326
327 setlocal filetype=nerdtree
328endfunction
329
330" FUNCTION: s:Creator._setupStatusline() {{{1
331function! s:Creator._setupStatusline()
332 if g:NERDTreeStatusline != -1
333 let &l:statusline = g:NERDTreeStatusline
334 endif
335endfunction
336
337" FUNCTION: s:Creator._tabpagevar(tabnr, var) {{{1
338function! s:Creator._tabpagevar(tabnr, var)
339 let currentTab = tabpagenr()
340 let old_ei = &eventignore
341 set eventignore=all
342
343 try
344 exec 'tabnext ' . a:tabnr
345 let v = -1
346 if exists('t:' . a:var)
347 exec 'let v = t:' . a:var
348 endif
349 exec 'tabnext ' . currentTab
350
351 finally
352 let &eventignore = old_ei
353 endtry
354
355 return v
356endfunction
357
358" FUNCTION: s:Creator.ToggleTabTree(dir) {{{1
359function! s:Creator.ToggleTabTree(dir)
360 let creator = s:Creator.New()
361 call creator.toggleTabTree(a:dir)
362endfunction
363
364" FUNCTION: s:Creator.toggleTabTree(dir) {{{1
365" Toggles the NERD tree. I.e if the NERD tree is open, it is closed. If it is
366" closed, it is restored or initialized. If dir is not empty, it will be set
367" as the new root.
368"
369" Args:
370" dir: the full path for the root node (is used if the NERD tree is being
371" initialized, or to change the root to a new dir.)
372function! s:Creator.toggleTabTree(dir)
373 if g:NERDTree.ExistsForTab()
374 if !g:NERDTree.IsOpen()
375 call self._createTreeWin()
376 if !empty(a:dir) && a:dir !=# b:NERDTree.root.path.str()
377 call self.createTabTree(a:dir)
378 elseif !&hidden
379 call b:NERDTree.render()
380 endif
381 call b:NERDTree.ui.restoreScreenState()
382 else
383 call g:NERDTree.Close()
384 endif
385 else
386 call self.createTabTree(a:dir)
387 endif
388endfunction
389
390" Function: s:Creator._uniq(list) {{{1
391" returns a:list without duplicates
392function! s:Creator._uniq(list)
393 let uniqlist = []
394 for elem in a:list
395 if index(uniqlist, elem) ==# -1
396 let uniqlist += [elem]
397 endif
398 endfor
399 return uniqlist
400endfunction
401
402" vim: set sw=4 sts=4 et fdm=marker:
diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/event.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/event.vim
new file mode 100644
index 0000000..964e8ff
--- /dev/null
+++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/event.vim
@@ -0,0 +1,13 @@
1"CLASS: Event
2"============================================================
3let s:Event = {}
4let g:NERDTreeEvent = s:Event
5
6function! s:Event.New(nerdtree, subject, action, params) abort
7 let newObj = copy(self)
8 let newObj.nerdtree = a:nerdtree
9 let newObj.subject = a:subject
10 let newObj.action = a:action
11 let newObj.params = a:params
12 return newObj
13endfunction
diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/flag_set.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/flag_set.vim
new file mode 100644
index 0000000..7552867
--- /dev/null
+++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/flag_set.vim
@@ -0,0 +1,58 @@
1"CLASS: FlagSet
2"============================================================
3let s:FlagSet = {}
4let g:NERDTreeFlagSet = s:FlagSet
5
6"FUNCTION: FlagSet.addFlag(scope, flag) {{{1
7function! s:FlagSet.addFlag(scope, flag)
8 let flags = self._flagsForScope(a:scope)
9 if index(flags, a:flag) == -1
10 call add(flags, a:flag)
11 end
12endfunction
13
14"FUNCTION: FlagSet.clearFlags(scope) {{{1
15function! s:FlagSet.clearFlags(scope)
16 let self._flags[a:scope] = []
17endfunction
18
19"FUNCTION: FlagSet._flagsForScope(scope) {{{1
20function! s:FlagSet._flagsForScope(scope)
21 if !has_key(self._flags, a:scope)
22 let self._flags[a:scope] = []
23 endif
24 return self._flags[a:scope]
25endfunction
26
27"FUNCTION: FlagSet.New() {{{1
28function! s:FlagSet.New()
29 let newObj = copy(self)
30 let newObj._flags = {}
31 return newObj
32endfunction
33
34"FUNCTION: FlagSet.removeFlag(scope, flag) {{{1
35function! s:FlagSet.removeFlag(scope, flag)
36 let flags = self._flagsForScope(a:scope)
37
38 let i = index(flags, a:flag)
39 if i >= 0
40 call remove(flags, i)
41 endif
42endfunction
43
44"FUNCTION: FlagSet.renderToString() {{{1
45function! s:FlagSet.renderToString()
46 let flagstring = ''
47 for i in values(self._flags)
48 let flagstring .= join(i)
49 endfor
50
51 if len(flagstring) == 0
52 return ''
53 endif
54
55 return '[' . flagstring . ']'
56endfunction
57
58" vim: set sw=4 sts=4 et fdm=marker:
diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/key_map.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/key_map.vim
new file mode 100644
index 0000000..ed79167
--- /dev/null
+++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/key_map.vim
@@ -0,0 +1,164 @@
1"CLASS: KeyMap
2"============================================================
3let s:KeyMap = {}
4let g:NERDTreeKeyMap = s:KeyMap
5let s:keyMaps = {}
6
7"FUNCTION: KeyMap.All() {{{1
8function! s:KeyMap.All()
9 let sortedKeyMaps = values(s:keyMaps)
10 call sort(sortedKeyMaps, s:KeyMap.Compare, s:KeyMap)
11
12 return sortedKeyMaps
13endfunction
14
15"FUNCTION: KeyMap.Compare(keyMap1, keyMap2) {{{1
16function! s:KeyMap.Compare(keyMap1, keyMap2)
17
18 if a:keyMap1.key >? a:keyMap2.key
19 return 1
20 endif
21
22 if a:keyMap1.key <? a:keyMap2.key
23 return -1
24 endif
25
26 return 0
27endfunction
28
29"FUNCTION: KeyMap.FindFor(key, scope) {{{1
30function! s:KeyMap.FindFor(key, scope)
31 return get(s:keyMaps, a:key . a:scope, {})
32endfunction
33
34"FUNCTION: KeyMap.BindAll() {{{1
35function! s:KeyMap.BindAll()
36 for i in values(s:keyMaps)
37 call i.bind()
38 endfor
39endfunction
40
41"FUNCTION: KeyMap.bind() {{{1
42function! s:KeyMap.bind()
43 " If the key sequence we're trying to map contains any '<>' notation, we
44 " must replace each of the '<' characters with '<lt>' to ensure the string
45 " is not translated into its corresponding keycode during the later part
46 " of the map command below
47 " :he <>
48 let specialNotationRegex = '\m<\([[:alnum:]_-]\+>\)'
49 if self.key =~# specialNotationRegex
50 let keymapInvokeString = substitute(self.key, specialNotationRegex, '<lt>\1', 'g')
51 else
52 let keymapInvokeString = self.key
53 endif
54 let keymapInvokeString = escape(keymapInvokeString, '\"')
55
56 let premap = self.key ==# '<LeftRelease>' ? ' <LeftRelease>' : ' '
57
58 exec 'nnoremap <buffer> <silent> '. self.key . premap . ':call nerdtree#ui_glue#invokeKeyMap("'. keymapInvokeString .'")<cr>'
59endfunction
60
61"FUNCTION: KeyMap.Remove(key, scope) {{{1
62function! s:KeyMap.Remove(key, scope)
63 return remove(s:keyMaps, a:key . a:scope)
64endfunction
65
66"FUNCTION: KeyMap.invoke() {{{1
67"Call the KeyMaps callback function
68function! s:KeyMap.invoke(...)
69 let l:Callback = type(self.callback) ==# type(function('tr')) ? self.callback : function(self.callback)
70 if a:0
71 call l:Callback(a:1)
72 else
73 call l:Callback()
74 endif
75endfunction
76
77"FUNCTION: KeyMap.Invoke() {{{1
78"Find a keymapping for a:key and the current scope invoke it.
79"
80"Scope is determined as follows:
81" * if the cursor is on a dir node then DirNode
82" * if the cursor is on a file node then FileNode
83" * if the cursor is on a bookmark then Bookmark
84"
85"If a keymap has the scope of 'all' then it will be called if no other keymap
86"is found for a:key and the scope.
87function! s:KeyMap.Invoke(key)
88
89 "required because clicking the command window below another window still
90 "invokes the <LeftRelease> mapping - but changes the window cursor
91 "is in first
92 "
93 "TODO: remove this check when the vim bug is fixed
94 if !g:NERDTree.ExistsForBuf()
95 return {}
96 endif
97
98 let node = g:NERDTreeFileNode.GetSelected()
99 if !empty(node)
100
101 "try file node
102 if !node.path.isDirectory
103 let km = s:KeyMap.FindFor(a:key, 'FileNode')
104 if !empty(km)
105 return km.invoke(node)
106 endif
107 endif
108
109 "try dir node
110 if node.path.isDirectory
111 let km = s:KeyMap.FindFor(a:key, 'DirNode')
112 if !empty(km)
113 return km.invoke(node)
114 endif
115 endif
116
117 "try generic node
118 let km = s:KeyMap.FindFor(a:key, 'Node')
119 if !empty(km)
120 return km.invoke(node)
121 endif
122
123 endif
124
125 "try bookmark
126 let bm = g:NERDTreeBookmark.GetSelected()
127 if !empty(bm)
128 let km = s:KeyMap.FindFor(a:key, 'Bookmark')
129 if !empty(km)
130 return km.invoke(bm)
131 endif
132 endif
133
134 "try all
135 let km = s:KeyMap.FindFor(a:key, 'all')
136 if !empty(km)
137 return km.invoke()
138 endif
139endfunction
140
141"FUNCTION: KeyMap.Create(options) {{{1
142function! s:KeyMap.Create(options)
143 let opts = extend({'scope': 'all', 'quickhelpText': ''}, copy(a:options))
144
145 "dont override other mappings unless the 'override' option is given
146 if get(opts, 'override', 0) ==# 0 && !empty(s:KeyMap.FindFor(opts['key'], opts['scope']))
147 return
148 end
149
150 let newKeyMap = copy(self)
151 let newKeyMap.key = opts['key']
152 let newKeyMap.quickhelpText = opts['quickhelpText']
153 let newKeyMap.callback = opts['callback']
154 let newKeyMap.scope = opts['scope']
155
156 call s:KeyMap.Add(newKeyMap)
157endfunction
158
159"FUNCTION: KeyMap.Add(keymap) {{{1
160function! s:KeyMap.Add(keymap)
161 let s:keyMaps[a:keymap.key . a:keymap.scope] = a:keymap
162endfunction
163
164" vim: set sw=4 sts=4 et fdm=marker:
diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_controller.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_controller.vim
new file mode 100644
index 0000000..952c67b
--- /dev/null
+++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_controller.vim
@@ -0,0 +1,211 @@
1"CLASS: MenuController
2"============================================================
3let s:MenuController = {}
4let g:NERDTreeMenuController = s:MenuController
5
6"FUNCTION: MenuController.New(menuItems) {{{1
7"create a new menu controller that operates on the given menu items
8function! s:MenuController.New(menuItems)
9 let newMenuController = copy(self)
10 if a:menuItems[0].isSeparator()
11 let newMenuController.menuItems = a:menuItems[1:-1]
12 else
13 let newMenuController.menuItems = a:menuItems
14 endif
15 return newMenuController
16endfunction
17
18" FUNCTION: s:MenuController.isMinimal() {{{1
19function! s:MenuController.isMinimal()
20 return g:NERDTreeMinimalMenu
21endfunction
22
23" FUNCTION: MenuController.showMenu() {{{1
24" Enter the main loop of the NERDTree menu, prompting the user to select
25" a menu item.
26function! s:MenuController.showMenu()
27 call self._saveOptions()
28
29 try
30 let self.selection = 0
31 let l:done = 0
32
33 while !l:done
34 if has('nvim')
35 mode
36 else
37 redraw!
38 endif
39 call self._echoPrompt()
40
41 let l:key = nr2char(getchar())
42 let l:done = self._handleKeypress(l:key)
43 endwhile
44 finally
45 call self._restoreOptions()
46
47 " Redraw when Ctrl-C or Esc is received.
48 if !l:done || self.selection ==# -1
49 redraw!
50 endif
51 endtry
52
53 if self.selection !=# -1
54 let l:m = self._current()
55 call l:m.execute()
56 endif
57endfunction
58
59"FUNCTION: MenuController._echoPrompt() {{{1
60function! s:MenuController._echoPrompt()
61 let navHelp = 'Use ' . g:NERDTreeMenuDown . '/' . g:NERDTreeMenuUp . '/enter'
62
63 if self.isMinimal()
64 let selection = self.menuItems[self.selection].text
65 let keyword = matchstr(selection, '[^ ]*([^ ]*')
66
67 let shortcuts = map(copy(self.menuItems), "v:val['shortcut']")
68 let shortcuts[self.selection] = ' ' . keyword . ' '
69
70 echo 'Menu: [' . join(shortcuts, ',') . '] (' . navHelp . ' or shortcut): '
71 else
72 echo 'NERDTree Menu. ' . navHelp . ', or the shortcuts indicated'
73 echo '========================================================='
74
75 for i in range(0, len(self.menuItems)-1)
76 if self.selection ==# i
77 echo '> ' . self.menuItems[i].text
78 else
79 echo ' ' . self.menuItems[i].text
80 endif
81 endfor
82 endif
83endfunction
84
85"FUNCTION: MenuController._current(key) {{{1
86"get the MenuItem that is currently selected
87function! s:MenuController._current()
88 return self.menuItems[self.selection]
89endfunction
90
91"FUNCTION: MenuController._handleKeypress(key) {{{1
92"change the selection (if appropriate) and return 1 if the user has made
93"their choice, 0 otherwise
94function! s:MenuController._handleKeypress(key)
95 if a:key ==# g:NERDTreeMenuDown
96 call self._cursorDown()
97 elseif a:key ==# g:NERDTreeMenuUp
98 call self._cursorUp()
99 elseif a:key ==# nr2char(27) "escape
100 let self.selection = -1
101 return 1
102 elseif a:key ==# "\r" || a:key ==# "\n" "enter and ctrl-j
103 return 1
104 else
105 let index = self._nextIndexFor(a:key)
106 if index !=# -1
107 let self.selection = index
108 if len(self._allIndexesFor(a:key)) ==# 1
109 return 1
110 endif
111 endif
112 endif
113
114 return 0
115endfunction
116
117"FUNCTION: MenuController._allIndexesFor(shortcut) {{{1
118"get indexes to all menu items with the given shortcut
119function! s:MenuController._allIndexesFor(shortcut)
120 let toReturn = []
121
122 for i in range(0, len(self.menuItems)-1)
123 if self.menuItems[i].shortcut ==# a:shortcut
124 call add(toReturn, i)
125 endif
126 endfor
127
128 return toReturn
129endfunction
130
131"FUNCTION: MenuController._nextIndexFor(shortcut) {{{1
132"get the index to the next menu item with the given shortcut, starts from the
133"current cursor location and wraps around to the top again if need be
134function! s:MenuController._nextIndexFor(shortcut)
135 for i in range(self.selection+1, len(self.menuItems)-1)
136 if self.menuItems[i].shortcut ==# a:shortcut
137 return i
138 endif
139 endfor
140
141 for i in range(0, self.selection)
142 if self.menuItems[i].shortcut ==# a:shortcut
143 return i
144 endif
145 endfor
146
147 return -1
148endfunction
149
150"FUNCTION: MenuController._setCmdheight() {{{1
151"sets &cmdheight to whatever is needed to display the menu
152function! s:MenuController._setCmdheight()
153 if self.isMinimal()
154 let &cmdheight = 1
155 else
156 let &cmdheight = len(self.menuItems) + 3
157 endif
158endfunction
159
160"FUNCTION: MenuController._saveOptions() {{{1
161"set any vim options that are required to make the menu work (saving their old
162"values)
163function! s:MenuController._saveOptions()
164 let self._oldLazyredraw = &lazyredraw
165 let self._oldCmdheight = &cmdheight
166 set nolazyredraw
167 call self._setCmdheight()
168endfunction
169
170"FUNCTION: MenuController._restoreOptions() {{{1
171"restore the options we saved in _saveOptions()
172function! s:MenuController._restoreOptions()
173 let &cmdheight = self._oldCmdheight
174 let &lazyredraw = self._oldLazyredraw
175endfunction
176
177"FUNCTION: MenuController._cursorDown() {{{1
178"move the cursor to the next menu item, skipping separators
179function! s:MenuController._cursorDown()
180 let done = 0
181 while !done
182 if self.selection < len(self.menuItems)-1
183 let self.selection += 1
184 else
185 let self.selection = 0
186 endif
187
188 if !self._current().isSeparator()
189 let done = 1
190 endif
191 endwhile
192endfunction
193
194"FUNCTION: MenuController._cursorUp() {{{1
195"move the cursor to the previous menu item, skipping separators
196function! s:MenuController._cursorUp()
197 let done = 0
198 while !done
199 if self.selection > 0
200 let self.selection -= 1
201 else
202 let self.selection = len(self.menuItems)-1
203 endif
204
205 if !self._current().isSeparator()
206 let done = 1
207 endif
208 endwhile
209endfunction
210
211" vim: set sw=4 sts=4 et fdm=marker:
diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_item.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_item.vim
new file mode 100644
index 0000000..7f25917
--- /dev/null
+++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_item.vim
@@ -0,0 +1,118 @@
1"CLASS: MenuItem
2"============================================================
3let s:MenuItem = {}
4let g:NERDTreeMenuItem = s:MenuItem
5
6"FUNCTION: MenuItem.All() {{{1
7"get all top level menu items
8function! s:MenuItem.All()
9 if !exists('s:menuItems')
10 let s:menuItems = []
11 endif
12 return s:menuItems
13endfunction
14
15"FUNCTION: MenuItem.AllEnabled() {{{1
16"get all top level menu items that are currently enabled
17function! s:MenuItem.AllEnabled()
18 let toReturn = []
19 for i in s:MenuItem.All()
20 if i.enabled()
21 call add(toReturn, i)
22 endif
23 endfor
24 return toReturn
25endfunction
26
27"FUNCTION: MenuItem.Create(options) {{{1
28"make a new menu item and add it to the global list
29function! s:MenuItem.Create(options)
30 let newMenuItem = copy(self)
31
32 let newMenuItem.text = a:options['text']
33 let newMenuItem.shortcut = a:options['shortcut']
34 let newMenuItem.children = []
35
36 let newMenuItem.isActiveCallback = -1
37 if has_key(a:options, 'isActiveCallback')
38 let newMenuItem.isActiveCallback = a:options['isActiveCallback']
39 endif
40
41 let newMenuItem.callback = -1
42 if has_key(a:options, 'callback')
43 let newMenuItem.callback = a:options['callback']
44 endif
45
46 if has_key(a:options, 'parent')
47 call add(a:options['parent'].children, newMenuItem)
48 else
49 call add(s:MenuItem.All(), newMenuItem)
50 endif
51
52 return newMenuItem
53endfunction
54
55"FUNCTION: MenuItem.CreateSeparator(options) {{{1
56"make a new separator menu item and add it to the global list
57function! s:MenuItem.CreateSeparator(options)
58 let standard_options = { 'text': '--------------------',
59 \ 'shortcut': -1,
60 \ 'callback': -1 }
61 let options = extend(a:options, standard_options, 'force')
62
63 return s:MenuItem.Create(options)
64endfunction
65
66"FUNCTION: MenuItem.CreateSubmenu(options) {{{1
67"make a new submenu and add it to global list
68function! s:MenuItem.CreateSubmenu(options)
69 let standard_options = { 'callback': -1 }
70 let options = extend(a:options, standard_options, 'force')
71
72 return s:MenuItem.Create(options)
73endfunction
74
75"FUNCTION: MenuItem.enabled() {{{1
76"return 1 if this menu item should be displayed
77"
78"delegates off to the isActiveCallback, and defaults to 1 if no callback was
79"specified
80function! s:MenuItem.enabled()
81 if self.isActiveCallback != -1
82 return type(self.isActiveCallback) == type(function('tr')) ? self.isActiveCallback() : {self.isActiveCallback}()
83 endif
84 return 1
85endfunction
86
87"FUNCTION: MenuItem.execute() {{{1
88"perform the action behind this menu item, if this menuitem has children then
89"display a new menu for them, otherwise deletegate off to the menuitem's
90"callback
91function! s:MenuItem.execute()
92 if len(self.children)
93 let mc = g:NERDTreeMenuController.New(self.children)
94 call mc.showMenu()
95 else
96 if self.callback != -1
97 if type(self.callback) == type(function('tr'))
98 call self.callback()
99 else
100 call {self.callback}()
101 endif
102 endif
103 endif
104endfunction
105
106"FUNCTION: MenuItem.isSeparator() {{{1
107"return 1 if this menuitem is a separator
108function! s:MenuItem.isSeparator()
109 return self.callback == -1 && self.children == []
110endfunction
111
112"FUNCTION: MenuItem.isSubmenu() {{{1
113"return 1 if this menuitem is a submenu
114function! s:MenuItem.isSubmenu()
115 return self.callback == -1 && !empty(self.children)
116endfunction
117
118" vim: set sw=4 sts=4 et fdm=marker:
diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/nerdtree.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/nerdtree.vim
new file mode 100644
index 0000000..61a11a9
--- /dev/null
+++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/nerdtree.vim
@@ -0,0 +1,209 @@
1"CLASS: NERDTree
2"============================================================
3let s:NERDTree = {}
4let g:NERDTree = s:NERDTree
5
6"FUNCTION: s:NERDTree.AddPathFilter() {{{1
7function! s:NERDTree.AddPathFilter(callback)
8 call add(s:NERDTree.PathFilters(), a:callback)
9endfunction
10
11"FUNCTION: s:NERDTree.changeRoot(node) {{{1
12function! s:NERDTree.changeRoot(node)
13 if a:node.path.isDirectory
14 let self.root = a:node
15 else
16 call a:node.cacheParent()
17 let self.root = a:node.parent
18 endif
19
20 call self.root.open()
21
22 "change dir to the dir of the new root if instructed to
23 if g:NERDTreeChDirMode >= 2
24 call self.root.path.changeToDir()
25 endif
26
27 call self.render()
28 call self.root.putCursorHere(0, 0)
29
30 if exists('#User#NERDTreeNewRoot')
31 doautocmd User NERDTreeNewRoot
32 endif
33endfunction
34
35"FUNCTION: s:NERDTree.Close() {{{1
36"Closes the tab tree window for this tab
37function! s:NERDTree.Close()
38 if !s:NERDTree.IsOpen()
39 return
40 endif
41
42 if winnr('$') !=# 1
43 " Use the window ID to identify the currently active window or fall
44 " back on the buffer ID if win_getid/win_gotoid are not available, in
45 " which case we'll focus an arbitrary window showing the buffer.
46 let l:useWinId = exists('*win_getid') && exists('*win_gotoid')
47
48 if winnr() ==# s:NERDTree.GetWinNum()
49 call nerdtree#exec('wincmd p', 1)
50 let l:activeBufOrWin = l:useWinId ? win_getid() : bufnr('')
51 call nerdtree#exec('wincmd p', 1)
52 else
53 let l:activeBufOrWin = l:useWinId ? win_getid() : bufnr('')
54 endif
55
56 call nerdtree#exec(s:NERDTree.GetWinNum() . ' wincmd w', 1)
57 call nerdtree#exec('close', 0)
58 if l:useWinId
59 call nerdtree#exec('call win_gotoid(' . l:activeBufOrWin . ')', 0)
60 else
61 call nerdtree#exec(bufwinnr(l:activeBufOrWin) . ' wincmd w', 0)
62 endif
63 else
64 close
65 endif
66endfunction
67
68"FUNCTION: s:NERDTree.CursorToBookmarkTable(){{{1
69"Places the cursor at the top of the bookmarks table
70function! s:NERDTree.CursorToBookmarkTable()
71 if !b:NERDTree.ui.getShowBookmarks()
72 throw 'NERDTree.IllegalOperationError: cant find bookmark table, bookmarks arent active'
73 endif
74
75 if g:NERDTreeMinimalUI
76 return cursor(1, 2)
77 endif
78
79 let rootNodeLine = b:NERDTree.ui.getRootLineNum()
80
81 let line = 1
82 while getline(line) !~# '^>-\+Bookmarks-\+$'
83 let line = line + 1
84 if line >= rootNodeLine
85 throw 'NERDTree.BookmarkTableNotFoundError: didnt find the bookmarks table'
86 endif
87 endwhile
88 call cursor(line, 2)
89endfunction
90
91"FUNCTION: s:NERDTree.CursorToTreeWin(){{{1
92"Places the cursor in the nerd tree window
93function! s:NERDTree.CursorToTreeWin(...)
94 call g:NERDTree.MustBeOpen()
95 call nerdtree#exec(g:NERDTree.GetWinNum() . 'wincmd w', a:0 >0 ? a:1 : 1)
96endfunction
97
98" Function: s:NERDTree.ExistsForBuffer() {{{1
99" Returns 1 if a nerd tree root exists in the current buffer
100function! s:NERDTree.ExistsForBuf()
101 return exists('b:NERDTree')
102endfunction
103
104" Function: s:NERDTree.ExistsForTab() {{{1
105" Returns 1 if a nerd tree root exists in the current tab
106function! s:NERDTree.ExistsForTab()
107 if !exists('t:NERDTreeBufName')
108 return
109 end
110
111 "check b:NERDTree is still there and hasn't been e.g. :bdeleted
112 return !empty(getbufvar(bufnr(t:NERDTreeBufName), 'NERDTree'))
113endfunction
114
115function! s:NERDTree.ForCurrentBuf()
116 if s:NERDTree.ExistsForBuf()
117 return b:NERDTree
118 else
119 return {}
120 endif
121endfunction
122
123"FUNCTION: s:NERDTree.ForCurrentTab() {{{1
124function! s:NERDTree.ForCurrentTab()
125 if !s:NERDTree.ExistsForTab()
126 return
127 endif
128
129 let bufnr = bufnr(t:NERDTreeBufName)
130 return getbufvar(bufnr, 'NERDTree')
131endfunction
132
133"FUNCTION: s:NERDTree.getRoot() {{{1
134function! s:NERDTree.getRoot()
135 return self.root
136endfunction
137
138"FUNCTION: s:NERDTree.GetWinNum() {{{1
139"gets the nerd tree window number for this tab
140function! s:NERDTree.GetWinNum()
141 if exists('t:NERDTreeBufName')
142 return bufwinnr(t:NERDTreeBufName)
143 endif
144
145 " If WindowTree, there is no t:NERDTreeBufName variable. Search all windows.
146 for w in range(1,winnr('$'))
147 if bufname(winbufnr(w)) =~# '^' . g:NERDTreeCreator.BufNamePrefix() . '\d\+$'
148 return w
149 endif
150 endfor
151
152 return -1
153endfunction
154
155"FUNCTION: s:NERDTree.IsOpen() {{{1
156function! s:NERDTree.IsOpen()
157 return s:NERDTree.GetWinNum() !=# -1
158endfunction
159
160"FUNCTION: s:NERDTree.isTabTree() {{{1
161function! s:NERDTree.isTabTree()
162 return self._type ==# 'tab'
163endfunction
164
165"FUNCTION: s:NERDTree.isWinTree() {{{1
166function! s:NERDTree.isWinTree()
167 return self._type ==# 'window'
168endfunction
169
170"FUNCTION: s:NERDTree.MustBeOpen() {{{1
171function! s:NERDTree.MustBeOpen()
172 if !s:NERDTree.IsOpen()
173 throw 'NERDTree.TreeNotOpen'
174 endif
175endfunction
176
177"FUNCTION: s:NERDTree.New() {{{1
178function! s:NERDTree.New(path, type)
179 let newObj = copy(self)
180 let newObj.ui = g:NERDTreeUI.New(newObj)
181 let newObj.root = g:NERDTreeDirNode.New(a:path, newObj)
182 let newObj._type = a:type
183 return newObj
184endfunction
185
186"FUNCTION: s:NERDTree.PathFilters() {{{1
187function! s:NERDTree.PathFilters()
188 if !exists('s:NERDTree._PathFilters')
189 let s:NERDTree._PathFilters = []
190 endif
191 return s:NERDTree._PathFilters
192endfunction
193
194"FUNCTION: s:NERDTree.previousBuf() {{{1
195function! s:NERDTree.previousBuf()
196 return self._previousBuf
197endfunction
198
199function! s:NERDTree.setPreviousBuf(bnum)
200 let self._previousBuf = a:bnum
201endfunction
202
203"FUNCTION: s:NERDTree.render() {{{1
204"A convenience function - since this is called often
205function! s:NERDTree.render()
206 call self.ui.render()
207endfunction
208
209" vim: set sw=4 sts=4 et fdm=marker:
diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/notifier.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/notifier.vim
new file mode 100644
index 0000000..ffa2853
--- /dev/null
+++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/notifier.vim
@@ -0,0 +1,35 @@
1"CLASS: Notifier
2"============================================================
3let s:Notifier = {}
4
5function! s:Notifier.AddListener(event, funcname)
6 let listeners = s:Notifier.GetListenersForEvent(a:event)
7 if listeners == []
8 let listenersMap = s:Notifier.GetListenersMap()
9 let listenersMap[a:event] = listeners
10 endif
11 call add(listeners, a:funcname)
12endfunction
13
14function! s:Notifier.NotifyListeners(event, path, nerdtree, params)
15 let event = g:NERDTreeEvent.New(a:nerdtree, a:path, a:event, a:params)
16
17 for Listener in s:Notifier.GetListenersForEvent(a:event)
18 let l:Callback = type(Listener) == type(function('tr')) ? Listener : function(Listener)
19 call l:Callback(event)
20 endfor
21endfunction
22
23function! s:Notifier.GetListenersMap()
24 if !exists('s:refreshListenersMap')
25 let s:refreshListenersMap = {}
26 endif
27 return s:refreshListenersMap
28endfunction
29
30function! s:Notifier.GetListenersForEvent(name)
31 let listenersMap = s:Notifier.GetListenersMap()
32 return get(listenersMap, a:name, [])
33endfunction
34
35let g:NERDTreePathNotifier = deepcopy(s:Notifier)
diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/opener.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/opener.vim
new file mode 100644
index 0000000..27993ac
--- /dev/null
+++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/opener.vim
@@ -0,0 +1,326 @@
1" ============================================================================
2" CLASS: Opener
3"
4" The Opener class defines an API for 'opening' operations.
5" ============================================================================
6
7
8let s:Opener = {}
9let g:NERDTreeOpener = s:Opener
10
11" FUNCTION: s:Opener._bufInWindows(bnum) {{{1
12" [[STOLEN FROM VTREEEXPLORER.VIM]]
13" Determine the number of windows open to this buffer number.
14" Care of Yegappan Lakshman. Thanks!
15"
16" Args:
17" bnum: the subject buffers buffer number
18function! s:Opener._bufInWindows(bnum)
19 let cnt = 0
20 let winnum = 1
21 while 1
22 let bufnum = winbufnr(winnum)
23 if bufnum < 0
24 break
25 endif
26 if bufnum ==# a:bnum
27 let cnt = cnt + 1
28 endif
29 let winnum = winnum + 1
30 endwhile
31
32 return cnt
33endfunction
34
35" FUNCTION: Opener._checkToCloseTree(newtab) {{{1
36" Check the class options to see if the tree should be closed now.
37"
38" Args:
39" a:newtab - boolean. If set, only close the tree now if we are opening the
40" target in a new tab. This is needed because we have to close tree before we
41" leave the tab
42function! s:Opener._checkToCloseTree(newtab)
43 if self._keepopen
44 return
45 endif
46
47 if (a:newtab && self._where ==# 't') || !a:newtab
48 call g:NERDTree.Close()
49 endif
50endfunction
51
52" FUNCTION: s:Opener._firstUsableWindow() {{{1
53" find the window number of the first normal window
54function! s:Opener._firstUsableWindow()
55 let i = 1
56 while i <= winnr('$')
57 let bnum = winbufnr(i)
58 if bnum !=# -1 && getbufvar(bnum, '&buftype') ==# ''
59 \ && !getwinvar(i, '&previewwindow')
60 \ && (!getbufvar(bnum, '&modified') || &hidden)
61 return i
62 endif
63
64 let i += 1
65 endwhile
66 return -1
67endfunction
68
69" FUNCTION: Opener._gotoTargetWin() {{{1
70function! s:Opener._gotoTargetWin()
71 if b:NERDTree.isWinTree()
72 if self._where ==# 'v'
73 call self._newVSplit()
74 elseif self._where ==# 'h'
75 call self._newSplit()
76 elseif self._where ==# 't'
77 tabnew
78 endif
79 else
80 call self._checkToCloseTree(1)
81
82 if self._where ==# 'v'
83 call self._newVSplit()
84 elseif self._where ==# 'h'
85 call self._newSplit()
86 elseif self._where ==# 't'
87 tabnew
88 elseif self._where ==# 'p'
89 call self._previousWindow()
90 endif
91
92 call self._checkToCloseTree(0)
93 endif
94endfunction
95
96" FUNCTION: s:Opener._isWindowUsable(winnumber) {{{1
97" Returns 0 if opening a file from the tree in the given window requires it to
98" be split, 1 otherwise
99"
100" Args:
101" winnumber: the number of the window in question
102function! s:Opener._isWindowUsable(winnumber)
103 "gotta split if theres only one window (i.e. the NERD tree)
104 if winnr('$') ==# 1
105 return 0
106 endif
107
108 let oldwinnr = winnr()
109 call nerdtree#exec(a:winnumber . 'wincmd p', 1)
110 let specialWindow = getbufvar('%', '&buftype') !=# '' || getwinvar('%', '&previewwindow')
111 let modified = &modified
112 call nerdtree#exec(oldwinnr . 'wincmd p', 1)
113
114 "if its a special window e.g. quickfix or another explorer plugin then we
115 "have to split
116 if specialWindow
117 return 0
118 endif
119
120 if &hidden
121 return 1
122 endif
123
124 return !modified || self._bufInWindows(winbufnr(a:winnumber)) >= 2
125endfunction
126
127" FUNCTION: Opener.New(path, opts) {{{1
128" Instantiate a new NERDTreeOpener object.
129" Args:
130" a:path: the path object that is to be opened
131" a:opts: a dictionary containing the following optional keys...
132" 'where': specifies whether the node should be opened in new split, in
133" a new tab or, in the last window; takes values 'v', 'h', or 't'
134" 'reuse': if file is already shown in a window, jump there; takes values
135" 'all', 'currenttab', or empty
136" 'keepopen': boolean (0 or 1); if true, the tree window will not be closed
137" 'stay': boolean (0 or 1); if true, remain in tree window after opening
138function! s:Opener.New(path, opts)
139 let l:newOpener = copy(self)
140
141 let l:newOpener._keepopen = nerdtree#has_opt(a:opts, 'keepopen')
142 let l:newOpener._nerdtree = b:NERDTree
143 let l:newOpener._path = a:path
144 let l:newOpener._reuse = has_key(a:opts, 'reuse') ? a:opts['reuse'] : ''
145 let l:newOpener._stay = nerdtree#has_opt(a:opts, 'stay')
146 let l:newOpener._where = has_key(a:opts, 'where') ? a:opts['where'] : ''
147
148 call l:newOpener._saveCursorPos()
149
150 return l:newOpener
151endfunction
152
153" FUNCTION: Opener._newSplit() {{{1
154function! s:Opener._newSplit()
155 let onlyOneWin = (winnr('$') ==# 1)
156 let savesplitright = &splitright
157 if onlyOneWin
158 let &splitright = (g:NERDTreeWinPos ==# 'left')
159 endif
160 " If only one window (ie. NERDTree), split vertically instead.
161 let splitMode = onlyOneWin ? 'vertical' : ''
162
163 " Open the new window
164 try
165 call nerdtree#exec('wincmd p', 1)
166 call nerdtree#exec(splitMode . ' split',1)
167 catch /^Vim\%((\a\+)\)\=:E37/
168 call g:NERDTree.CursorToTreeWin()
169 throw 'NERDTree.FileAlreadyOpenAndModifiedError: '. self._path.str() .' is already open and modified.'
170 catch /^Vim\%((\a\+)\)\=:/
171 "do nothing
172 endtry
173
174 "resize the tree window if no other window was open before
175 if onlyOneWin
176 call nerdtree#exec('wincmd p', 1)
177 call nerdtree#exec('silent '. splitMode .' resize '. g:NERDTreeWinSize, 1)
178 call nerdtree#exec('wincmd p', 0)
179 endif
180
181 let &splitright=savesplitright
182endfunction
183
184" FUNCTION: Opener._newVSplit() {{{1
185function! s:Opener._newVSplit()
186 let l:winwidth = winwidth('.')
187
188 let onlyOneWin = (winnr('$') ==# 1)
189 let savesplitright = &splitright
190 if onlyOneWin
191 let &splitright = (g:NERDTreeWinPos ==# 'left')
192 let l:winwidth = g:NERDTreeWinSize
193 endif
194
195 call nerdtree#exec('wincmd p', 1)
196 call nerdtree#exec('vsplit', 1)
197
198 let l:currentWindowNumber = winnr()
199
200 " Restore the NERDTree to its original width.
201 call g:NERDTree.CursorToTreeWin()
202 execute 'silent vertical resize ' . l:winwidth
203
204 call nerdtree#exec(l:currentWindowNumber . 'wincmd w', 0)
205 let &splitright=savesplitright
206endfunction
207
208" FUNCTION: Opener.open(target) {{{1
209function! s:Opener.open(target)
210 if self._path.isDirectory
211 call self._openDirectory(a:target)
212 return
213 endif
214
215 call self._openFile()
216endfunction
217
218" FUNCTION: Opener._openFile() {{{1
219function! s:Opener._openFile()
220 if !self._stay && self._keepopen && get(b:, 'NERDTreeZoomed', 0)
221 call b:NERDTree.ui.toggleZoom()
222 endif
223
224 if self._reuseWindow()
225 return
226 endif
227
228 call self._gotoTargetWin()
229
230 if self._stay
231 silent call self._path.edit()
232 call self._restoreCursorPos()
233 return
234 endif
235
236 call self._path.edit()
237endfunction
238
239" FUNCTION: Opener._openDirectory(node) {{{1
240function! s:Opener._openDirectory(node)
241 call self._gotoTargetWin()
242
243 if self._nerdtree.isWinTree()
244 call g:NERDTreeCreator.CreateWindowTree(a:node.path.str())
245 else
246 if empty(self._where)
247 call b:NERDTree.changeRoot(a:node)
248 elseif self._where ==# 't'
249 call g:NERDTreeCreator.CreateTabTree(a:node.path.str())
250 else
251 call g:NERDTreeCreator.CreateWindowTree(a:node.path.str())
252 endif
253 endif
254
255 if self._stay
256 call self._restoreCursorPos()
257 endif
258endfunction
259
260" FUNCTION: Opener._previousWindow() {{{1
261function! s:Opener._previousWindow()
262 if !self._isWindowUsable(winnr('#')) && self._firstUsableWindow() ==# -1
263 call self._newSplit()
264 else
265 try
266 if !self._isWindowUsable(winnr('#'))
267 call nerdtree#exec(self._firstUsableWindow() . 'wincmd w', 1)
268 else
269 call nerdtree#exec('wincmd p', 1)
270 endif
271 catch /^Vim\%((\a\+)\)\=:E37/
272 call g:NERDTree.CursorToTreeWin()
273 throw 'NERDTree.FileAlreadyOpenAndModifiedError: '. self._path.str() .' is already open and modified.'
274 catch /^Vim\%((\a\+)\)\=:/
275 echo v:exception
276 endtry
277 endif
278endfunction
279
280" FUNCTION: Opener._restoreCursorPos() {{{1
281function! s:Opener._restoreCursorPos()
282 call nerdtree#exec(self._tabnr . 'tabnext', 1)
283 call nerdtree#exec(bufwinnr(self._bufnr) . 'wincmd w', 1)
284endfunction
285
286" FUNCTION: Opener._reuseWindow() {{{1
287" put the cursor in the first window we find for this file
288"
289" return 1 if we were successful
290function! s:Opener._reuseWindow()
291 if empty(self._reuse)
292 return 0
293 endif
294
295 "check the current tab for the window
296 let winnr = bufwinnr('^' . self._path.str() . '$')
297 if winnr !=# -1
298 call nerdtree#exec(winnr . 'wincmd w', 0)
299 call self._checkToCloseTree(0)
300 return 1
301 endif
302
303 if self._reuse ==# 'currenttab'
304 return 0
305 endif
306
307 "check other tabs
308 let tabnr = self._path.tabnr()
309 if tabnr
310 call self._checkToCloseTree(1)
311 call nerdtree#exec(tabnr . 'tabnext', 1)
312 let winnr = bufwinnr('^' . self._path.str() . '$')
313 call nerdtree#exec(winnr . 'wincmd w', 0)
314 return 1
315 endif
316
317 return 0
318endfunction
319
320" FUNCTION: Opener._saveCursorPos() {{{1
321function! s:Opener._saveCursorPos()
322 let self._bufnr = bufnr('')
323 let self._tabnr = tabpagenr()
324endfunction
325
326" vim: set sw=4 sts=4 et fdm=marker:
diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/path.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/path.vim
new file mode 100644
index 0000000..997abf3
--- /dev/null
+++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/path.vim
@@ -0,0 +1,852 @@
1" ============================================================================
2" CLASS: Path
3"
4" The Path class provides an abstracted representation of a file system
5" pathname. Various operations on pathnames are provided and a number of
6" representations of a given path name can be accessed here.
7" ============================================================================
8
9
10let s:Path = {}
11let g:NERDTreePath = s:Path
12
13" FUNCTION: Path.AbsolutePathFor(pathStr) {{{1
14function! s:Path.AbsolutePathFor(pathStr)
15 let l:prependWorkingDir = 0
16
17 if nerdtree#runningWindows()
18 let l:prependWorkingDir = a:pathStr !~# '^.:\(\\\|\/\)\?' && a:pathStr !~# '^\(\\\\\|\/\/\)'
19 else
20 let l:prependWorkingDir = a:pathStr !~# '^/'
21 endif
22
23 let l:result = a:pathStr
24
25 if l:prependWorkingDir
26 let l:result = getcwd()
27
28 if l:result[-1:] == nerdtree#slash()
29 let l:result = l:result . a:pathStr
30 else
31 let l:result = l:result . nerdtree#slash() . a:pathStr
32 endif
33 endif
34
35 return l:result
36endfunction
37
38" FUNCTION: Path.bookmarkNames() {{{1
39function! s:Path.bookmarkNames()
40 if !exists('self._bookmarkNames')
41 call self.cacheDisplayString()
42 endif
43 return self._bookmarkNames
44endfunction
45
46" FUNCTION: Path.cacheDisplayString() {{{1
47function! s:Path.cacheDisplayString() abort
48 let self.cachedDisplayString = g:NERDTreeNodeDelimiter . self.getLastPathComponent(1)
49
50 if self.isExecutable
51 let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . '*'
52 endif
53
54 let self._bookmarkNames = []
55 for i in g:NERDTreeBookmark.Bookmarks()
56 if i.path.equals(self)
57 call add(self._bookmarkNames, i.name)
58 endif
59 endfor
60 if !empty(self._bookmarkNames) && g:NERDTreeMarkBookmarks ==# 1
61 let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . ' {' . join(self._bookmarkNames) . '}'
62 endif
63
64 if self.isSymLink
65 let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . ' -> ' . self.symLinkDest
66 endif
67
68 if self.isReadOnly
69 let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . ' ['.g:NERDTreeGlyphReadOnly.']'
70 endif
71endfunction
72
73" FUNCTION: Path.addDelimiter() {{{1
74function! s:Path.addDelimiter(line)
75 if a:line =~# '\(.*' . g:NERDTreeNodeDelimiter . '\)\{2}'
76 return a:line
77 else
78 return a:line . g:NERDTreeNodeDelimiter
79 endif
80endfunction
81
82" FUNCTION: Path.changeToDir() {{{1
83function! s:Path.changeToDir()
84 let dir = self.str({'format': 'Cd'})
85 if self.isDirectory ==# 0
86 let dir = self.getParent().str({'format': 'Cd'})
87 endif
88
89 try
90 if g:NERDTreeUseTCD && exists(':tcd') ==# 2
91 execute 'tcd ' . dir
92 call nerdtree#echo("Tab's CWD is now: " . getcwd())
93 else
94 execute 'cd ' . dir
95 call nerdtree#echo('CWD is now: ' . getcwd())
96 endif
97 catch
98 throw 'NERDTree.PathChangeError: cannot change CWD to ' . dir
99 endtry
100endfunction
101
102" FUNCTION: Path.Create(fullpath) {{{1
103"
104" Factory method.
105"
106" Creates a path object with the given path. The path is also created on the
107" filesystem. If the path already exists, a NERDTree.Path.Exists exception is
108" thrown. If any other errors occur, a NERDTree.Path exception is thrown.
109"
110" Args:
111" fullpath: the full filesystem path to the file/dir to create
112function! s:Path.Create(fullpath)
113 "bail if the a:fullpath already exists
114 if isdirectory(a:fullpath) || filereadable(a:fullpath)
115 throw "NERDTree.CreatePathError: Directory Exists: '" . a:fullpath . "'"
116 endif
117
118 try
119
120 "if it ends with a slash, assume its a dir create it
121 if a:fullpath =~# '\(\\\|\/\)$'
122 "whack the trailing slash off the end if it exists
123 let fullpath = substitute(a:fullpath, '\(\\\|\/\)$', '', '')
124
125 call mkdir(fullpath, 'p')
126
127 "assume its a file and create
128 else
129 call s:Path.createParentDirectories(a:fullpath)
130 call writefile([], a:fullpath)
131 endif
132 catch
133 throw "NERDTree.CreatePathError: Could not create path: '" . a:fullpath . "'"
134 endtry
135
136 return s:Path.New(a:fullpath)
137endfunction
138
139" FUNCTION: Path.copy(dest) {{{1
140"
141" Copies the file/dir represented by this Path to the given location
142"
143" Args:
144" dest: the location to copy this dir/file to
145function! s:Path.copy(dest)
146 if !s:Path.CopyingSupported()
147 throw 'NERDTree.CopyingNotSupportedError: Copying is not supported on this OS'
148 endif
149
150 call s:Path.createParentDirectories(a:dest)
151
152 if exists('g:NERDTreeCopyCmd')
153 let cmd_prefix = g:NERDTreeCopyCmd
154 else
155 let cmd_prefix = (self.isDirectory ? g:NERDTreeCopyDirCmd : g:NERDTreeCopyFileCmd)
156 endif
157
158 let cmd = cmd_prefix . ' ' . shellescape(self.str()) . ' ' . shellescape(a:dest)
159 let success = system(cmd)
160 if v:shell_error !=# 0
161 throw "NERDTree.CopyError: Could not copy '". self.str() ."' to: '" . a:dest . "'"
162 endif
163endfunction
164
165" FUNCTION: Path.CopyingSupported() {{{1
166"
167" returns 1 if copying is supported for this OS
168function! s:Path.CopyingSupported()
169 return exists('g:NERDTreeCopyCmd') || (exists('g:NERDTreeCopyDirCmd') && exists('g:NERDTreeCopyFileCmd'))
170endfunction
171
172" FUNCTION: Path.copyingWillOverwrite(dest) {{{1
173"
174" returns 1 if copy this path to the given location will cause files to
175" overwritten
176"
177" Args:
178" dest: the location this path will be copied to
179function! s:Path.copyingWillOverwrite(dest)
180 if filereadable(a:dest)
181 return 1
182 endif
183
184 if isdirectory(a:dest)
185 let path = s:Path.JoinPathStrings(a:dest, self.getLastPathComponent(0))
186 if filereadable(path)
187 return 1
188 endif
189 endif
190endfunction
191
192" FUNCTION: Path.createParentDirectories(path) {{{1
193"
194" create parent directories for this path if needed
195" without throwing any errors if those directories already exist
196"
197" Args:
198" path: full path of the node whose parent directories may need to be created
199function! s:Path.createParentDirectories(path)
200 let dir_path = fnamemodify(a:path, ':h')
201 if !isdirectory(dir_path)
202 call mkdir(dir_path, 'p')
203 endif
204endfunction
205
206" FUNCTION: Path.delete() {{{1
207"
208" Deletes the file or directory represented by this path.
209"
210" Throws NERDTree.Path.Deletion exceptions
211function! s:Path.delete()
212 if self.isDirectory
213
214 let cmd = g:NERDTreeRemoveDirCmd . self.str({'escape': 1})
215 let success = system(cmd)
216
217 if v:shell_error !=# 0
218 throw "NERDTree.PathDeletionError: Could not delete directory: '" . self.str() . "'"
219 endif
220 else
221 if exists('g:NERDTreeRemoveFileCmd')
222 let cmd = g:NERDTreeRemoveFileCmd . self.str({'escape': 1})
223 let success = system(cmd)
224 else
225 let success = delete(self.str())
226 endif
227
228 if success !=# 0
229 throw "NERDTree.PathDeletionError: Could not delete file: '" . self.str() . "'"
230 endif
231 endif
232
233 "delete all bookmarks for this path
234 for i in self.bookmarkNames()
235 let bookmark = g:NERDTreeBookmark.BookmarkFor(i)
236 call bookmark.delete()
237 endfor
238endfunction
239
240" FUNCTION: Path.displayString() {{{1
241"
242" Returns a string that specifies how the path should be represented as a
243" string
244function! s:Path.displayString()
245 if self.cachedDisplayString ==# ''
246 call self.cacheDisplayString()
247 endif
248
249 return self.cachedDisplayString
250endfunction
251
252" FUNCTION: Path.edit() {{{1
253function! s:Path.edit()
254 let l:bufname = self.str({'format': 'Edit'})
255 if bufname('%') !=# l:bufname
256 exec 'edit ' . l:bufname
257 endif
258endfunction
259
260" FUNCTION: Path.extractDriveLetter(fullpath) {{{1
261"
262" If running windows, cache the drive letter for this path
263function! s:Path.extractDriveLetter(fullpath)
264 if nerdtree#runningWindows()
265 if a:fullpath =~# '^\(\\\\\|\/\/\)'
266 "For network shares, the 'drive' consists of the first two parts of the path, i.e. \\boxname\share
267 let self.drive = substitute(a:fullpath, '^\(\(\\\\\|\/\/\)[^\\\/]*\(\\\|\/\)[^\\\/]*\).*', '\1', '')
268 let self.drive = substitute(self.drive, '/', '\', 'g')
269 else
270 let self.drive = substitute(a:fullpath, '\(^[a-zA-Z]:\).*', '\1', '')
271 endif
272 else
273 let self.drive = ''
274 endif
275
276endfunction
277
278" FUNCTION: Path.exists() {{{1
279" return 1 if this path points to a location that is readable or is a directory
280function! s:Path.exists()
281 let p = self.str()
282 return filereadable(p) || isdirectory(p)
283endfunction
284
285" FUNCTION: Path._escChars() {{{1
286function! s:Path._escChars()
287 if nerdtree#runningWindows()
288 return " `\|\"#%&,?()\*^<>$"
289 endif
290
291 return " \\`\|\"#%&,?()\*^<>[]{}$"
292endfunction
293
294" FUNCTION: Path.getDir() {{{1
295"
296" Returns this path if it is a directory, else this paths parent.
297"
298" Return:
299" a Path object
300function! s:Path.getDir()
301 if self.isDirectory
302 return self
303 else
304 return self.getParent()
305 endif
306endfunction
307
308" FUNCTION: Path.getParent() {{{1
309"
310" Returns a new path object for this paths parent
311"
312" Return:
313" a new Path object
314function! s:Path.getParent()
315 if nerdtree#runningWindows()
316 let path = self.drive . '\' . join(self.pathSegments[0:-2], '\')
317 else
318 let path = '/'. join(self.pathSegments[0:-2], '/')
319 endif
320
321 return s:Path.New(path)
322endfunction
323
324" FUNCTION: Path.getLastPathComponent(dirSlash) {{{1
325"
326" Gets the last part of this path.
327"
328" Args:
329" dirSlash: if 1 then a trailing slash will be added to the returned value for
330" directory nodes.
331function! s:Path.getLastPathComponent(dirSlash)
332 if empty(self.pathSegments)
333 return ''
334 endif
335 let toReturn = self.pathSegments[-1]
336 if a:dirSlash && self.isDirectory
337 let toReturn = toReturn . '/'
338 endif
339 return toReturn
340endfunction
341
342" FUNCTION: Path.getSortOrderIndex() {{{1
343" returns the index of the pattern in g:NERDTreeSortOrder that this path matches
344function! s:Path.getSortOrderIndex()
345 let i = 0
346 while i < len(g:NERDTreeSortOrder)
347 if g:NERDTreeSortOrder[i] !~? '\[\[-\?\(timestamp\|size\|extension\)\]\]' &&
348 \ self.getLastPathComponent(1) =~# g:NERDTreeSortOrder[i]
349 return i
350 endif
351 let i = i + 1
352 endwhile
353
354 return index(g:NERDTreeSortOrder, '*')
355endfunction
356
357" FUNCTION: Path._splitChunks(path) {{{1
358" returns a list of path chunks
359function! s:Path._splitChunks(path)
360 let chunks = split(a:path, '\(\D\+\|\d\+\)\zs')
361 let i = 0
362 while i < len(chunks)
363 "convert number literals to numbers
364 if match(chunks[i], '^\d\+$') ==# 0
365 let chunks[i] = str2nr(chunks[i])
366 endif
367 let i = i + 1
368 endwhile
369 return chunks
370endfunction
371
372" FUNCTION: Path.getSortKey() {{{1
373" returns a key used in compare function for sorting
374function! s:Path.getSortKey()
375 if !exists('self._sortKey') || g:NERDTreeSortOrder !=# g:NERDTreeOldSortOrder
376 " Look for file metadata tags: [[timestamp]], [[extension]], [[size]]
377 let metadata = []
378 for tag in g:NERDTreeSortOrder
379 if tag =~? '\[\[-\?timestamp\]\]'
380 let metadata += [self.isDirectory ? 0 : getftime(self.str()) * (tag =~# '-' ? -1 : 1)]
381 elseif tag =~? '\[\[-\?size\]\]'
382 let metadata += [self.isDirectory ? 0 : getfsize(self.str()) * (tag =~# '-' ? -1 : 1)]
383 elseif tag =~? '\[\[extension\]\]'
384 let extension = matchstr(self.getLastPathComponent(0), '[^.]\+\.\zs[^.]\+$')
385 let metadata += [self.isDirectory ? '' : (extension ==# '' ? nr2char(str2nr('0x10ffff',16)) : extension)]
386 endif
387 endfor
388
389 if g:NERDTreeSortOrder[0] =~# '\[\[.*\]\]'
390 " Apply tags' sorting first if specified first.
391 let self._sortKey = metadata + [self.getSortOrderIndex()]
392 else
393 " Otherwise, do regex grouping first.
394 let self._sortKey = [self.getSortOrderIndex()] + metadata
395 endif
396
397 let path = self.getLastPathComponent(0)
398 if !g:NERDTreeSortHiddenFirst
399 let path = substitute(path, '^[._]', '', '')
400 endif
401 if !g:NERDTreeCaseSensitiveSort
402 let path = tolower(path)
403 endif
404
405 call extend(self._sortKey, (g:NERDTreeNaturalSort ? self._splitChunks(path) : [path]))
406 endif
407 return self._sortKey
408endfunction
409
410" FUNCTION: Path.isHiddenUnder(path) {{{1
411function! s:Path.isHiddenUnder(path)
412
413 if !self.isUnder(a:path)
414 return 0
415 endif
416
417 let l:startIndex = len(a:path.pathSegments)
418 let l:segments = self.pathSegments[l:startIndex : ]
419
420 for l:segment in l:segments
421
422 if l:segment =~# '^\.'
423 return 1
424 endif
425 endfor
426
427 return 0
428endfunction
429
430" FUNCTION: Path.isUnixHiddenFile() {{{1
431" check for unix hidden files
432function! s:Path.isUnixHiddenFile()
433 return self.getLastPathComponent(0) =~# '^\.'
434endfunction
435
436" FUNCTION: Path.isUnixHiddenPath() {{{1
437" check for unix path with hidden components
438function! s:Path.isUnixHiddenPath()
439 if self.getLastPathComponent(0) =~# '^\.'
440 return 1
441 else
442 for segment in self.pathSegments
443 if segment =~# '^\.'
444 return 1
445 endif
446 endfor
447 return 0
448 endif
449endfunction
450
451" FUNCTION: Path.ignore(nerdtree) {{{1
452" returns true if this path should be ignored
453function! s:Path.ignore(nerdtree)
454 "filter out the user specified paths to ignore
455 if a:nerdtree.ui.isIgnoreFilterEnabled()
456 for i in g:NERDTreeIgnore
457 if self._ignorePatternMatches(i)
458 return 1
459 endif
460 endfor
461
462 for l:Callback in g:NERDTree.PathFilters()
463 let l:Callback = type(l:Callback) ==# type(function('tr')) ? l:Callback : function(l:Callback)
464 if l:Callback({'path': self, 'nerdtree': a:nerdtree})
465 return 1
466 endif
467 endfor
468 endif
469
470 "dont show hidden files unless instructed to
471 if !a:nerdtree.ui.getShowHidden() && self.isUnixHiddenFile()
472 return 1
473 endif
474
475 if a:nerdtree.ui.getShowFiles() ==# 0 && self.isDirectory ==# 0
476 return 1
477 endif
478
479 return 0
480endfunction
481
482" FUNCTION: Path._ignorePatternMatches(pattern) {{{1
483" returns true if this path matches the given ignore pattern
484function! s:Path._ignorePatternMatches(pattern)
485 let pat = a:pattern
486 if strpart(pat,len(pat)-8) ==# '[[path]]'
487 let pat = strpart(pat,0, len(pat)-8)
488 return self.str() =~# pat
489 elseif strpart(pat,len(pat)-7) ==# '[[dir]]'
490 if !self.isDirectory
491 return 0
492 endif
493 let pat = strpart(pat,0, len(pat)-7)
494 elseif strpart(pat,len(pat)-8) ==# '[[file]]'
495 if self.isDirectory
496 return 0
497 endif
498 let pat = strpart(pat,0, len(pat)-8)
499 endif
500
501 return self.getLastPathComponent(0) =~# pat
502endfunction
503
504" FUNCTION: Path.isAncestor(path) {{{1
505" return 1 if this path is somewhere above the given path in the filesystem.
506"
507" a:path should be a dir
508function! s:Path.isAncestor(child)
509 return a:child.isUnder(self)
510endfunction
511
512" FUNCTION: Path.isUnder(path) {{{1
513" return 1 if this path is somewhere under the given path in the filesystem.
514function! s:Path.isUnder(parent)
515 if a:parent.isDirectory ==# 0
516 return 0
517 endif
518 if nerdtree#runningWindows() && a:parent.drive !=# self.drive
519 return 0
520 endif
521 let l:this_count = len(self.pathSegments)
522 if l:this_count ==# 0
523 return 0
524 endif
525 let l:that_count = len(a:parent.pathSegments)
526 if l:that_count ==# 0
527 return 1
528 endif
529 if l:that_count >= l:this_count
530 return 0
531 endif
532 for i in range(0, l:that_count-1)
533 if self.pathSegments[i] !=# a:parent.pathSegments[i]
534 return 0
535 endif
536 endfor
537 return 1
538endfunction
539
540" FUNCTION: Path.JoinPathStrings(...) {{{1
541function! s:Path.JoinPathStrings(...)
542 let components = []
543 for i in a:000
544 let components = extend(components, split(i, '/'))
545 endfor
546 return '/' . join(components, '/')
547endfunction
548
549" FUNCTION: Path.equals() {{{1
550"
551" Determines whether 2 path objects are "equal".
552" They are equal if the paths they represent are the same
553"
554" Args:
555" path: the other path obj to compare this with
556function! s:Path.equals(path)
557 if nerdtree#runningWindows()
558 return self.str() ==? a:path.str()
559 else
560 return self.str() ==# a:path.str()
561 endif
562endfunction
563
564" FUNCTION: Path.New(pathStr) {{{1
565function! s:Path.New(pathStr)
566 let l:newPath = copy(self)
567
568 call l:newPath.readInfoFromDisk(s:Path.AbsolutePathFor(a:pathStr))
569
570 let l:newPath.cachedDisplayString = ''
571 let l:newPath.flagSet = g:NERDTreeFlagSet.New()
572
573 return l:newPath
574endfunction
575
576" FUNCTION: Path.Resolve() {{{1
577" Invoke the vim resolve() function and return the result
578" This is necessary because in some versions of vim resolve() removes trailing
579" slashes while in other versions it doesn't. This always removes the trailing
580" slash
581function! s:Path.Resolve(path)
582 let tmp = resolve(a:path)
583 return tmp =~# '.\+/$' ? substitute(tmp, '/$', '', '') : tmp
584endfunction
585
586" FUNCTION: Path.readInfoFromDisk(fullpath) {{{1
587"
588"
589" Throws NERDTree.Path.InvalidArguments exception.
590function! s:Path.readInfoFromDisk(fullpath)
591 call self.extractDriveLetter(a:fullpath)
592
593 let fullpath = s:Path.WinToUnixPath(a:fullpath)
594
595 if getftype(fullpath) ==# 'fifo'
596 throw 'NERDTree.InvalidFiletypeError: Cant handle FIFO files: ' . a:fullpath
597 endif
598
599 let self.pathSegments = filter(split(fullpath, '/'), '!empty(v:val)')
600
601 let self.isReadOnly = 0
602 if isdirectory(a:fullpath)
603 let self.isDirectory = 1
604 elseif filereadable(a:fullpath)
605 let self.isDirectory = 0
606 let self.isReadOnly = filewritable(a:fullpath) ==# 0
607 else
608 throw 'NERDTree.InvalidArgumentsError: Invalid path = ' . a:fullpath
609 endif
610
611 let self.isExecutable = 0
612 if !self.isDirectory
613 let self.isExecutable = getfperm(a:fullpath) =~# 'x'
614 endif
615
616 "grab the last part of the path (minus the trailing slash)
617 let lastPathComponent = self.getLastPathComponent(0)
618
619 "get the path to the new node with the parent dir fully resolved
620 let hardPath = s:Path.Resolve(self.strTrunk()) . '/' . lastPathComponent
621
622 "if the last part of the path is a symlink then flag it as such
623 let self.isSymLink = (s:Path.Resolve(hardPath) !=# hardPath)
624 if self.isSymLink
625 let self.symLinkDest = s:Path.Resolve(fullpath)
626
627 "if the link is a dir then slap a / on the end of its dest
628 if isdirectory(self.symLinkDest)
629
630 "we always wanna treat MS windows shortcuts as files for
631 "simplicity
632 if hardPath !~# '\.lnk$'
633
634 let self.symLinkDest = self.symLinkDest . '/'
635 endif
636 endif
637 endif
638endfunction
639
640" FUNCTION: Path.refresh(nerdtree) {{{1
641function! s:Path.refresh(nerdtree)
642 call self.readInfoFromDisk(self.str())
643 call g:NERDTreePathNotifier.NotifyListeners('refresh', self, a:nerdtree, {})
644 call self.cacheDisplayString()
645endfunction
646
647" FUNCTION: Path.refreshFlags(nerdtree) {{{1
648function! s:Path.refreshFlags(nerdtree)
649 call g:NERDTreePathNotifier.NotifyListeners('refreshFlags', self, a:nerdtree, {})
650 call self.cacheDisplayString()
651endfunction
652
653" FUNCTION: Path.rename() {{{1
654"
655" Renames this node on the filesystem
656function! s:Path.rename(newPath)
657 if a:newPath ==# ''
658 throw 'NERDTree.InvalidArgumentsError: Invalid newPath for renaming = '. a:newPath
659 endif
660
661 call s:Path.createParentDirectories(a:newPath)
662
663 let success = rename(self.str(), a:newPath)
664 if success !=# 0
665 throw "NERDTree.PathRenameError: Could not rename: '" . self.str() . "'" . 'to:' . a:newPath
666 endif
667 call self.readInfoFromDisk(a:newPath)
668
669 for i in self.bookmarkNames()
670 let b = g:NERDTreeBookmark.BookmarkFor(i)
671 call b.setPath(copy(self))
672 endfor
673 call g:NERDTreeBookmark.Write()
674endfunction
675
676" FUNCTION: Path.str() {{{1
677" Return a string representation of this Path object.
678"
679" Args:
680" This function takes a single dictionary (optional) with keys and values that
681" specify how the returned pathname should be formatted.
682"
683" The dictionary may have the following keys:
684" 'format'
685" 'escape'
686" 'truncateTo'
687"
688" The 'format' key may have a value of:
689" 'Cd' - a string to be used with ":cd" and similar commands
690" 'Edit' - a string to be used with ":edit" and similar commands
691" 'UI' - a string to be displayed in the NERDTree user interface
692"
693" The 'escape' key, if specified, will cause the output to be escaped with
694" Vim's internal "shellescape()" function.
695"
696" The 'truncateTo' key shortens the length of the path to that given by the
697" value associated with 'truncateTo'. A '<' is prepended.
698function! s:Path.str(...)
699 let options = a:0 ? a:1 : {}
700 let toReturn = ''
701
702 if has_key(options, 'format')
703 let format = options['format']
704 if has_key(self, '_strFor' . format)
705 exec 'let toReturn = self._strFor' . format . '()'
706 else
707 throw 'NERDTree.UnknownFormatError: unknown format "'. format .'"'
708 endif
709 else
710 let toReturn = self._str()
711 endif
712
713 if nerdtree#has_opt(options, 'escape')
714 let toReturn = shellescape(toReturn)
715 endif
716
717 if has_key(options, 'truncateTo')
718 let limit = options['truncateTo']
719 if strdisplaywidth(toReturn) > limit-1
720 while strdisplaywidth(toReturn) > limit-1 && strchars(toReturn) > 0
721 let toReturn = substitute(toReturn, '^.', '', '')
722 endwhile
723 if len(split(toReturn, '/')) > 1
724 let toReturn = '</' . join(split(toReturn, '/')[1:], '/') . '/'
725 else
726 let toReturn = '<' . toReturn
727 endif
728 endif
729 endif
730
731 return toReturn
732endfunction
733
734" FUNCTION: Path._strForUI() {{{1
735function! s:Path._strForUI()
736 let toReturn = '/' . join(self.pathSegments, '/')
737 if self.isDirectory && toReturn !=# '/'
738 let toReturn = toReturn . '/'
739 endif
740 return toReturn
741endfunction
742
743" FUNCTION: Path._strForCd() {{{1
744" Return a string representation of this Path that is suitable for use as an
745" argument to Vim's internal ":cd" command.
746function! s:Path._strForCd()
747 return fnameescape(self.str())
748endfunction
749
750" FUNCTION: Path._strForEdit() {{{1
751" Return a string representation of this Path that is suitable for use as an
752" argument to Vim's internal ":edit" command.
753function! s:Path._strForEdit()
754
755 " Make the path relative to the current working directory, if possible.
756 let l:result = fnamemodify(self.str(), ':.')
757
758 " On Windows, the drive letter may be removed by "fnamemodify()". Add it
759 " back, if necessary.
760 if nerdtree#runningWindows() && l:result[0] == nerdtree#slash()
761 let l:result = self.drive . l:result
762 endif
763
764 let l:result = fnameescape(l:result)
765
766 if empty(l:result)
767 let l:result = '.'
768 endif
769
770 return l:result
771endfunction
772
773" FUNCTION: Path._strForGlob() {{{1
774function! s:Path._strForGlob()
775 let lead = nerdtree#slash()
776
777 "if we are running windows then slap a drive letter on the front
778 if nerdtree#runningWindows()
779 let lead = self.drive . '\'
780 endif
781
782 let toReturn = lead . join(self.pathSegments, nerdtree#slash())
783
784 if !nerdtree#runningWindows()
785 let toReturn = escape(toReturn, self._escChars())
786 endif
787 return toReturn
788endfunction
789
790" FUNCTION: Path._str() {{{1
791" Return the absolute pathname associated with this Path object. The pathname
792" returned is appropriate for the underlying file system.
793function! s:Path._str()
794 let l:separator = nerdtree#slash()
795 let l:leader = l:separator
796
797 if nerdtree#runningWindows()
798 let l:leader = self.drive . l:separator
799 endif
800
801 return l:leader . join(self.pathSegments, l:separator)
802endfunction
803
804" FUNCTION: Path.strTrunk() {{{1
805" Gets the path without the last segment on the end.
806function! s:Path.strTrunk()
807 return self.drive . '/' . join(self.pathSegments[0:-2], '/')
808endfunction
809
810" FUNCTION: Path.tabnr() {{{1
811" return the number of the first tab that is displaying this file
812"
813" return 0 if no tab was found
814function! s:Path.tabnr()
815 let str = self.str()
816 for t in range(tabpagenr('$'))
817 for b in tabpagebuflist(t+1)
818 if str ==# expand('#' . b . ':p')
819 return t+1
820 endif
821 endfor
822 endfor
823 return 0
824endfunction
825
826" FUNCTION: Path.WinToUnixPath(pathstr){{{1
827" Takes in a windows path and returns the unix equiv
828"
829" A class level method
830"
831" Args:
832" pathstr: the windows path to convert
833function! s:Path.WinToUnixPath(pathstr)
834 if !nerdtree#runningWindows()
835 return a:pathstr
836 endif
837
838 let toReturn = a:pathstr
839
840 "remove the x:\ of the front
841 let toReturn = substitute(toReturn, '^.*:\(\\\|/\)\?', '/', '')
842
843 "remove the \\ network share from the front
844 let toReturn = substitute(toReturn, '^\(\\\\\|\/\/\)[^\\\/]*\(\\\|\/\)[^\\\/]*\(\\\|\/\)\?', '/', '')
845
846 "convert all \ chars to /
847 let toReturn = substitute(toReturn, '\', '/', 'g')
848
849 return toReturn
850endfunction
851
852" vim: set sw=4 sts=4 et fdm=marker:
diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/tree_dir_node.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/tree_dir_node.vim
new file mode 100644
index 0000000..f5f7682
--- /dev/null
+++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/tree_dir_node.vim
@@ -0,0 +1,706 @@
1" ============================================================================
2" CLASS: TreeDirNode
3"
4" A subclass of NERDTreeFileNode.
5"
6" The 'composite' part of the file/dir composite.
7" ============================================================================
8
9
10let s:TreeDirNode = copy(g:NERDTreeFileNode)
11let g:NERDTreeDirNode = s:TreeDirNode
12
13" FUNCTION: TreeDirNode.AbsoluteTreeRoot(){{{1
14" Class method that returns the highest cached ancestor of the current root.
15function! s:TreeDirNode.AbsoluteTreeRoot()
16 let currentNode = b:NERDTree.root
17 while currentNode.parent !=# {}
18 let currentNode = currentNode.parent
19 endwhile
20 return currentNode
21endfunction
22
23" FUNCTION: TreeDirNode.activate([options]) {{{1
24function! s:TreeDirNode.activate(...)
25 let l:options = (a:0 > 0) ? a:1 : {}
26
27 call self.toggleOpen(l:options)
28
29 " Note that we only re-render the NERDTree for this node if we did NOT
30 " create a new node and render it in a new window or tab. In the latter
31 " case, rendering the NERDTree for this node could overwrite the text of
32 " the new NERDTree!
33 if !has_key(l:options, 'where') || empty(l:options['where'])
34 call self.getNerdtree().render()
35 call self.putCursorHere(0, 0)
36 endif
37endfunction
38
39" FUNCTION: TreeDirNode.addChild(treenode, inOrder) {{{1
40" Adds the given treenode to the list of children for this node
41"
42" Args:
43" -treenode: the node to add
44" -inOrder: 1 if the new node should be inserted in sorted order
45function! s:TreeDirNode.addChild(treenode, inOrder)
46 call add(self.children, a:treenode)
47 let a:treenode.parent = self
48
49 if a:inOrder
50 call self.sortChildren()
51 endif
52endfunction
53
54" FUNCTION: TreeDirNode.close() {{{1
55" Mark this TreeDirNode as closed.
56function! s:TreeDirNode.close()
57
58 " Close all directories in this directory node's cascade. This is
59 " necessary to ensure consistency when cascades are rendered.
60 for l:dirNode in self.getCascade()
61 let l:dirNode.isOpen = 0
62 endfor
63endfunction
64
65" FUNCTION: TreeDirNode.closeChildren() {{{1
66" Recursively close any directory nodes that are descendants of this node.
67function! s:TreeDirNode.closeChildren()
68 for l:child in self.children
69 if l:child.path.isDirectory
70 call l:child.close()
71 call l:child.closeChildren()
72 endif
73 endfor
74endfunction
75
76" FUNCTION: TreeDirNode.createChild(path, inOrder) {{{1
77" Instantiates a new child node for this node with the given path. The new
78" nodes parent is set to this node.
79"
80" Args:
81" path: a Path object that this node will represent/contain
82" inOrder: 1 if the new node should be inserted in sorted order
83"
84" Returns:
85" the newly created node
86function! s:TreeDirNode.createChild(path, inOrder)
87 let newTreeNode = g:NERDTreeFileNode.New(a:path, self.getNerdtree())
88 call self.addChild(newTreeNode, a:inOrder)
89 return newTreeNode
90endfunction
91
92" FUNCTION: TreeDirNode.displayString() {{{1
93" Assemble and return a string that can represent this TreeDirNode object in
94" the NERDTree window.
95function! s:TreeDirNode.displayString()
96 let l:result = ''
97
98 " Build a label that identifies this TreeDirNode.
99 let l:label = ''
100 let l:cascade = self.getCascade()
101 for l:dirNode in l:cascade
102 let l:next = l:dirNode.path.displayString()
103 let l:label .= l:label ==# '' ? l:next : substitute(l:next,'^.','','')
104 endfor
105
106 " Select the appropriate open/closed status indicator symbol.
107 let l:symbol = (l:cascade[-1].isOpen ? g:NERDTreeDirArrowCollapsible : g:NERDTreeDirArrowExpandable )
108 let l:symbol .= (g:NERDTreeDirArrowExpandable ==# '' ? '' : ' ')
109 let l:flags = l:cascade[-1].path.flagSet.renderToString()
110
111 return l:symbol . l:flags . l:label
112endfunction
113
114" FUNCTION: TreeDirNode.findNode(path) {{{1
115" Will find one of the children (recursively) that has the given path
116"
117" Args:
118" path: a path object
119unlet s:TreeDirNode.findNode
120function! s:TreeDirNode.findNode(path)
121 if a:path.equals(self.path)
122 return self
123 endif
124 if stridx(a:path.str(), self.path.str(), 0) ==# -1
125 return {}
126 endif
127
128 if self.path.isDirectory
129 for i in self.children
130 let retVal = i.findNode(a:path)
131 if retVal !=# {}
132 return retVal
133 endif
134 endfor
135 endif
136 return {}
137endfunction
138
139" FUNCTION: TreeDirNode.getCascade() {{{1
140" Return an array of dir nodes (starting from self) that can be cascade opened.
141function! s:TreeDirNode.getCascade()
142 if !self.isCascadable()
143 return [self]
144 endif
145
146 let vc = self.getVisibleChildren()
147 let visChild = vc[0]
148
149 return [self] + visChild.getCascade()
150endfunction
151
152" FUNCTION: TreeDirNode.getCascadeRoot() {{{1
153" Return the first directory node in the cascade in which this directory node
154" is rendered.
155function! s:TreeDirNode.getCascadeRoot()
156
157 " Don't search above the current NERDTree root node.
158 if self.isRoot()
159 return self
160 endif
161
162 let l:cascadeRoot = self
163 let l:parent = self.parent
164
165 while !empty(l:parent) && !l:parent.isRoot()
166
167 if index(l:parent.getCascade(), self) ==# -1
168 break
169 endif
170
171 let l:cascadeRoot = l:parent
172 let l:parent = l:parent.parent
173 endwhile
174
175 return l:cascadeRoot
176endfunction
177
178" FUNCTION: TreeDirNode.getChildCount() {{{1
179" Returns the number of children this node has
180function! s:TreeDirNode.getChildCount()
181 return len(self.children)
182endfunction
183
184" FUNCTION: TreeDirNode.getChild(path) {{{1
185" Returns child node of this node that has the given path or {} if no such node
186" exists.
187"
188" This function doesnt not recurse into child dir nodes
189"
190" Args:
191" path: a path object
192function! s:TreeDirNode.getChild(path)
193 if stridx(a:path.str(), self.path.str(), 0) ==# -1
194 return {}
195 endif
196
197 let index = self.getChildIndex(a:path)
198 if index ==# -1
199 return {}
200 else
201 return self.children[index]
202 endif
203
204endfunction
205
206" FUNCTION: TreeDirNode.getChildByIndex(indx, visible) {{{1
207" returns the child at the given index
208"
209" Args:
210" indx: the index to get the child from
211" visible: 1 if only the visible children array should be used, 0 if all the
212" children should be searched.
213function! s:TreeDirNode.getChildByIndex(indx, visible)
214 let array_to_search = a:visible? self.getVisibleChildren() : self.children
215 if a:indx > len(array_to_search)
216 throw 'NERDTree.InvalidArgumentsError: Index is out of bounds.'
217 endif
218 return array_to_search[a:indx]
219endfunction
220
221" FUNCTION: TreeDirNode.getChildIndex(path) {{{1
222" Returns the index of the child node of this node that has the given path or
223" -1 if no such node exists.
224"
225" This function doesnt not recurse into child dir nodes
226"
227" Args:
228" path: a path object
229function! s:TreeDirNode.getChildIndex(path)
230 if stridx(a:path.str(), self.path.str(), 0) ==# -1
231 return -1
232 endif
233
234 "do a binary search for the child
235 let a = 0
236 let z = self.getChildCount()
237 while a < z
238 let mid = (a+z)/2
239 let diff = nerdtree#compareNodePaths(a:path, self.children[mid].path)
240
241 if diff ==# -1
242 let z = mid
243 elseif diff ==# 1
244 let a = mid+1
245 else
246 return mid
247 endif
248 endwhile
249 return -1
250endfunction
251
252" FUNCTION: TreeDirNode.getDirChildren() {{{1
253" Return a list of all child nodes from 'self.children' that are of type
254" TreeDirNode. This function supports http://github.com/scrooloose/nerdtree-project-plugin.git.
255function! s:TreeDirNode.getDirChildren()
256 return filter(copy(self.children), 'v:val.path.isDirectory ==# 1')
257endfunction
258
259" FUNCTION: TreeDirNode._glob(pattern, all) {{{1
260" Return a list of strings naming the descendants of the directory in this
261" TreeDirNode object that match the specified glob pattern.
262"
263" Args:
264" pattern: (string) the glob pattern to apply
265" all: (0 or 1) if 1, include '.' and '..' if they match 'pattern'; if 0,
266" always exclude them
267"
268" Note: If the pathnames in the result list are below the working directory,
269" they are returned as pathnames relative to that directory. This is because
270" this function, internally, attempts to obey 'wildignore' rules that use
271" relative paths.
272function! s:TreeDirNode._glob(pattern, all)
273
274 " Construct a path specification such that globpath() will return
275 " relative pathnames, if possible.
276 if self.path.str() ==# getcwd()
277 let l:pathSpec = ','
278 else
279 let l:pathSpec = escape(fnamemodify(self.path.str({'format': 'Glob'}), ':.'), ',')
280
281 " On Windows, the drive letter may be removed by "fnamemodify()".
282 if nerdtree#runningWindows() && l:pathSpec[0] == nerdtree#slash()
283 let l:pathSpec = self.path.drive . l:pathSpec
284 endif
285 endif
286
287 let l:globList = []
288
289 " See ':h version7.txt' and ':h version8.txt' for details on the
290 " development of the glob() and globpath() functions.
291 if v:version > 704 || (v:version ==# 704 && has('patch654'))
292 let l:globList = globpath(l:pathSpec, a:pattern, !g:NERDTreeRespectWildIgnore, 1, 0)
293 elseif v:version ==# 704 && has('patch279')
294 let l:globList = globpath(l:pathSpec, a:pattern, !g:NERDTreeRespectWildIgnore, 1)
295 elseif v:version > 702 || (v:version ==# 702 && has('patch051'))
296 let l:globString = globpath(l:pathSpec, a:pattern, !g:NERDTreeRespectWildIgnore)
297 let l:globList = split(l:globString, "\n")
298 else
299 let l:globString = globpath(l:pathSpec, a:pattern)
300 let l:globList = split(l:globString, "\n")
301 endif
302
303 " If a:all is false, filter '.' and '..' from the output.
304 if !a:all
305 let l:toRemove = []
306
307 for l:file in l:globList
308 let l:tail = fnamemodify(l:file, ':t')
309
310 " If l:file has a trailing slash, then its :tail will be ''. Use
311 " :h to drop the slash and the empty string after it; then use :t
312 " to get the directory name.
313 if l:tail ==# ''
314 let l:tail = fnamemodify(l:file, ':h:t')
315 endif
316
317 if l:tail ==# '.' || l:tail ==# '..'
318 call add(l:toRemove, l:file)
319 if len(l:toRemove) ==# 2
320 break
321 endif
322 endif
323 endfor
324
325 for l:file in l:toRemove
326 call remove(l:globList, index(l:globList, l:file))
327 endfor
328 endif
329
330 return l:globList
331endfunction
332
333" FUNCTION: TreeDirNode.GetSelected() {{{1
334" Returns the current node if it is a dir node, or else returns the current
335" nodes parent
336unlet s:TreeDirNode.GetSelected
337function! s:TreeDirNode.GetSelected()
338 let currentDir = g:NERDTreeFileNode.GetSelected()
339 if currentDir !=# {} && !currentDir.isRoot()
340 if currentDir.path.isDirectory ==# 0
341 let currentDir = currentDir.parent
342 endif
343 endif
344 return currentDir
345endfunction
346
347" FUNCTION: TreeDirNode.getVisibleChildCount() {{{1
348" Returns the number of visible children this node has
349function! s:TreeDirNode.getVisibleChildCount()
350 return len(self.getVisibleChildren())
351endfunction
352
353" FUNCTION: TreeDirNode.getVisibleChildren() {{{1
354" Returns a list of children to display for this node, in the correct order
355"
356" Return:
357" an array of treenodes
358function! s:TreeDirNode.getVisibleChildren()
359 let toReturn = []
360 for i in self.children
361 if i.path.ignore(self.getNerdtree()) ==# 0
362 call add(toReturn, i)
363 endif
364 endfor
365 return toReturn
366endfunction
367
368" FUNCTION: TreeDirNode.hasVisibleChildren() {{{1
369" returns 1 if this node has any childre, 0 otherwise..
370function! s:TreeDirNode.hasVisibleChildren()
371 return self.getVisibleChildCount() !=# 0
372endfunction
373
374" FUNCTION: TreeDirNode.isCascadable() {{{1
375" true if this dir has only one visible child that is also a dir
376" false if this dir is bookmarked or symlinked. Why? Two reasons:
377" 1. If cascaded, we don't know which dir is bookmarked or is a symlink.
378" 2. If the parent is a symlink or is bookmarked, you end up with unparsable
379" text, and NERDTree cannot get the path of any child node.
380" Also, return false if this directory is the tree root, which should never be
381" part of a cascade.
382function! s:TreeDirNode.isCascadable()
383 if g:NERDTreeCascadeSingleChildDir ==# 0
384 return 0
385 endif
386
387 if self.isRoot()
388 return 0
389 endif
390
391 if self.path.isSymLink
392 return 0
393 endif
394
395 for i in g:NERDTreeBookmark.Bookmarks()
396 if i.path.equals(self.path)
397 return 0
398 endif
399 endfor
400
401 let c = self.getVisibleChildren()
402 return len(c) ==# 1 && c[0].path.isDirectory
403endfunction
404
405" FUNCTION: TreeDirNode._initChildren() {{{1
406" Removes all childen from this node and re-reads them
407"
408" Args:
409" silent: 1 if the function should not echo any 'please wait' messages for
410" large directories
411"
412" Return: the number of child nodes read
413function! s:TreeDirNode._initChildren(silent)
414 "remove all the current child nodes
415 let self.children = []
416
417 let files = self._glob('*', 1) + self._glob('.*', 0)
418
419 if !a:silent && len(files) > g:NERDTreeNotificationThreshold
420 call nerdtree#echo('Please wait, caching a large dir ...')
421 endif
422
423 let invalidFilesFound = 0
424 for i in files
425 try
426 let path = g:NERDTreePath.New(i)
427 call self.createChild(path, 0)
428 call g:NERDTreePathNotifier.NotifyListeners('init', path, self.getNerdtree(), {})
429 catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/
430 let invalidFilesFound += 1
431 endtry
432 endfor
433
434 let g:NERDTreeOldSortOrder = g:NERDTreeSortOrder
435 call self.sortChildren()
436
437 call nerdtree#echo('')
438
439 if invalidFilesFound
440 call nerdtree#echoWarning(invalidFilesFound . ' file(s) could not be loaded into the NERD tree')
441 endif
442 return self.getChildCount()
443endfunction
444
445" FUNCTION: TreeDirNode.New(path, nerdtree) {{{1
446" Return a new TreeDirNode object with the given path and parent.
447"
448" Args:
449" path: dir that the node represents
450" nerdtree: the tree the node belongs to
451function! s:TreeDirNode.New(path, nerdtree)
452 if a:path.isDirectory !=# 1
453 throw 'NERDTree.InvalidArgumentsError: A TreeDirNode object must be instantiated with a directory Path object.'
454 endif
455
456 let newTreeNode = copy(self)
457 let newTreeNode.path = a:path
458
459 let newTreeNode.isOpen = 0
460 let newTreeNode.children = []
461
462 let newTreeNode.parent = {}
463 let newTreeNode._nerdtree = a:nerdtree
464
465 return newTreeNode
466endfunction
467
468" FUNCTION: TreeDirNode.open([options]) {{{1
469" Open this directory node in the current tree or elsewhere if special options
470" are provided. Return 0 if options were processed. Otherwise, return the
471" number of new cached nodes.
472function! s:TreeDirNode.open(...)
473 let l:options = a:0 ? a:1 : {}
474
475 " If special options were specified, process them and return.
476 if has_key(l:options, 'where') && !empty(l:options['where'])
477 let l:opener = g:NERDTreeOpener.New(self.path, l:options)
478 call l:opener.open(self)
479 return 0
480 endif
481
482 " Open any ancestors of this node that render within the same cascade.
483 let l:parent = self.parent
484 while !empty(l:parent) && !l:parent.isRoot()
485 if index(l:parent.getCascade(), self) >= 0
486 let l:parent.isOpen = 1
487 let l:parent = l:parent.parent
488 else
489 break
490 endif
491 endwhile
492
493 let self.isOpen = 1
494
495 let l:numChildrenCached = 0
496 if empty(self.children)
497 let l:numChildrenCached = self._initChildren(0)
498 endif
499
500 return l:numChildrenCached
501endfunction
502
503" FUNCTION: TreeDirNode.openAlong([opts]) {{{1
504" recursive open the dir if it has only one directory child.
505"
506" return the level of opened directories.
507function! s:TreeDirNode.openAlong(...)
508 let opts = a:0 ? a:1 : {}
509 let level = 0
510
511 let node = self
512 while node.path.isDirectory
513 call node.open(opts)
514 let level += 1
515 if node.getVisibleChildCount() ==# 1
516 let node = node.getChildByIndex(0, 1)
517 else
518 break
519 endif
520 endwhile
521 return level
522endfunction
523
524" FUNCTION: TreeDirNode.openExplorer() {{{1
525" Open an explorer window for this node in the previous window. The explorer
526" can be a NERDTree window or a netrw window.
527function! s:TreeDirNode.openExplorer()
528 execute 'wincmd p'
529 execute 'edit '.self.path.str({'format':'Edit'})
530endfunction
531
532" FUNCTION: TreeDirNode.openInNewTab(options) {{{1
533unlet s:TreeDirNode.openInNewTab
534function! s:TreeDirNode.openInNewTab(options)
535 call nerdtree#deprecated('TreeDirNode.openInNewTab', 'is deprecated, use open() instead')
536 call self.open({'where': 't'})
537endfunction
538
539" FUNCTION: TreeDirNode._openInNewTab() {{{1
540function! s:TreeDirNode._openInNewTab()
541 tabnew
542 call g:NERDTreeCreator.CreateTabTree(self.path.str())
543endfunction
544
545" FUNCTION: TreeDirNode.openRecursively() {{{1
546" Open this directory node and any descendant directory nodes whose pathnames
547" are not ignored.
548function! s:TreeDirNode.openRecursively()
549 silent call self.open()
550
551 for l:child in self.children
552 if l:child.path.isDirectory && !l:child.path.ignore(l:child.getNerdtree())
553 call l:child.openRecursively()
554 endif
555 endfor
556endfunction
557
558" FUNCTION: TreeDirNode.refresh() {{{1
559function! s:TreeDirNode.refresh()
560 call self.path.refresh(self.getNerdtree())
561
562 "if this node was ever opened, refresh its children
563 if self.isOpen || !empty(self.children)
564 let files = self._glob('*', 1) + self._glob('.*', 0)
565 let newChildNodes = []
566 let invalidFilesFound = 0
567 for i in files
568 try
569 "create a new path and see if it exists in this nodes children
570 let path = g:NERDTreePath.New(i)
571 let newNode = self.getChild(path)
572 if newNode !=# {}
573 call newNode.refresh()
574 call add(newChildNodes, newNode)
575
576 "the node doesnt exist so create it
577 else
578 let newNode = g:NERDTreeFileNode.New(path, self.getNerdtree())
579 let newNode.parent = self
580 call add(newChildNodes, newNode)
581 endif
582 catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/
583 let invalidFilesFound = 1
584 endtry
585 endfor
586
587 "swap this nodes children out for the children we just read/refreshed
588 let self.children = newChildNodes
589 call self.sortChildren()
590
591 if invalidFilesFound
592 call nerdtree#echoWarning('some files could not be loaded into the NERD tree')
593 endif
594 endif
595endfunction
596
597" FUNCTION: TreeDirNode.refreshFlags() {{{1
598unlet s:TreeDirNode.refreshFlags
599function! s:TreeDirNode.refreshFlags()
600 call self.path.refreshFlags(self.getNerdtree())
601 for i in self.children
602 call i.refreshFlags()
603 endfor
604endfunction
605
606" FUNCTION: TreeDirNode.refreshDirFlags() {{{1
607function! s:TreeDirNode.refreshDirFlags()
608 call self.path.refreshFlags(self.getNerdtree())
609endfunction
610
611" FUNCTION: TreeDirNode.reveal(path) {{{1
612" reveal the given path, i.e. cache and open all treenodes needed to display it
613" in the UI
614" Returns the revealed node
615function! s:TreeDirNode.reveal(path, ...)
616 let opts = a:0 ? a:1 : {}
617
618 if !a:path.isUnder(self.path)
619 throw 'NERDTree.InvalidArgumentsError: ' . a:path.str() . ' should be under ' . self.path.str()
620 endif
621
622 call self.open()
623
624 if self.path.equals(a:path.getParent())
625 let n = self.findNode(a:path)
626 " We may be looking for a newly-saved file that isn't in the tree yet.
627 if n ==# {}
628 call self.refresh()
629 let n = self.findNode(a:path)
630 endif
631 if has_key(opts, 'open')
632 call n.open()
633 endif
634 return n
635 endif
636
637 let p = a:path
638 while !p.getParent().equals(self.path)
639 let p = p.getParent()
640 endwhile
641
642 let n = self.findNode(p)
643 return n.reveal(a:path, opts)
644endfunction
645
646" FUNCTION: TreeDirNode.removeChild(treenode) {{{1
647" Remove the given treenode from self.children.
648" Throws NERDTree.ChildNotFoundError if the node is not found.
649"
650" Args:
651" treenode: the node object to remove
652function! s:TreeDirNode.removeChild(treenode)
653 for i in range(0, self.getChildCount()-1)
654 if self.children[i].equals(a:treenode)
655 call remove(self.children, i)
656 return
657 endif
658 endfor
659
660 throw 'NERDTree.ChildNotFoundError: child node was not found'
661endfunction
662
663" FUNCTION: TreeDirNode.sortChildren() {{{1
664" Sort self.children by alphabetical order and directory priority.
665function! s:TreeDirNode.sortChildren()
666 if count(g:NERDTreeSortOrder, '*') < 1
667 call add(g:NERDTreeSortOrder, '*')
668 endif
669 let CompareFunc = function('nerdtree#compareNodes')
670 call sort(self.children, CompareFunc)
671 let g:NERDTreeOldSortOrder = g:NERDTreeSortOrder
672endfunction
673
674" FUNCTION: TreeDirNode.toggleOpen([options]) {{{1
675" Opens this directory if it is closed and vice versa
676function! s:TreeDirNode.toggleOpen(...)
677 let opts = a:0 ? a:1 : {}
678 if self.isOpen ==# 1
679 call self.close()
680 else
681 if g:NERDTreeCascadeOpenSingleChildDir ==# 0
682 call self.open(opts)
683 else
684 call self.openAlong(opts)
685 endif
686 endif
687endfunction
688
689" FUNCTION: TreeDirNode.transplantChild(newNode) {{{1
690" Replaces the child of this with the given node (where the child node's full
691" path matches a:newNode's fullpath). The search for the matching node is
692" non-recursive
693"
694" Arg:
695" newNode: the node to graft into the tree
696function! s:TreeDirNode.transplantChild(newNode)
697 for i in range(0, self.getChildCount()-1)
698 if self.children[i].equals(a:newNode)
699 let self.children[i] = a:newNode
700 let a:newNode.parent = self
701 break
702 endif
703 endfor
704endfunction
705
706" vim: set sw=4 sts=4 et fdm=marker:
diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/tree_file_node.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/tree_file_node.vim
new file mode 100644
index 0000000..957b98a
--- /dev/null
+++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/tree_file_node.vim
@@ -0,0 +1,349 @@
1" ============================================================================
2" CLASS: TreeFileNode
3"
4" This class is the parent of the TreeDirNode class and is the 'Component'
5" part of the composite design pattern between the NERDTree node classes.
6" ============================================================================
7
8
9let s:TreeFileNode = {}
10let g:NERDTreeFileNode = s:TreeFileNode
11
12" FUNCTION: TreeFileNode.activate(...) {{{1
13function! s:TreeFileNode.activate(...)
14 call self.open(a:0 ? a:1 : {})
15endfunction
16
17" FUNCTION: TreeFileNode.bookmark(name) {{{1
18" bookmark this node with a:name
19function! s:TreeFileNode.bookmark(name)
20
21 " if a bookmark exists with the same name and the node is cached then save
22 " it so we can update its display string
23 let oldMarkedNode = {}
24 try
25 let oldMarkedNode = g:NERDTreeBookmark.GetNodeForName(a:name, 1, self.getNerdtree())
26 catch /^NERDTree.BookmarkNotFoundError/
27 catch /^NERDTree.BookmarkedNodeNotFoundError/
28 endtry
29
30 call g:NERDTreeBookmark.AddBookmark(a:name, self.path)
31 call self.path.cacheDisplayString()
32 call g:NERDTreeBookmark.Write()
33
34 if !empty(oldMarkedNode)
35 call oldMarkedNode.path.cacheDisplayString()
36 endif
37endfunction
38
39" FUNCTION: TreeFileNode.cacheParent() {{{1
40" initializes self.parent if it isnt already
41function! s:TreeFileNode.cacheParent()
42 if empty(self.parent)
43 let parentPath = self.path.getParent()
44 if parentPath.equals(self.path)
45 throw 'NERDTree.CannotCacheParentError: already at root'
46 endif
47 let self.parent = s:TreeFileNode.New(parentPath, self.getNerdtree())
48 endif
49endfunction
50
51" FUNCTION: TreeFileNode.clearBookmarks() {{{1
52function! s:TreeFileNode.clearBookmarks()
53 for i in g:NERDTreeBookmark.Bookmarks()
54 if i.path.equals(self.path)
55 call i.delete()
56 end
57 endfor
58 call self.path.cacheDisplayString()
59endfunction
60
61" FUNCTION: TreeFileNode.copy(dest) {{{1
62function! s:TreeFileNode.copy(dest)
63 call self.path.copy(a:dest)
64 let newPath = g:NERDTreePath.New(a:dest)
65 let parent = self.getNerdtree().root.findNode(newPath.getParent())
66 if !empty(parent)
67 call parent.refresh()
68 return parent.findNode(newPath)
69 else
70 return {}
71 endif
72endfunction
73
74" FUNCTION: TreeFileNode.delete {{{1
75" Removes this node from the tree and calls the Delete method for its path obj
76function! s:TreeFileNode.delete()
77 call self.path.delete()
78 call self.parent.removeChild(self)
79endfunction
80
81" FUNCTION: TreeFileNode.displayString() {{{1
82"
83" Returns a string that specifies how the node should be represented as a
84" string
85"
86" Return:
87" a string that can be used in the view to represent this node
88function! s:TreeFileNode.displayString()
89 return self.path.flagSet.renderToString() . self.path.displayString()
90endfunction
91
92" FUNCTION: TreeFileNode.equals(treenode) {{{1
93"
94" Compares this treenode to the input treenode and returns 1 if they are the
95" same node.
96"
97" Use this method instead of == because sometimes when the treenodes contain
98" many children, vim seg faults when doing ==
99"
100" Args:
101" treenode: the other treenode to compare to
102function! s:TreeFileNode.equals(treenode)
103 return self.path.str() ==# a:treenode.path.str()
104endfunction
105
106" FUNCTION: TreeFileNode.findNode(path) {{{1
107" Returns self if this node.path.Equals the given path.
108" Returns {} if not equal.
109"
110" Args:
111" path: the path object to compare against
112function! s:TreeFileNode.findNode(path)
113 if a:path.equals(self.path)
114 return self
115 endif
116 return {}
117endfunction
118
119" FUNCTION: TreeFileNode.findSibling(direction) {{{1
120" Find the next or previous sibling of this node.
121"
122" Args:
123" direction: 0 for previous, 1 for next
124"
125" Return:
126" The next/previous TreeFileNode object or an empty dictionary if not found.
127function! s:TreeFileNode.findSibling(direction)
128
129 " There can be no siblings if there is no parent.
130 if empty(self.parent)
131 return {}
132 endif
133
134 let l:nodeIndex = self.parent.getChildIndex(self.path)
135
136 if l:nodeIndex == -1
137 return {}
138 endif
139
140 " Get the next index to begin the search.
141 let l:nodeIndex += a:direction ? 1 : -1
142
143 while 0 <= l:nodeIndex && l:nodeIndex < self.parent.getChildCount()
144
145 " Return the next node if it is not ignored.
146 if !self.parent.children[l:nodeIndex].path.ignore(self.getNerdtree())
147 return self.parent.children[l:nodeIndex]
148 endif
149
150 let l:nodeIndex += a:direction ? 1 : -1
151 endwhile
152
153 return {}
154endfunction
155
156" FUNCTION: TreeFileNode.getNerdtree(){{{1
157function! s:TreeFileNode.getNerdtree()
158 return self._nerdtree
159endfunction
160
161" FUNCTION: TreeFileNode.GetRootForTab(){{{1
162" get the root node for this tab
163function! s:TreeFileNode.GetRootForTab()
164 if g:NERDTree.ExistsForTab()
165 return getbufvar(t:NERDTreeBufName, 'NERDTree').root
166 end
167 return {}
168endfunction
169
170" FUNCTION: TreeFileNode.GetSelected() {{{1
171" If the cursor is currently positioned on a tree node, return the node.
172" Otherwise, return the empty dictionary.
173function! s:TreeFileNode.GetSelected()
174
175 try
176 let l:path = b:NERDTree.ui.getPath(line('.'))
177
178 if empty(l:path)
179 return {}
180 endif
181
182 return b:NERDTree.root.findNode(l:path)
183 catch
184 return {}
185 endtry
186endfunction
187
188" FUNCTION: TreeFileNode.isVisible() {{{1
189" returns 1 if this node should be visible according to the tree filters and
190" hidden file filters (and their on/off status)
191function! s:TreeFileNode.isVisible()
192 return !self.path.ignore(self.getNerdtree())
193endfunction
194
195" FUNCTION: TreeFileNode.isRoot() {{{1
196function! s:TreeFileNode.isRoot()
197 if !g:NERDTree.ExistsForBuf()
198 throw 'NERDTree.NoTreeError: No tree exists for the current buffer'
199 endif
200
201 return self.equals(self.getNerdtree().root)
202endfunction
203
204" FUNCTION: TreeFileNode.New(path, nerdtree) {{{1
205" Returns a new TreeNode object with the given path and parent
206"
207" Args:
208" path: file/dir that the node represents
209" nerdtree: the tree the node belongs to
210function! s:TreeFileNode.New(path, nerdtree)
211 if a:path.isDirectory
212 return g:NERDTreeDirNode.New(a:path, a:nerdtree)
213 else
214 let newTreeNode = copy(self)
215 let newTreeNode.path = a:path
216 let newTreeNode.parent = {}
217 let newTreeNode._nerdtree = a:nerdtree
218 return newTreeNode
219 endif
220endfunction
221
222" FUNCTION: TreeFileNode.open() {{{1
223function! s:TreeFileNode.open(...)
224 let opts = a:0 ? a:1 : {}
225 let opener = g:NERDTreeOpener.New(self.path, opts)
226 call opener.open(self)
227endfunction
228
229" FUNCTION: TreeFileNode.openSplit() {{{1
230" Open this node in a new window
231function! s:TreeFileNode.openSplit()
232 call nerdtree#deprecated('TreeFileNode.openSplit', 'is deprecated, use .open() instead.')
233 call self.open({'where': 'h'})
234endfunction
235
236" FUNCTION: TreeFileNode.openVSplit() {{{1
237" Open this node in a new vertical window
238function! s:TreeFileNode.openVSplit()
239 call nerdtree#deprecated('TreeFileNode.openVSplit', 'is deprecated, use .open() instead.')
240 call self.open({'where': 'v'})
241endfunction
242
243" FUNCTION: TreeFileNode.openInNewTab(options) {{{1
244function! s:TreeFileNode.openInNewTab(options)
245 call nerdtree#deprecated('TreeFileNode.openinNewTab', 'is deprecated, use .open() instead.')
246 call self.open(extend({'where': 't'}, a:options))
247endfunction
248
249" FUNCTION: TreeFileNode.openExplorer()
250function! s:TreeFileNode.openExplorer()
251 execute 'wincmd p'
252 execute 'edit '.self.path.getParent().str({'format':'Edit'})
253endfunction
254
255" FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{1
256" Places the cursor on the line number this node is rendered on
257"
258" Args:
259" isJump: 1 if this cursor movement should be counted as a jump by vim
260" recurseUpward: try to put the cursor on the parent if the this node isnt
261" visible
262function! s:TreeFileNode.putCursorHere(isJump, recurseUpward)
263 let ln = self.getNerdtree().ui.getLineNum(self)
264 if ln != -1
265 if a:isJump
266 mark '
267 endif
268 call cursor(ln, col('.'))
269 else
270 if a:recurseUpward
271 let node = self
272 while node != {} && self.getNerdtree().ui.getLineNum(node) ==# -1
273 let node = node.parent
274 call node.open()
275 endwhile
276 call self._nerdtree.render()
277 call node.putCursorHere(a:isJump, 0)
278 endif
279 endif
280endfunction
281
282" FUNCTION: TreeFileNode.refresh() {{{1
283function! s:TreeFileNode.refresh()
284 call self.path.refresh(self.getNerdtree())
285endfunction
286
287" FUNCTION: TreeFileNode.refreshFlags() {{{1
288function! s:TreeFileNode.refreshFlags()
289 call self.path.refreshFlags(self.getNerdtree())
290endfunction
291
292" FUNCTION: TreeFileNode.rename() {{{1
293" Calls the rename method for this nodes path obj
294function! s:TreeFileNode.rename(newName)
295 let newName = substitute(a:newName, '\(\\\|\/\)$', '', '')
296 call self.path.rename(newName)
297 call self.parent.removeChild(self)
298
299 let parentPath = self.path.getParent()
300 let newParent = self.getNerdtree().root.findNode(parentPath)
301
302 if newParent != {}
303 call newParent.createChild(self.path, 1)
304 call newParent.refresh()
305 endif
306endfunction
307
308" FUNCTION: TreeFileNode.renderToString {{{1
309" returns a string representation for this tree to be rendered in the view
310function! s:TreeFileNode.renderToString()
311 return self._renderToString(0, 0)
312endfunction
313
314" Args:
315" depth: the current depth in the tree for this call
316" drawText: 1 if we should actually draw the line for this node (if 0 then the
317" child nodes are rendered only)
318" for each depth in the tree
319function! s:TreeFileNode._renderToString(depth, drawText)
320 let output = ''
321 if a:drawText ==# 1
322
323 let treeParts = repeat(' ', a:depth - 1)
324 let treeParts .= (self.path.isDirectory || g:NERDTreeDirArrowExpandable ==# '' ? '' : ' ')
325
326 let line = treeParts . self.displayString()
327 let output = output . line . "\n"
328 endif
329
330 " if the node is an open dir, draw its children
331 if self.path.isDirectory ==# 1 && self.isOpen ==# 1
332
333 let childNodesToDraw = self.getVisibleChildren()
334
335 if self.isCascadable() && a:depth > 0
336
337 let output = output . childNodesToDraw[0]._renderToString(a:depth, 0)
338
339 elseif len(childNodesToDraw) > 0
340 for i in childNodesToDraw
341 let output = output . i._renderToString(a:depth + 1, 1)
342 endfor
343 endif
344 endif
345
346 return output
347endfunction
348
349" vim: set sw=4 sts=4 et fdm=marker:
diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/ui.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/ui.vim
new file mode 100644
index 0000000..a481ba4
--- /dev/null
+++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/ui.vim
@@ -0,0 +1,532 @@
1" ============================================================================
2" CLASS: UI
3" ============================================================================
4
5
6let s:UI = {}
7let g:NERDTreeUI = s:UI
8
9" FUNCTION: s:UI.centerView() {{{1
10" centers the nerd tree window around the cursor (provided the nerd tree
11" options permit)
12function! s:UI.centerView()
13 if g:NERDTreeAutoCenter
14 let current_line = winline()
15 let lines_to_top = current_line
16 let lines_to_bottom = winheight(g:NERDTree.GetWinNum()) - current_line
17 if lines_to_top < g:NERDTreeAutoCenterThreshold || lines_to_bottom < g:NERDTreeAutoCenterThreshold
18 normal! zz
19 endif
20 endif
21endfunction
22
23" FUNCTION: s:UI._dumpHelp {{{1
24" prints out the quick help
25function! s:UI._dumpHelp()
26 if self.getShowHelp()
27 let help = "\" NERDTree (" . nerdtree#version() . ") quickhelp~\n"
28 let help .= "\" ============================\n"
29 let help .= "\" File node mappings~\n"
30 let help .= '" '. (g:NERDTreeMouseMode ==# 3 ? 'single' : 'double') ."-click,\n"
31 if self.nerdtree.isTabTree()
32 let help .= '" '. g:NERDTreeMapActivateNode .": open in prev window\n"
33 else
34 let help .= '" '. g:NERDTreeMapActivateNode .": open in current window\n"
35 endif
36 if self.nerdtree.isTabTree()
37 let help .= '" '. g:NERDTreeMapPreview .": preview\n"
38 endif
39 let help .= '" '. g:NERDTreeMapOpenInTab.": open in new tab\n"
40 let help .= '" '. g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n"
41 let help .= "\" middle-click,\n"
42 let help .= '" '. g:NERDTreeMapOpenSplit .": open split\n"
43 let help .= '" '. g:NERDTreeMapPreviewSplit .": preview split\n"
44 let help .= '" '. g:NERDTreeMapOpenVSplit .": open vsplit\n"
45 let help .= '" '. g:NERDTreeMapPreviewVSplit .": preview vsplit\n"
46 let help .= '" '. g:NERDTreeMapCustomOpen .": custom open\n"
47
48 let help .= "\"\n\" ----------------------------\n"
49 let help .= "\" Directory node mappings~\n"
50 let help .= '" '. (g:NERDTreeMouseMode ==# 1 ? 'double' : 'single') ."-click,\n"
51 let help .= '" '. g:NERDTreeMapActivateNode .": open & close node\n"
52 let help .= '" '. g:NERDTreeMapOpenRecursively .": recursively open node\n"
53 let help .= '" '. g:NERDTreeMapOpenInTab.": open in new tab\n"
54 let help .= '" '. g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n"
55 let help .= '" '. g:NERDTreeMapCustomOpen .": custom open\n"
56 let help .= '" '. g:NERDTreeMapCloseDir .": close parent of node\n"
57 let help .= '" '. g:NERDTreeMapCloseChildren .": close all child nodes of\n"
58 let help .= "\" current node recursively\n"
59 let help .= "\" middle-click,\n"
60 let help .= '" '. g:NERDTreeMapOpenExpl.": explore selected dir\n"
61
62 let help .= "\"\n\" ----------------------------\n"
63 let help .= "\" Bookmark table mappings~\n"
64 let help .= "\" double-click,\n"
65 let help .= '" '. g:NERDTreeMapActivateNode .": open bookmark\n"
66 let help .= '" '. g:NERDTreeMapPreview .": preview file\n"
67 let help .= '" '. g:NERDTreeMapPreview .": find dir in tree\n"
68 let help .= '" '. g:NERDTreeMapOpenInTab.": open in new tab\n"
69 let help .= '" '. g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n"
70 let help .= '" '. g:NERDTreeMapOpenSplit .": open split\n"
71 let help .= '" '. g:NERDTreeMapPreviewSplit .": preview split\n"
72 let help .= '" '. g:NERDTreeMapOpenVSplit .": open vsplit\n"
73 let help .= '" '. g:NERDTreeMapPreviewVSplit .": preview vsplit\n"
74 let help .= '" '. g:NERDTreeMapCustomOpen .": custom open\n"
75 let help .= '" '. g:NERDTreeMapDeleteBookmark .": delete bookmark\n"
76
77 let help .= "\"\n\" ----------------------------\n"
78 let help .= "\" Tree navigation mappings~\n"
79 let help .= '" '. g:NERDTreeMapJumpRoot .": go to root\n"
80 let help .= '" '. g:NERDTreeMapJumpParent .": go to parent\n"
81 let help .= '" '. g:NERDTreeMapJumpFirstChild .": go to first child\n"
82 let help .= '" '. g:NERDTreeMapJumpLastChild .": go to last child\n"
83 let help .= '" '. g:NERDTreeMapJumpNextSibling .": go to next sibling\n"
84 let help .= '" '. g:NERDTreeMapJumpPrevSibling .": go to prev sibling\n"
85
86 let help .= "\"\n\" ----------------------------\n"
87 let help .= "\" Filesystem mappings~\n"
88 let help .= '" '. g:NERDTreeMapChangeRoot .": change tree root to the\n"
89 let help .= "\" selected dir\n"
90 let help .= '" '. g:NERDTreeMapUpdir .": move tree root up a dir\n"
91 let help .= '" '. g:NERDTreeMapUpdirKeepOpen .": move tree root up a dir\n"
92 let help .= "\" but leave old root open\n"
93 let help .= '" '. g:NERDTreeMapRefresh .": refresh cursor dir\n"
94 let help .= '" '. g:NERDTreeMapRefreshRoot .": refresh current root\n"
95 let help .= '" '. g:NERDTreeMapMenu .": Show menu\n"
96 let help .= '" '. g:NERDTreeMapChdir .":change the CWD to the\n"
97 let help .= "\" selected dir\n"
98 let help .= '" '. g:NERDTreeMapCWD .":change tree root to CWD\n"
99
100 let help .= "\"\n\" ----------------------------\n"
101 let help .= "\" Tree filtering mappings~\n"
102 let help .= '" '. g:NERDTreeMapToggleHidden .': hidden files (' . (self.getShowHidden() ? 'on' : 'off') . ")\n"
103 let help .= '" '. g:NERDTreeMapToggleFilters .': file filters (' . (self.isIgnoreFilterEnabled() ? 'on' : 'off') . ")\n"
104 let help .= '" '. g:NERDTreeMapToggleFiles .': files (' . (self.getShowFiles() ? 'on' : 'off') . ")\n"
105 let help .= '" '. g:NERDTreeMapToggleBookmarks .': bookmarks (' . (self.getShowBookmarks() ? 'on' : 'off') . ")\n"
106
107 " add quickhelp entries for each custom key map
108 let help .= "\"\n\" ----------------------------\n"
109 let help .= "\" Custom mappings~\n"
110 for i in g:NERDTreeKeyMap.All()
111 if !empty(i.quickhelpText)
112 let help .= '" '. i.key .': '. i.quickhelpText ."\n"
113 endif
114 endfor
115
116 let help .= "\"\n\" ----------------------------\n"
117 let help .= "\" Other mappings~\n"
118 let help .= '" '. g:NERDTreeMapQuit .": Close the NERDTree window\n"
119 let help .= '" '. g:NERDTreeMapToggleZoom .": Zoom (maximize-minimize)\n"
120 let help .= "\" the NERDTree window\n"
121 let help .= '" '. g:NERDTreeMapHelp .": toggle help\n"
122 let help .= "\"\n\" ----------------------------\n"
123 let help .= "\" Bookmark commands~\n"
124 let help .= "\" :Bookmark [<name>]\n"
125 let help .= "\" :BookmarkToRoot <name>\n"
126 let help .= "\" :RevealBookmark <name>\n"
127 let help .= "\" :OpenBookmark <name>\n"
128 let help .= "\" :ClearBookmarks [<names>]\n"
129 let help .= "\" :ClearAllBookmarks\n"
130 let help .= "\" :ReadBookmarks\n"
131 let help .= "\" :WriteBookmarks\n"
132 let help .= "\" :EditBookmarks\n"
133 silent! put =help
134 elseif !self.isMinimal()
135 let help ='" Press '. g:NERDTreeMapHelp ." for help\n"
136 silent! put =help
137 endif
138endfunction
139
140
141" FUNCTION: s:UI.new(nerdtree) {{{1
142function! s:UI.New(nerdtree)
143 let newObj = copy(self)
144 let newObj.nerdtree = a:nerdtree
145 let newObj._showHelp = 0
146 let newObj._ignoreEnabled = 1
147 let newObj._showFiles = g:NERDTreeShowFiles
148 let newObj._showHidden = g:NERDTreeShowHidden
149 let newObj._showBookmarks = g:NERDTreeShowBookmarks
150
151 return newObj
152endfunction
153
154" FUNCTION: s:UI.getPath(ln) {{{1
155" Return the Path object for the node that is rendered on the given line
156" number. If the 'up a dir' line is selected, return the Path object for
157" the parent of the root. Return the empty dictionary if the given line
158" does not reference a tree node.
159function! s:UI.getPath(ln)
160 let line = getline(a:ln)
161
162 let rootLine = self.getRootLineNum()
163
164 if a:ln ==# rootLine
165 return self.nerdtree.root.path
166 endif
167
168 if line ==# s:UI.UpDirLine()
169 return self.nerdtree.root.path.getParent()
170 endif
171
172 if a:ln < rootLine
173 return {}
174 endif
175
176 let indent = self._indentLevelFor(line)
177
178 " remove the tree parts and the leading space
179 let curFile = self._stripMarkup(line)
180
181 let dir = ''
182 let lnum = a:ln
183 while lnum > 0
184 let lnum = lnum - 1
185 let curLine = getline(lnum)
186 let curLineStripped = self._stripMarkup(curLine)
187
188 " have we reached the top of the tree?
189 if lnum ==# rootLine
190 let dir = self.nerdtree.root.path.str({'format': 'UI'}) . dir
191 break
192 endif
193 if curLineStripped =~# '/$'
194 let lpindent = self._indentLevelFor(curLine)
195 if lpindent < indent
196 let indent = indent - 1
197
198 let dir = substitute (curLineStripped,'^\\', '', '') . dir
199 continue
200 endif
201 endif
202 endwhile
203 let curFile = self.nerdtree.root.path.drive . dir . curFile
204 let toReturn = g:NERDTreePath.New(curFile)
205 return toReturn
206endfunction
207
208" FUNCTION: s:UI.getLineNum(node) {{{1
209" Return the line number where the given node is rendered. Return -1 if the
210" given node is not visible.
211function! s:UI.getLineNum(node)
212
213 if a:node.isRoot()
214 return self.getRootLineNum()
215 endif
216
217 let l:pathComponents = [substitute(self.nerdtree.root.path.str({'format': 'UI'}), '/\s*$', '', '')]
218 let l:currentPathComponent = 1
219
220 let l:fullPath = a:node.path.str({'format': 'UI'})
221
222 for l:lineNumber in range(self.getRootLineNum() + 1, line('$'))
223 let l:currentLine = getline(l:lineNumber)
224 let l:indentLevel = self._indentLevelFor(l:currentLine)
225
226 if l:indentLevel !=# l:currentPathComponent
227 continue
228 endif
229
230 let l:currentLine = self._stripMarkup(l:currentLine)
231 let l:currentPath = join(l:pathComponents, '/') . '/' . l:currentLine
232
233 " Directories: If the current path 'starts with' the full path, then
234 " either the paths are equal or the line is a cascade containing the
235 " full path.
236 if l:fullPath[-1:] ==# '/' && stridx(l:currentPath, l:fullPath) ==# 0
237 return l:lineNumber
238 endif
239
240 " Files: The paths must exactly match.
241 if l:fullPath ==# l:currentPath
242 return l:lineNumber
243 endif
244
245 " Otherwise: If the full path starts with the current path and the
246 " current path is a directory, we add a new path component.
247 if stridx(l:fullPath, l:currentPath) ==# 0 && l:currentPath[-1:] ==# '/'
248 let l:currentLine = substitute(l:currentLine, '/\s*$', '', '')
249 call add(l:pathComponents, l:currentLine)
250 let l:currentPathComponent += 1
251 endif
252 endfor
253
254 return -1
255endfunction
256
257" FUNCTION: s:UI.getRootLineNum(){{{1
258" gets the line number of the root node
259function! s:UI.getRootLineNum()
260 let rootLine = 1
261 while rootLine <= line('$') && getline(rootLine) !~# '^\(/\|<\)'
262 let rootLine = rootLine + 1
263 endwhile
264 return rootLine
265endfunction
266
267" FUNCTION: s:UI.getShowBookmarks() {{{1
268function! s:UI.getShowBookmarks()
269 return self._showBookmarks
270endfunction
271
272" FUNCTION: s:UI.getShowFiles() {{{1
273function! s:UI.getShowFiles()
274 return self._showFiles
275endfunction
276
277" FUNCTION: s:UI.getShowHelp() {{{1
278function! s:UI.getShowHelp()
279 return self._showHelp
280endfunction
281
282" FUNCTION: s:UI.getShowHidden() {{{1
283function! s:UI.getShowHidden()
284 return self._showHidden
285endfunction
286
287" FUNCTION: s:UI._indentLevelFor(line) {{{1
288function! s:UI._indentLevelFor(line)
289 " Replace multi-character DirArrows with a single space so the
290 " indentation calculation doesn't get messed up.
291 if g:NERDTreeDirArrowExpandable ==# ''
292 let l:line = ' '.a:line
293 else
294 let l:line = substitute(substitute(a:line, '\V'.g:NERDTreeDirArrowExpandable, ' ', ''), '\V'.g:NERDTreeDirArrowCollapsible, ' ', '')
295 endif
296 let leadChars = match(l:line, '\M\[^ ]')
297 return leadChars / s:UI.IndentWid()
298endfunction
299
300" FUNCTION: s:UI.IndentWid() {{{1
301function! s:UI.IndentWid()
302 return 2
303endfunction
304
305" FUNCTION: s:UI.isIgnoreFilterEnabled() {{{1
306function! s:UI.isIgnoreFilterEnabled()
307 return self._ignoreEnabled ==# 1
308endfunction
309
310" FUNCTION: s:UI.isMinimal() {{{1
311function! s:UI.isMinimal()
312 return g:NERDTreeMinimalUI
313endfunction
314
315" FUNCTION: s:UI.MarkupReg() {{{1
316function! s:UI.MarkupReg()
317 return '^ *['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.']\? '
318endfunction
319
320" FUNCTION: s:UI._renderBookmarks {{{1
321function! s:UI._renderBookmarks()
322
323 if !self.isMinimal()
324 call setline(line('.')+1, '>----------Bookmarks----------')
325 call cursor(line('.')+1, col('.'))
326 endif
327
328 if g:NERDTreeBookmarksSort ==# 1 || g:NERDTreeBookmarksSort ==# 2
329 call g:NERDTreeBookmark.SortBookmarksList()
330 endif
331
332 for i in g:NERDTreeBookmark.Bookmarks()
333 call setline(line('.')+1, i.str())
334 call cursor(line('.')+1, col('.'))
335 endfor
336
337 call setline(line('.')+1, '')
338 call cursor(line('.')+1, col('.'))
339endfunction
340
341" FUNCTION: s:UI.restoreScreenState() {{{1
342"
343" Sets the screen state back to what it was when nerdtree#saveScreenState was last
344" called.
345"
346" Assumes the cursor is in the NERDTree window
347function! s:UI.restoreScreenState()
348 if !has_key(self, '_screenState')
349 return
350 endif
351 call nerdtree#exec('silent vertical resize ' . self._screenState['oldWindowSize'], 1)
352
353 let old_scrolloff=&scrolloff
354 let &scrolloff=0
355 call cursor(self._screenState['oldTopLine'], 0)
356 normal! zt
357 call setpos('.', self._screenState['oldPos'])
358 let &scrolloff=old_scrolloff
359endfunction
360
361" FUNCTION: s:UI.saveScreenState() {{{1
362" Saves the current cursor position in the current buffer and the window
363" scroll position
364function! s:UI.saveScreenState()
365 let win = winnr()
366 let self._screenState = {}
367 try
368 call g:NERDTree.CursorToTreeWin()
369 let self._screenState['oldPos'] = getpos('.')
370 let self._screenState['oldTopLine'] = line('w0')
371 let self._screenState['oldWindowSize'] = winnr('$')==1 ? g:NERDTreeWinSize : winwidth('')
372 call nerdtree#exec(win . 'wincmd w', 1)
373 catch
374 endtry
375endfunction
376
377" FUNCTION: s:UI.setShowHidden(val) {{{1
378function! s:UI.setShowHidden(val)
379 let self._showHidden = a:val
380endfunction
381
382" FUNCTION: s:UI._stripMarkup(line){{{1
383" find the filename in the given line, and return it.
384"
385" Args:
386" line: the subject line
387function! s:UI._stripMarkup(line)
388 let l:line = substitute(a:line, '^.\{-}' . g:NERDTreeNodeDelimiter, '', '')
389 return substitute(l:line, g:NERDTreeNodeDelimiter.'.*$', '', '')
390endfunction
391
392" FUNCTION: s:UI.render() {{{1
393function! s:UI.render()
394 setlocal noreadonly modifiable
395
396 " remember the top line of the buffer and the current line so we can
397 " restore the view exactly how it was
398 let curLine = line('.')
399 let curCol = col('.')
400 let topLine = line('w0')
401
402 " delete all lines in the buffer (being careful not to clobber a register)
403 silent 1,$delete _
404
405 call self._dumpHelp()
406
407 " delete the blank line before the help and add one after it
408 if !self.isMinimal()
409 call setline(line('.')+1, '')
410 call cursor(line('.')+1, col('.'))
411 endif
412
413 if self.getShowBookmarks()
414 call self._renderBookmarks()
415 endif
416
417 " add the 'up a dir' line
418 if !self.isMinimal()
419 call setline(line('.')+1, s:UI.UpDirLine())
420 call cursor(line('.')+1, col('.'))
421 endif
422
423 " draw the header line
424 let header = self.nerdtree.root.path.str({'format': 'UI', 'truncateTo': winwidth(0)})
425 call setline(line('.')+1, header)
426 call cursor(line('.')+1, col('.'))
427
428 " draw the tree
429 silent put =self.nerdtree.root.renderToString()
430
431 " delete the blank line at the top of the buffer
432 silent 1,1delete _
433
434 " restore the view
435 let old_scrolloff=&scrolloff
436 let &scrolloff=0
437 call cursor(topLine, 1)
438 normal! zt
439 call cursor(curLine, curCol)
440 let &scrolloff = old_scrolloff
441
442 setlocal readonly nomodifiable
443endfunction
444
445
446" FUNCTION: UI.renderViewSavingPosition {{{1
447" Renders the tree and ensures the cursor stays on the current node or the
448" current nodes parent if it is no longer available upon re-rendering
449function! s:UI.renderViewSavingPosition()
450 let currentNode = g:NERDTreeFileNode.GetSelected()
451
452 " go up the tree till we find a node that will be visible or till we run
453 " out of nodes
454 while currentNode !=# {} && !currentNode.isVisible() && !currentNode.isRoot()
455 let currentNode = currentNode.parent
456 endwhile
457
458 call self.render()
459
460 if currentNode !=# {}
461 call currentNode.putCursorHere(0, 0)
462 endif
463endfunction
464
465" FUNCTION: s:UI.toggleHelp() {{{1
466function! s:UI.toggleHelp()
467 let self._showHelp = !self._showHelp
468endfunction
469
470" FUNCTION: s:UI.toggleIgnoreFilter() {{{1
471" toggles the use of the NERDTreeIgnore option
472function! s:UI.toggleIgnoreFilter()
473 let self._ignoreEnabled = !self._ignoreEnabled
474 call self.renderViewSavingPosition()
475 call self.centerView()
476endfunction
477
478" FUNCTION: s:UI.toggleShowBookmarks() {{{1
479" Toggle the visibility of the Bookmark table.
480function! s:UI.toggleShowBookmarks()
481 let self._showBookmarks = !self._showBookmarks
482
483 if self.getShowBookmarks()
484 call self.nerdtree.render()
485 call g:NERDTree.CursorToBookmarkTable()
486 else
487
488 if empty(g:NERDTreeFileNode.GetSelected())
489 call b:NERDTree.root.putCursorHere(0, 0)
490 normal! 0
491 endif
492
493 call self.renderViewSavingPosition()
494 endif
495
496 call self.centerView()
497endfunction
498
499" FUNCTION: s:UI.toggleShowFiles() {{{1
500" toggles the display of hidden files
501function! s:UI.toggleShowFiles()
502 let self._showFiles = !self._showFiles
503 call self.renderViewSavingPosition()
504 call self.centerView()
505endfunction
506
507" FUNCTION: s:UI.toggleShowHidden() {{{1
508" toggles the display of hidden files
509function! s:UI.toggleShowHidden()
510 let self._showHidden = !self._showHidden
511 call self.renderViewSavingPosition()
512 call self.centerView()
513endfunction
514
515" FUNCTION: s:UI.toggleZoom() {{{1
516" zoom (maximize/minimize) the NERDTree window
517function! s:UI.toggleZoom()
518 if exists('b:NERDTreeZoomed') && b:NERDTreeZoomed
519 call nerdtree#exec('silent vertical resize '. g:NERDTreeWinSize, 1)
520 let b:NERDTreeZoomed = 0
521 else
522 call nerdtree#exec('vertical resize '. get(g:, 'NERDTreeWinSizeMax', ''), 1)
523 let b:NERDTreeZoomed = 1
524 endif
525endfunction
526
527" FUNCTION: s:UI.UpDirLine() {{{1
528function! s:UI.UpDirLine()
529 return '.. (up a dir)'
530endfunction
531
532" vim: set sw=4 sts=4 et fdm=marker: