vim-nerdtree 0.0.1

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