1 | " ============================================================================
|
---|
2 | " File: NERD_tree.vim
|
---|
3 | " Description: vim global plugin that provides a nice tree explorer
|
---|
4 | " Maintainer: Martin Grenfell <martin.grenfell at gmail dot com>
|
---|
5 | " Last Change: 1 December, 2009
|
---|
6 | " License: This program is free software. It comes without any warranty,
|
---|
7 | " to the extent permitted by applicable law. You can redistribute
|
---|
8 | " it and/or modify it under the terms of the Do What The Fuck You
|
---|
9 | " Want To Public License, Version 2, as published by Sam Hocevar.
|
---|
10 | " See http://sam.zoy.org/wtfpl/COPYING for more details.
|
---|
11 | "
|
---|
12 | " ============================================================================
|
---|
13 | let s:NERD_tree_version = '4.1.0'
|
---|
14 |
|
---|
15 | " SECTION: Script init stuff {{{1
|
---|
16 | "============================================================
|
---|
17 | if exists("loaded_nerd_tree")
|
---|
18 | finish
|
---|
19 | endif
|
---|
20 | if v:version < 700
|
---|
21 | echoerr "NERDTree: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!"
|
---|
22 | finish
|
---|
23 | endif
|
---|
24 | let loaded_nerd_tree = 1
|
---|
25 |
|
---|
26 | "for line continuation - i.e dont want C in &cpo
|
---|
27 | let s:old_cpo = &cpo
|
---|
28 | set cpo&vim
|
---|
29 |
|
---|
30 | "Function: s:initVariable() function {{{2
|
---|
31 | "This function is used to initialise a given variable to a given value. The
|
---|
32 | "variable is only initialised if it does not exist prior
|
---|
33 | "
|
---|
34 | "Args:
|
---|
35 | "var: the name of the var to be initialised
|
---|
36 | "value: the value to initialise var to
|
---|
37 | "
|
---|
38 | "Returns:
|
---|
39 | "1 if the var is set, 0 otherwise
|
---|
40 | function! s:initVariable(var, value)
|
---|
41 | if !exists(a:var)
|
---|
42 | exec 'let ' . a:var . ' = ' . "'" . a:value . "'"
|
---|
43 | return 1
|
---|
44 | endif
|
---|
45 | return 0
|
---|
46 | endfunction
|
---|
47 |
|
---|
48 | "SECTION: Init variable calls and other random constants {{{2
|
---|
49 | call s:initVariable("g:NERDChristmasTree", 1)
|
---|
50 | call s:initVariable("g:NERDTreeAutoCenter", 1)
|
---|
51 | call s:initVariable("g:NERDTreeAutoCenterThreshold", 3)
|
---|
52 | call s:initVariable("g:NERDTreeCaseSensitiveSort", 0)
|
---|
53 | call s:initVariable("g:NERDTreeChDirMode", 0)
|
---|
54 | if !exists("g:NERDTreeIgnore")
|
---|
55 | let g:NERDTreeIgnore = ['\~$']
|
---|
56 | endif
|
---|
57 | call s:initVariable("g:NERDTreeBookmarksFile", expand('$HOME') . '/.NERDTreeBookmarks')
|
---|
58 | call s:initVariable("g:NERDTreeHighlightCursorline", 1)
|
---|
59 | call s:initVariable("g:NERDTreeHijackNetrw", 1)
|
---|
60 | call s:initVariable("g:NERDTreeMouseMode", 1)
|
---|
61 | call s:initVariable("g:NERDTreeNotificationThreshold", 100)
|
---|
62 | call s:initVariable("g:NERDTreeQuitOnOpen", 0)
|
---|
63 | call s:initVariable("g:NERDTreeShowBookmarks", 0)
|
---|
64 | call s:initVariable("g:NERDTreeShowFiles", 1)
|
---|
65 | call s:initVariable("g:NERDTreeShowHidden", 0)
|
---|
66 | call s:initVariable("g:NERDTreeShowLineNumbers", 0)
|
---|
67 | call s:initVariable("g:NERDTreeSortDirs", 1)
|
---|
68 |
|
---|
69 | if !exists("g:NERDTreeSortOrder")
|
---|
70 | let g:NERDTreeSortOrder = ['\/$', '*', '\.swp$', '\.bak$', '\~$']
|
---|
71 | else
|
---|
72 | "if there isnt a * in the sort sequence then add one
|
---|
73 | if count(g:NERDTreeSortOrder, '*') < 1
|
---|
74 | call add(g:NERDTreeSortOrder, '*')
|
---|
75 | endif
|
---|
76 | endif
|
---|
77 |
|
---|
78 | "we need to use this number many times for sorting... so we calculate it only
|
---|
79 | "once here
|
---|
80 | let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*')
|
---|
81 |
|
---|
82 | if !exists('g:NERDTreeStatusline')
|
---|
83 |
|
---|
84 | "the exists() crap here is a hack to stop vim spazzing out when
|
---|
85 | "loading a session that was created with an open nerd tree. It spazzes
|
---|
86 | "because it doesnt store b:NERDTreeRoot (its a b: var, and its a hash)
|
---|
87 | let g:NERDTreeStatusline = "%{exists('b:NERDTreeRoot')?b:NERDTreeRoot.path.str():''}"
|
---|
88 |
|
---|
89 | endif
|
---|
90 | call s:initVariable("g:NERDTreeWinPos", "left")
|
---|
91 | call s:initVariable("g:NERDTreeWinSize", 31)
|
---|
92 |
|
---|
93 | let s:running_windows = has("win16") || has("win32") || has("win64")
|
---|
94 |
|
---|
95 | "init the shell commands that will be used to copy nodes, and remove dir trees
|
---|
96 | "
|
---|
97 | "Note: the space after the command is important
|
---|
98 | if s:running_windows
|
---|
99 | call s:initVariable("g:NERDTreeRemoveDirCmd", 'rmdir /s /q ')
|
---|
100 | else
|
---|
101 | call s:initVariable("g:NERDTreeRemoveDirCmd", 'rm -rf ')
|
---|
102 | call s:initVariable("g:NERDTreeCopyCmd", 'cp -r ')
|
---|
103 | endif
|
---|
104 |
|
---|
105 |
|
---|
106 | "SECTION: Init variable calls for key mappings {{{2
|
---|
107 | call s:initVariable("g:NERDTreeMapActivateNode", "o")
|
---|
108 | call s:initVariable("g:NERDTreeMapChangeRoot", "C")
|
---|
109 | call s:initVariable("g:NERDTreeMapChdir", "cd")
|
---|
110 | call s:initVariable("g:NERDTreeMapCloseChildren", "X")
|
---|
111 | call s:initVariable("g:NERDTreeMapCloseDir", "x")
|
---|
112 | call s:initVariable("g:NERDTreeMapDeleteBookmark", "D")
|
---|
113 | call s:initVariable("g:NERDTreeMapMenu", "m")
|
---|
114 | call s:initVariable("g:NERDTreeMapHelp", "?")
|
---|
115 | call s:initVariable("g:NERDTreeMapJumpFirstChild", "K")
|
---|
116 | call s:initVariable("g:NERDTreeMapJumpLastChild", "J")
|
---|
117 | call s:initVariable("g:NERDTreeMapJumpNextSibling", "<C-j>")
|
---|
118 | call s:initVariable("g:NERDTreeMapJumpParent", "p")
|
---|
119 | call s:initVariable("g:NERDTreeMapJumpPrevSibling", "<C-k>")
|
---|
120 | call s:initVariable("g:NERDTreeMapJumpRoot", "P")
|
---|
121 | call s:initVariable("g:NERDTreeMapOpenExpl", "e")
|
---|
122 | call s:initVariable("g:NERDTreeMapOpenInTab", "t")
|
---|
123 | call s:initVariable("g:NERDTreeMapOpenInTabSilent", "T")
|
---|
124 | call s:initVariable("g:NERDTreeMapOpenRecursively", "O")
|
---|
125 | call s:initVariable("g:NERDTreeMapOpenSplit", "i")
|
---|
126 | call s:initVariable("g:NERDTreeMapOpenVSplit", "s")
|
---|
127 | call s:initVariable("g:NERDTreeMapPreview", "g" . NERDTreeMapActivateNode)
|
---|
128 | call s:initVariable("g:NERDTreeMapPreviewSplit", "g" . NERDTreeMapOpenSplit)
|
---|
129 | call s:initVariable("g:NERDTreeMapPreviewVSplit", "g" . NERDTreeMapOpenVSplit)
|
---|
130 | call s:initVariable("g:NERDTreeMapQuit", "q")
|
---|
131 | call s:initVariable("g:NERDTreeMapRefresh", "r")
|
---|
132 | call s:initVariable("g:NERDTreeMapRefreshRoot", "R")
|
---|
133 | call s:initVariable("g:NERDTreeMapToggleBookmarks", "B")
|
---|
134 | call s:initVariable("g:NERDTreeMapToggleFiles", "F")
|
---|
135 | call s:initVariable("g:NERDTreeMapToggleFilters", "f")
|
---|
136 | call s:initVariable("g:NERDTreeMapToggleHidden", "I")
|
---|
137 | call s:initVariable("g:NERDTreeMapToggleZoom", "A")
|
---|
138 | call s:initVariable("g:NERDTreeMapUpdir", "u")
|
---|
139 | call s:initVariable("g:NERDTreeMapUpdirKeepOpen", "U")
|
---|
140 |
|
---|
141 | "SECTION: Script level variable declaration{{{2
|
---|
142 | if s:running_windows
|
---|
143 | let s:escape_chars = " `\|\"#%&,?()\*^<>"
|
---|
144 | else
|
---|
145 | let s:escape_chars = " \\`\|\"#%&,?()\*^<>"
|
---|
146 | endif
|
---|
147 | let s:NERDTreeBufName = 'NERD_tree_'
|
---|
148 |
|
---|
149 | let s:tree_wid = 2
|
---|
150 | let s:tree_markup_reg = '^[ `|]*[\-+~]'
|
---|
151 | let s:tree_up_dir_line = '.. (up a dir)'
|
---|
152 |
|
---|
153 | "the number to add to the nerd tree buffer name to make the buf name unique
|
---|
154 | let s:next_buffer_number = 1
|
---|
155 |
|
---|
156 | " SECTION: Commands {{{1
|
---|
157 | "============================================================
|
---|
158 | "init the command that users start the nerd tree with
|
---|
159 | command! -n=? -complete=dir -bar NERDTree :call s:initNerdTree('<args>')
|
---|
160 | command! -n=? -complete=dir -bar NERDTreeToggle :call s:toggle('<args>')
|
---|
161 | command! -n=0 -bar NERDTreeClose :call s:closeTreeIfOpen()
|
---|
162 | command! -n=1 -complete=customlist,s:completeBookmarks -bar NERDTreeFromBookmark call s:initNerdTree('<args>')
|
---|
163 | command! -n=0 -bar NERDTreeMirror call s:initNerdTreeMirror()
|
---|
164 | command! -n=0 -bar NERDTreeFind call s:findAndRevealPath()
|
---|
165 | " SECTION: Auto commands {{{1
|
---|
166 | "============================================================
|
---|
167 | augroup NERDTree
|
---|
168 | "Save the cursor position whenever we close the nerd tree
|
---|
169 | exec "autocmd BufWinLeave ". s:NERDTreeBufName ."* call <SID>saveScreenState()"
|
---|
170 | "cache bookmarks when vim loads
|
---|
171 | autocmd VimEnter * call s:Bookmark.CacheBookmarks(0)
|
---|
172 |
|
---|
173 | "load all nerdtree plugins after vim starts
|
---|
174 | autocmd VimEnter * runtime! nerdtree_plugin/**/*.vim
|
---|
175 | augroup END
|
---|
176 |
|
---|
177 | if g:NERDTreeHijackNetrw
|
---|
178 | augroup NERDTreeHijackNetrw
|
---|
179 | autocmd VimEnter * silent! autocmd! FileExplorer
|
---|
180 | au BufEnter,VimEnter * call s:checkForBrowse(expand("<amatch>"))
|
---|
181 | augroup END
|
---|
182 | endif
|
---|
183 |
|
---|
184 | "SECTION: Classes {{{1
|
---|
185 | "============================================================
|
---|
186 | "CLASS: Bookmark {{{2
|
---|
187 | "============================================================
|
---|
188 | let s:Bookmark = {}
|
---|
189 | " FUNCTION: Bookmark.activate() {{{3
|
---|
190 | function! s:Bookmark.activate()
|
---|
191 | if self.path.isDirectory
|
---|
192 | call self.toRoot()
|
---|
193 | else
|
---|
194 | if self.validate()
|
---|
195 | let n = s:TreeFileNode.New(self.path)
|
---|
196 | call n.open()
|
---|
197 | endif
|
---|
198 | endif
|
---|
199 | endfunction
|
---|
200 | " FUNCTION: Bookmark.AddBookmark(name, path) {{{3
|
---|
201 | " Class method to add a new bookmark to the list, if a previous bookmark exists
|
---|
202 | " with the same name, just update the path for that bookmark
|
---|
203 | function! s:Bookmark.AddBookmark(name, path)
|
---|
204 | for i in s:Bookmark.Bookmarks()
|
---|
205 | if i.name ==# a:name
|
---|
206 | let i.path = a:path
|
---|
207 | return
|
---|
208 | endif
|
---|
209 | endfor
|
---|
210 | call add(s:Bookmark.Bookmarks(), s:Bookmark.New(a:name, a:path))
|
---|
211 | call s:Bookmark.Sort()
|
---|
212 | endfunction
|
---|
213 | " Function: Bookmark.Bookmarks() {{{3
|
---|
214 | " Class method to get all bookmarks. Lazily initializes the bookmarks global
|
---|
215 | " variable
|
---|
216 | function! s:Bookmark.Bookmarks()
|
---|
217 | if !exists("g:NERDTreeBookmarks")
|
---|
218 | let g:NERDTreeBookmarks = []
|
---|
219 | endif
|
---|
220 | return g:NERDTreeBookmarks
|
---|
221 | endfunction
|
---|
222 | " Function: Bookmark.BookmarkExistsFor(name) {{{3
|
---|
223 | " class method that returns 1 if a bookmark with the given name is found, 0
|
---|
224 | " otherwise
|
---|
225 | function! s:Bookmark.BookmarkExistsFor(name)
|
---|
226 | try
|
---|
227 | call s:Bookmark.BookmarkFor(a:name)
|
---|
228 | return 1
|
---|
229 | catch /^NERDTree.BookmarkNotFoundError/
|
---|
230 | return 0
|
---|
231 | endtry
|
---|
232 | endfunction
|
---|
233 | " Function: Bookmark.BookmarkFor(name) {{{3
|
---|
234 | " Class method to get the bookmark that has the given name. {} is return if no
|
---|
235 | " bookmark is found
|
---|
236 | function! s:Bookmark.BookmarkFor(name)
|
---|
237 | for i in s:Bookmark.Bookmarks()
|
---|
238 | if i.name ==# a:name
|
---|
239 | return i
|
---|
240 | endif
|
---|
241 | endfor
|
---|
242 | throw "NERDTree.BookmarkNotFoundError: no bookmark found for name: \"". a:name .'"'
|
---|
243 | endfunction
|
---|
244 | " Function: Bookmark.BookmarkNames() {{{3
|
---|
245 | " Class method to return an array of all bookmark names
|
---|
246 | function! s:Bookmark.BookmarkNames()
|
---|
247 | let names = []
|
---|
248 | for i in s:Bookmark.Bookmarks()
|
---|
249 | call add(names, i.name)
|
---|
250 | endfor
|
---|
251 | return names
|
---|
252 | endfunction
|
---|
253 | " FUNCTION: Bookmark.CacheBookmarks(silent) {{{3
|
---|
254 | " Class method to read all bookmarks from the bookmarks file intialize
|
---|
255 | " bookmark objects for each one.
|
---|
256 | "
|
---|
257 | " Args:
|
---|
258 | " silent - dont echo an error msg if invalid bookmarks are found
|
---|
259 | function! s:Bookmark.CacheBookmarks(silent)
|
---|
260 | if filereadable(g:NERDTreeBookmarksFile)
|
---|
261 | let g:NERDTreeBookmarks = []
|
---|
262 | let g:NERDTreeInvalidBookmarks = []
|
---|
263 | let bookmarkStrings = readfile(g:NERDTreeBookmarksFile)
|
---|
264 | let invalidBookmarksFound = 0
|
---|
265 | for i in bookmarkStrings
|
---|
266 |
|
---|
267 | "ignore blank lines
|
---|
268 | if i != ''
|
---|
269 |
|
---|
270 | let name = substitute(i, '^\(.\{-}\) .*$', '\1', '')
|
---|
271 | let path = substitute(i, '^.\{-} \(.*\)$', '\1', '')
|
---|
272 |
|
---|
273 | try
|
---|
274 | let bookmark = s:Bookmark.New(name, s:Path.New(path))
|
---|
275 | call add(g:NERDTreeBookmarks, bookmark)
|
---|
276 | catch /^NERDTree.InvalidArgumentsError/
|
---|
277 | call add(g:NERDTreeInvalidBookmarks, i)
|
---|
278 | let invalidBookmarksFound += 1
|
---|
279 | endtry
|
---|
280 | endif
|
---|
281 | endfor
|
---|
282 | if invalidBookmarksFound
|
---|
283 | call s:Bookmark.Write()
|
---|
284 | if !a:silent
|
---|
285 | call s:echo(invalidBookmarksFound . " invalid bookmarks were read. See :help NERDTreeInvalidBookmarks for info.")
|
---|
286 | endif
|
---|
287 | endif
|
---|
288 | call s:Bookmark.Sort()
|
---|
289 | endif
|
---|
290 | endfunction
|
---|
291 | " FUNCTION: Bookmark.compareTo(otherbookmark) {{{3
|
---|
292 | " Compare these two bookmarks for sorting purposes
|
---|
293 | function! s:Bookmark.compareTo(otherbookmark)
|
---|
294 | return a:otherbookmark.name < self.name
|
---|
295 | endfunction
|
---|
296 | " FUNCTION: Bookmark.ClearAll() {{{3
|
---|
297 | " Class method to delete all bookmarks.
|
---|
298 | function! s:Bookmark.ClearAll()
|
---|
299 | for i in s:Bookmark.Bookmarks()
|
---|
300 | call i.delete()
|
---|
301 | endfor
|
---|
302 | call s:Bookmark.Write()
|
---|
303 | endfunction
|
---|
304 | " FUNCTION: Bookmark.delete() {{{3
|
---|
305 | " Delete this bookmark. If the node for this bookmark is under the current
|
---|
306 | " root, then recache bookmarks for its Path object
|
---|
307 | function! s:Bookmark.delete()
|
---|
308 | let node = {}
|
---|
309 | try
|
---|
310 | let node = self.getNode(1)
|
---|
311 | catch /^NERDTree.BookmarkedNodeNotFoundError/
|
---|
312 | endtry
|
---|
313 | call remove(s:Bookmark.Bookmarks(), index(s:Bookmark.Bookmarks(), self))
|
---|
314 | if !empty(node)
|
---|
315 | call node.path.cacheDisplayString()
|
---|
316 | endif
|
---|
317 | call s:Bookmark.Write()
|
---|
318 | endfunction
|
---|
319 | " FUNCTION: Bookmark.getNode(searchFromAbsoluteRoot) {{{3
|
---|
320 | " Gets the treenode for this bookmark
|
---|
321 | "
|
---|
322 | " Args:
|
---|
323 | " searchFromAbsoluteRoot: specifies whether we should search from the current
|
---|
324 | " tree root, or the highest cached node
|
---|
325 | function! s:Bookmark.getNode(searchFromAbsoluteRoot)
|
---|
326 | let searchRoot = a:searchFromAbsoluteRoot ? s:TreeDirNode.AbsoluteTreeRoot() : b:NERDTreeRoot
|
---|
327 | let targetNode = searchRoot.findNode(self.path)
|
---|
328 | if empty(targetNode)
|
---|
329 | throw "NERDTree.BookmarkedNodeNotFoundError: no node was found for bookmark: " . self.name
|
---|
330 | endif
|
---|
331 | return targetNode
|
---|
332 | endfunction
|
---|
333 | " FUNCTION: Bookmark.GetNodeForName(name, searchFromAbsoluteRoot) {{{3
|
---|
334 | " Class method that finds the bookmark with the given name and returns the
|
---|
335 | " treenode for it.
|
---|
336 | function! s:Bookmark.GetNodeForName(name, searchFromAbsoluteRoot)
|
---|
337 | let bookmark = s:Bookmark.BookmarkFor(a:name)
|
---|
338 | return bookmark.getNode(a:searchFromAbsoluteRoot)
|
---|
339 | endfunction
|
---|
340 | " FUNCTION: Bookmark.GetSelected() {{{3
|
---|
341 | " returns the Bookmark the cursor is over, or {}
|
---|
342 | function! s:Bookmark.GetSelected()
|
---|
343 | let line = getline(".")
|
---|
344 | let name = substitute(line, '^>\(.\{-}\) .\+$', '\1', '')
|
---|
345 | if name != line
|
---|
346 | try
|
---|
347 | return s:Bookmark.BookmarkFor(name)
|
---|
348 | catch /^NERDTree.BookmarkNotFoundError/
|
---|
349 | return {}
|
---|
350 | endtry
|
---|
351 | endif
|
---|
352 | return {}
|
---|
353 | endfunction
|
---|
354 |
|
---|
355 | " Function: Bookmark.InvalidBookmarks() {{{3
|
---|
356 | " Class method to get all invalid bookmark strings read from the bookmarks
|
---|
357 | " file
|
---|
358 | function! s:Bookmark.InvalidBookmarks()
|
---|
359 | if !exists("g:NERDTreeInvalidBookmarks")
|
---|
360 | let g:NERDTreeInvalidBookmarks = []
|
---|
361 | endif
|
---|
362 | return g:NERDTreeInvalidBookmarks
|
---|
363 | endfunction
|
---|
364 | " FUNCTION: Bookmark.mustExist() {{{3
|
---|
365 | function! s:Bookmark.mustExist()
|
---|
366 | if !self.path.exists()
|
---|
367 | call s:Bookmark.CacheBookmarks(1)
|
---|
368 | throw "NERDTree.BookmarkPointsToInvalidLocationError: the bookmark \"".
|
---|
369 | \ self.name ."\" points to a non existing location: \"". self.path.str()
|
---|
370 | endif
|
---|
371 | endfunction
|
---|
372 | " FUNCTION: Bookmark.New(name, path) {{{3
|
---|
373 | " Create a new bookmark object with the given name and path object
|
---|
374 | function! s:Bookmark.New(name, path)
|
---|
375 | if a:name =~ ' '
|
---|
376 | throw "NERDTree.IllegalBookmarkNameError: illegal name:" . a:name
|
---|
377 | endif
|
---|
378 |
|
---|
379 | let newBookmark = copy(self)
|
---|
380 | let newBookmark.name = a:name
|
---|
381 | let newBookmark.path = a:path
|
---|
382 | return newBookmark
|
---|
383 | endfunction
|
---|
384 | " FUNCTION: Bookmark.openInNewTab(options) {{{3
|
---|
385 | " Create a new bookmark object with the given name and path object
|
---|
386 | function! s:Bookmark.openInNewTab(options)
|
---|
387 | let currentTab = tabpagenr()
|
---|
388 | if self.path.isDirectory
|
---|
389 | tabnew
|
---|
390 | call s:initNerdTree(self.name)
|
---|
391 | else
|
---|
392 | exec "tabedit " . bookmark.path.str({'format': 'Edit'})
|
---|
393 | endif
|
---|
394 |
|
---|
395 | if has_key(a:options, 'stayInCurrentTab')
|
---|
396 | exec "tabnext " . currentTab
|
---|
397 | endif
|
---|
398 | endfunction
|
---|
399 | " Function: Bookmark.setPath(path) {{{3
|
---|
400 | " makes this bookmark point to the given path
|
---|
401 | function! s:Bookmark.setPath(path)
|
---|
402 | let self.path = a:path
|
---|
403 | endfunction
|
---|
404 | " Function: Bookmark.Sort() {{{3
|
---|
405 | " Class method that sorts all bookmarks
|
---|
406 | function! s:Bookmark.Sort()
|
---|
407 | let CompareFunc = function("s:compareBookmarks")
|
---|
408 | call sort(s:Bookmark.Bookmarks(), CompareFunc)
|
---|
409 | endfunction
|
---|
410 | " Function: Bookmark.str() {{{3
|
---|
411 | " Get the string that should be rendered in the view for this bookmark
|
---|
412 | function! s:Bookmark.str()
|
---|
413 | let pathStrMaxLen = winwidth(s:getTreeWinNum()) - 4 - len(self.name)
|
---|
414 | if &nu
|
---|
415 | let pathStrMaxLen = pathStrMaxLen - &numberwidth
|
---|
416 | endif
|
---|
417 |
|
---|
418 | let pathStr = self.path.str({'format': 'UI'})
|
---|
419 | if len(pathStr) > pathStrMaxLen
|
---|
420 | let pathStr = '<' . strpart(pathStr, len(pathStr) - pathStrMaxLen)
|
---|
421 | endif
|
---|
422 | return '>' . self.name . ' ' . pathStr
|
---|
423 | endfunction
|
---|
424 | " FUNCTION: Bookmark.toRoot() {{{3
|
---|
425 | " Make the node for this bookmark the new tree root
|
---|
426 | function! s:Bookmark.toRoot()
|
---|
427 | if self.validate()
|
---|
428 | try
|
---|
429 | let targetNode = self.getNode(1)
|
---|
430 | catch /^NERDTree.BookmarkedNodeNotFoundError/
|
---|
431 | let targetNode = s:TreeFileNode.New(s:Bookmark.BookmarkFor(self.name).path)
|
---|
432 | endtry
|
---|
433 | call targetNode.makeRoot()
|
---|
434 | call s:renderView()
|
---|
435 | call targetNode.putCursorHere(0, 0)
|
---|
436 | endif
|
---|
437 | endfunction
|
---|
438 | " FUNCTION: Bookmark.ToRoot(name) {{{3
|
---|
439 | " Make the node for this bookmark the new tree root
|
---|
440 | function! s:Bookmark.ToRoot(name)
|
---|
441 | let bookmark = s:Bookmark.BookmarkFor(a:name)
|
---|
442 | call bookmark.toRoot()
|
---|
443 | endfunction
|
---|
444 |
|
---|
445 |
|
---|
446 | "FUNCTION: Bookmark.validate() {{{3
|
---|
447 | function! s:Bookmark.validate()
|
---|
448 | if self.path.exists()
|
---|
449 | return 1
|
---|
450 | else
|
---|
451 | call s:Bookmark.CacheBookmarks(1)
|
---|
452 | call s:renderView()
|
---|
453 | call s:echo(self.name . "now points to an invalid location. See :help NERDTreeInvalidBookmarks for info.")
|
---|
454 | return 0
|
---|
455 | endif
|
---|
456 | endfunction
|
---|
457 |
|
---|
458 | " Function: Bookmark.Write() {{{3
|
---|
459 | " Class method to write all bookmarks to the bookmarks file
|
---|
460 | function! s:Bookmark.Write()
|
---|
461 | let bookmarkStrings = []
|
---|
462 | for i in s:Bookmark.Bookmarks()
|
---|
463 | call add(bookmarkStrings, i.name . ' ' . i.path.str())
|
---|
464 | endfor
|
---|
465 |
|
---|
466 | "add a blank line before the invalid ones
|
---|
467 | call add(bookmarkStrings, "")
|
---|
468 |
|
---|
469 | for j in s:Bookmark.InvalidBookmarks()
|
---|
470 | call add(bookmarkStrings, j)
|
---|
471 | endfor
|
---|
472 | call writefile(bookmarkStrings, g:NERDTreeBookmarksFile)
|
---|
473 | endfunction
|
---|
474 | "CLASS: KeyMap {{{2
|
---|
475 | "============================================================
|
---|
476 | let s:KeyMap = {}
|
---|
477 | "FUNCTION: KeyMap.All() {{{3
|
---|
478 | function! s:KeyMap.All()
|
---|
479 | if !exists("s:keyMaps")
|
---|
480 | let s:keyMaps = []
|
---|
481 | endif
|
---|
482 | return s:keyMaps
|
---|
483 | endfunction
|
---|
484 |
|
---|
485 | "FUNCTION: KeyMap.BindAll() {{{3
|
---|
486 | function! s:KeyMap.BindAll()
|
---|
487 | for i in s:KeyMap.All()
|
---|
488 | call i.bind()
|
---|
489 | endfor
|
---|
490 | endfunction
|
---|
491 |
|
---|
492 | "FUNCTION: KeyMap.bind() {{{3
|
---|
493 | function! s:KeyMap.bind()
|
---|
494 | exec "nnoremap <silent> <buffer> ". self.key ." :call ". self.callback ."()<cr>"
|
---|
495 | endfunction
|
---|
496 |
|
---|
497 | "FUNCTION: KeyMap.Create(options) {{{3
|
---|
498 | function! s:KeyMap.Create(options)
|
---|
499 | let newKeyMap = copy(self)
|
---|
500 | let newKeyMap.key = a:options['key']
|
---|
501 | let newKeyMap.quickhelpText = a:options['quickhelpText']
|
---|
502 | let newKeyMap.callback = a:options['callback']
|
---|
503 | call add(s:KeyMap.All(), newKeyMap)
|
---|
504 | endfunction
|
---|
505 | "CLASS: MenuController {{{2
|
---|
506 | "============================================================
|
---|
507 | let s:MenuController = {}
|
---|
508 | "FUNCTION: MenuController.New(menuItems) {{{3
|
---|
509 | "create a new menu controller that operates on the given menu items
|
---|
510 | function! s:MenuController.New(menuItems)
|
---|
511 | let newMenuController = copy(self)
|
---|
512 | if a:menuItems[0].isSeparator()
|
---|
513 | let newMenuController.menuItems = a:menuItems[1:-1]
|
---|
514 | else
|
---|
515 | let newMenuController.menuItems = a:menuItems
|
---|
516 | endif
|
---|
517 | return newMenuController
|
---|
518 | endfunction
|
---|
519 |
|
---|
520 | "FUNCTION: MenuController.showMenu() {{{3
|
---|
521 | "start the main loop of the menu and get the user to choose/execute a menu
|
---|
522 | "item
|
---|
523 | function! s:MenuController.showMenu()
|
---|
524 | call self._saveOptions()
|
---|
525 |
|
---|
526 | try
|
---|
527 | let self.selection = 0
|
---|
528 |
|
---|
529 | let done = 0
|
---|
530 | while !done
|
---|
531 | redraw!
|
---|
532 | call self._echoPrompt()
|
---|
533 | let key = nr2char(getchar())
|
---|
534 | let done = self._handleKeypress(key)
|
---|
535 | endwhile
|
---|
536 | finally
|
---|
537 | call self._restoreOptions()
|
---|
538 | endtry
|
---|
539 |
|
---|
540 | if self.selection != -1
|
---|
541 | let m = self._current()
|
---|
542 | call m.execute()
|
---|
543 | endif
|
---|
544 | endfunction
|
---|
545 |
|
---|
546 | "FUNCTION: MenuController._echoPrompt() {{{3
|
---|
547 | function! s:MenuController._echoPrompt()
|
---|
548 | echo "NERDTree Menu. Use j/k/enter and the shortcuts indicated"
|
---|
549 | echo "=========================================================="
|
---|
550 |
|
---|
551 | for i in range(0, len(self.menuItems)-1)
|
---|
552 | if self.selection == i
|
---|
553 | echo "> " . self.menuItems[i].text
|
---|
554 | else
|
---|
555 | echo " " . self.menuItems[i].text
|
---|
556 | endif
|
---|
557 | endfor
|
---|
558 | endfunction
|
---|
559 |
|
---|
560 | "FUNCTION: MenuController._current(key) {{{3
|
---|
561 | "get the MenuItem that is curently selected
|
---|
562 | function! s:MenuController._current()
|
---|
563 | return self.menuItems[self.selection]
|
---|
564 | endfunction
|
---|
565 |
|
---|
566 | "FUNCTION: MenuController._handleKeypress(key) {{{3
|
---|
567 | "change the selection (if appropriate) and return 1 if the user has made
|
---|
568 | "their choice, 0 otherwise
|
---|
569 | function! s:MenuController._handleKeypress(key)
|
---|
570 | if a:key == 'j'
|
---|
571 | call self._cursorDown()
|
---|
572 | elseif a:key == 'k'
|
---|
573 | call self._cursorUp()
|
---|
574 | elseif a:key == nr2char(27) "escape
|
---|
575 | let self.selection = -1
|
---|
576 | return 1
|
---|
577 | elseif a:key == "\r" || a:key == "\n" "enter and ctrl-j
|
---|
578 | return 1
|
---|
579 | else
|
---|
580 | let index = self._nextIndexFor(a:key)
|
---|
581 | if index != -1
|
---|
582 | let self.selection = index
|
---|
583 | if len(self._allIndexesFor(a:key)) == 1
|
---|
584 | return 1
|
---|
585 | endif
|
---|
586 | endif
|
---|
587 | endif
|
---|
588 |
|
---|
589 | return 0
|
---|
590 | endfunction
|
---|
591 |
|
---|
592 | "FUNCTION: MenuController._allIndexesFor(shortcut) {{{3
|
---|
593 | "get indexes to all menu items with the given shortcut
|
---|
594 | function! s:MenuController._allIndexesFor(shortcut)
|
---|
595 | let toReturn = []
|
---|
596 |
|
---|
597 | for i in range(0, len(self.menuItems)-1)
|
---|
598 | if self.menuItems[i].shortcut == a:shortcut
|
---|
599 | call add(toReturn, i)
|
---|
600 | endif
|
---|
601 | endfor
|
---|
602 |
|
---|
603 | return toReturn
|
---|
604 | endfunction
|
---|
605 |
|
---|
606 | "FUNCTION: MenuController._nextIndexFor(shortcut) {{{3
|
---|
607 | "get the index to the next menu item with the given shortcut, starts from the
|
---|
608 | "current cursor location and wraps around to the top again if need be
|
---|
609 | function! s:MenuController._nextIndexFor(shortcut)
|
---|
610 | for i in range(self.selection+1, len(self.menuItems)-1)
|
---|
611 | if self.menuItems[i].shortcut == a:shortcut
|
---|
612 | return i
|
---|
613 | endif
|
---|
614 | endfor
|
---|
615 |
|
---|
616 | for i in range(0, self.selection)
|
---|
617 | if self.menuItems[i].shortcut == a:shortcut
|
---|
618 | return i
|
---|
619 | endif
|
---|
620 | endfor
|
---|
621 |
|
---|
622 | return -1
|
---|
623 | endfunction
|
---|
624 |
|
---|
625 | "FUNCTION: MenuController._setCmdheight() {{{3
|
---|
626 | "sets &cmdheight to whatever is needed to display the menu
|
---|
627 | function! s:MenuController._setCmdheight()
|
---|
628 | let &cmdheight = len(self.menuItems) + 3
|
---|
629 | endfunction
|
---|
630 |
|
---|
631 | "FUNCTION: MenuController._saveOptions() {{{3
|
---|
632 | "set any vim options that are required to make the menu work (saving their old
|
---|
633 | "values)
|
---|
634 | function! s:MenuController._saveOptions()
|
---|
635 | let self._oldLazyredraw = &lazyredraw
|
---|
636 | let self._oldCmdheight = &cmdheight
|
---|
637 | set nolazyredraw
|
---|
638 | call self._setCmdheight()
|
---|
639 | endfunction
|
---|
640 |
|
---|
641 | "FUNCTION: MenuController._restoreOptions() {{{3
|
---|
642 | "restore the options we saved in _saveOptions()
|
---|
643 | function! s:MenuController._restoreOptions()
|
---|
644 | let &cmdheight = self._oldCmdheight
|
---|
645 | let &lazyredraw = self._oldLazyredraw
|
---|
646 | endfunction
|
---|
647 |
|
---|
648 | "FUNCTION: MenuController._cursorDown() {{{3
|
---|
649 | "move the cursor to the next menu item, skipping separators
|
---|
650 | function! s:MenuController._cursorDown()
|
---|
651 | let done = 0
|
---|
652 | while !done
|
---|
653 | if self.selection < len(self.menuItems)-1
|
---|
654 | let self.selection += 1
|
---|
655 | else
|
---|
656 | let self.selection = 0
|
---|
657 | endif
|
---|
658 |
|
---|
659 | if !self._current().isSeparator()
|
---|
660 | let done = 1
|
---|
661 | endif
|
---|
662 | endwhile
|
---|
663 | endfunction
|
---|
664 |
|
---|
665 | "FUNCTION: MenuController._cursorUp() {{{3
|
---|
666 | "move the cursor to the previous menu item, skipping separators
|
---|
667 | function! s:MenuController._cursorUp()
|
---|
668 | let done = 0
|
---|
669 | while !done
|
---|
670 | if self.selection > 0
|
---|
671 | let self.selection -= 1
|
---|
672 | else
|
---|
673 | let self.selection = len(self.menuItems)-1
|
---|
674 | endif
|
---|
675 |
|
---|
676 | if !self._current().isSeparator()
|
---|
677 | let done = 1
|
---|
678 | endif
|
---|
679 | endwhile
|
---|
680 | endfunction
|
---|
681 |
|
---|
682 | "CLASS: MenuItem {{{2
|
---|
683 | "============================================================
|
---|
684 | let s:MenuItem = {}
|
---|
685 | "FUNCTION: MenuItem.All() {{{3
|
---|
686 | "get all top level menu items
|
---|
687 | function! s:MenuItem.All()
|
---|
688 | if !exists("s:menuItems")
|
---|
689 | let s:menuItems = []
|
---|
690 | endif
|
---|
691 | return s:menuItems
|
---|
692 | endfunction
|
---|
693 |
|
---|
694 | "FUNCTION: MenuItem.AllEnabled() {{{3
|
---|
695 | "get all top level menu items that are currently enabled
|
---|
696 | function! s:MenuItem.AllEnabled()
|
---|
697 | let toReturn = []
|
---|
698 | for i in s:MenuItem.All()
|
---|
699 | if i.enabled()
|
---|
700 | call add(toReturn, i)
|
---|
701 | endif
|
---|
702 | endfor
|
---|
703 | return toReturn
|
---|
704 | endfunction
|
---|
705 |
|
---|
706 | "FUNCTION: MenuItem.Create(options) {{{3
|
---|
707 | "make a new menu item and add it to the global list
|
---|
708 | function! s:MenuItem.Create(options)
|
---|
709 | let newMenuItem = copy(self)
|
---|
710 |
|
---|
711 | let newMenuItem.text = a:options['text']
|
---|
712 | let newMenuItem.shortcut = a:options['shortcut']
|
---|
713 | let newMenuItem.children = []
|
---|
714 |
|
---|
715 | let newMenuItem.isActiveCallback = -1
|
---|
716 | if has_key(a:options, 'isActiveCallback')
|
---|
717 | let newMenuItem.isActiveCallback = a:options['isActiveCallback']
|
---|
718 | endif
|
---|
719 |
|
---|
720 | let newMenuItem.callback = -1
|
---|
721 | if has_key(a:options, 'callback')
|
---|
722 | let newMenuItem.callback = a:options['callback']
|
---|
723 | endif
|
---|
724 |
|
---|
725 | if has_key(a:options, 'parent')
|
---|
726 | call add(a:options['parent'].children, newMenuItem)
|
---|
727 | else
|
---|
728 | call add(s:MenuItem.All(), newMenuItem)
|
---|
729 | endif
|
---|
730 |
|
---|
731 | return newMenuItem
|
---|
732 | endfunction
|
---|
733 |
|
---|
734 | "FUNCTION: MenuItem.CreateSeparator(options) {{{3
|
---|
735 | "make a new separator menu item and add it to the global list
|
---|
736 | function! s:MenuItem.CreateSeparator(options)
|
---|
737 | let standard_options = { 'text': '--------------------',
|
---|
738 | \ 'shortcut': -1,
|
---|
739 | \ 'callback': -1 }
|
---|
740 | let options = extend(a:options, standard_options, "force")
|
---|
741 |
|
---|
742 | return s:MenuItem.Create(options)
|
---|
743 | endfunction
|
---|
744 |
|
---|
745 | "FUNCTION: MenuItem.CreateSubmenu(options) {{{3
|
---|
746 | "make a new submenu and add it to global list
|
---|
747 | function! s:MenuItem.CreateSubmenu(options)
|
---|
748 | let standard_options = { 'callback': -1 }
|
---|
749 | let options = extend(a:options, standard_options, "force")
|
---|
750 |
|
---|
751 | return s:MenuItem.Create(options)
|
---|
752 | endfunction
|
---|
753 |
|
---|
754 | "FUNCTION: MenuItem.enabled() {{{3
|
---|
755 | "return 1 if this menu item should be displayed
|
---|
756 | "
|
---|
757 | "delegates off to the isActiveCallback, and defaults to 1 if no callback was
|
---|
758 | "specified
|
---|
759 | function! s:MenuItem.enabled()
|
---|
760 | if self.isActiveCallback != -1
|
---|
761 | return {self.isActiveCallback}()
|
---|
762 | endif
|
---|
763 | return 1
|
---|
764 | endfunction
|
---|
765 |
|
---|
766 | "FUNCTION: MenuItem.execute() {{{3
|
---|
767 | "perform the action behind this menu item, if this menuitem has children then
|
---|
768 | "display a new menu for them, otherwise deletegate off to the menuitem's
|
---|
769 | "callback
|
---|
770 | function! s:MenuItem.execute()
|
---|
771 | if len(self.children)
|
---|
772 | let mc = s:MenuController.New(self.children)
|
---|
773 | call mc.showMenu()
|
---|
774 | else
|
---|
775 | if self.callback != -1
|
---|
776 | call {self.callback}()
|
---|
777 | endif
|
---|
778 | endif
|
---|
779 | endfunction
|
---|
780 |
|
---|
781 | "FUNCTION: MenuItem.isSeparator() {{{3
|
---|
782 | "return 1 if this menuitem is a separator
|
---|
783 | function! s:MenuItem.isSeparator()
|
---|
784 | return self.callback == -1 && self.children == []
|
---|
785 | endfunction
|
---|
786 |
|
---|
787 | "FUNCTION: MenuItem.isSubmenu() {{{3
|
---|
788 | "return 1 if this menuitem is a submenu
|
---|
789 | function! s:MenuItem.isSubmenu()
|
---|
790 | return self.callback == -1 && !empty(self.children)
|
---|
791 | endfunction
|
---|
792 |
|
---|
793 | "CLASS: TreeFileNode {{{2
|
---|
794 | "This class is the parent of the TreeDirNode class and constitures the
|
---|
795 | "'Component' part of the composite design pattern between the treenode
|
---|
796 | "classes.
|
---|
797 | "============================================================
|
---|
798 | let s:TreeFileNode = {}
|
---|
799 | "FUNCTION: TreeFileNode.activate(forceKeepWinOpen) {{{3
|
---|
800 | function! s:TreeFileNode.activate(forceKeepWinOpen)
|
---|
801 | call self.open()
|
---|
802 | if !a:forceKeepWinOpen
|
---|
803 | call s:closeTreeIfQuitOnOpen()
|
---|
804 | end
|
---|
805 | endfunction
|
---|
806 | "FUNCTION: TreeFileNode.bookmark(name) {{{3
|
---|
807 | "bookmark this node with a:name
|
---|
808 | function! s:TreeFileNode.bookmark(name)
|
---|
809 | try
|
---|
810 | let oldMarkedNode = s:Bookmark.GetNodeForName(a:name, 1)
|
---|
811 | call oldMarkedNode.path.cacheDisplayString()
|
---|
812 | catch /^NERDTree.BookmarkNotFoundError/
|
---|
813 | endtry
|
---|
814 |
|
---|
815 | call s:Bookmark.AddBookmark(a:name, self.path)
|
---|
816 | call self.path.cacheDisplayString()
|
---|
817 | call s:Bookmark.Write()
|
---|
818 | endfunction
|
---|
819 | "FUNCTION: TreeFileNode.cacheParent() {{{3
|
---|
820 | "initializes self.parent if it isnt already
|
---|
821 | function! s:TreeFileNode.cacheParent()
|
---|
822 | if empty(self.parent)
|
---|
823 | let parentPath = self.path.getParent()
|
---|
824 | if parentPath.equals(self.path)
|
---|
825 | throw "NERDTree.CannotCacheParentError: already at root"
|
---|
826 | endif
|
---|
827 | let self.parent = s:TreeFileNode.New(parentPath)
|
---|
828 | endif
|
---|
829 | endfunction
|
---|
830 | "FUNCTION: TreeFileNode.compareNodes {{{3
|
---|
831 | "This is supposed to be a class level method but i cant figure out how to
|
---|
832 | "get func refs to work from a dict..
|
---|
833 | "
|
---|
834 | "A class level method that compares two nodes
|
---|
835 | "
|
---|
836 | "Args:
|
---|
837 | "n1, n2: the 2 nodes to compare
|
---|
838 | function! s:compareNodes(n1, n2)
|
---|
839 | return a:n1.path.compareTo(a:n2.path)
|
---|
840 | endfunction
|
---|
841 |
|
---|
842 | "FUNCTION: TreeFileNode.clearBoomarks() {{{3
|
---|
843 | function! s:TreeFileNode.clearBoomarks()
|
---|
844 | for i in s:Bookmark.Bookmarks()
|
---|
845 | if i.path.equals(self.path)
|
---|
846 | call i.delete()
|
---|
847 | end
|
---|
848 | endfor
|
---|
849 | call self.path.cacheDisplayString()
|
---|
850 | endfunction
|
---|
851 | "FUNCTION: TreeFileNode.copy(dest) {{{3
|
---|
852 | function! s:TreeFileNode.copy(dest)
|
---|
853 | call self.path.copy(a:dest)
|
---|
854 | let newPath = s:Path.New(a:dest)
|
---|
855 | let parent = b:NERDTreeRoot.findNode(newPath.getParent())
|
---|
856 | if !empty(parent)
|
---|
857 | call parent.refresh()
|
---|
858 | endif
|
---|
859 | return parent.findNode(newPath)
|
---|
860 | endfunction
|
---|
861 |
|
---|
862 | "FUNCTION: TreeFileNode.delete {{{3
|
---|
863 | "Removes this node from the tree and calls the Delete method for its path obj
|
---|
864 | function! s:TreeFileNode.delete()
|
---|
865 | call self.path.delete()
|
---|
866 | call self.parent.removeChild(self)
|
---|
867 | endfunction
|
---|
868 |
|
---|
869 | "FUNCTION: TreeFileNode.displayString() {{{3
|
---|
870 | "
|
---|
871 | "Returns a string that specifies how the node should be represented as a
|
---|
872 | "string
|
---|
873 | "
|
---|
874 | "Return:
|
---|
875 | "a string that can be used in the view to represent this node
|
---|
876 | function! s:TreeFileNode.displayString()
|
---|
877 | return self.path.displayString()
|
---|
878 | endfunction
|
---|
879 |
|
---|
880 | "FUNCTION: TreeFileNode.equals(treenode) {{{3
|
---|
881 | "
|
---|
882 | "Compares this treenode to the input treenode and returns 1 if they are the
|
---|
883 | "same node.
|
---|
884 | "
|
---|
885 | "Use this method instead of == because sometimes when the treenodes contain
|
---|
886 | "many children, vim seg faults when doing ==
|
---|
887 | "
|
---|
888 | "Args:
|
---|
889 | "treenode: the other treenode to compare to
|
---|
890 | function! s:TreeFileNode.equals(treenode)
|
---|
891 | return self.path.str() ==# a:treenode.path.str()
|
---|
892 | endfunction
|
---|
893 |
|
---|
894 | "FUNCTION: TreeFileNode.findNode(path) {{{3
|
---|
895 | "Returns self if this node.path.Equals the given path.
|
---|
896 | "Returns {} if not equal.
|
---|
897 | "
|
---|
898 | "Args:
|
---|
899 | "path: the path object to compare against
|
---|
900 | function! s:TreeFileNode.findNode(path)
|
---|
901 | if a:path.equals(self.path)
|
---|
902 | return self
|
---|
903 | endif
|
---|
904 | return {}
|
---|
905 | endfunction
|
---|
906 | "FUNCTION: TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) {{{3
|
---|
907 | "
|
---|
908 | "Finds the next sibling for this node in the indicated direction. This sibling
|
---|
909 | "must be a directory and may/may not have children as specified.
|
---|
910 | "
|
---|
911 | "Args:
|
---|
912 | "direction: 0 if you want to find the previous sibling, 1 for the next sibling
|
---|
913 | "
|
---|
914 | "Return:
|
---|
915 | "a treenode object or {} if no appropriate sibling could be found
|
---|
916 | function! s:TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction)
|
---|
917 | "if we have no parent then we can have no siblings
|
---|
918 | if self.parent != {}
|
---|
919 | let nextSibling = self.findSibling(a:direction)
|
---|
920 |
|
---|
921 | while nextSibling != {}
|
---|
922 | if nextSibling.path.isDirectory && nextSibling.hasVisibleChildren() && nextSibling.isOpen
|
---|
923 | return nextSibling
|
---|
924 | endif
|
---|
925 | let nextSibling = nextSibling.findSibling(a:direction)
|
---|
926 | endwhile
|
---|
927 | endif
|
---|
928 |
|
---|
929 | return {}
|
---|
930 | endfunction
|
---|
931 | "FUNCTION: TreeFileNode.findSibling(direction) {{{3
|
---|
932 | "
|
---|
933 | "Finds the next sibling for this node in the indicated direction
|
---|
934 | "
|
---|
935 | "Args:
|
---|
936 | "direction: 0 if you want to find the previous sibling, 1 for the next sibling
|
---|
937 | "
|
---|
938 | "Return:
|
---|
939 | "a treenode object or {} if no sibling could be found
|
---|
940 | function! s:TreeFileNode.findSibling(direction)
|
---|
941 | "if we have no parent then we can have no siblings
|
---|
942 | if self.parent != {}
|
---|
943 |
|
---|
944 | "get the index of this node in its parents children
|
---|
945 | let siblingIndx = self.parent.getChildIndex(self.path)
|
---|
946 |
|
---|
947 | if siblingIndx != -1
|
---|
948 | "move a long to the next potential sibling node
|
---|
949 | let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1
|
---|
950 |
|
---|
951 | "keep moving along to the next sibling till we find one that is valid
|
---|
952 | let numSiblings = self.parent.getChildCount()
|
---|
953 | while siblingIndx >= 0 && siblingIndx < numSiblings
|
---|
954 |
|
---|
955 | "if the next node is not an ignored node (i.e. wont show up in the
|
---|
956 | "view) then return it
|
---|
957 | if self.parent.children[siblingIndx].path.ignore() ==# 0
|
---|
958 | return self.parent.children[siblingIndx]
|
---|
959 | endif
|
---|
960 |
|
---|
961 | "go to next node
|
---|
962 | let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1
|
---|
963 | endwhile
|
---|
964 | endif
|
---|
965 | endif
|
---|
966 |
|
---|
967 | return {}
|
---|
968 | endfunction
|
---|
969 |
|
---|
970 | "FUNCTION: TreeFileNode.getLineNum(){{{3
|
---|
971 | "returns the line number this node is rendered on, or -1 if it isnt rendered
|
---|
972 | function! s:TreeFileNode.getLineNum()
|
---|
973 | "if the node is the root then return the root line no.
|
---|
974 | if self.isRoot()
|
---|
975 | return s:TreeFileNode.GetRootLineNum()
|
---|
976 | endif
|
---|
977 |
|
---|
978 | let totalLines = line("$")
|
---|
979 |
|
---|
980 | "the path components we have matched so far
|
---|
981 | let pathcomponents = [substitute(b:NERDTreeRoot.path.str({'format': 'UI'}), '/ *$', '', '')]
|
---|
982 | "the index of the component we are searching for
|
---|
983 | let curPathComponent = 1
|
---|
984 |
|
---|
985 | let fullpath = self.path.str({'format': 'UI'})
|
---|
986 |
|
---|
987 |
|
---|
988 | let lnum = s:TreeFileNode.GetRootLineNum()
|
---|
989 | while lnum > 0
|
---|
990 | let lnum = lnum + 1
|
---|
991 | "have we reached the bottom of the tree?
|
---|
992 | if lnum ==# totalLines+1
|
---|
993 | return -1
|
---|
994 | endif
|
---|
995 |
|
---|
996 | let curLine = getline(lnum)
|
---|
997 |
|
---|
998 | let indent = s:indentLevelFor(curLine)
|
---|
999 | if indent ==# curPathComponent
|
---|
1000 | let curLine = s:stripMarkupFromLine(curLine, 1)
|
---|
1001 |
|
---|
1002 | let curPath = join(pathcomponents, '/') . '/' . curLine
|
---|
1003 | if stridx(fullpath, curPath, 0) ==# 0
|
---|
1004 | if fullpath ==# curPath || strpart(fullpath, len(curPath)-1,1) ==# '/'
|
---|
1005 | let curLine = substitute(curLine, '/ *$', '', '')
|
---|
1006 | call add(pathcomponents, curLine)
|
---|
1007 | let curPathComponent = curPathComponent + 1
|
---|
1008 |
|
---|
1009 | if fullpath ==# curPath
|
---|
1010 | return lnum
|
---|
1011 | endif
|
---|
1012 | endif
|
---|
1013 | endif
|
---|
1014 | endif
|
---|
1015 | endwhile
|
---|
1016 | return -1
|
---|
1017 | endfunction
|
---|
1018 |
|
---|
1019 | "FUNCTION: TreeFileNode.GetRootForTab(){{{3
|
---|
1020 | "get the root node for this tab
|
---|
1021 | function! s:TreeFileNode.GetRootForTab()
|
---|
1022 | if s:treeExistsForTab()
|
---|
1023 | return getbufvar(t:NERDTreeBufName, 'NERDTreeRoot')
|
---|
1024 | end
|
---|
1025 | return {}
|
---|
1026 | endfunction
|
---|
1027 | "FUNCTION: TreeFileNode.GetRootLineNum(){{{3
|
---|
1028 | "gets the line number of the root node
|
---|
1029 | function! s:TreeFileNode.GetRootLineNum()
|
---|
1030 | let rootLine = 1
|
---|
1031 | while getline(rootLine) !~ '^\(/\|<\)'
|
---|
1032 | let rootLine = rootLine + 1
|
---|
1033 | endwhile
|
---|
1034 | return rootLine
|
---|
1035 | endfunction
|
---|
1036 |
|
---|
1037 | "FUNCTION: TreeFileNode.GetSelected() {{{3
|
---|
1038 | "gets the treenode that the cursor is currently over
|
---|
1039 | function! s:TreeFileNode.GetSelected()
|
---|
1040 | try
|
---|
1041 | let path = s:getPath(line("."))
|
---|
1042 | if path ==# {}
|
---|
1043 | return {}
|
---|
1044 | endif
|
---|
1045 | return b:NERDTreeRoot.findNode(path)
|
---|
1046 | catch /NERDTree/
|
---|
1047 | return {}
|
---|
1048 | endtry
|
---|
1049 | endfunction
|
---|
1050 | "FUNCTION: TreeFileNode.isVisible() {{{3
|
---|
1051 | "returns 1 if this node should be visible according to the tree filters and
|
---|
1052 | "hidden file filters (and their on/off status)
|
---|
1053 | function! s:TreeFileNode.isVisible()
|
---|
1054 | return !self.path.ignore()
|
---|
1055 | endfunction
|
---|
1056 | "FUNCTION: TreeFileNode.isRoot() {{{3
|
---|
1057 | "returns 1 if this node is b:NERDTreeRoot
|
---|
1058 | function! s:TreeFileNode.isRoot()
|
---|
1059 | if !s:treeExistsForBuf()
|
---|
1060 | throw "NERDTree.NoTreeError: No tree exists for the current buffer"
|
---|
1061 | endif
|
---|
1062 |
|
---|
1063 | return self.equals(b:NERDTreeRoot)
|
---|
1064 | endfunction
|
---|
1065 |
|
---|
1066 | "FUNCTION: TreeFileNode.makeRoot() {{{3
|
---|
1067 | "Make this node the root of the tree
|
---|
1068 | function! s:TreeFileNode.makeRoot()
|
---|
1069 | if self.path.isDirectory
|
---|
1070 | let b:NERDTreeRoot = self
|
---|
1071 | else
|
---|
1072 | call self.cacheParent()
|
---|
1073 | let b:NERDTreeRoot = self.parent
|
---|
1074 | endif
|
---|
1075 |
|
---|
1076 | call b:NERDTreeRoot.open()
|
---|
1077 |
|
---|
1078 | "change dir to the dir of the new root if instructed to
|
---|
1079 | if g:NERDTreeChDirMode ==# 2
|
---|
1080 | exec "cd " . b:NERDTreeRoot.path.str({'format': 'Edit'})
|
---|
1081 | endif
|
---|
1082 | endfunction
|
---|
1083 | "FUNCTION: TreeFileNode.New(path) {{{3
|
---|
1084 | "Returns a new TreeNode object with the given path and parent
|
---|
1085 | "
|
---|
1086 | "Args:
|
---|
1087 | "path: a path object representing the full filesystem path to the file/dir that the node represents
|
---|
1088 | function! s:TreeFileNode.New(path)
|
---|
1089 | if a:path.isDirectory
|
---|
1090 | return s:TreeDirNode.New(a:path)
|
---|
1091 | else
|
---|
1092 | let newTreeNode = copy(self)
|
---|
1093 | let newTreeNode.path = a:path
|
---|
1094 | let newTreeNode.parent = {}
|
---|
1095 | return newTreeNode
|
---|
1096 | endif
|
---|
1097 | endfunction
|
---|
1098 |
|
---|
1099 | "FUNCTION: TreeFileNode.open() {{{3
|
---|
1100 | "Open the file represented by the given node in the current window, splitting
|
---|
1101 | "the window if needed
|
---|
1102 | "
|
---|
1103 | "ARGS:
|
---|
1104 | "treenode: file node to open
|
---|
1105 | function! s:TreeFileNode.open()
|
---|
1106 | if b:NERDTreeType ==# "secondary"
|
---|
1107 | exec 'edit ' . self.path.str({'format': 'Edit'})
|
---|
1108 | return
|
---|
1109 | endif
|
---|
1110 |
|
---|
1111 | "if the file is already open in this tab then just stick the cursor in it
|
---|
1112 | let winnr = bufwinnr('^' . self.path.str() . '$')
|
---|
1113 | if winnr != -1
|
---|
1114 | call s:exec(winnr . "wincmd w")
|
---|
1115 |
|
---|
1116 | else
|
---|
1117 | if !s:isWindowUsable(winnr("#")) && s:firstUsableWindow() ==# -1
|
---|
1118 | call self.openSplit()
|
---|
1119 | else
|
---|
1120 | try
|
---|
1121 | if !s:isWindowUsable(winnr("#"))
|
---|
1122 | call s:exec(s:firstUsableWindow() . "wincmd w")
|
---|
1123 | else
|
---|
1124 | call s:exec('wincmd p')
|
---|
1125 | endif
|
---|
1126 | exec ("edit " . self.path.str({'format': 'Edit'}))
|
---|
1127 | catch /^Vim\%((\a\+)\)\=:E37/
|
---|
1128 | call s:putCursorInTreeWin()
|
---|
1129 | throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self.path.str() ." is already open and modified."
|
---|
1130 | catch /^Vim\%((\a\+)\)\=:/
|
---|
1131 | echo v:exception
|
---|
1132 | endtry
|
---|
1133 | endif
|
---|
1134 | endif
|
---|
1135 | endfunction
|
---|
1136 | "FUNCTION: TreeFileNode.openSplit() {{{3
|
---|
1137 | "Open this node in a new window
|
---|
1138 | function! s:TreeFileNode.openSplit()
|
---|
1139 |
|
---|
1140 | if b:NERDTreeType ==# "secondary"
|
---|
1141 | exec "split " . self.path.str({'format': 'Edit'})
|
---|
1142 | return
|
---|
1143 | endif
|
---|
1144 |
|
---|
1145 | " Save the user's settings for splitbelow and splitright
|
---|
1146 | let savesplitbelow=&splitbelow
|
---|
1147 | let savesplitright=&splitright
|
---|
1148 |
|
---|
1149 | " 'there' will be set to a command to move from the split window
|
---|
1150 | " back to the explorer window
|
---|
1151 | "
|
---|
1152 | " 'back' will be set to a command to move from the explorer window
|
---|
1153 | " back to the newly split window
|
---|
1154 | "
|
---|
1155 | " 'right' and 'below' will be set to the settings needed for
|
---|
1156 | " splitbelow and splitright IF the explorer is the only window.
|
---|
1157 | "
|
---|
1158 | let there= g:NERDTreeWinPos ==# "left" ? "wincmd h" : "wincmd l"
|
---|
1159 | let back = g:NERDTreeWinPos ==# "left" ? "wincmd l" : "wincmd h"
|
---|
1160 | let right= g:NERDTreeWinPos ==# "left"
|
---|
1161 | let below=0
|
---|
1162 |
|
---|
1163 | " Attempt to go to adjacent window
|
---|
1164 | call s:exec(back)
|
---|
1165 |
|
---|
1166 | let onlyOneWin = (winnr("$") ==# 1)
|
---|
1167 |
|
---|
1168 | " If no adjacent window, set splitright and splitbelow appropriately
|
---|
1169 | if onlyOneWin
|
---|
1170 | let &splitright=right
|
---|
1171 | let &splitbelow=below
|
---|
1172 | else
|
---|
1173 | " found adjacent window - invert split direction
|
---|
1174 | let &splitright=!right
|
---|
1175 | let &splitbelow=!below
|
---|
1176 | endif
|
---|
1177 |
|
---|
1178 | let splitMode = onlyOneWin ? "vertical" : ""
|
---|
1179 |
|
---|
1180 | " Open the new window
|
---|
1181 | try
|
---|
1182 | exec(splitMode." sp " . self.path.str({'format': 'Edit'}))
|
---|
1183 | catch /^Vim\%((\a\+)\)\=:E37/
|
---|
1184 | call s:putCursorInTreeWin()
|
---|
1185 | throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self.path.str() ." is already open and modified."
|
---|
1186 | catch /^Vim\%((\a\+)\)\=:/
|
---|
1187 | "do nothing
|
---|
1188 | endtry
|
---|
1189 |
|
---|
1190 | "resize the tree window if no other window was open before
|
---|
1191 | if onlyOneWin
|
---|
1192 | let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize
|
---|
1193 | call s:exec(there)
|
---|
1194 | exec("silent ". splitMode ." resize ". size)
|
---|
1195 | call s:exec('wincmd p')
|
---|
1196 | endif
|
---|
1197 |
|
---|
1198 | " Restore splitmode settings
|
---|
1199 | let &splitbelow=savesplitbelow
|
---|
1200 | let &splitright=savesplitright
|
---|
1201 | endfunction
|
---|
1202 | "FUNCTION: TreeFileNode.openVSplit() {{{3
|
---|
1203 | "Open this node in a new vertical window
|
---|
1204 | function! s:TreeFileNode.openVSplit()
|
---|
1205 | if b:NERDTreeType ==# "secondary"
|
---|
1206 | exec "vnew " . self.path.str({'format': 'Edit'})
|
---|
1207 | return
|
---|
1208 | endif
|
---|
1209 |
|
---|
1210 | let winwidth = winwidth(".")
|
---|
1211 | if winnr("$")==#1
|
---|
1212 | let winwidth = g:NERDTreeWinSize
|
---|
1213 | endif
|
---|
1214 |
|
---|
1215 | call s:exec("wincmd p")
|
---|
1216 | exec "vnew " . self.path.str({'format': 'Edit'})
|
---|
1217 |
|
---|
1218 | "resize the nerd tree back to the original size
|
---|
1219 | call s:putCursorInTreeWin()
|
---|
1220 | exec("silent vertical resize ". winwidth)
|
---|
1221 | call s:exec('wincmd p')
|
---|
1222 | endfunction
|
---|
1223 | "FUNCTION: TreeFileNode.openInNewTab(options) {{{3
|
---|
1224 | function! s:TreeFileNode.openInNewTab(options)
|
---|
1225 | let currentTab = tabpagenr()
|
---|
1226 |
|
---|
1227 | if !has_key(a:options, 'keepTreeOpen')
|
---|
1228 | call s:closeTreeIfQuitOnOpen()
|
---|
1229 | endif
|
---|
1230 |
|
---|
1231 | exec "tabedit " . self.path.str({'format': 'Edit'})
|
---|
1232 |
|
---|
1233 | if has_key(a:options, 'stayInCurrentTab') && a:options['stayInCurrentTab']
|
---|
1234 | exec "tabnext " . currentTab
|
---|
1235 | endif
|
---|
1236 |
|
---|
1237 | endfunction
|
---|
1238 | "FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{3
|
---|
1239 | "Places the cursor on the line number this node is rendered on
|
---|
1240 | "
|
---|
1241 | "Args:
|
---|
1242 | "isJump: 1 if this cursor movement should be counted as a jump by vim
|
---|
1243 | "recurseUpward: try to put the cursor on the parent if the this node isnt
|
---|
1244 | "visible
|
---|
1245 | function! s:TreeFileNode.putCursorHere(isJump, recurseUpward)
|
---|
1246 | let ln = self.getLineNum()
|
---|
1247 | if ln != -1
|
---|
1248 | if a:isJump
|
---|
1249 | mark '
|
---|
1250 | endif
|
---|
1251 | call cursor(ln, col("."))
|
---|
1252 | else
|
---|
1253 | if a:recurseUpward
|
---|
1254 | let node = self
|
---|
1255 | while node != {} && node.getLineNum() ==# -1
|
---|
1256 | let node = node.parent
|
---|
1257 | call node.open()
|
---|
1258 | endwhile
|
---|
1259 | call s:renderView()
|
---|
1260 | call node.putCursorHere(a:isJump, 0)
|
---|
1261 | endif
|
---|
1262 | endif
|
---|
1263 | endfunction
|
---|
1264 |
|
---|
1265 | "FUNCTION: TreeFileNode.refresh() {{{3
|
---|
1266 | function! s:TreeFileNode.refresh()
|
---|
1267 | call self.path.refresh()
|
---|
1268 | endfunction
|
---|
1269 | "FUNCTION: TreeFileNode.rename() {{{3
|
---|
1270 | "Calls the rename method for this nodes path obj
|
---|
1271 | function! s:TreeFileNode.rename(newName)
|
---|
1272 | let newName = substitute(a:newName, '\(\\\|\/\)$', '', '')
|
---|
1273 | call self.path.rename(newName)
|
---|
1274 | call self.parent.removeChild(self)
|
---|
1275 |
|
---|
1276 | let parentPath = self.path.getParent()
|
---|
1277 | let newParent = b:NERDTreeRoot.findNode(parentPath)
|
---|
1278 |
|
---|
1279 | if newParent != {}
|
---|
1280 | call newParent.createChild(self.path, 1)
|
---|
1281 | call newParent.refresh()
|
---|
1282 | endif
|
---|
1283 | endfunction
|
---|
1284 | "FUNCTION: TreeFileNode.renderToString {{{3
|
---|
1285 | "returns a string representation for this tree to be rendered in the view
|
---|
1286 | function! s:TreeFileNode.renderToString()
|
---|
1287 | return self._renderToString(0, 0, [], self.getChildCount() ==# 1)
|
---|
1288 | endfunction
|
---|
1289 |
|
---|
1290 |
|
---|
1291 | "Args:
|
---|
1292 | "depth: the current depth in the tree for this call
|
---|
1293 | "drawText: 1 if we should actually draw the line for this node (if 0 then the
|
---|
1294 | "child nodes are rendered only)
|
---|
1295 | "vertMap: a binary array that indicates whether a vertical bar should be draw
|
---|
1296 | "for each depth in the tree
|
---|
1297 | "isLastChild:true if this curNode is the last child of its parent
|
---|
1298 | function! s:TreeFileNode._renderToString(depth, drawText, vertMap, isLastChild)
|
---|
1299 | let output = ""
|
---|
1300 | if a:drawText ==# 1
|
---|
1301 |
|
---|
1302 | let treeParts = ''
|
---|
1303 |
|
---|
1304 | "get all the leading spaces and vertical tree parts for this line
|
---|
1305 | if a:depth > 1
|
---|
1306 | for j in a:vertMap[0:-2]
|
---|
1307 | if j ==# 1
|
---|
1308 | let treeParts = treeParts . '| '
|
---|
1309 | else
|
---|
1310 | let treeParts = treeParts . ' '
|
---|
1311 | endif
|
---|
1312 | endfor
|
---|
1313 | endif
|
---|
1314 |
|
---|
1315 | "get the last vertical tree part for this line which will be different
|
---|
1316 | "if this node is the last child of its parent
|
---|
1317 | if a:isLastChild
|
---|
1318 | let treeParts = treeParts . '`'
|
---|
1319 | else
|
---|
1320 | let treeParts = treeParts . '|'
|
---|
1321 | endif
|
---|
1322 |
|
---|
1323 |
|
---|
1324 | "smack the appropriate dir/file symbol on the line before the file/dir
|
---|
1325 | "name itself
|
---|
1326 | if self.path.isDirectory
|
---|
1327 | if self.isOpen
|
---|
1328 | let treeParts = treeParts . '~'
|
---|
1329 | else
|
---|
1330 | let treeParts = treeParts . '+'
|
---|
1331 | endif
|
---|
1332 | else
|
---|
1333 | let treeParts = treeParts . '-'
|
---|
1334 | endif
|
---|
1335 | let line = treeParts . self.displayString()
|
---|
1336 |
|
---|
1337 | let output = output . line . "\n"
|
---|
1338 | endif
|
---|
1339 |
|
---|
1340 | "if the node is an open dir, draw its children
|
---|
1341 | if self.path.isDirectory ==# 1 && self.isOpen ==# 1
|
---|
1342 |
|
---|
1343 | let childNodesToDraw = self.getVisibleChildren()
|
---|
1344 | if len(childNodesToDraw) > 0
|
---|
1345 |
|
---|
1346 | "draw all the nodes children except the last
|
---|
1347 | let lastIndx = len(childNodesToDraw)-1
|
---|
1348 | if lastIndx > 0
|
---|
1349 | for i in childNodesToDraw[0:lastIndx-1]
|
---|
1350 | let output = output . i._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 1), 0)
|
---|
1351 | endfor
|
---|
1352 | endif
|
---|
1353 |
|
---|
1354 | "draw the last child, indicating that it IS the last
|
---|
1355 | let output = output . childNodesToDraw[lastIndx]._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 0), 1)
|
---|
1356 | endif
|
---|
1357 | endif
|
---|
1358 |
|
---|
1359 | return output
|
---|
1360 | endfunction
|
---|
1361 | "CLASS: TreeDirNode {{{2
|
---|
1362 | "This class is a child of the TreeFileNode class and constitutes the
|
---|
1363 | "'Composite' part of the composite design pattern between the treenode
|
---|
1364 | "classes.
|
---|
1365 | "============================================================
|
---|
1366 | let s:TreeDirNode = copy(s:TreeFileNode)
|
---|
1367 | "FUNCTION: TreeDirNode.AbsoluteTreeRoot(){{{3
|
---|
1368 | "class method that returns the highest cached ancestor of the current root
|
---|
1369 | function! s:TreeDirNode.AbsoluteTreeRoot()
|
---|
1370 | let currentNode = b:NERDTreeRoot
|
---|
1371 | while currentNode.parent != {}
|
---|
1372 | let currentNode = currentNode.parent
|
---|
1373 | endwhile
|
---|
1374 | return currentNode
|
---|
1375 | endfunction
|
---|
1376 | "FUNCTION: TreeDirNode.activate(forceKeepWinOpen) {{{3
|
---|
1377 | unlet s:TreeDirNode.activate
|
---|
1378 | function! s:TreeDirNode.activate(forceKeepWinOpen)
|
---|
1379 | call self.toggleOpen()
|
---|
1380 | call s:renderView()
|
---|
1381 | call self.putCursorHere(0, 0)
|
---|
1382 | endfunction
|
---|
1383 | "FUNCTION: TreeDirNode.addChild(treenode, inOrder) {{{3
|
---|
1384 | "Adds the given treenode to the list of children for this node
|
---|
1385 | "
|
---|
1386 | "Args:
|
---|
1387 | "-treenode: the node to add
|
---|
1388 | "-inOrder: 1 if the new node should be inserted in sorted order
|
---|
1389 | function! s:TreeDirNode.addChild(treenode, inOrder)
|
---|
1390 | call add(self.children, a:treenode)
|
---|
1391 | let a:treenode.parent = self
|
---|
1392 |
|
---|
1393 | if a:inOrder
|
---|
1394 | call self.sortChildren()
|
---|
1395 | endif
|
---|
1396 | endfunction
|
---|
1397 |
|
---|
1398 | "FUNCTION: TreeDirNode.close() {{{3
|
---|
1399 | "Closes this directory
|
---|
1400 | function! s:TreeDirNode.close()
|
---|
1401 | let self.isOpen = 0
|
---|
1402 | endfunction
|
---|
1403 |
|
---|
1404 | "FUNCTION: TreeDirNode.closeChildren() {{{3
|
---|
1405 | "Closes all the child dir nodes of this node
|
---|
1406 | function! s:TreeDirNode.closeChildren()
|
---|
1407 | for i in self.children
|
---|
1408 | if i.path.isDirectory
|
---|
1409 | call i.close()
|
---|
1410 | call i.closeChildren()
|
---|
1411 | endif
|
---|
1412 | endfor
|
---|
1413 | endfunction
|
---|
1414 |
|
---|
1415 | "FUNCTION: TreeDirNode.createChild(path, inOrder) {{{3
|
---|
1416 | "Instantiates a new child node for this node with the given path. The new
|
---|
1417 | "nodes parent is set to this node.
|
---|
1418 | "
|
---|
1419 | "Args:
|
---|
1420 | "path: a Path object that this node will represent/contain
|
---|
1421 | "inOrder: 1 if the new node should be inserted in sorted order
|
---|
1422 | "
|
---|
1423 | "Returns:
|
---|
1424 | "the newly created node
|
---|
1425 | function! s:TreeDirNode.createChild(path, inOrder)
|
---|
1426 | let newTreeNode = s:TreeFileNode.New(a:path)
|
---|
1427 | call self.addChild(newTreeNode, a:inOrder)
|
---|
1428 | return newTreeNode
|
---|
1429 | endfunction
|
---|
1430 |
|
---|
1431 | "FUNCTION: TreeDirNode.findNode(path) {{{3
|
---|
1432 | "Will find one of the children (recursively) that has the given path
|
---|
1433 | "
|
---|
1434 | "Args:
|
---|
1435 | "path: a path object
|
---|
1436 | unlet s:TreeDirNode.findNode
|
---|
1437 | function! s:TreeDirNode.findNode(path)
|
---|
1438 | if a:path.equals(self.path)
|
---|
1439 | return self
|
---|
1440 | endif
|
---|
1441 | if stridx(a:path.str(), self.path.str(), 0) ==# -1
|
---|
1442 | return {}
|
---|
1443 | endif
|
---|
1444 |
|
---|
1445 | if self.path.isDirectory
|
---|
1446 | for i in self.children
|
---|
1447 | let retVal = i.findNode(a:path)
|
---|
1448 | if retVal != {}
|
---|
1449 | return retVal
|
---|
1450 | endif
|
---|
1451 | endfor
|
---|
1452 | endif
|
---|
1453 | return {}
|
---|
1454 | endfunction
|
---|
1455 | "FUNCTION: TreeDirNode.getChildCount() {{{3
|
---|
1456 | "Returns the number of children this node has
|
---|
1457 | function! s:TreeDirNode.getChildCount()
|
---|
1458 | return len(self.children)
|
---|
1459 | endfunction
|
---|
1460 |
|
---|
1461 | "FUNCTION: TreeDirNode.getChild(path) {{{3
|
---|
1462 | "Returns child node of this node that has the given path or {} if no such node
|
---|
1463 | "exists.
|
---|
1464 | "
|
---|
1465 | "This function doesnt not recurse into child dir nodes
|
---|
1466 | "
|
---|
1467 | "Args:
|
---|
1468 | "path: a path object
|
---|
1469 | function! s:TreeDirNode.getChild(path)
|
---|
1470 | if stridx(a:path.str(), self.path.str(), 0) ==# -1
|
---|
1471 | return {}
|
---|
1472 | endif
|
---|
1473 |
|
---|
1474 | let index = self.getChildIndex(a:path)
|
---|
1475 | if index ==# -1
|
---|
1476 | return {}
|
---|
1477 | else
|
---|
1478 | return self.children[index]
|
---|
1479 | endif
|
---|
1480 |
|
---|
1481 | endfunction
|
---|
1482 |
|
---|
1483 | "FUNCTION: TreeDirNode.getChildByIndex(indx, visible) {{{3
|
---|
1484 | "returns the child at the given index
|
---|
1485 | "Args:
|
---|
1486 | "indx: the index to get the child from
|
---|
1487 | "visible: 1 if only the visible children array should be used, 0 if all the
|
---|
1488 | "children should be searched.
|
---|
1489 | function! s:TreeDirNode.getChildByIndex(indx, visible)
|
---|
1490 | let array_to_search = a:visible? self.getVisibleChildren() : self.children
|
---|
1491 | if a:indx > len(array_to_search)
|
---|
1492 | throw "NERDTree.InvalidArgumentsError: Index is out of bounds."
|
---|
1493 | endif
|
---|
1494 | return array_to_search[a:indx]
|
---|
1495 | endfunction
|
---|
1496 |
|
---|
1497 | "FUNCTION: TreeDirNode.getChildIndex(path) {{{3
|
---|
1498 | "Returns the index of the child node of this node that has the given path or
|
---|
1499 | "-1 if no such node exists.
|
---|
1500 | "
|
---|
1501 | "This function doesnt not recurse into child dir nodes
|
---|
1502 | "
|
---|
1503 | "Args:
|
---|
1504 | "path: a path object
|
---|
1505 | function! s:TreeDirNode.getChildIndex(path)
|
---|
1506 | if stridx(a:path.str(), self.path.str(), 0) ==# -1
|
---|
1507 | return -1
|
---|
1508 | endif
|
---|
1509 |
|
---|
1510 | "do a binary search for the child
|
---|
1511 | let a = 0
|
---|
1512 | let z = self.getChildCount()
|
---|
1513 | while a < z
|
---|
1514 | let mid = (a+z)/2
|
---|
1515 | let diff = a:path.compareTo(self.children[mid].path)
|
---|
1516 |
|
---|
1517 | if diff ==# -1
|
---|
1518 | let z = mid
|
---|
1519 | elseif diff ==# 1
|
---|
1520 | let a = mid+1
|
---|
1521 | else
|
---|
1522 | return mid
|
---|
1523 | endif
|
---|
1524 | endwhile
|
---|
1525 | return -1
|
---|
1526 | endfunction
|
---|
1527 |
|
---|
1528 | "FUNCTION: TreeDirNode.GetSelected() {{{3
|
---|
1529 | "Returns the current node if it is a dir node, or else returns the current
|
---|
1530 | "nodes parent
|
---|
1531 | unlet s:TreeDirNode.GetSelected
|
---|
1532 | function! s:TreeDirNode.GetSelected()
|
---|
1533 | let currentDir = s:TreeFileNode.GetSelected()
|
---|
1534 | if currentDir != {} && !currentDir.isRoot()
|
---|
1535 | if currentDir.path.isDirectory ==# 0
|
---|
1536 | let currentDir = currentDir.parent
|
---|
1537 | endif
|
---|
1538 | endif
|
---|
1539 | return currentDir
|
---|
1540 | endfunction
|
---|
1541 | "FUNCTION: TreeDirNode.getVisibleChildCount() {{{3
|
---|
1542 | "Returns the number of visible children this node has
|
---|
1543 | function! s:TreeDirNode.getVisibleChildCount()
|
---|
1544 | return len(self.getVisibleChildren())
|
---|
1545 | endfunction
|
---|
1546 |
|
---|
1547 | "FUNCTION: TreeDirNode.getVisibleChildren() {{{3
|
---|
1548 | "Returns a list of children to display for this node, in the correct order
|
---|
1549 | "
|
---|
1550 | "Return:
|
---|
1551 | "an array of treenodes
|
---|
1552 | function! s:TreeDirNode.getVisibleChildren()
|
---|
1553 | let toReturn = []
|
---|
1554 | for i in self.children
|
---|
1555 | if i.path.ignore() ==# 0
|
---|
1556 | call add(toReturn, i)
|
---|
1557 | endif
|
---|
1558 | endfor
|
---|
1559 | return toReturn
|
---|
1560 | endfunction
|
---|
1561 |
|
---|
1562 | "FUNCTION: TreeDirNode.hasVisibleChildren() {{{3
|
---|
1563 | "returns 1 if this node has any childre, 0 otherwise..
|
---|
1564 | function! s:TreeDirNode.hasVisibleChildren()
|
---|
1565 | return self.getVisibleChildCount() != 0
|
---|
1566 | endfunction
|
---|
1567 |
|
---|
1568 | "FUNCTION: TreeDirNode._initChildren() {{{3
|
---|
1569 | "Removes all childen from this node and re-reads them
|
---|
1570 | "
|
---|
1571 | "Args:
|
---|
1572 | "silent: 1 if the function should not echo any "please wait" messages for
|
---|
1573 | "large directories
|
---|
1574 | "
|
---|
1575 | "Return: the number of child nodes read
|
---|
1576 | function! s:TreeDirNode._initChildren(silent)
|
---|
1577 | "remove all the current child nodes
|
---|
1578 | let self.children = []
|
---|
1579 |
|
---|
1580 | "get an array of all the files in the nodes dir
|
---|
1581 | let dir = self.path
|
---|
1582 | let globDir = dir.str({'format': 'Glob'})
|
---|
1583 | let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*')
|
---|
1584 | let files = split(filesStr, "\n")
|
---|
1585 |
|
---|
1586 | if !a:silent && len(files) > g:NERDTreeNotificationThreshold
|
---|
1587 | call s:echo("Please wait, caching a large dir ...")
|
---|
1588 | endif
|
---|
1589 |
|
---|
1590 | let invalidFilesFound = 0
|
---|
1591 | for i in files
|
---|
1592 |
|
---|
1593 | "filter out the .. and . directories
|
---|
1594 | "Note: we must match .. AND ../ cos sometimes the globpath returns
|
---|
1595 | "../ for path with strange chars (eg $)
|
---|
1596 | if i !~ '\/\.\.\/\?$' && i !~ '\/\.\/\?$'
|
---|
1597 |
|
---|
1598 | "put the next file in a new node and attach it
|
---|
1599 | try
|
---|
1600 | let path = s:Path.New(i)
|
---|
1601 | call self.createChild(path, 0)
|
---|
1602 | catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/
|
---|
1603 | let invalidFilesFound += 1
|
---|
1604 | endtry
|
---|
1605 | endif
|
---|
1606 | endfor
|
---|
1607 |
|
---|
1608 | call self.sortChildren()
|
---|
1609 |
|
---|
1610 | if !a:silent && len(files) > g:NERDTreeNotificationThreshold
|
---|
1611 | call s:echo("Please wait, caching a large dir ... DONE (". self.getChildCount() ." nodes cached).")
|
---|
1612 | endif
|
---|
1613 |
|
---|
1614 | if invalidFilesFound
|
---|
1615 | call s:echoWarning(invalidFilesFound . " file(s) could not be loaded into the NERD tree")
|
---|
1616 | endif
|
---|
1617 | return self.getChildCount()
|
---|
1618 | endfunction
|
---|
1619 | "FUNCTION: TreeDirNode.New(path) {{{3
|
---|
1620 | "Returns a new TreeNode object with the given path and parent
|
---|
1621 | "
|
---|
1622 | "Args:
|
---|
1623 | "path: a path object representing the full filesystem path to the file/dir that the node represents
|
---|
1624 | unlet s:TreeDirNode.New
|
---|
1625 | function! s:TreeDirNode.New(path)
|
---|
1626 | if a:path.isDirectory != 1
|
---|
1627 | throw "NERDTree.InvalidArgumentsError: A TreeDirNode object must be instantiated with a directory Path object."
|
---|
1628 | endif
|
---|
1629 |
|
---|
1630 | let newTreeNode = copy(self)
|
---|
1631 | let newTreeNode.path = a:path
|
---|
1632 |
|
---|
1633 | let newTreeNode.isOpen = 0
|
---|
1634 | let newTreeNode.children = []
|
---|
1635 |
|
---|
1636 | let newTreeNode.parent = {}
|
---|
1637 |
|
---|
1638 | return newTreeNode
|
---|
1639 | endfunction
|
---|
1640 | "FUNCTION: TreeDirNode.open() {{{3
|
---|
1641 | "Reads in all this nodes children
|
---|
1642 | "
|
---|
1643 | "Return: the number of child nodes read
|
---|
1644 | unlet s:TreeDirNode.open
|
---|
1645 | function! s:TreeDirNode.open()
|
---|
1646 | let self.isOpen = 1
|
---|
1647 | if self.children ==# []
|
---|
1648 | return self._initChildren(0)
|
---|
1649 | else
|
---|
1650 | return 0
|
---|
1651 | endif
|
---|
1652 | endfunction
|
---|
1653 |
|
---|
1654 | " FUNCTION: TreeDirNode.openExplorer() {{{3
|
---|
1655 | " opens an explorer window for this node in the previous window (could be a
|
---|
1656 | " nerd tree or a netrw)
|
---|
1657 | function! s:TreeDirNode.openExplorer()
|
---|
1658 | let oldwin = winnr()
|
---|
1659 | call s:exec('wincmd p')
|
---|
1660 | if oldwin ==# winnr() || (&modified && s:bufInWindows(winbufnr(winnr())) < 2)
|
---|
1661 | call s:exec('wincmd p')
|
---|
1662 | call self.openSplit()
|
---|
1663 | else
|
---|
1664 | exec ("silent edit " . self.path.str({'format': 'Edit'}))
|
---|
1665 | endif
|
---|
1666 | endfunction
|
---|
1667 | "FUNCTION: TreeDirNode.openInNewTab(options) {{{3
|
---|
1668 | unlet s:TreeDirNode.openInNewTab
|
---|
1669 | function! s:TreeDirNode.openInNewTab(options)
|
---|
1670 | let currentTab = tabpagenr()
|
---|
1671 |
|
---|
1672 | if !has_key(a:options, 'keepTreeOpen') || !a:options['keepTreeOpen']
|
---|
1673 | call s:closeTreeIfQuitOnOpen()
|
---|
1674 | endif
|
---|
1675 |
|
---|
1676 | tabnew
|
---|
1677 | call s:initNerdTree(self.path.str())
|
---|
1678 |
|
---|
1679 | if has_key(a:options, 'stayInCurrentTab') && a:options['stayInCurrentTab']
|
---|
1680 | exec "tabnext " . currentTab
|
---|
1681 | endif
|
---|
1682 | endfunction
|
---|
1683 | "FUNCTION: TreeDirNode.openRecursively() {{{3
|
---|
1684 | "Opens this treenode and all of its children whose paths arent 'ignored'
|
---|
1685 | "because of the file filters.
|
---|
1686 | "
|
---|
1687 | "This method is actually a wrapper for the OpenRecursively2 method which does
|
---|
1688 | "the work.
|
---|
1689 | function! s:TreeDirNode.openRecursively()
|
---|
1690 | call self._openRecursively2(1)
|
---|
1691 | endfunction
|
---|
1692 |
|
---|
1693 | "FUNCTION: TreeDirNode._openRecursively2() {{{3
|
---|
1694 | "Opens this all children of this treenode recursively if either:
|
---|
1695 | " *they arent filtered by file filters
|
---|
1696 | " *a:forceOpen is 1
|
---|
1697 | "
|
---|
1698 | "Args:
|
---|
1699 | "forceOpen: 1 if this node should be opened regardless of file filters
|
---|
1700 | function! s:TreeDirNode._openRecursively2(forceOpen)
|
---|
1701 | if self.path.ignore() ==# 0 || a:forceOpen
|
---|
1702 | let self.isOpen = 1
|
---|
1703 | if self.children ==# []
|
---|
1704 | call self._initChildren(1)
|
---|
1705 | endif
|
---|
1706 |
|
---|
1707 | for i in self.children
|
---|
1708 | if i.path.isDirectory ==# 1
|
---|
1709 | call i._openRecursively2(0)
|
---|
1710 | endif
|
---|
1711 | endfor
|
---|
1712 | endif
|
---|
1713 | endfunction
|
---|
1714 |
|
---|
1715 | "FUNCTION: TreeDirNode.refresh() {{{3
|
---|
1716 | unlet s:TreeDirNode.refresh
|
---|
1717 | function! s:TreeDirNode.refresh()
|
---|
1718 | call self.path.refresh()
|
---|
1719 |
|
---|
1720 | "if this node was ever opened, refresh its children
|
---|
1721 | if self.isOpen || !empty(self.children)
|
---|
1722 | "go thru all the files/dirs under this node
|
---|
1723 | let newChildNodes = []
|
---|
1724 | let invalidFilesFound = 0
|
---|
1725 | let dir = self.path
|
---|
1726 | let globDir = dir.str({'format': 'Glob'})
|
---|
1727 | let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*')
|
---|
1728 | let files = split(filesStr, "\n")
|
---|
1729 | for i in files
|
---|
1730 | "filter out the .. and . directories
|
---|
1731 | "Note: we must match .. AND ../ cos sometimes the globpath returns
|
---|
1732 | "../ for path with strange chars (eg $)
|
---|
1733 | if i !~ '\/\.\.\/\?$' && i !~ '\/\.\/\?$'
|
---|
1734 |
|
---|
1735 | try
|
---|
1736 | "create a new path and see if it exists in this nodes children
|
---|
1737 | let path = s:Path.New(i)
|
---|
1738 | let newNode = self.getChild(path)
|
---|
1739 | if newNode != {}
|
---|
1740 | call newNode.refresh()
|
---|
1741 | call add(newChildNodes, newNode)
|
---|
1742 |
|
---|
1743 | "the node doesnt exist so create it
|
---|
1744 | else
|
---|
1745 | let newNode = s:TreeFileNode.New(path)
|
---|
1746 | let newNode.parent = self
|
---|
1747 | call add(newChildNodes, newNode)
|
---|
1748 | endif
|
---|
1749 |
|
---|
1750 |
|
---|
1751 | catch /^NERDTree.InvalidArgumentsError/
|
---|
1752 | let invalidFilesFound = 1
|
---|
1753 | endtry
|
---|
1754 | endif
|
---|
1755 | endfor
|
---|
1756 |
|
---|
1757 | "swap this nodes children out for the children we just read/refreshed
|
---|
1758 | let self.children = newChildNodes
|
---|
1759 | call self.sortChildren()
|
---|
1760 |
|
---|
1761 | if invalidFilesFound
|
---|
1762 | call s:echoWarning("some files could not be loaded into the NERD tree")
|
---|
1763 | endif
|
---|
1764 | endif
|
---|
1765 | endfunction
|
---|
1766 |
|
---|
1767 | "FUNCTION: TreeDirNode.reveal(path) {{{3
|
---|
1768 | "reveal the given path, i.e. cache and open all treenodes needed to display it
|
---|
1769 | "in the UI
|
---|
1770 | function! s:TreeDirNode.reveal(path)
|
---|
1771 | if !a:path.isUnder(self.path)
|
---|
1772 | throw "NERDTree.InvalidArgumentsError: " . a:path.str() . " should be under " . self.path.str()
|
---|
1773 | endif
|
---|
1774 |
|
---|
1775 | call self.open()
|
---|
1776 |
|
---|
1777 | if self.path.equals(a:path.getParent())
|
---|
1778 | let n = self.findNode(a:path)
|
---|
1779 | call s:renderView()
|
---|
1780 | call n.putCursorHere(1,0)
|
---|
1781 | return
|
---|
1782 | endif
|
---|
1783 |
|
---|
1784 | let p = a:path
|
---|
1785 | while !p.getParent().equals(self.path)
|
---|
1786 | let p = p.getParent()
|
---|
1787 | endwhile
|
---|
1788 |
|
---|
1789 | let n = self.findNode(p)
|
---|
1790 | call n.reveal(a:path)
|
---|
1791 | endfunction
|
---|
1792 | "FUNCTION: TreeDirNode.removeChild(treenode) {{{3
|
---|
1793 | "
|
---|
1794 | "Removes the given treenode from this nodes set of children
|
---|
1795 | "
|
---|
1796 | "Args:
|
---|
1797 | "treenode: the node to remove
|
---|
1798 | "
|
---|
1799 | "Throws a NERDTree.ChildNotFoundError if the given treenode is not found
|
---|
1800 | function! s:TreeDirNode.removeChild(treenode)
|
---|
1801 | for i in range(0, self.getChildCount()-1)
|
---|
1802 | if self.children[i].equals(a:treenode)
|
---|
1803 | call remove(self.children, i)
|
---|
1804 | return
|
---|
1805 | endif
|
---|
1806 | endfor
|
---|
1807 |
|
---|
1808 | throw "NERDTree.ChildNotFoundError: child node was not found"
|
---|
1809 | endfunction
|
---|
1810 |
|
---|
1811 | "FUNCTION: TreeDirNode.sortChildren() {{{3
|
---|
1812 | "
|
---|
1813 | "Sorts the children of this node according to alphabetical order and the
|
---|
1814 | "directory priority.
|
---|
1815 | "
|
---|
1816 | function! s:TreeDirNode.sortChildren()
|
---|
1817 | let CompareFunc = function("s:compareNodes")
|
---|
1818 | call sort(self.children, CompareFunc)
|
---|
1819 | endfunction
|
---|
1820 |
|
---|
1821 | "FUNCTION: TreeDirNode.toggleOpen() {{{3
|
---|
1822 | "Opens this directory if it is closed and vice versa
|
---|
1823 | function! s:TreeDirNode.toggleOpen()
|
---|
1824 | if self.isOpen ==# 1
|
---|
1825 | call self.close()
|
---|
1826 | else
|
---|
1827 | call self.open()
|
---|
1828 | endif
|
---|
1829 | endfunction
|
---|
1830 |
|
---|
1831 | "FUNCTION: TreeDirNode.transplantChild(newNode) {{{3
|
---|
1832 | "Replaces the child of this with the given node (where the child node's full
|
---|
1833 | "path matches a:newNode's fullpath). The search for the matching node is
|
---|
1834 | "non-recursive
|
---|
1835 | "
|
---|
1836 | "Arg:
|
---|
1837 | "newNode: the node to graft into the tree
|
---|
1838 | function! s:TreeDirNode.transplantChild(newNode)
|
---|
1839 | for i in range(0, self.getChildCount()-1)
|
---|
1840 | if self.children[i].equals(a:newNode)
|
---|
1841 | let self.children[i] = a:newNode
|
---|
1842 | let a:newNode.parent = self
|
---|
1843 | break
|
---|
1844 | endif
|
---|
1845 | endfor
|
---|
1846 | endfunction
|
---|
1847 | "============================================================
|
---|
1848 | "CLASS: Path {{{2
|
---|
1849 | "============================================================
|
---|
1850 | let s:Path = {}
|
---|
1851 | "FUNCTION: Path.AbsolutePathFor(str) {{{3
|
---|
1852 | function! s:Path.AbsolutePathFor(str)
|
---|
1853 | let prependCWD = 0
|
---|
1854 | if s:running_windows
|
---|
1855 | let prependCWD = a:str !~ '^.:\(\\\|\/\)'
|
---|
1856 | else
|
---|
1857 | let prependCWD = a:str !~ '^/'
|
---|
1858 | endif
|
---|
1859 |
|
---|
1860 | let toReturn = a:str
|
---|
1861 | if prependCWD
|
---|
1862 | let toReturn = getcwd() . s:Path.Slash() . a:str
|
---|
1863 | endif
|
---|
1864 |
|
---|
1865 | return toReturn
|
---|
1866 | endfunction
|
---|
1867 | "FUNCTION: Path.bookmarkNames() {{{3
|
---|
1868 | function! s:Path.bookmarkNames()
|
---|
1869 | if !exists("self._bookmarkNames")
|
---|
1870 | call self.cacheDisplayString()
|
---|
1871 | endif
|
---|
1872 | return self._bookmarkNames
|
---|
1873 | endfunction
|
---|
1874 | "FUNCTION: Path.cacheDisplayString() {{{3
|
---|
1875 | function! s:Path.cacheDisplayString()
|
---|
1876 | let self.cachedDisplayString = self.getLastPathComponent(1)
|
---|
1877 |
|
---|
1878 | if self.isExecutable
|
---|
1879 | let self.cachedDisplayString = self.cachedDisplayString . '*'
|
---|
1880 | endif
|
---|
1881 |
|
---|
1882 | let self._bookmarkNames = []
|
---|
1883 | for i in s:Bookmark.Bookmarks()
|
---|
1884 | if i.path.equals(self)
|
---|
1885 | call add(self._bookmarkNames, i.name)
|
---|
1886 | endif
|
---|
1887 | endfor
|
---|
1888 | if !empty(self._bookmarkNames)
|
---|
1889 | let self.cachedDisplayString .= ' {' . join(self._bookmarkNames) . '}'
|
---|
1890 | endif
|
---|
1891 |
|
---|
1892 | if self.isSymLink
|
---|
1893 | let self.cachedDisplayString .= ' -> ' . self.symLinkDest
|
---|
1894 | endif
|
---|
1895 |
|
---|
1896 | if self.isReadOnly
|
---|
1897 | let self.cachedDisplayString .= ' [RO]'
|
---|
1898 | endif
|
---|
1899 | endfunction
|
---|
1900 | "FUNCTION: Path.changeToDir() {{{3
|
---|
1901 | function! s:Path.changeToDir()
|
---|
1902 | let dir = self.str({'format': 'Cd'})
|
---|
1903 | if self.isDirectory ==# 0
|
---|
1904 | let dir = self.getParent().str({'format': 'Cd'})
|
---|
1905 | endif
|
---|
1906 |
|
---|
1907 | try
|
---|
1908 | execute "cd " . dir
|
---|
1909 | call s:echo("CWD is now: " . getcwd())
|
---|
1910 | catch
|
---|
1911 | throw "NERDTree.PathChangeError: cannot change CWD to " . dir
|
---|
1912 | endtry
|
---|
1913 | endfunction
|
---|
1914 |
|
---|
1915 | "FUNCTION: Path.compareTo() {{{3
|
---|
1916 | "
|
---|
1917 | "Compares this Path to the given path and returns 0 if they are equal, -1 if
|
---|
1918 | "this Path is "less than" the given path, or 1 if it is "greater".
|
---|
1919 | "
|
---|
1920 | "Args:
|
---|
1921 | "path: the path object to compare this to
|
---|
1922 | "
|
---|
1923 | "Return:
|
---|
1924 | "1, -1 or 0
|
---|
1925 | function! s:Path.compareTo(path)
|
---|
1926 | let thisPath = self.getLastPathComponent(1)
|
---|
1927 | let thatPath = a:path.getLastPathComponent(1)
|
---|
1928 |
|
---|
1929 | "if the paths are the same then clearly we return 0
|
---|
1930 | if thisPath ==# thatPath
|
---|
1931 | return 0
|
---|
1932 | endif
|
---|
1933 |
|
---|
1934 | let thisSS = self.getSortOrderIndex()
|
---|
1935 | let thatSS = a:path.getSortOrderIndex()
|
---|
1936 |
|
---|
1937 | "compare the sort sequences, if they are different then the return
|
---|
1938 | "value is easy
|
---|
1939 | if thisSS < thatSS
|
---|
1940 | return -1
|
---|
1941 | elseif thisSS > thatSS
|
---|
1942 | return 1
|
---|
1943 | else
|
---|
1944 | "if the sort sequences are the same then compare the paths
|
---|
1945 | "alphabetically
|
---|
1946 | let pathCompare = g:NERDTreeCaseSensitiveSort ? thisPath <# thatPath : thisPath <? thatPath
|
---|
1947 | if pathCompare
|
---|
1948 | return -1
|
---|
1949 | else
|
---|
1950 | return 1
|
---|
1951 | endif
|
---|
1952 | endif
|
---|
1953 | endfunction
|
---|
1954 |
|
---|
1955 | "FUNCTION: Path.Create(fullpath) {{{3
|
---|
1956 | "
|
---|
1957 | "Factory method.
|
---|
1958 | "
|
---|
1959 | "Creates a path object with the given path. The path is also created on the
|
---|
1960 | "filesystem. If the path already exists, a NERDTree.Path.Exists exception is
|
---|
1961 | "thrown. If any other errors occur, a NERDTree.Path exception is thrown.
|
---|
1962 | "
|
---|
1963 | "Args:
|
---|
1964 | "fullpath: the full filesystem path to the file/dir to create
|
---|
1965 | function! s:Path.Create(fullpath)
|
---|
1966 | "bail if the a:fullpath already exists
|
---|
1967 | if isdirectory(a:fullpath) || filereadable(a:fullpath)
|
---|
1968 | throw "NERDTree.CreatePathError: Directory Exists: '" . a:fullpath . "'"
|
---|
1969 | endif
|
---|
1970 |
|
---|
1971 | try
|
---|
1972 |
|
---|
1973 | "if it ends with a slash, assume its a dir create it
|
---|
1974 | if a:fullpath =~ '\(\\\|\/\)$'
|
---|
1975 | "whack the trailing slash off the end if it exists
|
---|
1976 | let fullpath = substitute(a:fullpath, '\(\\\|\/\)$', '', '')
|
---|
1977 |
|
---|
1978 | call mkdir(fullpath, 'p')
|
---|
1979 |
|
---|
1980 | "assume its a file and create
|
---|
1981 | else
|
---|
1982 | call writefile([], a:fullpath)
|
---|
1983 | endif
|
---|
1984 | catch
|
---|
1985 | throw "NERDTree.CreatePathError: Could not create path: '" . a:fullpath . "'"
|
---|
1986 | endtry
|
---|
1987 |
|
---|
1988 | return s:Path.New(a:fullpath)
|
---|
1989 | endfunction
|
---|
1990 |
|
---|
1991 | "FUNCTION: Path.copy(dest) {{{3
|
---|
1992 | "
|
---|
1993 | "Copies the file/dir represented by this Path to the given location
|
---|
1994 | "
|
---|
1995 | "Args:
|
---|
1996 | "dest: the location to copy this dir/file to
|
---|
1997 | function! s:Path.copy(dest)
|
---|
1998 | if !s:Path.CopyingSupported()
|
---|
1999 | throw "NERDTree.CopyingNotSupportedError: Copying is not supported on this OS"
|
---|
2000 | endif
|
---|
2001 |
|
---|
2002 | let dest = s:Path.WinToUnixPath(a:dest)
|
---|
2003 |
|
---|
2004 | let cmd = g:NERDTreeCopyCmd . " " . self.str() . " " . dest
|
---|
2005 | let success = system(cmd)
|
---|
2006 | if success != 0
|
---|
2007 | throw "NERDTree.CopyError: Could not copy ''". self.str() ."'' to: '" . a:dest . "'"
|
---|
2008 | endif
|
---|
2009 | endfunction
|
---|
2010 |
|
---|
2011 | "FUNCTION: Path.CopyingSupported() {{{3
|
---|
2012 | "
|
---|
2013 | "returns 1 if copying is supported for this OS
|
---|
2014 | function! s:Path.CopyingSupported()
|
---|
2015 | return exists('g:NERDTreeCopyCmd')
|
---|
2016 | endfunction
|
---|
2017 |
|
---|
2018 |
|
---|
2019 | "FUNCTION: Path.copyingWillOverwrite(dest) {{{3
|
---|
2020 | "
|
---|
2021 | "returns 1 if copy this path to the given location will cause files to
|
---|
2022 | "overwritten
|
---|
2023 | "
|
---|
2024 | "Args:
|
---|
2025 | "dest: the location this path will be copied to
|
---|
2026 | function! s:Path.copyingWillOverwrite(dest)
|
---|
2027 | if filereadable(a:dest)
|
---|
2028 | return 1
|
---|
2029 | endif
|
---|
2030 |
|
---|
2031 | if isdirectory(a:dest)
|
---|
2032 | let path = s:Path.JoinPathStrings(a:dest, self.getLastPathComponent(0))
|
---|
2033 | if filereadable(path)
|
---|
2034 | return 1
|
---|
2035 | endif
|
---|
2036 | endif
|
---|
2037 | endfunction
|
---|
2038 |
|
---|
2039 | "FUNCTION: Path.delete() {{{3
|
---|
2040 | "
|
---|
2041 | "Deletes the file represented by this path.
|
---|
2042 | "Deletion of directories is not supported
|
---|
2043 | "
|
---|
2044 | "Throws NERDTree.Path.Deletion exceptions
|
---|
2045 | function! s:Path.delete()
|
---|
2046 | if self.isDirectory
|
---|
2047 |
|
---|
2048 | let cmd = g:NERDTreeRemoveDirCmd . self.str({'escape': 1})
|
---|
2049 | let success = system(cmd)
|
---|
2050 |
|
---|
2051 | if v:shell_error != 0
|
---|
2052 | throw "NERDTree.PathDeletionError: Could not delete directory: '" . self.str() . "'"
|
---|
2053 | endif
|
---|
2054 | else
|
---|
2055 | let success = delete(self.str())
|
---|
2056 | if success != 0
|
---|
2057 | throw "NERDTree.PathDeletionError: Could not delete file: '" . self.str() . "'"
|
---|
2058 | endif
|
---|
2059 | endif
|
---|
2060 |
|
---|
2061 | "delete all bookmarks for this path
|
---|
2062 | for i in self.bookmarkNames()
|
---|
2063 | let bookmark = s:Bookmark.BookmarkFor(i)
|
---|
2064 | call bookmark.delete()
|
---|
2065 | endfor
|
---|
2066 | endfunction
|
---|
2067 |
|
---|
2068 | "FUNCTION: Path.displayString() {{{3
|
---|
2069 | "
|
---|
2070 | "Returns a string that specifies how the path should be represented as a
|
---|
2071 | "string
|
---|
2072 | function! s:Path.displayString()
|
---|
2073 | if self.cachedDisplayString ==# ""
|
---|
2074 | call self.cacheDisplayString()
|
---|
2075 | endif
|
---|
2076 |
|
---|
2077 | return self.cachedDisplayString
|
---|
2078 | endfunction
|
---|
2079 | "FUNCTION: Path.extractDriveLetter(fullpath) {{{3
|
---|
2080 | "
|
---|
2081 | "If running windows, cache the drive letter for this path
|
---|
2082 | function! s:Path.extractDriveLetter(fullpath)
|
---|
2083 | if s:running_windows
|
---|
2084 | let self.drive = substitute(a:fullpath, '\(^[a-zA-Z]:\).*', '\1', '')
|
---|
2085 | else
|
---|
2086 | let self.drive = ''
|
---|
2087 | endif
|
---|
2088 |
|
---|
2089 | endfunction
|
---|
2090 | "FUNCTION: Path.exists() {{{3
|
---|
2091 | "return 1 if this path points to a location that is readable or is a directory
|
---|
2092 | function! s:Path.exists()
|
---|
2093 | let p = self.str()
|
---|
2094 | return filereadable(p) || isdirectory(p)
|
---|
2095 | endfunction
|
---|
2096 | "FUNCTION: Path.getDir() {{{3
|
---|
2097 | "
|
---|
2098 | "Returns this path if it is a directory, else this paths parent.
|
---|
2099 | "
|
---|
2100 | "Return:
|
---|
2101 | "a Path object
|
---|
2102 | function! s:Path.getDir()
|
---|
2103 | if self.isDirectory
|
---|
2104 | return self
|
---|
2105 | else
|
---|
2106 | return self.getParent()
|
---|
2107 | endif
|
---|
2108 | endfunction
|
---|
2109 | "FUNCTION: Path.getParent() {{{3
|
---|
2110 | "
|
---|
2111 | "Returns a new path object for this paths parent
|
---|
2112 | "
|
---|
2113 | "Return:
|
---|
2114 | "a new Path object
|
---|
2115 | function! s:Path.getParent()
|
---|
2116 | if s:running_windows
|
---|
2117 | let path = self.drive . '\' . join(self.pathSegments[0:-2], '\')
|
---|
2118 | else
|
---|
2119 | let path = '/'. join(self.pathSegments[0:-2], '/')
|
---|
2120 | endif
|
---|
2121 |
|
---|
2122 | return s:Path.New(path)
|
---|
2123 | endfunction
|
---|
2124 | "FUNCTION: Path.getLastPathComponent(dirSlash) {{{3
|
---|
2125 | "
|
---|
2126 | "Gets the last part of this path.
|
---|
2127 | "
|
---|
2128 | "Args:
|
---|
2129 | "dirSlash: if 1 then a trailing slash will be added to the returned value for
|
---|
2130 | "directory nodes.
|
---|
2131 | function! s:Path.getLastPathComponent(dirSlash)
|
---|
2132 | if empty(self.pathSegments)
|
---|
2133 | return ''
|
---|
2134 | endif
|
---|
2135 | let toReturn = self.pathSegments[-1]
|
---|
2136 | if a:dirSlash && self.isDirectory
|
---|
2137 | let toReturn = toReturn . '/'
|
---|
2138 | endif
|
---|
2139 | return toReturn
|
---|
2140 | endfunction
|
---|
2141 |
|
---|
2142 | "FUNCTION: Path.getSortOrderIndex() {{{3
|
---|
2143 | "returns the index of the pattern in g:NERDTreeSortOrder that this path matches
|
---|
2144 | function! s:Path.getSortOrderIndex()
|
---|
2145 | let i = 0
|
---|
2146 | while i < len(g:NERDTreeSortOrder)
|
---|
2147 | if self.getLastPathComponent(1) =~ g:NERDTreeSortOrder[i]
|
---|
2148 | return i
|
---|
2149 | endif
|
---|
2150 | let i = i + 1
|
---|
2151 | endwhile
|
---|
2152 | return s:NERDTreeSortStarIndex
|
---|
2153 | endfunction
|
---|
2154 |
|
---|
2155 | "FUNCTION: Path.ignore() {{{3
|
---|
2156 | "returns true if this path should be ignored
|
---|
2157 | function! s:Path.ignore()
|
---|
2158 | let lastPathComponent = self.getLastPathComponent(0)
|
---|
2159 |
|
---|
2160 | "filter out the user specified paths to ignore
|
---|
2161 | if b:NERDTreeIgnoreEnabled
|
---|
2162 | for i in g:NERDTreeIgnore
|
---|
2163 | if lastPathComponent =~ i
|
---|
2164 | return 1
|
---|
2165 | endif
|
---|
2166 | endfor
|
---|
2167 | endif
|
---|
2168 |
|
---|
2169 | "dont show hidden files unless instructed to
|
---|
2170 | if b:NERDTreeShowHidden ==# 0 && lastPathComponent =~ '^\.'
|
---|
2171 | return 1
|
---|
2172 | endif
|
---|
2173 |
|
---|
2174 | if b:NERDTreeShowFiles ==# 0 && self.isDirectory ==# 0
|
---|
2175 | return 1
|
---|
2176 | endif
|
---|
2177 |
|
---|
2178 | return 0
|
---|
2179 | endfunction
|
---|
2180 |
|
---|
2181 | "FUNCTION: Path.isUnder(path) {{{3
|
---|
2182 | "return 1 if this path is somewhere under the given path in the filesystem.
|
---|
2183 | "
|
---|
2184 | "a:path should be a dir
|
---|
2185 | function! s:Path.isUnder(path)
|
---|
2186 | if a:path.isDirectory == 0
|
---|
2187 | return 0
|
---|
2188 | endif
|
---|
2189 |
|
---|
2190 | let this = self.str()
|
---|
2191 | let that = a:path.str()
|
---|
2192 | return stridx(this, that . s:Path.Slash()) == 0
|
---|
2193 | endfunction
|
---|
2194 |
|
---|
2195 | "FUNCTION: Path.JoinPathStrings(...) {{{3
|
---|
2196 | function! s:Path.JoinPathStrings(...)
|
---|
2197 | let components = []
|
---|
2198 | for i in a:000
|
---|
2199 | let components = extend(components, split(i, '/'))
|
---|
2200 | endfor
|
---|
2201 | return '/' . join(components, '/')
|
---|
2202 | endfunction
|
---|
2203 |
|
---|
2204 | "FUNCTION: Path.equals() {{{3
|
---|
2205 | "
|
---|
2206 | "Determines whether 2 path objects are "equal".
|
---|
2207 | "They are equal if the paths they represent are the same
|
---|
2208 | "
|
---|
2209 | "Args:
|
---|
2210 | "path: the other path obj to compare this with
|
---|
2211 | function! s:Path.equals(path)
|
---|
2212 | return self.str() ==# a:path.str()
|
---|
2213 | endfunction
|
---|
2214 |
|
---|
2215 | "FUNCTION: Path.New() {{{3
|
---|
2216 | "The Constructor for the Path object
|
---|
2217 | function! s:Path.New(path)
|
---|
2218 | let newPath = copy(self)
|
---|
2219 |
|
---|
2220 | call newPath.readInfoFromDisk(s:Path.AbsolutePathFor(a:path))
|
---|
2221 |
|
---|
2222 | let newPath.cachedDisplayString = ""
|
---|
2223 |
|
---|
2224 | return newPath
|
---|
2225 | endfunction
|
---|
2226 |
|
---|
2227 | "FUNCTION: Path.Slash() {{{3
|
---|
2228 | "return the slash to use for the current OS
|
---|
2229 | function! s:Path.Slash()
|
---|
2230 | return s:running_windows ? '\' : '/'
|
---|
2231 | endfunction
|
---|
2232 |
|
---|
2233 | "FUNCTION: Path.readInfoFromDisk(fullpath) {{{3
|
---|
2234 | "
|
---|
2235 | "
|
---|
2236 | "Throws NERDTree.Path.InvalidArguments exception.
|
---|
2237 | function! s:Path.readInfoFromDisk(fullpath)
|
---|
2238 | call self.extractDriveLetter(a:fullpath)
|
---|
2239 |
|
---|
2240 | let fullpath = s:Path.WinToUnixPath(a:fullpath)
|
---|
2241 |
|
---|
2242 | if getftype(fullpath) ==# "fifo"
|
---|
2243 | throw "NERDTree.InvalidFiletypeError: Cant handle FIFO files: " . a:fullpath
|
---|
2244 | endif
|
---|
2245 |
|
---|
2246 | let self.pathSegments = split(fullpath, '/')
|
---|
2247 |
|
---|
2248 | let self.isReadOnly = 0
|
---|
2249 | if isdirectory(a:fullpath)
|
---|
2250 | let self.isDirectory = 1
|
---|
2251 | elseif filereadable(a:fullpath)
|
---|
2252 | let self.isDirectory = 0
|
---|
2253 | let self.isReadOnly = filewritable(a:fullpath) ==# 0
|
---|
2254 | else
|
---|
2255 | throw "NERDTree.InvalidArgumentsError: Invalid path = " . a:fullpath
|
---|
2256 | endif
|
---|
2257 |
|
---|
2258 | let self.isExecutable = 0
|
---|
2259 | if !self.isDirectory
|
---|
2260 | let self.isExecutable = getfperm(a:fullpath) =~ 'x'
|
---|
2261 | endif
|
---|
2262 |
|
---|
2263 | "grab the last part of the path (minus the trailing slash)
|
---|
2264 | let lastPathComponent = self.getLastPathComponent(0)
|
---|
2265 |
|
---|
2266 | "get the path to the new node with the parent dir fully resolved
|
---|
2267 | let hardPath = resolve(self.strTrunk()) . '/' . lastPathComponent
|
---|
2268 |
|
---|
2269 | "if the last part of the path is a symlink then flag it as such
|
---|
2270 | let self.isSymLink = (resolve(hardPath) != hardPath)
|
---|
2271 | if self.isSymLink
|
---|
2272 | let self.symLinkDest = resolve(fullpath)
|
---|
2273 |
|
---|
2274 | "if the link is a dir then slap a / on the end of its dest
|
---|
2275 | if isdirectory(self.symLinkDest)
|
---|
2276 |
|
---|
2277 | "we always wanna treat MS windows shortcuts as files for
|
---|
2278 | "simplicity
|
---|
2279 | if hardPath !~ '\.lnk$'
|
---|
2280 |
|
---|
2281 | let self.symLinkDest = self.symLinkDest . '/'
|
---|
2282 | endif
|
---|
2283 | endif
|
---|
2284 | endif
|
---|
2285 | endfunction
|
---|
2286 |
|
---|
2287 | "FUNCTION: Path.refresh() {{{3
|
---|
2288 | function! s:Path.refresh()
|
---|
2289 | call self.readInfoFromDisk(self.str())
|
---|
2290 | call self.cacheDisplayString()
|
---|
2291 | endfunction
|
---|
2292 |
|
---|
2293 | "FUNCTION: Path.rename() {{{3
|
---|
2294 | "
|
---|
2295 | "Renames this node on the filesystem
|
---|
2296 | function! s:Path.rename(newPath)
|
---|
2297 | if a:newPath ==# ''
|
---|
2298 | throw "NERDTree.InvalidArgumentsError: Invalid newPath for renaming = ". a:newPath
|
---|
2299 | endif
|
---|
2300 |
|
---|
2301 | let success = rename(self.str(), a:newPath)
|
---|
2302 | if success != 0
|
---|
2303 | throw "NERDTree.PathRenameError: Could not rename: '" . self.str() . "'" . 'to:' . a:newPath
|
---|
2304 | endif
|
---|
2305 | call self.readInfoFromDisk(a:newPath)
|
---|
2306 |
|
---|
2307 | for i in self.bookmarkNames()
|
---|
2308 | let b = s:Bookmark.BookmarkFor(i)
|
---|
2309 | call b.setPath(copy(self))
|
---|
2310 | endfor
|
---|
2311 | call s:Bookmark.Write()
|
---|
2312 | endfunction
|
---|
2313 |
|
---|
2314 | "FUNCTION: Path.str() {{{3
|
---|
2315 | "
|
---|
2316 | "Returns a string representation of this Path
|
---|
2317 | "
|
---|
2318 | "Takes an optional dictionary param to specify how the output should be
|
---|
2319 | "formatted.
|
---|
2320 | "
|
---|
2321 | "The dict may have the following keys:
|
---|
2322 | " 'format'
|
---|
2323 | " 'escape'
|
---|
2324 | " 'truncateTo'
|
---|
2325 | "
|
---|
2326 | "The 'format' key may have a value of:
|
---|
2327 | " 'Cd' - a string to be used with the :cd command
|
---|
2328 | " 'Edit' - a string to be used with :e :sp :new :tabedit etc
|
---|
2329 | " 'UI' - a string used in the NERD tree UI
|
---|
2330 | "
|
---|
2331 | "The 'escape' key, if specified will cause the output to be escaped with
|
---|
2332 | "shellescape()
|
---|
2333 | "
|
---|
2334 | "The 'truncateTo' key causes the resulting string to be truncated to the value
|
---|
2335 | "'truncateTo' maps to. A '<' char will be prepended.
|
---|
2336 | function! s:Path.str(...)
|
---|
2337 | let options = a:0 ? a:1 : {}
|
---|
2338 | let toReturn = ""
|
---|
2339 |
|
---|
2340 | if has_key(options, 'format')
|
---|
2341 | let format = options['format']
|
---|
2342 | if has_key(self, '_strFor' . format)
|
---|
2343 | exec 'let toReturn = self._strFor' . format . '()'
|
---|
2344 | else
|
---|
2345 | raise 'NERDTree.UnknownFormatError: unknown format "'. format .'"'
|
---|
2346 | endif
|
---|
2347 | else
|
---|
2348 | let toReturn = self._str()
|
---|
2349 | endif
|
---|
2350 |
|
---|
2351 | if has_key(options, 'escape') && options['escape']
|
---|
2352 | let toReturn = shellescape(toReturn)
|
---|
2353 | endif
|
---|
2354 |
|
---|
2355 | if has_key(options, 'truncateTo')
|
---|
2356 | let limit = options['truncateTo']
|
---|
2357 | if len(toReturn) > limit
|
---|
2358 | let toReturn = "<" . strpart(toReturn, len(toReturn) - limit + 1)
|
---|
2359 | endif
|
---|
2360 | endif
|
---|
2361 |
|
---|
2362 | return toReturn
|
---|
2363 | endfunction
|
---|
2364 |
|
---|
2365 | "FUNCTION: Path._strForUI() {{{3
|
---|
2366 | function! s:Path._strForUI()
|
---|
2367 | let toReturn = '/' . join(self.pathSegments, '/')
|
---|
2368 | if self.isDirectory && toReturn != '/'
|
---|
2369 | let toReturn = toReturn . '/'
|
---|
2370 | endif
|
---|
2371 | return toReturn
|
---|
2372 | endfunction
|
---|
2373 |
|
---|
2374 | "FUNCTION: Path._strForCd() {{{3
|
---|
2375 | "
|
---|
2376 | " returns a string that can be used with :cd
|
---|
2377 | function! s:Path._strForCd()
|
---|
2378 | return escape(self.str(), s:escape_chars)
|
---|
2379 | endfunction
|
---|
2380 | "FUNCTION: Path._strForEdit() {{{3
|
---|
2381 | "
|
---|
2382 | "Return: the string for this path that is suitable to be used with the :edit
|
---|
2383 | "command
|
---|
2384 | function! s:Path._strForEdit()
|
---|
2385 | let p = self.str({'format': 'UI'})
|
---|
2386 | let cwd = getcwd()
|
---|
2387 |
|
---|
2388 | if s:running_windows
|
---|
2389 | let p = tolower(self.str())
|
---|
2390 | let cwd = tolower(getcwd())
|
---|
2391 | endif
|
---|
2392 |
|
---|
2393 | let p = escape(p, s:escape_chars)
|
---|
2394 |
|
---|
2395 | let cwd = cwd . s:Path.Slash()
|
---|
2396 |
|
---|
2397 | "return a relative path if we can
|
---|
2398 | if stridx(p, cwd) ==# 0
|
---|
2399 | let p = strpart(p, strlen(cwd))
|
---|
2400 | endif
|
---|
2401 |
|
---|
2402 | if p ==# ''
|
---|
2403 | let p = '.'
|
---|
2404 | endif
|
---|
2405 |
|
---|
2406 | return p
|
---|
2407 |
|
---|
2408 | endfunction
|
---|
2409 | "FUNCTION: Path._strForGlob() {{{3
|
---|
2410 | function! s:Path._strForGlob()
|
---|
2411 | let lead = s:Path.Slash()
|
---|
2412 |
|
---|
2413 | "if we are running windows then slap a drive letter on the front
|
---|
2414 | if s:running_windows
|
---|
2415 | let lead = self.drive . '\'
|
---|
2416 | endif
|
---|
2417 |
|
---|
2418 | let toReturn = lead . join(self.pathSegments, s:Path.Slash())
|
---|
2419 |
|
---|
2420 | if !s:running_windows
|
---|
2421 | let toReturn = escape(toReturn, s:escape_chars)
|
---|
2422 | endif
|
---|
2423 | return toReturn
|
---|
2424 | endfunction
|
---|
2425 | "FUNCTION: Path._str() {{{3
|
---|
2426 | "
|
---|
2427 | "Gets the string path for this path object that is appropriate for the OS.
|
---|
2428 | "EG, in windows c:\foo\bar
|
---|
2429 | " in *nix /foo/bar
|
---|
2430 | function! s:Path._str()
|
---|
2431 | let lead = s:Path.Slash()
|
---|
2432 |
|
---|
2433 | "if we are running windows then slap a drive letter on the front
|
---|
2434 | if s:running_windows
|
---|
2435 | let lead = self.drive . '\'
|
---|
2436 | endif
|
---|
2437 |
|
---|
2438 | return lead . join(self.pathSegments, s:Path.Slash())
|
---|
2439 | endfunction
|
---|
2440 |
|
---|
2441 | "FUNCTION: Path.strTrunk() {{{3
|
---|
2442 | "Gets the path without the last segment on the end.
|
---|
2443 | function! s:Path.strTrunk()
|
---|
2444 | return self.drive . '/' . join(self.pathSegments[0:-2], '/')
|
---|
2445 | endfunction
|
---|
2446 |
|
---|
2447 | "FUNCTION: Path.WinToUnixPath(pathstr){{{3
|
---|
2448 | "Takes in a windows path and returns the unix equiv
|
---|
2449 | "
|
---|
2450 | "A class level method
|
---|
2451 | "
|
---|
2452 | "Args:
|
---|
2453 | "pathstr: the windows path to convert
|
---|
2454 | function! s:Path.WinToUnixPath(pathstr)
|
---|
2455 | if !s:running_windows
|
---|
2456 | return a:pathstr
|
---|
2457 | endif
|
---|
2458 |
|
---|
2459 | let toReturn = a:pathstr
|
---|
2460 |
|
---|
2461 | "remove the x:\ of the front
|
---|
2462 | let toReturn = substitute(toReturn, '^.*:\(\\\|/\)\?', '/', "")
|
---|
2463 |
|
---|
2464 | "convert all \ chars to /
|
---|
2465 | let toReturn = substitute(toReturn, '\', '/', "g")
|
---|
2466 |
|
---|
2467 | return toReturn
|
---|
2468 | endfunction
|
---|
2469 |
|
---|
2470 | " SECTION: General Functions {{{1
|
---|
2471 | "============================================================
|
---|
2472 | "FUNCTION: s:bufInWindows(bnum){{{2
|
---|
2473 | "[[STOLEN FROM VTREEEXPLORER.VIM]]
|
---|
2474 | "Determine the number of windows open to this buffer number.
|
---|
2475 | "Care of Yegappan Lakshman. Thanks!
|
---|
2476 | "
|
---|
2477 | "Args:
|
---|
2478 | "bnum: the subject buffers buffer number
|
---|
2479 | function! s:bufInWindows(bnum)
|
---|
2480 | let cnt = 0
|
---|
2481 | let winnum = 1
|
---|
2482 | while 1
|
---|
2483 | let bufnum = winbufnr(winnum)
|
---|
2484 | if bufnum < 0
|
---|
2485 | break
|
---|
2486 | endif
|
---|
2487 | if bufnum ==# a:bnum
|
---|
2488 | let cnt = cnt + 1
|
---|
2489 | endif
|
---|
2490 | let winnum = winnum + 1
|
---|
2491 | endwhile
|
---|
2492 |
|
---|
2493 | return cnt
|
---|
2494 | endfunction " >>>
|
---|
2495 | "FUNCTION: s:checkForBrowse(dir) {{{2
|
---|
2496 | "inits a secondary nerd tree in the current buffer if appropriate
|
---|
2497 | function! s:checkForBrowse(dir)
|
---|
2498 | if a:dir != '' && isdirectory(a:dir)
|
---|
2499 | call s:initNerdTreeInPlace(a:dir)
|
---|
2500 | endif
|
---|
2501 | endfunction
|
---|
2502 | "FUNCTION: s:compareBookmarks(first, second) {{{2
|
---|
2503 | "Compares two bookmarks
|
---|
2504 | function! s:compareBookmarks(first, second)
|
---|
2505 | return a:first.compareTo(a:second)
|
---|
2506 | endfunction
|
---|
2507 |
|
---|
2508 | " FUNCTION: s:completeBookmarks(A,L,P) {{{2
|
---|
2509 | " completion function for the bookmark commands
|
---|
2510 | function! s:completeBookmarks(A,L,P)
|
---|
2511 | return filter(s:Bookmark.BookmarkNames(), 'v:val =~ "^' . a:A . '"')
|
---|
2512 | endfunction
|
---|
2513 | " FUNCTION: s:exec(cmd) {{{2
|
---|
2514 | " same as :exec cmd but eventignore=all is set for the duration
|
---|
2515 | function! s:exec(cmd)
|
---|
2516 | let old_ei = &ei
|
---|
2517 | set ei=all
|
---|
2518 | exec a:cmd
|
---|
2519 | let &ei = old_ei
|
---|
2520 | endfunction
|
---|
2521 | " FUNCTION: s:findAndRevealPath() {{{2
|
---|
2522 | function! s:findAndRevealPath()
|
---|
2523 | try
|
---|
2524 | let p = s:Path.New(expand("%"))
|
---|
2525 | catch /^NERDTree.InvalidArgumentsError/
|
---|
2526 | call s:echo("no file for the current buffer")
|
---|
2527 | return
|
---|
2528 | endtry
|
---|
2529 |
|
---|
2530 | if !s:treeExistsForTab()
|
---|
2531 | call s:initNerdTree(p.getParent().str())
|
---|
2532 | else
|
---|
2533 | if !p.isUnder(s:TreeFileNode.GetRootForTab().path)
|
---|
2534 | call s:initNerdTree(p.getParent().str())
|
---|
2535 | else
|
---|
2536 | if !s:isTreeOpen()
|
---|
2537 | call s:toggle("")
|
---|
2538 | endif
|
---|
2539 | endif
|
---|
2540 | endif
|
---|
2541 | call s:putCursorInTreeWin()
|
---|
2542 | call b:NERDTreeRoot.reveal(p)
|
---|
2543 | endfunction
|
---|
2544 | "FUNCTION: s:initNerdTree(name) {{{2
|
---|
2545 | "Initialise the nerd tree for this tab. The tree will start in either the
|
---|
2546 | "given directory, or the directory associated with the given bookmark
|
---|
2547 | "
|
---|
2548 | "Args:
|
---|
2549 | "name: the name of a bookmark or a directory
|
---|
2550 | function! s:initNerdTree(name)
|
---|
2551 | let path = {}
|
---|
2552 | if s:Bookmark.BookmarkExistsFor(a:name)
|
---|
2553 | let path = s:Bookmark.BookmarkFor(a:name).path
|
---|
2554 | else
|
---|
2555 | let dir = a:name ==# '' ? getcwd() : a:name
|
---|
2556 |
|
---|
2557 | "hack to get an absolute path if a relative path is given
|
---|
2558 | if dir =~ '^\.'
|
---|
2559 | let dir = getcwd() . s:Path.Slash() . dir
|
---|
2560 | endif
|
---|
2561 | let dir = resolve(dir)
|
---|
2562 |
|
---|
2563 | try
|
---|
2564 | let path = s:Path.New(dir)
|
---|
2565 | catch /^NERDTree.InvalidArgumentsError/
|
---|
2566 | call s:echo("No bookmark or directory found for: " . a:name)
|
---|
2567 | return
|
---|
2568 | endtry
|
---|
2569 | endif
|
---|
2570 | if !path.isDirectory
|
---|
2571 | let path = path.getParent()
|
---|
2572 | endif
|
---|
2573 |
|
---|
2574 | "if instructed to, then change the vim CWD to the dir the NERDTree is
|
---|
2575 | "inited in
|
---|
2576 | if g:NERDTreeChDirMode != 0
|
---|
2577 | call path.changeToDir()
|
---|
2578 | endif
|
---|
2579 |
|
---|
2580 | if s:treeExistsForTab()
|
---|
2581 | if s:isTreeOpen()
|
---|
2582 | call s:closeTree()
|
---|
2583 | endif
|
---|
2584 | unlet t:NERDTreeBufName
|
---|
2585 | endif
|
---|
2586 |
|
---|
2587 | let newRoot = s:TreeDirNode.New(path)
|
---|
2588 | call newRoot.open()
|
---|
2589 |
|
---|
2590 | call s:createTreeWin()
|
---|
2591 | let b:treeShowHelp = 0
|
---|
2592 | let b:NERDTreeIgnoreEnabled = 1
|
---|
2593 | let b:NERDTreeShowFiles = g:NERDTreeShowFiles
|
---|
2594 | let b:NERDTreeShowHidden = g:NERDTreeShowHidden
|
---|
2595 | let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks
|
---|
2596 | let b:NERDTreeRoot = newRoot
|
---|
2597 |
|
---|
2598 | let b:NERDTreeType = "primary"
|
---|
2599 |
|
---|
2600 | call s:renderView()
|
---|
2601 | call b:NERDTreeRoot.putCursorHere(0, 0)
|
---|
2602 | endfunction
|
---|
2603 |
|
---|
2604 | "FUNCTION: s:initNerdTreeInPlace(dir) {{{2
|
---|
2605 | function! s:initNerdTreeInPlace(dir)
|
---|
2606 | try
|
---|
2607 | let path = s:Path.New(a:dir)
|
---|
2608 | catch /^NERDTree.InvalidArgumentsError/
|
---|
2609 | call s:echo("Invalid directory name:" . a:name)
|
---|
2610 | return
|
---|
2611 | endtry
|
---|
2612 |
|
---|
2613 | "we want the directory buffer to disappear when we do the :edit below
|
---|
2614 | setlocal bufhidden=wipe
|
---|
2615 |
|
---|
2616 | let previousBuf = expand("#")
|
---|
2617 |
|
---|
2618 | "we need a unique name for each secondary tree buffer to ensure they are
|
---|
2619 | "all independent
|
---|
2620 | exec "silent edit " . s:nextBufferName()
|
---|
2621 |
|
---|
2622 | let b:NERDTreePreviousBuf = bufnr(previousBuf)
|
---|
2623 |
|
---|
2624 | let b:NERDTreeRoot = s:TreeDirNode.New(path)
|
---|
2625 | call b:NERDTreeRoot.open()
|
---|
2626 |
|
---|
2627 | "throwaway buffer options
|
---|
2628 | setlocal noswapfile
|
---|
2629 | setlocal buftype=nofile
|
---|
2630 | setlocal bufhidden=hide
|
---|
2631 | setlocal nowrap
|
---|
2632 | setlocal foldcolumn=0
|
---|
2633 | setlocal nobuflisted
|
---|
2634 | setlocal nospell
|
---|
2635 | if g:NERDTreeShowLineNumbers
|
---|
2636 | setlocal nu
|
---|
2637 | else
|
---|
2638 | setlocal nonu
|
---|
2639 | endif
|
---|
2640 |
|
---|
2641 | iabc <buffer>
|
---|
2642 |
|
---|
2643 | if g:NERDTreeHighlightCursorline
|
---|
2644 | setlocal cursorline
|
---|
2645 | endif
|
---|
2646 |
|
---|
2647 | call s:setupStatusline()
|
---|
2648 |
|
---|
2649 | let b:treeShowHelp = 0
|
---|
2650 | let b:NERDTreeIgnoreEnabled = 1
|
---|
2651 | let b:NERDTreeShowFiles = g:NERDTreeShowFiles
|
---|
2652 | let b:NERDTreeShowHidden = g:NERDTreeShowHidden
|
---|
2653 | let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks
|
---|
2654 |
|
---|
2655 | let b:NERDTreeType = "secondary"
|
---|
2656 |
|
---|
2657 | call s:bindMappings()
|
---|
2658 | setfiletype nerdtree
|
---|
2659 | " syntax highlighting
|
---|
2660 | if has("syntax") && exists("g:syntax_on")
|
---|
2661 | call s:setupSyntaxHighlighting()
|
---|
2662 | endif
|
---|
2663 |
|
---|
2664 | call s:renderView()
|
---|
2665 | endfunction
|
---|
2666 | " FUNCTION: s:initNerdTreeMirror() {{{2
|
---|
2667 | function! s:initNerdTreeMirror()
|
---|
2668 |
|
---|
2669 | "get the names off all the nerd tree buffers
|
---|
2670 | let treeBufNames = []
|
---|
2671 | for i in range(1, tabpagenr("$"))
|
---|
2672 | let nextName = s:tabpagevar(i, 'NERDTreeBufName')
|
---|
2673 | if nextName != -1 && (!exists("t:NERDTreeBufName") || nextName != t:NERDTreeBufName)
|
---|
2674 | call add(treeBufNames, nextName)
|
---|
2675 | endif
|
---|
2676 | endfor
|
---|
2677 | let treeBufNames = s:unique(treeBufNames)
|
---|
2678 |
|
---|
2679 | "map the option names (that the user will be prompted with) to the nerd
|
---|
2680 | "tree buffer names
|
---|
2681 | let options = {}
|
---|
2682 | let i = 0
|
---|
2683 | while i < len(treeBufNames)
|
---|
2684 | let bufName = treeBufNames[i]
|
---|
2685 | let treeRoot = getbufvar(bufName, "NERDTreeRoot")
|
---|
2686 | let options[i+1 . '. ' . treeRoot.path.str() . ' (buf name: ' . bufName . ')'] = bufName
|
---|
2687 | let i = i + 1
|
---|
2688 | endwhile
|
---|
2689 |
|
---|
2690 | "work out which tree to mirror, if there is more than 1 then ask the user
|
---|
2691 | let bufferName = ''
|
---|
2692 | if len(keys(options)) > 1
|
---|
2693 | let choices = ["Choose a tree to mirror"]
|
---|
2694 | let choices = extend(choices, sort(keys(options)))
|
---|
2695 | let choice = inputlist(choices)
|
---|
2696 | if choice < 1 || choice > len(options) || choice ==# ''
|
---|
2697 | return
|
---|
2698 | endif
|
---|
2699 |
|
---|
2700 | let bufferName = options[sort(keys(options))[choice-1]]
|
---|
2701 | elseif len(keys(options)) ==# 1
|
---|
2702 | let bufferName = values(options)[0]
|
---|
2703 | else
|
---|
2704 | call s:echo("No trees to mirror")
|
---|
2705 | return
|
---|
2706 | endif
|
---|
2707 |
|
---|
2708 | if s:treeExistsForTab() && s:isTreeOpen()
|
---|
2709 | call s:closeTree()
|
---|
2710 | endif
|
---|
2711 |
|
---|
2712 | let t:NERDTreeBufName = bufferName
|
---|
2713 | call s:createTreeWin()
|
---|
2714 | exec 'buffer ' . bufferName
|
---|
2715 | if !&hidden
|
---|
2716 | call s:renderView()
|
---|
2717 | endif
|
---|
2718 | endfunction
|
---|
2719 | " FUNCTION: s:nextBufferName() {{{2
|
---|
2720 | " returns the buffer name for the next nerd tree
|
---|
2721 | function! s:nextBufferName()
|
---|
2722 | let name = s:NERDTreeBufName . s:next_buffer_number
|
---|
2723 | let s:next_buffer_number += 1
|
---|
2724 | return name
|
---|
2725 | endfunction
|
---|
2726 | " FUNCTION: s:tabpagevar(tabnr, var) {{{2
|
---|
2727 | function! s:tabpagevar(tabnr, var)
|
---|
2728 | let currentTab = tabpagenr()
|
---|
2729 | let old_ei = &ei
|
---|
2730 | set ei=all
|
---|
2731 |
|
---|
2732 | exec "tabnext " . a:tabnr
|
---|
2733 | let v = -1
|
---|
2734 | if exists('t:' . a:var)
|
---|
2735 | exec 'let v = t:' . a:var
|
---|
2736 | endif
|
---|
2737 | exec "tabnext " . currentTab
|
---|
2738 |
|
---|
2739 | let &ei = old_ei
|
---|
2740 |
|
---|
2741 | return v
|
---|
2742 | endfunction
|
---|
2743 | " Function: s:treeExistsForBuffer() {{{2
|
---|
2744 | " Returns 1 if a nerd tree root exists in the current buffer
|
---|
2745 | function! s:treeExistsForBuf()
|
---|
2746 | return exists("b:NERDTreeRoot")
|
---|
2747 | endfunction
|
---|
2748 | " Function: s:treeExistsForTab() {{{2
|
---|
2749 | " Returns 1 if a nerd tree root exists in the current tab
|
---|
2750 | function! s:treeExistsForTab()
|
---|
2751 | return exists("t:NERDTreeBufName")
|
---|
2752 | endfunction
|
---|
2753 | " Function: s:unique(list) {{{2
|
---|
2754 | " returns a:list without duplicates
|
---|
2755 | function! s:unique(list)
|
---|
2756 | let uniqlist = []
|
---|
2757 | for elem in a:list
|
---|
2758 | if index(uniqlist, elem) ==# -1
|
---|
2759 | let uniqlist += [elem]
|
---|
2760 | endif
|
---|
2761 | endfor
|
---|
2762 | return uniqlist
|
---|
2763 | endfunction
|
---|
2764 | " SECTION: Public API {{{1
|
---|
2765 | "============================================================
|
---|
2766 | let g:NERDTreePath = s:Path
|
---|
2767 | let g:NERDTreeDirNode = s:TreeDirNode
|
---|
2768 | let g:NERDTreeFileNode = s:TreeFileNode
|
---|
2769 | let g:NERDTreeBookmark = s:Bookmark
|
---|
2770 |
|
---|
2771 | function! NERDTreeAddMenuItem(options)
|
---|
2772 | call s:MenuItem.Create(a:options)
|
---|
2773 | endfunction
|
---|
2774 |
|
---|
2775 | function! NERDTreeAddMenuSeparator(...)
|
---|
2776 | let opts = a:0 ? a:1 : {}
|
---|
2777 | call s:MenuItem.CreateSeparator(opts)
|
---|
2778 | endfunction
|
---|
2779 |
|
---|
2780 | function! NERDTreeAddSubmenu(options)
|
---|
2781 | return s:MenuItem.Create(a:options)
|
---|
2782 | endfunction
|
---|
2783 |
|
---|
2784 | function! NERDTreeAddKeyMap(options)
|
---|
2785 | call s:KeyMap.Create(a:options)
|
---|
2786 | endfunction
|
---|
2787 |
|
---|
2788 | function! NERDTreeRender()
|
---|
2789 | call s:renderView()
|
---|
2790 | endfunction
|
---|
2791 |
|
---|
2792 | " SECTION: View Functions {{{1
|
---|
2793 | "============================================================
|
---|
2794 | "FUNCTION: s:centerView() {{{2
|
---|
2795 | "centers the nerd tree window around the cursor (provided the nerd tree
|
---|
2796 | "options permit)
|
---|
2797 | function! s:centerView()
|
---|
2798 | if g:NERDTreeAutoCenter
|
---|
2799 | let current_line = winline()
|
---|
2800 | let lines_to_top = current_line
|
---|
2801 | let lines_to_bottom = winheight(s:getTreeWinNum()) - current_line
|
---|
2802 | if lines_to_top < g:NERDTreeAutoCenterThreshold || lines_to_bottom < g:NERDTreeAutoCenterThreshold
|
---|
2803 | normal! zz
|
---|
2804 | endif
|
---|
2805 | endif
|
---|
2806 | endfunction
|
---|
2807 | "FUNCTION: s:closeTree() {{{2
|
---|
2808 | "Closes the primary NERD tree window for this tab
|
---|
2809 | function! s:closeTree()
|
---|
2810 | if !s:isTreeOpen()
|
---|
2811 | throw "NERDTree.NoTreeFoundError: no NERDTree is open"
|
---|
2812 | endif
|
---|
2813 |
|
---|
2814 | if winnr("$") != 1
|
---|
2815 | call s:exec(s:getTreeWinNum() . " wincmd w")
|
---|
2816 | close
|
---|
2817 | call s:exec("wincmd p")
|
---|
2818 | else
|
---|
2819 | close
|
---|
2820 | endif
|
---|
2821 | endfunction
|
---|
2822 |
|
---|
2823 | "FUNCTION: s:closeTreeIfOpen() {{{2
|
---|
2824 | "Closes the NERD tree window if it is open
|
---|
2825 | function! s:closeTreeIfOpen()
|
---|
2826 | if s:isTreeOpen()
|
---|
2827 | call s:closeTree()
|
---|
2828 | endif
|
---|
2829 | endfunction
|
---|
2830 | "FUNCTION: s:closeTreeIfQuitOnOpen() {{{2
|
---|
2831 | "Closes the NERD tree window if the close on open option is set
|
---|
2832 | function! s:closeTreeIfQuitOnOpen()
|
---|
2833 | if g:NERDTreeQuitOnOpen && s:isTreeOpen()
|
---|
2834 | call s:closeTree()
|
---|
2835 | endif
|
---|
2836 | endfunction
|
---|
2837 | "FUNCTION: s:createTreeWin() {{{2
|
---|
2838 | "Inits the NERD tree window. ie. opens it, sizes it, sets all the local
|
---|
2839 | "options etc
|
---|
2840 | function! s:createTreeWin()
|
---|
2841 | "create the nerd tree window
|
---|
2842 | let splitLocation = g:NERDTreeWinPos ==# "left" ? "topleft " : "botright "
|
---|
2843 | let splitSize = g:NERDTreeWinSize
|
---|
2844 |
|
---|
2845 | if !exists('t:NERDTreeBufName')
|
---|
2846 | let t:NERDTreeBufName = s:nextBufferName()
|
---|
2847 | silent! exec splitLocation . 'vertical ' . splitSize . ' new'
|
---|
2848 | silent! exec "edit " . t:NERDTreeBufName
|
---|
2849 | else
|
---|
2850 | silent! exec splitLocation . 'vertical ' . splitSize . ' split'
|
---|
2851 | silent! exec "buffer " . t:NERDTreeBufName
|
---|
2852 | endif
|
---|
2853 |
|
---|
2854 | setlocal winfixwidth
|
---|
2855 |
|
---|
2856 | "throwaway buffer options
|
---|
2857 | setlocal noswapfile
|
---|
2858 | setlocal buftype=nofile
|
---|
2859 | setlocal nowrap
|
---|
2860 | setlocal foldcolumn=0
|
---|
2861 | setlocal nobuflisted
|
---|
2862 | setlocal nospell
|
---|
2863 | if g:NERDTreeShowLineNumbers
|
---|
2864 | setlocal nu
|
---|
2865 | else
|
---|
2866 | setlocal nonu
|
---|
2867 | endif
|
---|
2868 |
|
---|
2869 | iabc <buffer>
|
---|
2870 |
|
---|
2871 | if g:NERDTreeHighlightCursorline
|
---|
2872 | setlocal cursorline
|
---|
2873 | endif
|
---|
2874 |
|
---|
2875 | call s:setupStatusline()
|
---|
2876 |
|
---|
2877 | call s:bindMappings()
|
---|
2878 | setfiletype nerdtree
|
---|
2879 | " syntax highlighting
|
---|
2880 | if has("syntax") && exists("g:syntax_on")
|
---|
2881 | call s:setupSyntaxHighlighting()
|
---|
2882 | endif
|
---|
2883 | endfunction
|
---|
2884 |
|
---|
2885 | "FUNCTION: s:dumpHelp {{{2
|
---|
2886 | "prints out the quick help
|
---|
2887 | function! s:dumpHelp()
|
---|
2888 | let old_h = @h
|
---|
2889 | if b:treeShowHelp ==# 1
|
---|
2890 | let @h= "\" NERD tree (" . s:NERD_tree_version . ") quickhelp~\n"
|
---|
2891 | let @h=@h."\" ============================\n"
|
---|
2892 | let @h=@h."\" File node mappings~\n"
|
---|
2893 | let @h=@h."\" ". (g:NERDTreeMouseMode ==# 3 ? "single" : "double") ."-click,\n"
|
---|
2894 | let @h=@h."\" <CR>,\n"
|
---|
2895 | if b:NERDTreeType ==# "primary"
|
---|
2896 | let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in prev window\n"
|
---|
2897 | else
|
---|
2898 | let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in current window\n"
|
---|
2899 | endif
|
---|
2900 | if b:NERDTreeType ==# "primary"
|
---|
2901 | let @h=@h."\" ". g:NERDTreeMapPreview .": preview\n"
|
---|
2902 | endif
|
---|
2903 | let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n"
|
---|
2904 | let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n"
|
---|
2905 | let @h=@h."\" middle-click,\n"
|
---|
2906 | let @h=@h."\" ". g:NERDTreeMapOpenSplit .": open split\n"
|
---|
2907 | let @h=@h."\" ". g:NERDTreeMapPreviewSplit .": preview split\n"
|
---|
2908 | let @h=@h."\" ". g:NERDTreeMapOpenVSplit .": open vsplit\n"
|
---|
2909 | let @h=@h."\" ". g:NERDTreeMapPreviewVSplit .": preview vsplit\n"
|
---|
2910 |
|
---|
2911 | let @h=@h."\"\n\" ----------------------------\n"
|
---|
2912 | let @h=@h."\" Directory node mappings~\n"
|
---|
2913 | let @h=@h."\" ". (g:NERDTreeMouseMode ==# 1 ? "double" : "single") ."-click,\n"
|
---|
2914 | let @h=@h."\" ". g:NERDTreeMapActivateNode .": open & close node\n"
|
---|
2915 | let @h=@h."\" ". g:NERDTreeMapOpenRecursively .": recursively open node\n"
|
---|
2916 | let @h=@h."\" ". g:NERDTreeMapCloseDir .": close parent of node\n"
|
---|
2917 | let @h=@h."\" ". g:NERDTreeMapCloseChildren .": close all child nodes of\n"
|
---|
2918 | let @h=@h."\" current node recursively\n"
|
---|
2919 | let @h=@h."\" middle-click,\n"
|
---|
2920 | let @h=@h."\" ". g:NERDTreeMapOpenExpl.": explore selected dir\n"
|
---|
2921 |
|
---|
2922 | let @h=@h."\"\n\" ----------------------------\n"
|
---|
2923 | let @h=@h."\" Bookmark table mappings~\n"
|
---|
2924 | let @h=@h."\" double-click,\n"
|
---|
2925 | let @h=@h."\" ". g:NERDTreeMapActivateNode .": open bookmark\n"
|
---|
2926 | let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n"
|
---|
2927 | let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n"
|
---|
2928 | let @h=@h."\" ". g:NERDTreeMapDeleteBookmark .": delete bookmark\n"
|
---|
2929 |
|
---|
2930 | let @h=@h."\"\n\" ----------------------------\n"
|
---|
2931 | let @h=@h."\" Tree navigation mappings~\n"
|
---|
2932 | let @h=@h."\" ". g:NERDTreeMapJumpRoot .": go to root\n"
|
---|
2933 | let @h=@h."\" ". g:NERDTreeMapJumpParent .": go to parent\n"
|
---|
2934 | let @h=@h."\" ". g:NERDTreeMapJumpFirstChild .": go to first child\n"
|
---|
2935 | let @h=@h."\" ". g:NERDTreeMapJumpLastChild .": go to last child\n"
|
---|
2936 | let @h=@h."\" ". g:NERDTreeMapJumpNextSibling .": go to next sibling\n"
|
---|
2937 | let @h=@h."\" ". g:NERDTreeMapJumpPrevSibling .": go to prev sibling\n"
|
---|
2938 |
|
---|
2939 | let @h=@h."\"\n\" ----------------------------\n"
|
---|
2940 | let @h=@h."\" Filesystem mappings~\n"
|
---|
2941 | let @h=@h."\" ". g:NERDTreeMapChangeRoot .": change tree root to the\n"
|
---|
2942 | let @h=@h."\" selected dir\n"
|
---|
2943 | let @h=@h."\" ". g:NERDTreeMapUpdir .": move tree root up a dir\n"
|
---|
2944 | let @h=@h."\" ". g:NERDTreeMapUpdirKeepOpen .": move tree root up a dir\n"
|
---|
2945 | let @h=@h."\" but leave old root open\n"
|
---|
2946 | let @h=@h."\" ". g:NERDTreeMapRefresh .": refresh cursor dir\n"
|
---|
2947 | let @h=@h."\" ". g:NERDTreeMapRefreshRoot .": refresh current root\n"
|
---|
2948 | let @h=@h."\" ". g:NERDTreeMapMenu .": Show menu\n"
|
---|
2949 | let @h=@h."\" ". g:NERDTreeMapChdir .":change the CWD to the\n"
|
---|
2950 | let @h=@h."\" selected dir\n"
|
---|
2951 |
|
---|
2952 | let @h=@h."\"\n\" ----------------------------\n"
|
---|
2953 | let @h=@h."\" Tree filtering mappings~\n"
|
---|
2954 | let @h=@h."\" ". g:NERDTreeMapToggleHidden .": hidden files (" . (b:NERDTreeShowHidden ? "on" : "off") . ")\n"
|
---|
2955 | let @h=@h."\" ". g:NERDTreeMapToggleFilters .": file filters (" . (b:NERDTreeIgnoreEnabled ? "on" : "off") . ")\n"
|
---|
2956 | let @h=@h."\" ". g:NERDTreeMapToggleFiles .": files (" . (b:NERDTreeShowFiles ? "on" : "off") . ")\n"
|
---|
2957 | let @h=@h."\" ". g:NERDTreeMapToggleBookmarks .": bookmarks (" . (b:NERDTreeShowBookmarks ? "on" : "off") . ")\n"
|
---|
2958 |
|
---|
2959 | "add quickhelp entries for each custom key map
|
---|
2960 | if len(s:KeyMap.All())
|
---|
2961 | let @h=@h."\"\n\" ----------------------------\n"
|
---|
2962 | let @h=@h."\" Custom mappings~\n"
|
---|
2963 | for i in s:KeyMap.All()
|
---|
2964 | let @h=@h."\" ". i.key .": ". i.quickhelpText ."\n"
|
---|
2965 | endfor
|
---|
2966 | endif
|
---|
2967 |
|
---|
2968 | let @h=@h."\"\n\" ----------------------------\n"
|
---|
2969 | let @h=@h."\" Other mappings~\n"
|
---|
2970 | let @h=@h."\" ". g:NERDTreeMapQuit .": Close the NERDTree window\n"
|
---|
2971 | let @h=@h."\" ". g:NERDTreeMapToggleZoom .": Zoom (maximize-minimize)\n"
|
---|
2972 | let @h=@h."\" the NERDTree window\n"
|
---|
2973 | let @h=@h."\" ". g:NERDTreeMapHelp .": toggle help\n"
|
---|
2974 | let @h=@h."\"\n\" ----------------------------\n"
|
---|
2975 | let @h=@h."\" Bookmark commands~\n"
|
---|
2976 | let @h=@h."\" :Bookmark <name>\n"
|
---|
2977 | let @h=@h."\" :BookmarkToRoot <name>\n"
|
---|
2978 | let @h=@h."\" :RevealBookmark <name>\n"
|
---|
2979 | let @h=@h."\" :OpenBookmark <name>\n"
|
---|
2980 | let @h=@h."\" :ClearBookmarks [<names>]\n"
|
---|
2981 | let @h=@h."\" :ClearAllBookmarks\n"
|
---|
2982 | else
|
---|
2983 | let @h="\" Press ". g:NERDTreeMapHelp ." for help\n"
|
---|
2984 | endif
|
---|
2985 |
|
---|
2986 | silent! put h
|
---|
2987 |
|
---|
2988 | let @h = old_h
|
---|
2989 | endfunction
|
---|
2990 | "FUNCTION: s:echo {{{2
|
---|
2991 | "A wrapper for :echo. Appends 'NERDTree:' on the front of all messages
|
---|
2992 | "
|
---|
2993 | "Args:
|
---|
2994 | "msg: the message to echo
|
---|
2995 | function! s:echo(msg)
|
---|
2996 | redraw
|
---|
2997 | echomsg "NERDTree: " . a:msg
|
---|
2998 | endfunction
|
---|
2999 | "FUNCTION: s:echoWarning {{{2
|
---|
3000 | "Wrapper for s:echo, sets the message type to warningmsg for this message
|
---|
3001 | "Args:
|
---|
3002 | "msg: the message to echo
|
---|
3003 | function! s:echoWarning(msg)
|
---|
3004 | echohl warningmsg
|
---|
3005 | call s:echo(a:msg)
|
---|
3006 | echohl normal
|
---|
3007 | endfunction
|
---|
3008 | "FUNCTION: s:echoError {{{2
|
---|
3009 | "Wrapper for s:echo, sets the message type to errormsg for this message
|
---|
3010 | "Args:
|
---|
3011 | "msg: the message to echo
|
---|
3012 | function! s:echoError(msg)
|
---|
3013 | echohl errormsg
|
---|
3014 | call s:echo(a:msg)
|
---|
3015 | echohl normal
|
---|
3016 | endfunction
|
---|
3017 | "FUNCTION: s:firstUsableWindow(){{{2
|
---|
3018 | "find the window number of the first normal window
|
---|
3019 | function! s:firstUsableWindow()
|
---|
3020 | let i = 1
|
---|
3021 | while i <= winnr("$")
|
---|
3022 | let bnum = winbufnr(i)
|
---|
3023 | if bnum != -1 && getbufvar(bnum, '&buftype') ==# ''
|
---|
3024 | \ && !getwinvar(i, '&previewwindow')
|
---|
3025 | \ && (!getbufvar(bnum, '&modified') || &hidden)
|
---|
3026 | return i
|
---|
3027 | endif
|
---|
3028 |
|
---|
3029 | let i += 1
|
---|
3030 | endwhile
|
---|
3031 | return -1
|
---|
3032 | endfunction
|
---|
3033 | "FUNCTION: s:getPath(ln) {{{2
|
---|
3034 | "Gets the full path to the node that is rendered on the given line number
|
---|
3035 | "
|
---|
3036 | "Args:
|
---|
3037 | "ln: the line number to get the path for
|
---|
3038 | "
|
---|
3039 | "Return:
|
---|
3040 | "A path if a node was selected, {} if nothing is selected.
|
---|
3041 | "If the 'up a dir' line was selected then the path to the parent of the
|
---|
3042 | "current root is returned
|
---|
3043 | function! s:getPath(ln)
|
---|
3044 | let line = getline(a:ln)
|
---|
3045 |
|
---|
3046 | let rootLine = s:TreeFileNode.GetRootLineNum()
|
---|
3047 |
|
---|
3048 | "check to see if we have the root node
|
---|
3049 | if a:ln == rootLine
|
---|
3050 | return b:NERDTreeRoot.path
|
---|
3051 | endif
|
---|
3052 |
|
---|
3053 | " in case called from outside the tree
|
---|
3054 | if line !~ '^ *[|`]' || line =~ '^$'
|
---|
3055 | return {}
|
---|
3056 | endif
|
---|
3057 |
|
---|
3058 | if line ==# s:tree_up_dir_line
|
---|
3059 | return b:NERDTreeRoot.path.getParent()
|
---|
3060 | endif
|
---|
3061 |
|
---|
3062 | let indent = s:indentLevelFor(line)
|
---|
3063 |
|
---|
3064 | "remove the tree parts and the leading space
|
---|
3065 | let curFile = s:stripMarkupFromLine(line, 0)
|
---|
3066 |
|
---|
3067 | let wasdir = 0
|
---|
3068 | if curFile =~ '/$'
|
---|
3069 | let wasdir = 1
|
---|
3070 | let curFile = substitute(curFile, '/\?$', '/', "")
|
---|
3071 | endif
|
---|
3072 |
|
---|
3073 | let dir = ""
|
---|
3074 | let lnum = a:ln
|
---|
3075 | while lnum > 0
|
---|
3076 | let lnum = lnum - 1
|
---|
3077 | let curLine = getline(lnum)
|
---|
3078 | let curLineStripped = s:stripMarkupFromLine(curLine, 1)
|
---|
3079 |
|
---|
3080 | "have we reached the top of the tree?
|
---|
3081 | if lnum == rootLine
|
---|
3082 | let dir = b:NERDTreeRoot.path.str({'format': 'UI'}) . dir
|
---|
3083 | break
|
---|
3084 | endif
|
---|
3085 | if curLineStripped =~ '/$'
|
---|
3086 | let lpindent = s:indentLevelFor(curLine)
|
---|
3087 | if lpindent < indent
|
---|
3088 | let indent = indent - 1
|
---|
3089 |
|
---|
3090 | let dir = substitute (curLineStripped,'^\\', "", "") . dir
|
---|
3091 | continue
|
---|
3092 | endif
|
---|
3093 | endif
|
---|
3094 | endwhile
|
---|
3095 | let curFile = b:NERDTreeRoot.path.drive . dir . curFile
|
---|
3096 | let toReturn = s:Path.New(curFile)
|
---|
3097 | return toReturn
|
---|
3098 | endfunction
|
---|
3099 |
|
---|
3100 | "FUNCTION: s:getTreeWinNum() {{{2
|
---|
3101 | "gets the nerd tree window number for this tab
|
---|
3102 | function! s:getTreeWinNum()
|
---|
3103 | if exists("t:NERDTreeBufName")
|
---|
3104 | return bufwinnr(t:NERDTreeBufName)
|
---|
3105 | else
|
---|
3106 | return -1
|
---|
3107 | endif
|
---|
3108 | endfunction
|
---|
3109 | "FUNCTION: s:indentLevelFor(line) {{{2
|
---|
3110 | function! s:indentLevelFor(line)
|
---|
3111 | return match(a:line, '[^ \-+~`|]') / s:tree_wid
|
---|
3112 | endfunction
|
---|
3113 | "FUNCTION: s:isTreeOpen() {{{2
|
---|
3114 | function! s:isTreeOpen()
|
---|
3115 | return s:getTreeWinNum() != -1
|
---|
3116 | endfunction
|
---|
3117 | "FUNCTION: s:isWindowUsable(winnumber) {{{2
|
---|
3118 | "Returns 0 if opening a file from the tree in the given window requires it to
|
---|
3119 | "be split, 1 otherwise
|
---|
3120 | "
|
---|
3121 | "Args:
|
---|
3122 | "winnumber: the number of the window in question
|
---|
3123 | function! s:isWindowUsable(winnumber)
|
---|
3124 | "gotta split if theres only one window (i.e. the NERD tree)
|
---|
3125 | if winnr("$") ==# 1
|
---|
3126 | return 0
|
---|
3127 | endif
|
---|
3128 |
|
---|
3129 | let oldwinnr = winnr()
|
---|
3130 | call s:exec(a:winnumber . "wincmd p")
|
---|
3131 | let specialWindow = getbufvar("%", '&buftype') != '' || getwinvar('%', '&previewwindow')
|
---|
3132 | let modified = &modified
|
---|
3133 | call s:exec(oldwinnr . "wincmd p")
|
---|
3134 |
|
---|
3135 | "if its a special window e.g. quickfix or another explorer plugin then we
|
---|
3136 | "have to split
|
---|
3137 | if specialWindow
|
---|
3138 | return 0
|
---|
3139 | endif
|
---|
3140 |
|
---|
3141 | if &hidden
|
---|
3142 | return 1
|
---|
3143 | endif
|
---|
3144 |
|
---|
3145 | return !modified || s:bufInWindows(winbufnr(a:winnumber)) >= 2
|
---|
3146 | endfunction
|
---|
3147 |
|
---|
3148 | " FUNCTION: s:jumpToChild(direction) {{{2
|
---|
3149 | " Args:
|
---|
3150 | " direction: 0 if going to first child, 1 if going to last
|
---|
3151 | function! s:jumpToChild(direction)
|
---|
3152 | let currentNode = s:TreeFileNode.GetSelected()
|
---|
3153 | if currentNode ==# {} || currentNode.isRoot()
|
---|
3154 | call s:echo("cannot jump to " . (a:direction ? "last" : "first") . " child")
|
---|
3155 | return
|
---|
3156 | end
|
---|
3157 | let dirNode = currentNode.parent
|
---|
3158 | let childNodes = dirNode.getVisibleChildren()
|
---|
3159 |
|
---|
3160 | let targetNode = childNodes[0]
|
---|
3161 | if a:direction
|
---|
3162 | let targetNode = childNodes[len(childNodes) - 1]
|
---|
3163 | endif
|
---|
3164 |
|
---|
3165 | if targetNode.equals(currentNode)
|
---|
3166 | let siblingDir = currentNode.parent.findOpenDirSiblingWithVisibleChildren(a:direction)
|
---|
3167 | if siblingDir != {}
|
---|
3168 | let indx = a:direction ? siblingDir.getVisibleChildCount()-1 : 0
|
---|
3169 | let targetNode = siblingDir.getChildByIndex(indx, 1)
|
---|
3170 | endif
|
---|
3171 | endif
|
---|
3172 |
|
---|
3173 | call targetNode.putCursorHere(1, 0)
|
---|
3174 |
|
---|
3175 | call s:centerView()
|
---|
3176 | endfunction
|
---|
3177 |
|
---|
3178 |
|
---|
3179 | "FUNCTION: s:promptToDelBuffer(bufnum, msg){{{2
|
---|
3180 | "prints out the given msg and, if the user responds by pushing 'y' then the
|
---|
3181 | "buffer with the given bufnum is deleted
|
---|
3182 | "
|
---|
3183 | "Args:
|
---|
3184 | "bufnum: the buffer that may be deleted
|
---|
3185 | "msg: a message that will be echoed to the user asking them if they wish to
|
---|
3186 | " del the buffer
|
---|
3187 | function! s:promptToDelBuffer(bufnum, msg)
|
---|
3188 | echo a:msg
|
---|
3189 | if nr2char(getchar()) ==# 'y'
|
---|
3190 | exec "silent bdelete! " . a:bufnum
|
---|
3191 | endif
|
---|
3192 | endfunction
|
---|
3193 |
|
---|
3194 | "FUNCTION: s:putCursorOnBookmarkTable(){{{2
|
---|
3195 | "Places the cursor at the top of the bookmarks table
|
---|
3196 | function! s:putCursorOnBookmarkTable()
|
---|
3197 | if !b:NERDTreeShowBookmarks
|
---|
3198 | throw "NERDTree.IllegalOperationError: cant find bookmark table, bookmarks arent active"
|
---|
3199 | endif
|
---|
3200 |
|
---|
3201 | let rootNodeLine = s:TreeFileNode.GetRootLineNum()
|
---|
3202 |
|
---|
3203 | let line = 1
|
---|
3204 | while getline(line) !~ '^>-\+Bookmarks-\+$'
|
---|
3205 | let line = line + 1
|
---|
3206 | if line >= rootNodeLine
|
---|
3207 | throw "NERDTree.BookmarkTableNotFoundError: didnt find the bookmarks table"
|
---|
3208 | endif
|
---|
3209 | endwhile
|
---|
3210 | call cursor(line, 0)
|
---|
3211 | endfunction
|
---|
3212 |
|
---|
3213 | "FUNCTION: s:putCursorInTreeWin(){{{2
|
---|
3214 | "Places the cursor in the nerd tree window
|
---|
3215 | function! s:putCursorInTreeWin()
|
---|
3216 | if !s:isTreeOpen()
|
---|
3217 | throw "NERDTree.InvalidOperationError: cant put cursor in NERD tree window, no window exists"
|
---|
3218 | endif
|
---|
3219 |
|
---|
3220 | call s:exec(s:getTreeWinNum() . "wincmd w")
|
---|
3221 | endfunction
|
---|
3222 |
|
---|
3223 | "FUNCTION: s:renderBookmarks {{{2
|
---|
3224 | function! s:renderBookmarks()
|
---|
3225 |
|
---|
3226 | call setline(line(".")+1, ">----------Bookmarks----------")
|
---|
3227 | call cursor(line(".")+1, col("."))
|
---|
3228 |
|
---|
3229 | for i in s:Bookmark.Bookmarks()
|
---|
3230 | call setline(line(".")+1, i.str())
|
---|
3231 | call cursor(line(".")+1, col("."))
|
---|
3232 | endfor
|
---|
3233 |
|
---|
3234 | call setline(line(".")+1, '')
|
---|
3235 | call cursor(line(".")+1, col("."))
|
---|
3236 | endfunction
|
---|
3237 | "FUNCTION: s:renderView {{{2
|
---|
3238 | "The entry function for rendering the tree
|
---|
3239 | function! s:renderView()
|
---|
3240 | setlocal modifiable
|
---|
3241 |
|
---|
3242 | "remember the top line of the buffer and the current line so we can
|
---|
3243 | "restore the view exactly how it was
|
---|
3244 | let curLine = line(".")
|
---|
3245 | let curCol = col(".")
|
---|
3246 | let topLine = line("w0")
|
---|
3247 |
|
---|
3248 | "delete all lines in the buffer (being careful not to clobber a register)
|
---|
3249 | silent 1,$delete _
|
---|
3250 |
|
---|
3251 | call s:dumpHelp()
|
---|
3252 |
|
---|
3253 | "delete the blank line before the help and add one after it
|
---|
3254 | call setline(line(".")+1, "")
|
---|
3255 | call cursor(line(".")+1, col("."))
|
---|
3256 |
|
---|
3257 | if b:NERDTreeShowBookmarks
|
---|
3258 | call s:renderBookmarks()
|
---|
3259 | endif
|
---|
3260 |
|
---|
3261 | "add the 'up a dir' line
|
---|
3262 | call setline(line(".")+1, s:tree_up_dir_line)
|
---|
3263 | call cursor(line(".")+1, col("."))
|
---|
3264 |
|
---|
3265 | "draw the header line
|
---|
3266 | let header = b:NERDTreeRoot.path.str({'format': 'UI', 'truncateTo': winwidth(0)})
|
---|
3267 | call setline(line(".")+1, header)
|
---|
3268 | call cursor(line(".")+1, col("."))
|
---|
3269 |
|
---|
3270 | "draw the tree
|
---|
3271 | let old_o = @o
|
---|
3272 | let @o = b:NERDTreeRoot.renderToString()
|
---|
3273 | silent put o
|
---|
3274 | let @o = old_o
|
---|
3275 |
|
---|
3276 | "delete the blank line at the top of the buffer
|
---|
3277 | silent 1,1delete _
|
---|
3278 |
|
---|
3279 | "restore the view
|
---|
3280 | let old_scrolloff=&scrolloff
|
---|
3281 | let &scrolloff=0
|
---|
3282 | call cursor(topLine, 1)
|
---|
3283 | normal! zt
|
---|
3284 | call cursor(curLine, curCol)
|
---|
3285 | let &scrolloff = old_scrolloff
|
---|
3286 |
|
---|
3287 | setlocal nomodifiable
|
---|
3288 | endfunction
|
---|
3289 |
|
---|
3290 | "FUNCTION: s:renderViewSavingPosition {{{2
|
---|
3291 | "Renders the tree and ensures the cursor stays on the current node or the
|
---|
3292 | "current nodes parent if it is no longer available upon re-rendering
|
---|
3293 | function! s:renderViewSavingPosition()
|
---|
3294 | let currentNode = s:TreeFileNode.GetSelected()
|
---|
3295 |
|
---|
3296 | "go up the tree till we find a node that will be visible or till we run
|
---|
3297 | "out of nodes
|
---|
3298 | while currentNode != {} && !currentNode.isVisible() && !currentNode.isRoot()
|
---|
3299 | let currentNode = currentNode.parent
|
---|
3300 | endwhile
|
---|
3301 |
|
---|
3302 | call s:renderView()
|
---|
3303 |
|
---|
3304 | if currentNode != {}
|
---|
3305 | call currentNode.putCursorHere(0, 0)
|
---|
3306 | endif
|
---|
3307 | endfunction
|
---|
3308 | "FUNCTION: s:restoreScreenState() {{{2
|
---|
3309 | "
|
---|
3310 | "Sets the screen state back to what it was when s:saveScreenState was last
|
---|
3311 | "called.
|
---|
3312 | "
|
---|
3313 | "Assumes the cursor is in the NERDTree window
|
---|
3314 | function! s:restoreScreenState()
|
---|
3315 | if !exists("b:NERDTreeOldTopLine") || !exists("b:NERDTreeOldPos") || !exists("b:NERDTreeOldWindowSize")
|
---|
3316 | return
|
---|
3317 | endif
|
---|
3318 | exec("silent vertical resize ".b:NERDTreeOldWindowSize)
|
---|
3319 |
|
---|
3320 | let old_scrolloff=&scrolloff
|
---|
3321 | let &scrolloff=0
|
---|
3322 | call cursor(b:NERDTreeOldTopLine, 0)
|
---|
3323 | normal! zt
|
---|
3324 | call setpos(".", b:NERDTreeOldPos)
|
---|
3325 | let &scrolloff=old_scrolloff
|
---|
3326 | endfunction
|
---|
3327 |
|
---|
3328 | "FUNCTION: s:saveScreenState() {{{2
|
---|
3329 | "Saves the current cursor position in the current buffer and the window
|
---|
3330 | "scroll position
|
---|
3331 | function! s:saveScreenState()
|
---|
3332 | let win = winnr()
|
---|
3333 | try
|
---|
3334 | call s:putCursorInTreeWin()
|
---|
3335 | let b:NERDTreeOldPos = getpos(".")
|
---|
3336 | let b:NERDTreeOldTopLine = line("w0")
|
---|
3337 | let b:NERDTreeOldWindowSize = winwidth("")
|
---|
3338 | call s:exec(win . "wincmd w")
|
---|
3339 | catch /^NERDTree.InvalidOperationError/
|
---|
3340 | endtry
|
---|
3341 | endfunction
|
---|
3342 |
|
---|
3343 | "FUNCTION: s:setupStatusline() {{{2
|
---|
3344 | function! s:setupStatusline()
|
---|
3345 | if g:NERDTreeStatusline != -1
|
---|
3346 | let &l:statusline = g:NERDTreeStatusline
|
---|
3347 | endif
|
---|
3348 | endfunction
|
---|
3349 | "FUNCTION: s:setupSyntaxHighlighting() {{{2
|
---|
3350 | function! s:setupSyntaxHighlighting()
|
---|
3351 | "treeFlags are syntax items that should be invisible, but give clues as to
|
---|
3352 | "how things should be highlighted
|
---|
3353 | syn match treeFlag #\~#
|
---|
3354 | syn match treeFlag #\[RO\]#
|
---|
3355 |
|
---|
3356 | "highlighting for the .. (up dir) line at the top of the tree
|
---|
3357 | execute "syn match treeUp #". s:tree_up_dir_line ."#"
|
---|
3358 |
|
---|
3359 | "highlighting for the ~/+ symbols for the directory nodes
|
---|
3360 | syn match treeClosable #\~\<#
|
---|
3361 | syn match treeClosable #\~\.#
|
---|
3362 | syn match treeOpenable #+\<#
|
---|
3363 | syn match treeOpenable #+\.#he=e-1
|
---|
3364 |
|
---|
3365 | "highlighting for the tree structural parts
|
---|
3366 | syn match treePart #|#
|
---|
3367 | syn match treePart #`#
|
---|
3368 | syn match treePartFile #[|`]-#hs=s+1 contains=treePart
|
---|
3369 |
|
---|
3370 | "quickhelp syntax elements
|
---|
3371 | syn match treeHelpKey #" \{1,2\}[^ ]*:#hs=s+2,he=e-1
|
---|
3372 | syn match treeHelpKey #" \{1,2\}[^ ]*,#hs=s+2,he=e-1
|
---|
3373 | syn match treeHelpTitle #" .*\~#hs=s+2,he=e-1 contains=treeFlag
|
---|
3374 | syn match treeToggleOn #".*(on)#hs=e-2,he=e-1 contains=treeHelpKey
|
---|
3375 | syn match treeToggleOff #".*(off)#hs=e-3,he=e-1 contains=treeHelpKey
|
---|
3376 | syn match treeHelpCommand #" :.\{-}\>#hs=s+3
|
---|
3377 | syn match treeHelp #^".*# contains=treeHelpKey,treeHelpTitle,treeFlag,treeToggleOff,treeToggleOn,treeHelpCommand
|
---|
3378 |
|
---|
3379 | "highlighting for readonly files
|
---|
3380 | syn match treeRO #.*\[RO\]#hs=s+2 contains=treeFlag,treeBookmark,treePart,treePartFile
|
---|
3381 |
|
---|
3382 | "highlighting for sym links
|
---|
3383 | syn match treeLink #[^-| `].* -> # contains=treeBookmark,treeOpenable,treeClosable,treeDirSlash
|
---|
3384 |
|
---|
3385 | "highlighing for directory nodes and file nodes
|
---|
3386 | syn match treeDirSlash #/#
|
---|
3387 | syn match treeDir #[^-| `].*/# contains=treeLink,treeDirSlash,treeOpenable,treeClosable
|
---|
3388 | syn match treeExecFile #[|`]-.*\*\($\| \)# contains=treeLink,treePart,treeRO,treePartFile,treeBookmark
|
---|
3389 | syn match treeFile #|-.*# contains=treeLink,treePart,treeRO,treePartFile,treeBookmark,treeExecFile
|
---|
3390 | syn match treeFile #`-.*# contains=treeLink,treePart,treeRO,treePartFile,treeBookmark,treeExecFile
|
---|
3391 | syn match treeCWD #^/.*$#
|
---|
3392 |
|
---|
3393 | "highlighting for bookmarks
|
---|
3394 | syn match treeBookmark # {.*}#hs=s+1
|
---|
3395 |
|
---|
3396 | "highlighting for the bookmarks table
|
---|
3397 | syn match treeBookmarksLeader #^>#
|
---|
3398 | syn match treeBookmarksHeader #^>-\+Bookmarks-\+$# contains=treeBookmarksLeader
|
---|
3399 | syn match treeBookmarkName #^>.\{-} #he=e-1 contains=treeBookmarksLeader
|
---|
3400 | syn match treeBookmark #^>.*$# contains=treeBookmarksLeader,treeBookmarkName,treeBookmarksHeader
|
---|
3401 |
|
---|
3402 | if g:NERDChristmasTree
|
---|
3403 | hi def link treePart Special
|
---|
3404 | hi def link treePartFile Type
|
---|
3405 | hi def link treeFile Normal
|
---|
3406 | hi def link treeExecFile Title
|
---|
3407 | hi def link treeDirSlash Identifier
|
---|
3408 | hi def link treeClosable Type
|
---|
3409 | else
|
---|
3410 | hi def link treePart Normal
|
---|
3411 | hi def link treePartFile Normal
|
---|
3412 | hi def link treeFile Normal
|
---|
3413 | hi def link treeClosable Title
|
---|
3414 | endif
|
---|
3415 |
|
---|
3416 | hi def link treeBookmarksHeader statement
|
---|
3417 | hi def link treeBookmarksLeader ignore
|
---|
3418 | hi def link treeBookmarkName Identifier
|
---|
3419 | hi def link treeBookmark normal
|
---|
3420 |
|
---|
3421 | hi def link treeHelp String
|
---|
3422 | hi def link treeHelpKey Identifier
|
---|
3423 | hi def link treeHelpCommand Identifier
|
---|
3424 | hi def link treeHelpTitle Macro
|
---|
3425 | hi def link treeToggleOn Question
|
---|
3426 | hi def link treeToggleOff WarningMsg
|
---|
3427 |
|
---|
3428 | hi def link treeDir Directory
|
---|
3429 | hi def link treeUp Directory
|
---|
3430 | hi def link treeCWD Statement
|
---|
3431 | hi def link treeLink Macro
|
---|
3432 | hi def link treeOpenable Title
|
---|
3433 | hi def link treeFlag ignore
|
---|
3434 | hi def link treeRO WarningMsg
|
---|
3435 | hi def link treeBookmark Statement
|
---|
3436 |
|
---|
3437 | hi def link NERDTreeCurrentNode Search
|
---|
3438 | endfunction
|
---|
3439 |
|
---|
3440 | "FUNCTION: s:stripMarkupFromLine(line, removeLeadingSpaces){{{2
|
---|
3441 | "returns the given line with all the tree parts stripped off
|
---|
3442 | "
|
---|
3443 | "Args:
|
---|
3444 | "line: the subject line
|
---|
3445 | "removeLeadingSpaces: 1 if leading spaces are to be removed (leading spaces =
|
---|
3446 | "any spaces before the actual text of the node)
|
---|
3447 | function! s:stripMarkupFromLine(line, removeLeadingSpaces)
|
---|
3448 | let line = a:line
|
---|
3449 | "remove the tree parts and the leading space
|
---|
3450 | let line = substitute (line, s:tree_markup_reg,"","")
|
---|
3451 |
|
---|
3452 | "strip off any read only flag
|
---|
3453 | let line = substitute (line, ' \[RO\]', "","")
|
---|
3454 |
|
---|
3455 | "strip off any bookmark flags
|
---|
3456 | let line = substitute (line, ' {[^}]*}', "","")
|
---|
3457 |
|
---|
3458 | "strip off any executable flags
|
---|
3459 | let line = substitute (line, '*\ze\($\| \)', "","")
|
---|
3460 |
|
---|
3461 | let wasdir = 0
|
---|
3462 | if line =~ '/$'
|
---|
3463 | let wasdir = 1
|
---|
3464 | endif
|
---|
3465 | let line = substitute (line,' -> .*',"","") " remove link to
|
---|
3466 | if wasdir ==# 1
|
---|
3467 | let line = substitute (line, '/\?$', '/', "")
|
---|
3468 | endif
|
---|
3469 |
|
---|
3470 | if a:removeLeadingSpaces
|
---|
3471 | let line = substitute (line, '^ *', '', '')
|
---|
3472 | endif
|
---|
3473 |
|
---|
3474 | return line
|
---|
3475 | endfunction
|
---|
3476 |
|
---|
3477 | "FUNCTION: s:toggle(dir) {{{2
|
---|
3478 | "Toggles the NERD tree. I.e the NERD tree is open, it is closed, if it is
|
---|
3479 | "closed it is restored or initialized (if it doesnt exist)
|
---|
3480 | "
|
---|
3481 | "Args:
|
---|
3482 | "dir: the full path for the root node (is only used if the NERD tree is being
|
---|
3483 | "initialized.
|
---|
3484 | function! s:toggle(dir)
|
---|
3485 | if s:treeExistsForTab()
|
---|
3486 | if !s:isTreeOpen()
|
---|
3487 | call s:createTreeWin()
|
---|
3488 | if !&hidden
|
---|
3489 | call s:renderView()
|
---|
3490 | endif
|
---|
3491 | call s:restoreScreenState()
|
---|
3492 | else
|
---|
3493 | call s:closeTree()
|
---|
3494 | endif
|
---|
3495 | else
|
---|
3496 | call s:initNerdTree(a:dir)
|
---|
3497 | endif
|
---|
3498 | endfunction
|
---|
3499 | "SECTION: Interface bindings {{{1
|
---|
3500 | "============================================================
|
---|
3501 | "FUNCTION: s:activateNode(forceKeepWindowOpen) {{{2
|
---|
3502 | "If the current node is a file, open it in the previous window (or a new one
|
---|
3503 | "if the previous is modified). If it is a directory then it is opened.
|
---|
3504 | "
|
---|
3505 | "args:
|
---|
3506 | "forceKeepWindowOpen - dont close the window even if NERDTreeQuitOnOpen is set
|
---|
3507 | function! s:activateNode(forceKeepWindowOpen)
|
---|
3508 | if getline(".") ==# s:tree_up_dir_line
|
---|
3509 | return s:upDir(0)
|
---|
3510 | endif
|
---|
3511 |
|
---|
3512 | let treenode = s:TreeFileNode.GetSelected()
|
---|
3513 | if treenode != {}
|
---|
3514 | call treenode.activate(a:forceKeepWindowOpen)
|
---|
3515 | else
|
---|
3516 | let bookmark = s:Bookmark.GetSelected()
|
---|
3517 | if !empty(bookmark)
|
---|
3518 | call bookmark.activate()
|
---|
3519 | endif
|
---|
3520 | endif
|
---|
3521 | endfunction
|
---|
3522 |
|
---|
3523 | "FUNCTION: s:bindMappings() {{{2
|
---|
3524 | function! s:bindMappings()
|
---|
3525 | " set up mappings and commands for this buffer
|
---|
3526 | nnoremap <silent> <buffer> <middlerelease> :call <SID>handleMiddleMouse()<cr>
|
---|
3527 | nnoremap <silent> <buffer> <leftrelease> <leftrelease>:call <SID>checkForActivate()<cr>
|
---|
3528 | nnoremap <silent> <buffer> <2-leftmouse> :call <SID>activateNode(0)<cr>
|
---|
3529 |
|
---|
3530 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapActivateNode . " :call <SID>activateNode(0)<cr>"
|
---|
3531 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenSplit ." :call <SID>openEntrySplit(0,0)<cr>"
|
---|
3532 | exec "nnoremap <silent> <buffer> <cr> :call <SID>activateNode(0)<cr>"
|
---|
3533 |
|
---|
3534 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapPreview ." :call <SID>previewNode(0)<cr>"
|
---|
3535 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapPreviewSplit ." :call <SID>previewNode(1)<cr>"
|
---|
3536 |
|
---|
3537 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenVSplit ." :call <SID>openEntrySplit(1,0)<cr>"
|
---|
3538 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapPreviewVSplit ." :call <SID>previewNode(2)<cr>"
|
---|
3539 |
|
---|
3540 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenRecursively ." :call <SID>openNodeRecursively()<cr>"
|
---|
3541 |
|
---|
3542 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapUpdirKeepOpen ." :call <SID>upDir(1)<cr>"
|
---|
3543 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapUpdir ." :call <SID>upDir(0)<cr>"
|
---|
3544 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapChangeRoot ." :call <SID>chRoot()<cr>"
|
---|
3545 |
|
---|
3546 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapChdir ." :call <SID>chCwd()<cr>"
|
---|
3547 |
|
---|
3548 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapQuit ." :call <SID>closeTreeWindow()<cr>"
|
---|
3549 |
|
---|
3550 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapRefreshRoot ." :call <SID>refreshRoot()<cr>"
|
---|
3551 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapRefresh ." :call <SID>refreshCurrent()<cr>"
|
---|
3552 |
|
---|
3553 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapHelp ." :call <SID>displayHelp()<cr>"
|
---|
3554 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleZoom ." :call <SID>toggleZoom()<cr>"
|
---|
3555 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleHidden ." :call <SID>toggleShowHidden()<cr>"
|
---|
3556 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleFilters ." :call <SID>toggleIgnoreFilter()<cr>"
|
---|
3557 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleFiles ." :call <SID>toggleShowFiles()<cr>"
|
---|
3558 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleBookmarks ." :call <SID>toggleShowBookmarks()<cr>"
|
---|
3559 |
|
---|
3560 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapCloseDir ." :call <SID>closeCurrentDir()<cr>"
|
---|
3561 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapCloseChildren ." :call <SID>closeChildren()<cr>"
|
---|
3562 |
|
---|
3563 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapMenu ." :call <SID>showMenu()<cr>"
|
---|
3564 |
|
---|
3565 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpParent ." :call <SID>jumpToParent()<cr>"
|
---|
3566 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpNextSibling ." :call <SID>jumpToSibling(1)<cr>"
|
---|
3567 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpPrevSibling ." :call <SID>jumpToSibling(0)<cr>"
|
---|
3568 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpFirstChild ." :call <SID>jumpToFirstChild()<cr>"
|
---|
3569 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpLastChild ." :call <SID>jumpToLastChild()<cr>"
|
---|
3570 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpRoot ." :call <SID>jumpToRoot()<cr>"
|
---|
3571 |
|
---|
3572 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenInTab ." :call <SID>openInNewTab(0)<cr>"
|
---|
3573 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenInTabSilent ." :call <SID>openInNewTab(1)<cr>"
|
---|
3574 |
|
---|
3575 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenExpl ." :call <SID>openExplorer()<cr>"
|
---|
3576 |
|
---|
3577 | exec "nnoremap <silent> <buffer> ". g:NERDTreeMapDeleteBookmark ." :call <SID>deleteBookmark()<cr>"
|
---|
3578 |
|
---|
3579 | "bind all the user custom maps
|
---|
3580 | call s:KeyMap.BindAll()
|
---|
3581 |
|
---|
3582 | command! -buffer -nargs=1 Bookmark :call <SID>bookmarkNode('<args>')
|
---|
3583 | command! -buffer -complete=customlist,s:completeBookmarks -nargs=1 RevealBookmark :call <SID>revealBookmark('<args>')
|
---|
3584 | command! -buffer -complete=customlist,s:completeBookmarks -nargs=1 OpenBookmark :call <SID>openBookmark('<args>')
|
---|
3585 | command! -buffer -complete=customlist,s:completeBookmarks -nargs=* ClearBookmarks call <SID>clearBookmarks('<args>')
|
---|
3586 | command! -buffer -complete=customlist,s:completeBookmarks -nargs=+ BookmarkToRoot call s:Bookmark.ToRoot('<args>')
|
---|
3587 | command! -buffer -nargs=0 ClearAllBookmarks call s:Bookmark.ClearAll() <bar> call <SID>renderView()
|
---|
3588 | command! -buffer -nargs=0 ReadBookmarks call s:Bookmark.CacheBookmarks(0) <bar> call <SID>renderView()
|
---|
3589 | command! -buffer -nargs=0 WriteBookmarks call s:Bookmark.Write()
|
---|
3590 | endfunction
|
---|
3591 |
|
---|
3592 | " FUNCTION: s:bookmarkNode(name) {{{2
|
---|
3593 | " Associate the current node with the given name
|
---|
3594 | function! s:bookmarkNode(name)
|
---|
3595 | let currentNode = s:TreeFileNode.GetSelected()
|
---|
3596 | if currentNode != {}
|
---|
3597 | try
|
---|
3598 | call currentNode.bookmark(a:name)
|
---|
3599 | call s:renderView()
|
---|
3600 | catch /^NERDTree.IllegalBookmarkNameError/
|
---|
3601 | call s:echo("bookmark names must not contain spaces")
|
---|
3602 | endtry
|
---|
3603 | else
|
---|
3604 | call s:echo("select a node first")
|
---|
3605 | endif
|
---|
3606 | endfunction
|
---|
3607 | "FUNCTION: s:checkForActivate() {{{2
|
---|
3608 | "Checks if the click should open the current node, if so then activate() is
|
---|
3609 | "called (directories are automatically opened if the symbol beside them is
|
---|
3610 | "clicked)
|
---|
3611 | function! s:checkForActivate()
|
---|
3612 | let currentNode = s:TreeFileNode.GetSelected()
|
---|
3613 | if currentNode != {}
|
---|
3614 | let startToCur = strpart(getline(line(".")), 0, col("."))
|
---|
3615 | let char = strpart(startToCur, strlen(startToCur)-1, 1)
|
---|
3616 |
|
---|
3617 | "if they clicked a dir, check if they clicked on the + or ~ sign
|
---|
3618 | "beside it
|
---|
3619 | if currentNode.path.isDirectory
|
---|
3620 | if startToCur =~ s:tree_markup_reg . '$' && char =~ '[+~]'
|
---|
3621 | call s:activateNode(0)
|
---|
3622 | return
|
---|
3623 | endif
|
---|
3624 | endif
|
---|
3625 |
|
---|
3626 | if (g:NERDTreeMouseMode ==# 2 && currentNode.path.isDirectory) || g:NERDTreeMouseMode ==# 3
|
---|
3627 | if char !~ s:tree_markup_reg && startToCur !~ '\/$'
|
---|
3628 | call s:activateNode(0)
|
---|
3629 | return
|
---|
3630 | endif
|
---|
3631 | endif
|
---|
3632 | endif
|
---|
3633 | endfunction
|
---|
3634 |
|
---|
3635 | " FUNCTION: s:chCwd() {{{2
|
---|
3636 | function! s:chCwd()
|
---|
3637 | let treenode = s:TreeFileNode.GetSelected()
|
---|
3638 | if treenode ==# {}
|
---|
3639 | call s:echo("Select a node first")
|
---|
3640 | return
|
---|
3641 | endif
|
---|
3642 |
|
---|
3643 | try
|
---|
3644 | call treenode.path.changeToDir()
|
---|
3645 | catch /^NERDTree.PathChangeError/
|
---|
3646 | call s:echoWarning("could not change cwd")
|
---|
3647 | endtry
|
---|
3648 | endfunction
|
---|
3649 |
|
---|
3650 | " FUNCTION: s:chRoot() {{{2
|
---|
3651 | " changes the current root to the selected one
|
---|
3652 | function! s:chRoot()
|
---|
3653 | let treenode = s:TreeFileNode.GetSelected()
|
---|
3654 | if treenode ==# {}
|
---|
3655 | call s:echo("Select a node first")
|
---|
3656 | return
|
---|
3657 | endif
|
---|
3658 |
|
---|
3659 | call treenode.makeRoot()
|
---|
3660 | call s:renderView()
|
---|
3661 | call b:NERDTreeRoot.putCursorHere(0, 0)
|
---|
3662 | endfunction
|
---|
3663 |
|
---|
3664 | " FUNCTION: s:clearBookmarks(bookmarks) {{{2
|
---|
3665 | function! s:clearBookmarks(bookmarks)
|
---|
3666 | if a:bookmarks ==# ''
|
---|
3667 | let currentNode = s:TreeFileNode.GetSelected()
|
---|
3668 | if currentNode != {}
|
---|
3669 | call currentNode.clearBoomarks()
|
---|
3670 | endif
|
---|
3671 | else
|
---|
3672 | for name in split(a:bookmarks, ' ')
|
---|
3673 | let bookmark = s:Bookmark.BookmarkFor(name)
|
---|
3674 | call bookmark.delete()
|
---|
3675 | endfor
|
---|
3676 | endif
|
---|
3677 | call s:renderView()
|
---|
3678 | endfunction
|
---|
3679 | " FUNCTION: s:closeChildren() {{{2
|
---|
3680 | " closes all childnodes of the current node
|
---|
3681 | function! s:closeChildren()
|
---|
3682 | let currentNode = s:TreeDirNode.GetSelected()
|
---|
3683 | if currentNode ==# {}
|
---|
3684 | call s:echo("Select a node first")
|
---|
3685 | return
|
---|
3686 | endif
|
---|
3687 |
|
---|
3688 | call currentNode.closeChildren()
|
---|
3689 | call s:renderView()
|
---|
3690 | call currentNode.putCursorHere(0, 0)
|
---|
3691 | endfunction
|
---|
3692 | " FUNCTION: s:closeCurrentDir() {{{2
|
---|
3693 | " closes the parent dir of the current node
|
---|
3694 | function! s:closeCurrentDir()
|
---|
3695 | let treenode = s:TreeFileNode.GetSelected()
|
---|
3696 | if treenode ==# {}
|
---|
3697 | call s:echo("Select a node first")
|
---|
3698 | return
|
---|
3699 | endif
|
---|
3700 |
|
---|
3701 | let parent = treenode.parent
|
---|
3702 | if parent ==# {} || parent.isRoot()
|
---|
3703 | call s:echo("cannot close tree root")
|
---|
3704 | else
|
---|
3705 | call treenode.parent.close()
|
---|
3706 | call s:renderView()
|
---|
3707 | call treenode.parent.putCursorHere(0, 0)
|
---|
3708 | endif
|
---|
3709 | endfunction
|
---|
3710 | " FUNCTION: s:closeTreeWindow() {{{2
|
---|
3711 | " close the tree window
|
---|
3712 | function! s:closeTreeWindow()
|
---|
3713 | if b:NERDTreeType ==# "secondary" && b:NERDTreePreviousBuf != -1
|
---|
3714 | exec "buffer " . b:NERDTreePreviousBuf
|
---|
3715 | else
|
---|
3716 | if winnr("$") > 1
|
---|
3717 | call s:closeTree()
|
---|
3718 | else
|
---|
3719 | call s:echo("Cannot close last window")
|
---|
3720 | endif
|
---|
3721 | endif
|
---|
3722 | endfunction
|
---|
3723 | " FUNCTION: s:deleteBookmark() {{{2
|
---|
3724 | " if the cursor is on a bookmark, prompt to delete
|
---|
3725 | function! s:deleteBookmark()
|
---|
3726 | let bookmark = s:Bookmark.GetSelected()
|
---|
3727 | if bookmark ==# {}
|
---|
3728 | call s:echo("Put the cursor on a bookmark")
|
---|
3729 | return
|
---|
3730 | endif
|
---|
3731 |
|
---|
3732 | echo "Are you sure you wish to delete the bookmark:\n\"" . bookmark.name . "\" (yN):"
|
---|
3733 |
|
---|
3734 | if nr2char(getchar()) ==# 'y'
|
---|
3735 | try
|
---|
3736 | call bookmark.delete()
|
---|
3737 | call s:renderView()
|
---|
3738 | redraw
|
---|
3739 | catch /^NERDTree/
|
---|
3740 | call s:echoWarning("Could not remove bookmark")
|
---|
3741 | endtry
|
---|
3742 | else
|
---|
3743 | call s:echo("delete aborted" )
|
---|
3744 | endif
|
---|
3745 |
|
---|
3746 | endfunction
|
---|
3747 |
|
---|
3748 | " FUNCTION: s:displayHelp() {{{2
|
---|
3749 | " toggles the help display
|
---|
3750 | function! s:displayHelp()
|
---|
3751 | let b:treeShowHelp = b:treeShowHelp ? 0 : 1
|
---|
3752 | call s:renderView()
|
---|
3753 | call s:centerView()
|
---|
3754 | endfunction
|
---|
3755 |
|
---|
3756 | " FUNCTION: s:handleMiddleMouse() {{{2
|
---|
3757 | function! s:handleMiddleMouse()
|
---|
3758 | let curNode = s:TreeFileNode.GetSelected()
|
---|
3759 | if curNode ==# {}
|
---|
3760 | call s:echo("Put the cursor on a node first" )
|
---|
3761 | return
|
---|
3762 | endif
|
---|
3763 |
|
---|
3764 | if curNode.path.isDirectory
|
---|
3765 | call s:openExplorer()
|
---|
3766 | else
|
---|
3767 | call s:openEntrySplit(0,0)
|
---|
3768 | endif
|
---|
3769 | endfunction
|
---|
3770 |
|
---|
3771 |
|
---|
3772 | " FUNCTION: s:jumpToFirstChild() {{{2
|
---|
3773 | " wrapper for the jump to child method
|
---|
3774 | function! s:jumpToFirstChild()
|
---|
3775 | call s:jumpToChild(0)
|
---|
3776 | endfunction
|
---|
3777 |
|
---|
3778 | " FUNCTION: s:jumpToLastChild() {{{2
|
---|
3779 | " wrapper for the jump to child method
|
---|
3780 | function! s:jumpToLastChild()
|
---|
3781 | call s:jumpToChild(1)
|
---|
3782 | endfunction
|
---|
3783 |
|
---|
3784 | " FUNCTION: s:jumpToParent() {{{2
|
---|
3785 | " moves the cursor to the parent of the current node
|
---|
3786 | function! s:jumpToParent()
|
---|
3787 | let currentNode = s:TreeFileNode.GetSelected()
|
---|
3788 | if !empty(currentNode)
|
---|
3789 | if !empty(currentNode.parent)
|
---|
3790 | call currentNode.parent.putCursorHere(1, 0)
|
---|
3791 | call s:centerView()
|
---|
3792 | else
|
---|
3793 | call s:echo("cannot jump to parent")
|
---|
3794 | endif
|
---|
3795 | else
|
---|
3796 | call s:echo("put the cursor on a node first")
|
---|
3797 | endif
|
---|
3798 | endfunction
|
---|
3799 |
|
---|
3800 | " FUNCTION: s:jumpToRoot() {{{2
|
---|
3801 | " moves the cursor to the root node
|
---|
3802 | function! s:jumpToRoot()
|
---|
3803 | call b:NERDTreeRoot.putCursorHere(1, 0)
|
---|
3804 | call s:centerView()
|
---|
3805 | endfunction
|
---|
3806 |
|
---|
3807 | " FUNCTION: s:jumpToSibling() {{{2
|
---|
3808 | " moves the cursor to the sibling of the current node in the given direction
|
---|
3809 | "
|
---|
3810 | " Args:
|
---|
3811 | " forward: 1 if the cursor should move to the next sibling, 0 if it should
|
---|
3812 | " move back to the previous sibling
|
---|
3813 | function! s:jumpToSibling(forward)
|
---|
3814 | let currentNode = s:TreeFileNode.GetSelected()
|
---|
3815 | if !empty(currentNode)
|
---|
3816 | let sibling = currentNode.findSibling(a:forward)
|
---|
3817 |
|
---|
3818 | if !empty(sibling)
|
---|
3819 | call sibling.putCursorHere(1, 0)
|
---|
3820 | call s:centerView()
|
---|
3821 | endif
|
---|
3822 | else
|
---|
3823 | call s:echo("put the cursor on a node first")
|
---|
3824 | endif
|
---|
3825 | endfunction
|
---|
3826 |
|
---|
3827 | " FUNCTION: s:openBookmark(name) {{{2
|
---|
3828 | " put the cursor on the given bookmark and, if its a file, open it
|
---|
3829 | function! s:openBookmark(name)
|
---|
3830 | try
|
---|
3831 | let targetNode = s:Bookmark.GetNodeForName(a:name, 0)
|
---|
3832 | call targetNode.putCursorHere(0, 1)
|
---|
3833 | redraw!
|
---|
3834 | catch /^NERDTree.BookmarkedNodeNotFoundError/
|
---|
3835 | call s:echo("note - target node is not cached")
|
---|
3836 | let bookmark = s:Bookmark.BookmarkFor(a:name)
|
---|
3837 | let targetNode = s:TreeFileNode.New(bookmark.path)
|
---|
3838 | endtry
|
---|
3839 | if targetNode.path.isDirectory
|
---|
3840 | call targetNode.openExplorer()
|
---|
3841 | else
|
---|
3842 | call targetNode.open()
|
---|
3843 | endif
|
---|
3844 | endfunction
|
---|
3845 | " FUNCTION: s:openEntrySplit(vertical, forceKeepWindowOpen) {{{2
|
---|
3846 | "Opens the currently selected file from the explorer in a
|
---|
3847 | "new window
|
---|
3848 | "
|
---|
3849 | "args:
|
---|
3850 | "forceKeepWindowOpen - dont close the window even if NERDTreeQuitOnOpen is set
|
---|
3851 | function! s:openEntrySplit(vertical, forceKeepWindowOpen)
|
---|
3852 | let treenode = s:TreeFileNode.GetSelected()
|
---|
3853 | if treenode != {}
|
---|
3854 | if a:vertical
|
---|
3855 | call treenode.openVSplit()
|
---|
3856 | else
|
---|
3857 | call treenode.openSplit()
|
---|
3858 | endif
|
---|
3859 | if !a:forceKeepWindowOpen
|
---|
3860 | call s:closeTreeIfQuitOnOpen()
|
---|
3861 | endif
|
---|
3862 | else
|
---|
3863 | call s:echo("select a node first")
|
---|
3864 | endif
|
---|
3865 | endfunction
|
---|
3866 |
|
---|
3867 | " FUNCTION: s:openExplorer() {{{2
|
---|
3868 | function! s:openExplorer()
|
---|
3869 | let treenode = s:TreeDirNode.GetSelected()
|
---|
3870 | if treenode != {}
|
---|
3871 | call treenode.openExplorer()
|
---|
3872 | else
|
---|
3873 | call s:echo("select a node first")
|
---|
3874 | endif
|
---|
3875 | endfunction
|
---|
3876 |
|
---|
3877 | " FUNCTION: s:openInNewTab(stayCurrentTab) {{{2
|
---|
3878 | " Opens the selected node or bookmark in a new tab
|
---|
3879 | " Args:
|
---|
3880 | " stayCurrentTab: if 1 then vim will stay in the current tab, if 0 then vim
|
---|
3881 | " will go to the tab where the new file is opened
|
---|
3882 | function! s:openInNewTab(stayCurrentTab)
|
---|
3883 | let target = s:TreeFileNode.GetSelected()
|
---|
3884 | if target == {}
|
---|
3885 | let target = s:Bookmark.GetSelected()
|
---|
3886 | endif
|
---|
3887 |
|
---|
3888 | if target != {}
|
---|
3889 | call target.openInNewTab({'stayInCurrentTab': a:stayCurrentTab})
|
---|
3890 | endif
|
---|
3891 | endfunction
|
---|
3892 |
|
---|
3893 | " FUNCTION: s:openNodeRecursively() {{{2
|
---|
3894 | function! s:openNodeRecursively()
|
---|
3895 | let treenode = s:TreeFileNode.GetSelected()
|
---|
3896 | if treenode ==# {} || treenode.path.isDirectory ==# 0
|
---|
3897 | call s:echo("Select a directory node first" )
|
---|
3898 | else
|
---|
3899 | call s:echo("Recursively opening node. Please wait...")
|
---|
3900 | call treenode.openRecursively()
|
---|
3901 | call s:renderView()
|
---|
3902 | redraw
|
---|
3903 | call s:echo("Recursively opening node. Please wait... DONE")
|
---|
3904 | endif
|
---|
3905 |
|
---|
3906 | endfunction
|
---|
3907 |
|
---|
3908 | "FUNCTION: s:previewNode() {{{2
|
---|
3909 | "Args:
|
---|
3910 | " openNewWin: if 0, use the previous window, if 1 open in new split, if 2
|
---|
3911 | " open in a vsplit
|
---|
3912 | function! s:previewNode(openNewWin)
|
---|
3913 | let currentBuf = bufnr("")
|
---|
3914 | if a:openNewWin > 0
|
---|
3915 | call s:openEntrySplit(a:openNewWin ==# 2,1)
|
---|
3916 | else
|
---|
3917 | call s:activateNode(1)
|
---|
3918 | end
|
---|
3919 | call s:exec(bufwinnr(currentBuf) . "wincmd w")
|
---|
3920 | endfunction
|
---|
3921 |
|
---|
3922 | " FUNCTION: s:revealBookmark(name) {{{2
|
---|
3923 | " put the cursor on the node associate with the given name
|
---|
3924 | function! s:revealBookmark(name)
|
---|
3925 | try
|
---|
3926 | let targetNode = s:Bookmark.GetNodeForName(a:name, 0)
|
---|
3927 | call targetNode.putCursorHere(0, 1)
|
---|
3928 | catch /^NERDTree.BookmarkNotFoundError/
|
---|
3929 | call s:echo("Bookmark isnt cached under the current root")
|
---|
3930 | endtry
|
---|
3931 | endfunction
|
---|
3932 | " FUNCTION: s:refreshRoot() {{{2
|
---|
3933 | " Reloads the current root. All nodes below this will be lost and the root dir
|
---|
3934 | " will be reloaded.
|
---|
3935 | function! s:refreshRoot()
|
---|
3936 | call s:echo("Refreshing the root node. This could take a while...")
|
---|
3937 | call b:NERDTreeRoot.refresh()
|
---|
3938 | call s:renderView()
|
---|
3939 | redraw
|
---|
3940 | call s:echo("Refreshing the root node. This could take a while... DONE")
|
---|
3941 | endfunction
|
---|
3942 |
|
---|
3943 | " FUNCTION: s:refreshCurrent() {{{2
|
---|
3944 | " refreshes the root for the current node
|
---|
3945 | function! s:refreshCurrent()
|
---|
3946 | let treenode = s:TreeDirNode.GetSelected()
|
---|
3947 | if treenode ==# {}
|
---|
3948 | call s:echo("Refresh failed. Select a node first")
|
---|
3949 | return
|
---|
3950 | endif
|
---|
3951 |
|
---|
3952 | call s:echo("Refreshing node. This could take a while...")
|
---|
3953 | call treenode.refresh()
|
---|
3954 | call s:renderView()
|
---|
3955 | redraw
|
---|
3956 | call s:echo("Refreshing node. This could take a while... DONE")
|
---|
3957 | endfunction
|
---|
3958 | " FUNCTION: s:showMenu() {{{2
|
---|
3959 | function! s:showMenu()
|
---|
3960 | let curNode = s:TreeFileNode.GetSelected()
|
---|
3961 | if curNode ==# {}
|
---|
3962 | call s:echo("Put the cursor on a node first" )
|
---|
3963 | return
|
---|
3964 | endif
|
---|
3965 |
|
---|
3966 | let mc = s:MenuController.New(s:MenuItem.AllEnabled())
|
---|
3967 | call mc.showMenu()
|
---|
3968 | endfunction
|
---|
3969 |
|
---|
3970 | " FUNCTION: s:toggleIgnoreFilter() {{{2
|
---|
3971 | " toggles the use of the NERDTreeIgnore option
|
---|
3972 | function! s:toggleIgnoreFilter()
|
---|
3973 | let b:NERDTreeIgnoreEnabled = !b:NERDTreeIgnoreEnabled
|
---|
3974 | call s:renderViewSavingPosition()
|
---|
3975 | call s:centerView()
|
---|
3976 | endfunction
|
---|
3977 |
|
---|
3978 | " FUNCTION: s:toggleShowBookmarks() {{{2
|
---|
3979 | " toggles the display of bookmarks
|
---|
3980 | function! s:toggleShowBookmarks()
|
---|
3981 | let b:NERDTreeShowBookmarks = !b:NERDTreeShowBookmarks
|
---|
3982 | if b:NERDTreeShowBookmarks
|
---|
3983 | call s:renderView()
|
---|
3984 | call s:putCursorOnBookmarkTable()
|
---|
3985 | else
|
---|
3986 | call s:renderViewSavingPosition()
|
---|
3987 | endif
|
---|
3988 | call s:centerView()
|
---|
3989 | endfunction
|
---|
3990 | " FUNCTION: s:toggleShowFiles() {{{2
|
---|
3991 | " toggles the display of hidden files
|
---|
3992 | function! s:toggleShowFiles()
|
---|
3993 | let b:NERDTreeShowFiles = !b:NERDTreeShowFiles
|
---|
3994 | call s:renderViewSavingPosition()
|
---|
3995 | call s:centerView()
|
---|
3996 | endfunction
|
---|
3997 |
|
---|
3998 | " FUNCTION: s:toggleShowHidden() {{{2
|
---|
3999 | " toggles the display of hidden files
|
---|
4000 | function! s:toggleShowHidden()
|
---|
4001 | let b:NERDTreeShowHidden = !b:NERDTreeShowHidden
|
---|
4002 | call s:renderViewSavingPosition()
|
---|
4003 | call s:centerView()
|
---|
4004 | endfunction
|
---|
4005 |
|
---|
4006 | " FUNCTION: s:toggleZoom() {{2
|
---|
4007 | " zoom (maximize/minimize) the NERDTree window
|
---|
4008 | function! s:toggleZoom()
|
---|
4009 | if exists("b:NERDTreeZoomed") && b:NERDTreeZoomed
|
---|
4010 | let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize
|
---|
4011 | exec "silent vertical resize ". size
|
---|
4012 | let b:NERDTreeZoomed = 0
|
---|
4013 | else
|
---|
4014 | exec "vertical resize"
|
---|
4015 | let b:NERDTreeZoomed = 1
|
---|
4016 | endif
|
---|
4017 | endfunction
|
---|
4018 |
|
---|
4019 | "FUNCTION: s:upDir(keepState) {{{2
|
---|
4020 | "moves the tree up a level
|
---|
4021 | "
|
---|
4022 | "Args:
|
---|
4023 | "keepState: 1 if the current root should be left open when the tree is
|
---|
4024 | "re-rendered
|
---|
4025 | function! s:upDir(keepState)
|
---|
4026 | let cwd = b:NERDTreeRoot.path.str({'format': 'UI'})
|
---|
4027 | if cwd ==# "/" || cwd =~ '^[^/]..$'
|
---|
4028 | call s:echo("already at top dir")
|
---|
4029 | else
|
---|
4030 | if !a:keepState
|
---|
4031 | call b:NERDTreeRoot.close()
|
---|
4032 | endif
|
---|
4033 |
|
---|
4034 | let oldRoot = b:NERDTreeRoot
|
---|
4035 |
|
---|
4036 | if empty(b:NERDTreeRoot.parent)
|
---|
4037 | let path = b:NERDTreeRoot.path.getParent()
|
---|
4038 | let newRoot = s:TreeDirNode.New(path)
|
---|
4039 | call newRoot.open()
|
---|
4040 | call newRoot.transplantChild(b:NERDTreeRoot)
|
---|
4041 | let b:NERDTreeRoot = newRoot
|
---|
4042 | else
|
---|
4043 | let b:NERDTreeRoot = b:NERDTreeRoot.parent
|
---|
4044 | endif
|
---|
4045 |
|
---|
4046 | if g:NERDTreeChDirMode ==# 2
|
---|
4047 | call b:NERDTreeRoot.path.changeToDir()
|
---|
4048 | endif
|
---|
4049 |
|
---|
4050 | call s:renderView()
|
---|
4051 | call oldRoot.putCursorHere(0, 0)
|
---|
4052 | endif
|
---|
4053 | endfunction
|
---|
4054 |
|
---|
4055 |
|
---|
4056 | "reset &cpo back to users setting
|
---|
4057 | let &cpo = s:old_cpo
|
---|
4058 |
|
---|
4059 | " vim: set sw=4 sts=4 et fdm=marker:
|
---|