A tree explorer plugin for vim.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3255 lines
100 KiB

16 years ago
16 years ago
  1. " ============================================================================
  2. " File: NERD_tree.vim
  3. " Description: vim global plugin that provides a nice tree explorer
  4. " Maintainer: Martin Grenfell <martin_grenfell at msn dot com>
  5. " Last Change: 17 June, 2008
  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 = '2.10.0'
  14. " SECTION: Script init stuff {{{1
  15. "============================================================
  16. if exists("loaded_nerd_tree")
  17. finish
  18. endif
  19. if v:version < 700
  20. echoerr "NERDTree: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!"
  21. finish
  22. endif
  23. let loaded_nerd_tree = 1
  24. "Function: s:InitVariable() function {{{2
  25. "This function is used to initialise a given variable to a given value. The
  26. "variable is only initialised if it does not exist prior
  27. "
  28. "Args:
  29. "var: the name of the var to be initialised
  30. "value: the value to initialise var to
  31. "
  32. "Returns:
  33. "1 if the var is set, 0 otherwise
  34. function! s:InitVariable(var, value)
  35. if !exists(a:var)
  36. exec 'let ' . a:var . ' = ' . "'" . a:value . "'"
  37. return 1
  38. endif
  39. return 0
  40. endfunction
  41. "SECTION: Init variable calls and other random constants {{{2
  42. call s:InitVariable("g:NERDChristmasTree", 1)
  43. call s:InitVariable("g:NERDTreeAutoCenter", 1)
  44. call s:InitVariable("g:NERDTreeAutoCenterThreshold", 3)
  45. call s:InitVariable("g:NERDTreeCaseSensitiveSort", 0)
  46. call s:InitVariable("g:NERDTreeChDirMode", 1)
  47. if !exists("g:NERDTreeIgnore")
  48. let g:NERDTreeIgnore = ['\~$']
  49. endif
  50. call s:InitVariable("g:NERDTreeHighlightCursorline", 1)
  51. call s:InitVariable("g:NERDTreeBookmarksFile", expand('$HOME') . '/.NERDTreeBookmarks')
  52. call s:InitVariable("g:NERDTreeMouseMode", 1)
  53. call s:InitVariable("g:NERDTreeNotificationThreshold", 100)
  54. call s:InitVariable("g:NERDTreeShowFiles", 1)
  55. call s:InitVariable("g:NERDTreeShowHidden", 0)
  56. call s:InitVariable("g:NERDTreeShowLineNumbers", 0)
  57. call s:InitVariable("g:NERDTreeSortDirs", 1)
  58. if !exists("g:NERDTreeSortOrder")
  59. let g:NERDTreeSortOrder = ['\/$', '*', '\.swp$', '\.bak$', '\~$']
  60. else
  61. "if there isnt a * in the sort sequence then add one
  62. if count(g:NERDTreeSortOrder, '*') < 1
  63. call add(g:NERDTreeSortOrder, '*')
  64. endif
  65. endif
  66. "we need to use this number many times for sorting... so we calculate it only
  67. "once here
  68. let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*')
  69. call s:InitVariable("g:NERDTreeSplitVertical", 1)
  70. call s:InitVariable("g:NERDTreeWinPos", 1)
  71. call s:InitVariable("g:NERDTreeWinSize", 31)
  72. let s:running_windows = has("win16") || has("win32") || has("win64")
  73. "init the shell commands that will be used to copy nodes, and remove dir trees
  74. "
  75. "Note: the space after the command is important
  76. if s:running_windows
  77. call s:InitVariable("g:NERDTreeRemoveDirCmd", 'rmdir /s /q ')
  78. else
  79. call s:InitVariable("g:NERDTreeRemoveDirCmd", 'rm -rf ')
  80. call s:InitVariable("g:NERDTreeCopyCmd", 'cp -r ')
  81. endif
  82. "SECTION: Init variable calls for key mappings {{{2
  83. call s:InitVariable("g:NERDTreeMapActivateNode", "o")
  84. call s:InitVariable("g:NERDTreeMapChangeRoot", "C")
  85. call s:InitVariable("g:NERDTreeMapChdir", "cd")
  86. call s:InitVariable("g:NERDTreeMapCloseChildren", "X")
  87. call s:InitVariable("g:NERDTreeMapCloseDir", "x")
  88. call s:InitVariable("g:NERDTreeMapExecute", "!")
  89. call s:InitVariable("g:NERDTreeMapFilesystemMenu", "m")
  90. call s:InitVariable("g:NERDTreeMapHelp", "?")
  91. call s:InitVariable("g:NERDTreeMapJumpFirstChild", "K")
  92. call s:InitVariable("g:NERDTreeMapJumpLastChild", "J")
  93. call s:InitVariable("g:NERDTreeMapJumpNextSibling", "<C-j>")
  94. call s:InitVariable("g:NERDTreeMapJumpParent", "p")
  95. call s:InitVariable("g:NERDTreeMapJumpPrevSibling", "<C-k>")
  96. call s:InitVariable("g:NERDTreeMapJumpRoot", "P")
  97. call s:InitVariable("g:NERDTreeMapOpenExpl", "e")
  98. call s:InitVariable("g:NERDTreeMapOpenInTab", "t")
  99. call s:InitVariable("g:NERDTreeMapOpenInTabSilent", "T")
  100. call s:InitVariable("g:NERDTreeMapOpenRecursively", "O")
  101. call s:InitVariable("g:NERDTreeMapOpenSplit", "<tab>")
  102. call s:InitVariable("g:NERDTreeMapPreview", "g" . NERDTreeMapActivateNode)
  103. call s:InitVariable("g:NERDTreeMapPreviewSplit", "g" . NERDTreeMapOpenSplit)
  104. call s:InitVariable("g:NERDTreeMapQuit", "q")
  105. call s:InitVariable("g:NERDTreeMapRefresh", "r")
  106. call s:InitVariable("g:NERDTreeMapRefreshRoot", "R")
  107. call s:InitVariable("g:NERDTreeMapToggleFiles", "F")
  108. call s:InitVariable("g:NERDTreeMapToggleFilters", "f")
  109. call s:InitVariable("g:NERDTreeMapToggleHidden", "H")
  110. call s:InitVariable("g:NERDTreeMapUpdir", "u")
  111. call s:InitVariable("g:NERDTreeMapUpdirKeepOpen", "U")
  112. "SECTION: Script level variable declaration{{{2
  113. let s:escape_chars = " \\`\|\"#%&,?()\*^<>"
  114. let s:NERDTreeWinName = '_NERD_tree_'
  115. "init all the nerd tree markup
  116. let s:tree_vert = '|'
  117. let s:tree_vert_last = '`'
  118. let s:tree_wid = 2
  119. let s:tree_wid_str = ' '
  120. let s:tree_wid_strM1 = ' '
  121. let s:tree_dir_open = '~'
  122. let s:tree_dir_closed = '+'
  123. let s:tree_file = '-'
  124. let s:tree_markup_reg = '[ \-+~`|]'
  125. let s:tree_markup_reg_neg = '[^ \-+~`|]'
  126. let s:tree_up_dir_line = '.. (up a dir)'
  127. let s:tree_RO_str = ' [RO]'
  128. let s:tree_RO_str_reg = ' \[RO\]'
  129. let s:os_slash = '/'
  130. if s:running_windows
  131. let s:os_slash = '\'
  132. endif
  133. " SECTION: Commands {{{1
  134. "============================================================
  135. "init the command that users start the nerd tree with
  136. command! -n=? -complete=dir NERDTree :call s:InitNerdTree('<args>')
  137. command! -n=? -complete=dir NERDTreeToggle :call s:Toggle('<args>')
  138. command! -n=0 NERDTreeClose :call s:CloseTreeIfOpen()
  139. command! -n=1 -complete=customlist,s:FindBookmarks NERDTreeFromBookmark call s:InitNerdTree('<args>')
  140. " SECTION: Auto commands {{{1
  141. "============================================================
  142. "Save the cursor position whenever we close the nerd tree
  143. exec "autocmd BufWinLeave *". s:NERDTreeWinName ."* :call <SID>SaveScreenState()"
  144. "cache bookmarks when vim loads
  145. autocmd VimEnter * call <SID>ReadBookmarks()
  146. "SECTION: Classes {{{1
  147. "============================================================
  148. "CLASS: oTreeFileNode {{{2
  149. "This class is the parent of the oTreeDirNode class and constitures the
  150. "'Component' part of the composite design pattern between the treenode
  151. "classes.
  152. "============================================================
  153. let s:oTreeFileNode = {}
  154. "FUNCTION: oTreeFileNode.CacheParent {{{3
  155. "initializes self.parent if it isnt already
  156. function! s:oTreeFileNode.CacheParent() dict
  157. if empty(self.parent)
  158. let parentPath = self.path.GetParent()
  159. if parentPath.Equals(self.path)
  160. throw "NERDTree.CannotCacheParent exception: already at root"
  161. endif
  162. let self.parent = s:oTreeFileNode.New(parentPath)
  163. endif
  164. endfunction
  165. "FUNCTION: oTreeFileNode.CompareNodes {{{3
  166. "This is supposed to be a class level method but i cant figure out how to
  167. "get func refs to work from a dict..
  168. "
  169. "A class level method that compares two nodes
  170. "
  171. "Args:
  172. "n1, n2: the 2 nodes to compare
  173. function! s:CompareNodes(n1, n2)
  174. return a:n1.path.CompareTo(a:n2.path)
  175. endfunction
  176. "FUNCTION: oTreeFileNode.ClearBookmarks() {{{3
  177. function! s:oTreeFileNode.ClearBookmarks() dict
  178. let bookmarks = s:GetBookmarks()
  179. for i in keys(bookmarks)
  180. if bookmarks[i].Equals(self.path)
  181. call remove(bookmarks, i)
  182. end
  183. endfor
  184. call self.path.CacheBookmarkNames()
  185. endfunction
  186. "FUNCTION: oTreeFileNode.Copy(dest) {{{3
  187. function! s:oTreeFileNode.Copy(dest) dict
  188. call self.path.Copy(a:dest)
  189. let newPath = s:oPath.New(a:dest)
  190. let parent = t:NERDTreeRoot.FindNode(newPath.GetParent())
  191. if !empty(parent)
  192. call parent.Refresh()
  193. endif
  194. return parent.FindNode(newPath)
  195. endfunction
  196. "FUNCTION: oTreeFileNode.Delete {{{3
  197. "Removes this node from the tree and calls the Delete method for its path obj
  198. function! s:oTreeFileNode.Delete() dict
  199. call self.path.Delete()
  200. call self.parent.RemoveChild(self)
  201. endfunction
  202. "FUNCTION: oTreeFileNode.Equals(treenode) {{{3
  203. "
  204. "Compares this treenode to the input treenode and returns 1 if they are the
  205. "same node.
  206. "
  207. "Use this method instead of == because sometimes when the treenodes contain
  208. "many children, vim seg faults when doing ==
  209. "
  210. "Args:
  211. "treenode: the other treenode to compare to
  212. function! s:oTreeFileNode.Equals(treenode) dict
  213. return self.path.Str(1) == a:treenode.path.Str(1)
  214. endfunction
  215. "FUNCTION: oTreeFileNode.FindNode(path) {{{3
  216. "Returns self if this node.path.Equals the given path.
  217. "Returns {} if not equal.
  218. "
  219. "Args:
  220. "path: the path object to compare against
  221. function! s:oTreeFileNode.FindNode(path) dict
  222. if a:path.Equals(self.path)
  223. return self
  224. endif
  225. return {}
  226. endfunction
  227. "FUNCTION: oTreeFileNode.FindOpenDirSiblingWithChildren(direction) {{{3
  228. "
  229. "Finds the next sibling for this node in the indicated direction. This sibling
  230. "must be a directory and may/may not have children as specified.
  231. "
  232. "Args:
  233. "direction: 0 if you want to find the previous sibling, 1 for the next sibling
  234. "
  235. "Return:
  236. "a treenode object or {} if no appropriate sibling could be found
  237. function! s:oTreeFileNode.FindOpenDirSiblingWithChildren(direction) dict
  238. "if we have no parent then we can have no siblings
  239. if self.parent != {}
  240. let nextSibling = self.FindSibling(a:direction)
  241. while nextSibling != {}
  242. if nextSibling.path.isDirectory && nextSibling.HasVisibleChildren() && nextSibling.isOpen
  243. return nextSibling
  244. endif
  245. let nextSibling = nextSibling.FindSibling(a:direction)
  246. endwhile
  247. endif
  248. return {}
  249. endfunction
  250. "FUNCTION: oTreeFileNode.FindSibling(direction) {{{3
  251. "
  252. "Finds the next sibling for this node in the indicated direction
  253. "
  254. "Args:
  255. "direction: 0 if you want to find the previous sibling, 1 for the next sibling
  256. "
  257. "Return:
  258. "a treenode object or {} if no sibling could be found
  259. function! s:oTreeFileNode.FindSibling(direction) dict
  260. "if we have no parent then we can have no siblings
  261. if self.parent != {}
  262. "get the index of this node in its parents children
  263. let siblingIndx = self.parent.GetChildIndex(self.path)
  264. if siblingIndx != -1
  265. "move a long to the next potential sibling node
  266. let siblingIndx = a:direction == 1 ? siblingIndx+1 : siblingIndx-1
  267. "keep moving along to the next sibling till we find one that is valid
  268. let numSiblings = self.parent.GetChildCount()
  269. while siblingIndx >= 0 && siblingIndx < numSiblings
  270. "if the next node is not an ignored node (i.e. wont show up in the
  271. "view) then return it
  272. if self.parent.children[siblingIndx].path.Ignore() == 0
  273. return self.parent.children[siblingIndx]
  274. endif
  275. "go to next node
  276. let siblingIndx = a:direction == 1 ? siblingIndx+1 : siblingIndx-1
  277. endwhile
  278. endif
  279. endif
  280. return {}
  281. endfunction
  282. "FUNCTION: oTreeFileNode.IsVisible() {{{3
  283. "returns 1 if this node should be visible according to the tree filters and
  284. "hidden file filters (and their on/off status)
  285. function! s:oTreeFileNode.IsVisible() dict
  286. return !self.path.Ignore()
  287. endfunction
  288. "FUNCTION: oTreeFileNode.IsRoot() {{{3
  289. "returns 1 if this node is t:NERDTreeRoot
  290. function! s:oTreeFileNode.IsRoot() dict
  291. if !s:TreeExistsForTab()
  292. throw "NERDTree.TreeFileNode.IsRoot exception: No tree exists for the current tab"
  293. endif
  294. return self.Equals(t:NERDTreeRoot)
  295. endfunction
  296. "FUNCTION: oTreeFileNode.MakeRoot() {{{3
  297. "Make this node the root of the tree
  298. function! s:oTreeFileNode.MakeRoot() dict
  299. if self.path.isDirectory
  300. let t:NERDTreeRoot = self
  301. else
  302. call self.CacheParent()
  303. let t:NERDTreeRoot = self.parent
  304. endif
  305. call t:NERDTreeRoot.Open()
  306. "change dir to the dir of the new root if instructed to
  307. if g:NERDTreeChDirMode == 2
  308. exec "cd " . t:NERDTreeRoot.path.StrForEditCmd()
  309. endif
  310. endfunction
  311. "FUNCTION: oTreeFileNode.New(path) {{{3
  312. "Returns a new TreeNode object with the given path and parent
  313. "
  314. "Args:
  315. "path: a path object representing the full filesystem path to the file/dir that the node represents
  316. function! s:oTreeFileNode.New(path) dict
  317. if a:path.isDirectory
  318. return s:oTreeDirNode.New(a:path)
  319. else
  320. let newTreeNode = {}
  321. let newTreeNode = copy(self)
  322. let newTreeNode.path = a:path
  323. let newTreeNode.parent = {}
  324. return newTreeNode
  325. endif
  326. endfunction
  327. "FUNCTION: oTreeFileNode.Refresh {{{3
  328. function! s:oTreeFileNode.Refresh() dict
  329. call self.path.Refresh()
  330. endfunction
  331. "FUNCTION: oTreeFileNode.Rename {{{3
  332. "Calls the rename method for this nodes path obj
  333. function! s:oTreeFileNode.Rename(newName) dict
  334. let newName = substitute(a:newName, '\(\\\|\/\)$', '', '')
  335. call self.path.Rename(newName)
  336. call self.parent.RemoveChild(self)
  337. let parentPath = self.path.GetPathTrunk()
  338. let newParent = t:NERDTreeRoot.FindNode(parentPath)
  339. if newParent != {}
  340. call newParent.CreateChild(self.path, 1)
  341. endif
  342. endfunction
  343. "FUNCTION: oTreeFileNode.StrDisplay() {{{3
  344. "
  345. "Returns a string that specifies how the node should be represented as a
  346. "string
  347. "
  348. "Return:
  349. "a string that can be used in the view to represent this node
  350. function! s:oTreeFileNode.StrDisplay() dict
  351. return self.path.StrDisplay()
  352. endfunction
  353. "CLASS: oTreeDirNode {{{2
  354. "This class is a child of the oTreeFileNode class and constitutes the
  355. "'Composite' part of the composite design pattern between the treenode
  356. "classes.
  357. "============================================================
  358. let s:oTreeDirNode = copy(s:oTreeFileNode)
  359. "FUNCTION: oTreeDirNode.AddChild(treenode, inOrder) {{{3
  360. "Adds the given treenode to the list of children for this node
  361. "
  362. "Args:
  363. "-treenode: the node to add
  364. "-inOrder: 1 if the new node should be inserted in sorted order
  365. function! s:oTreeDirNode.AddChild(treenode, inOrder) dict
  366. call add(self.children, a:treenode)
  367. let a:treenode.parent = self
  368. if a:inOrder
  369. call self.SortChildren()
  370. endif
  371. endfunction
  372. "FUNCTION: oTreeDirNode.Close {{{3
  373. "Closes this directory
  374. function! s:oTreeDirNode.Close() dict
  375. let self.isOpen = 0
  376. endfunction
  377. "FUNCTION: oTreeDirNode.CloseChildren {{{3
  378. "Closes all the child dir nodes of this node
  379. function! s:oTreeDirNode.CloseChildren() dict
  380. for i in self.children
  381. if i.path.isDirectory
  382. call i.Close()
  383. call i.CloseChildren()
  384. endif
  385. endfor
  386. endfunction
  387. "FUNCTION: oTreeDirNode.CreateChild(path, inOrder) {{{3
  388. "Instantiates a new child node for this node with the given path. The new
  389. "nodes parent is set to this node.
  390. "
  391. "Args:
  392. "path: a Path object that this node will represent/contain
  393. "inOrder: 1 if the new node should be inserted in sorted order
  394. "
  395. "Returns:
  396. "the newly created node
  397. function! s:oTreeDirNode.CreateChild(path, inOrder) dict
  398. let newTreeNode = s:oTreeFileNode.New(a:path)
  399. call self.AddChild(newTreeNode, a:inOrder)
  400. return newTreeNode
  401. endfunction
  402. "FUNCTION: oTreeDirNode.FindNode(path) {{{3
  403. "Will find one of the children (recursively) that has the given path
  404. "
  405. "Args:
  406. "path: a path object
  407. unlet s:oTreeDirNode.FindNode
  408. function! s:oTreeDirNode.FindNode(path) dict
  409. if a:path.Equals(self.path)
  410. return self
  411. endif
  412. if stridx(a:path.Str(1), self.path.Str(1), 0) == -1
  413. return {}
  414. endif
  415. if self.path.isDirectory
  416. for i in self.children
  417. let retVal = i.FindNode(a:path)
  418. if retVal != {}
  419. return retVal
  420. endif
  421. endfor
  422. endif
  423. return {}
  424. endfunction
  425. "FUNCTION: oTreeDirNode.GetChildDirs() {{{3
  426. "Returns the number of children this node has
  427. function! s:oTreeDirNode.GetChildCount() dict
  428. return len(self.children)
  429. endfunction
  430. "FUNCTION: oTreeDirNode.GetChildDirs() {{{3
  431. "Returns an array of all children of this node that are directories
  432. "
  433. "Return:
  434. "an array of directory treenodes
  435. function! s:oTreeDirNode.GetChildDirs() dict
  436. let toReturn = []
  437. for i in self.children
  438. if i.path.isDirectory
  439. call add(toReturn, i)
  440. endif
  441. endfor
  442. return toReturn
  443. endfunction
  444. "FUNCTION: oTreeDirNode.GetChildFiles() {{{3
  445. "Returns an array of all children of this node that are files
  446. "
  447. "Return:
  448. "an array of file treenodes
  449. function! s:oTreeDirNode.GetChildFiles() dict
  450. let toReturn = []
  451. for i in self.children
  452. if i.path.isDirectory == 0
  453. call add(toReturn, i)
  454. endif
  455. endfor
  456. return toReturn
  457. endfunction
  458. "FUNCTION: oTreeDirNode.GetChild(path) {{{3
  459. "Returns child node of this node that has the given path or {} if no such node
  460. "exists.
  461. "
  462. "This function doesnt not recurse into child dir nodes
  463. "
  464. "Args:
  465. "path: a path object
  466. function! s:oTreeDirNode.GetChild(path) dict
  467. if stridx(a:path.Str(1), self.path.Str(1), 0) == -1
  468. return {}
  469. endif
  470. let index = self.GetChildIndex(a:path)
  471. if index == -1
  472. return {}
  473. else
  474. return self.children[index]
  475. endif
  476. endfunction
  477. "FUNCTION: oTreeDirNode.GetChildByIndex(indx, visible) {{{3
  478. "returns the child at the given index
  479. "Args:
  480. "indx: the index to get the child from
  481. "visible: 1 if only the visible children array should be used, 0 if all the
  482. "children should be searched.
  483. function! s:oTreeDirNode.GetChildByIndex(indx, visible) dict
  484. let array_to_search = a:visible? self.GetVisibleChildren() : self.children
  485. if a:indx > len(array_to_search)
  486. throw "NERDTree.TreeDirNode.InvalidArguments exception. Index is out of bounds."
  487. endif
  488. return array_to_search[a:indx]
  489. endfunction
  490. "FUNCTION: oTreeDirNode.GetChildIndex(path) {{{3
  491. "Returns the index of the child node of this node that has the given path or
  492. "-1 if no such node exists.
  493. "
  494. "This function doesnt not recurse into child dir nodes
  495. "
  496. "Args:
  497. "path: a path object
  498. function! s:oTreeDirNode.GetChildIndex(path) dict
  499. if stridx(a:path.Str(1), self.path.Str(1), 0) == -1
  500. return -1
  501. endif
  502. "do a binary search for the child
  503. let a = 0
  504. let z = self.GetChildCount()
  505. while a < z
  506. let mid = (a+z)/2
  507. let diff = a:path.CompareTo(self.children[mid].path)
  508. if diff == -1
  509. let z = mid
  510. elseif diff == 1
  511. let a = mid+1
  512. else
  513. return mid
  514. endif
  515. endwhile
  516. return -1
  517. endfunction
  518. "FUNCTION: oTreeDirNode.GetVisibleChildCount() {{{3
  519. "Returns the number of visible children this node has
  520. function! s:oTreeDirNode.GetVisibleChildCount() dict
  521. return len(self.GetVisibleChildren())
  522. endfunction
  523. "FUNCTION: oTreeDirNode.GetVisibleChildren() {{{3
  524. "Returns a list of children to display for this node, in the correct order
  525. "
  526. "Return:
  527. "an array of treenodes
  528. function! s:oTreeDirNode.GetVisibleChildren() dict
  529. let toReturn = []
  530. for i in self.children
  531. if i.path.Ignore() == 0
  532. call add(toReturn, i)
  533. endif
  534. endfor
  535. return toReturn
  536. endfunction
  537. "FUNCTION: oTreeDirNode.HasVisibleChildren {{{3
  538. "returns 1 if this node has any childre, 0 otherwise..
  539. function! s:oTreeDirNode.HasVisibleChildren()
  540. return self.GetChildCount() != 0
  541. endfunction
  542. "FUNCTION: oTreeDirNode.InitChildren {{{3
  543. "Removes all childen from this node and re-reads them
  544. "
  545. "Args:
  546. "silent: 1 if the function should not echo any "please wait" messages for
  547. "large directories
  548. "
  549. "Return: the number of child nodes read
  550. function! s:oTreeDirNode.InitChildren(silent) dict
  551. "remove all the current child nodes
  552. let self.children = []
  553. "get an array of all the files in the nodes dir
  554. let dir = self.path
  555. let filesStr = globpath(dir.StrForGlob(), '*') . "\n" . globpath(dir.StrForGlob(), '.*')
  556. let files = split(filesStr, "\n")
  557. if !a:silent && len(files) > g:NERDTreeNotificationThreshold
  558. call s:Echo("Please wait, caching a large dir ...")
  559. endif
  560. let invalidFilesFound = 0
  561. for i in files
  562. "filter out the .. and . directories
  563. "Note: we must match .. AND ../ cos sometimes the globpath returns
  564. "../ for path with strange chars (eg $)
  565. if i !~ '\.\.\/\?$' && i !~ '\.\/\?$'
  566. "put the next file in a new node and attach it
  567. try
  568. let path = s:oPath.New(i)
  569. call self.CreateChild(path, 0)
  570. catch /^NERDTree.Path.InvalidArguments/
  571. let invalidFilesFound = 1
  572. endtry
  573. endif
  574. endfor
  575. call self.SortChildren()
  576. if !a:silent && len(files) > g:NERDTreeNotificationThreshold
  577. call s:Echo("Please wait, caching a large dir ... DONE (". self.GetChildCount() ." nodes cached).")
  578. endif
  579. if invalidFilesFound
  580. call s:EchoWarning("some files could not be loaded into the NERD tree")
  581. endif
  582. return self.GetChildCount()
  583. endfunction
  584. "FUNCTION: oTreeDirNode.New(path) {{{3
  585. "Returns a new TreeNode object with the given path and parent
  586. "
  587. "Args:
  588. "path: a path object representing the full filesystem path to the file/dir that the node represents
  589. unlet s:oTreeDirNode.New
  590. function! s:oTreeDirNode.New(path) dict
  591. if a:path.isDirectory != 1
  592. throw "NERDTree.TreeDirNode.InvalidArguments exception. A TreeDirNode object must be instantiated with a directory Path object."
  593. endif
  594. let newTreeNode = copy(self)
  595. let newTreeNode.path = a:path
  596. let newTreeNode.isOpen = 0
  597. let newTreeNode.children = []
  598. let newTreeNode.parent = {}
  599. return newTreeNode
  600. endfunction
  601. "FUNCTION: oTreeDirNode.Open {{{3
  602. "Reads in all this nodes children
  603. "
  604. "Return: the number of child nodes read
  605. function! s:oTreeDirNode.Open() dict
  606. let self.isOpen = 1
  607. if self.children == []
  608. return self.InitChildren(0)
  609. else
  610. return 0
  611. endif
  612. endfunction
  613. "FUNCTION: oTreeDirNode.OpenRecursively {{{3
  614. "Opens this treenode and all of its children whose paths arent 'ignored'
  615. "because of the file filters.
  616. "
  617. "This method is actually a wrapper for the OpenRecursively2 method which does
  618. "the work.
  619. function! s:oTreeDirNode.OpenRecursively() dict
  620. call self.OpenRecursively2(1)
  621. endfunction
  622. "FUNCTION: oTreeDirNode.OpenRecursively2 {{{3
  623. "Dont call this method from outside this object.
  624. "
  625. "Opens this all children of this treenode recursively if either:
  626. " *they arent filtered by file filters
  627. " *a:forceOpen is 1
  628. "
  629. "Args:
  630. "forceOpen: 1 if this node should be opened regardless of file filters
  631. function! s:oTreeDirNode.OpenRecursively2(forceOpen) dict
  632. if self.path.Ignore() == 0 || a:forceOpen
  633. let self.isOpen = 1
  634. if self.children == []
  635. call self.InitChildren(1)
  636. endif
  637. for i in self.children
  638. if i.path.isDirectory == 1
  639. call i.OpenRecursively2(0)
  640. endif
  641. endfor
  642. endif
  643. endfunction
  644. "FUNCTION: oTreeDirNode.Refresh {{{3
  645. unlet s:oTreeDirNode.Refresh
  646. function! s:oTreeDirNode.Refresh() dict
  647. call self.path.Refresh()
  648. "if this node was ever opened, refresh its children
  649. if self.isOpen || !empty(self.children)
  650. "go thru all the files/dirs under this node
  651. let newChildNodes = []
  652. let invalidFilesFound = 0
  653. let dir = self.path
  654. let filesStr = globpath(dir.StrForGlob(), '*') . "\n" . globpath(dir.StrForGlob(), '.*')
  655. let files = split(filesStr, "\n")
  656. for i in files
  657. if i !~ '\.\.$' && i !~ '\.$'
  658. try
  659. "create a new path and see if it exists in this nodes children
  660. let path = s:oPath.New(i)
  661. let newNode = self.GetChild(path)
  662. if newNode != {}
  663. call newNode.Refresh()
  664. call add(newChildNodes, newNode)
  665. "the node doesnt exist so create it
  666. else
  667. let newNode = s:oTreeFileNode.New(path)
  668. let newNode.parent = self
  669. call add(newChildNodes, newNode)
  670. endif
  671. catch /^NERDTree.InvalidArguments/
  672. let invalidFilesFound = 1
  673. endtry
  674. endif
  675. endfor
  676. "swap this nodes children out for the children we just read/refreshed
  677. let self.children = newChildNodes
  678. call self.SortChildren()
  679. if invalidFilesFound
  680. call s:EchoWarning("some files could not be loaded into the NERD tree")
  681. endif
  682. endif
  683. endfunction
  684. "FUNCTION: oTreeDirNode.RemoveChild {{{3
  685. "
  686. "Removes the given treenode from this nodes set of children
  687. "
  688. "Args:
  689. "treenode: the node to remove
  690. "
  691. "Throws a NERDTree.TreeDirNode exception if the given treenode is not found
  692. function! s:oTreeDirNode.RemoveChild(treenode) dict
  693. for i in range(0, self.GetChildCount()-1)
  694. if self.children[i].Equals(a:treenode)
  695. call remove(self.children, i)
  696. return
  697. endif
  698. endfor
  699. throw "NERDTree.TreeDirNode exception: child node was not found"
  700. endfunction
  701. "FUNCTION: oTreeDirNode.SortChildren {{{3
  702. "
  703. "Sorts the children of this node according to alphabetical order and the
  704. "directory priority.
  705. "
  706. function! s:oTreeDirNode.SortChildren() dict
  707. let CompareFunc = function("s:CompareNodes")
  708. call sort(self.children, CompareFunc)
  709. endfunction
  710. "FUNCTION: oTreeDirNode.ToggleOpen {{{3
  711. "Opens this directory if it is closed and vice versa
  712. function! s:oTreeDirNode.ToggleOpen() dict
  713. if self.isOpen == 1
  714. call self.Close()
  715. else
  716. call self.Open()
  717. endif
  718. endfunction
  719. "FUNCTION: oTreeDirNode.TransplantChild(newNode) {{{3
  720. "Replaces the child of this with the given node (where the child node's full
  721. "path matches a:newNode's fullpath). The search for the matching node is
  722. "non-recursive
  723. "
  724. "Arg:
  725. "newNode: the node to graft into the tree
  726. function! s:oTreeDirNode.TransplantChild(newNode) dict
  727. for i in range(0, self.GetChildCount()-1)
  728. if self.children[i].Equals(a:newNode)
  729. let self.children[i] = a:newNode
  730. let a:newNode.parent = self
  731. break
  732. endif
  733. endfor
  734. endfunction
  735. "============================================================
  736. "CLASS: oPath {{{2
  737. "============================================================
  738. let s:oPath = {}
  739. let oPath = s:oPath
  740. "FUNCTION: oPath.BookmarkNames() {{{3
  741. function! s:oPath.BookmarkNames() dict
  742. if !exists("self.bookmarkNames")
  743. call self.CacheBookmarkNames()
  744. endif
  745. return self.bookmarkNames
  746. endfunction
  747. "FUNCTION: oPath.CacheBookmarkNames() {{{3
  748. function! s:oPath.CacheBookmarkNames() dict
  749. let self.bookmarkNames = []
  750. let bookmarks = s:GetBookmarks()
  751. for k in keys(bookmarks)
  752. if bookmarks[k].Equals(self)
  753. call add(self.bookmarkNames, k)
  754. endif
  755. endfor
  756. return self.bookmarkNames
  757. endfunction
  758. "FUNCTION: oPath.ChangeToDir() {{{3
  759. function! s:oPath.ChangeToDir() dict
  760. let dir = self.StrForCd()
  761. if self.isDirectory == 0
  762. let dir = self.GetPathTrunk().StrForCd()
  763. endif
  764. try
  765. execute "cd " . dir
  766. call s:Echo("CWD is now: " . getcwd())
  767. catch
  768. throw "NERDTree.Path.Change exception: cannot change to " . dir
  769. endtry
  770. endfunction
  771. "FUNCTION: oPath.ChopTrailingSlash(str) {{{3
  772. function! s:oPath.ChopTrailingSlash(str) dict
  773. if a:str =~ '\/$'
  774. return substitute(a:str, "\/$", "", "")
  775. else
  776. return substitute(a:str, "\\$", "", "")
  777. endif
  778. endfunction
  779. "FUNCTION: oPath.CompareTo() {{{3
  780. "
  781. "Compares this oPath to the given path and returns 0 if they are equal, -1 if
  782. "this oPath is "less than" the given path, or 1 if it is "greater".
  783. "
  784. "Args:
  785. "path: the path object to compare this to
  786. "
  787. "Return:
  788. "1, -1 or 0
  789. function! s:oPath.CompareTo(path) dict
  790. let thisPath = self.GetLastPathComponent(1)
  791. let thatPath = a:path.GetLastPathComponent(1)
  792. "if the paths are the same then clearly we return 0
  793. if thisPath == thatPath
  794. return 0
  795. endif
  796. let thisSS = self.GetSortOrderIndex()
  797. let thatSS = a:path.GetSortOrderIndex()
  798. "compare the sort sequences, if they are different then the return
  799. "value is easy
  800. if thisSS < thatSS
  801. return -1
  802. elseif thisSS > thatSS
  803. return 1
  804. else
  805. "if the sort sequences are the same then compare the paths
  806. "alphabetically
  807. let pathCompare = g:NERDTreeCaseSensitiveSort ? thisPath <# thatPath : thisPath <? thatPath
  808. if pathCompare
  809. return -1
  810. else
  811. return 1
  812. endif
  813. endif
  814. endfunction
  815. "FUNCTION: oPath.Create(fullpath) {{{3
  816. "
  817. "Factory method.
  818. "
  819. "Creates a path object with the given path. The path is also created on the
  820. "filesystem. If the path already exists, a NERDTree.Path.Exists exception is
  821. "thrown. If any other errors occur, a NERDTree.Path exception is thrown.
  822. "
  823. "Args:
  824. "fullpath: the full filesystem path to the file/dir to create
  825. function! s:oPath.Create(fullpath) dict
  826. "bail if the a:fullpath already exists
  827. if isdirectory(a:fullpath) || filereadable(a:fullpath)
  828. throw "NERDTree.Path.Exists Exception: Directory Exists: '" . a:fullpath . "'"
  829. endif
  830. try
  831. "if it ends with a slash, assume its a dir create it
  832. if a:fullpath =~ '\(\\\|\/\)$'
  833. "whack the trailing slash off the end if it exists
  834. let fullpath = substitute(a:fullpath, '\(\\\|\/\)$', '', '')
  835. call mkdir(fullpath, 'p')
  836. "assume its a file and create
  837. else
  838. call writefile([], a:fullpath)
  839. endif
  840. catch /.*/
  841. throw "NERDTree.Path Exception: Could not create path: '" . a:fullpath . "'"
  842. endtry
  843. return s:oPath.New(a:fullpath)
  844. endfunction
  845. "FUNCTION: oPath.Copy(dest) {{{3
  846. "
  847. "Copies the file/dir represented by this Path to the given location
  848. "
  849. "Args:
  850. "dest: the location to copy this dir/file to
  851. function! s:oPath.Copy(dest) dict
  852. if !s:oPath.CopyingSupported()
  853. throw "NERDTree.Path.CopyingNotSupported Exception: Copying is not supported on this OS"
  854. endif
  855. let dest = s:oPath.WinToUnixPath(a:dest)
  856. let cmd = g:NERDTreeCopyCmd . " " . self.StrForOS(0) . " " . dest
  857. let success = system(cmd)
  858. if success != 0
  859. throw "NERDTree.Path Exception: Could not copy ''". self.StrForOS(0) ."'' to: '" . a:dest . "'"
  860. endif
  861. endfunction
  862. "FUNCTION: oPath.CopyingSupported() {{{3
  863. "
  864. "returns 1 if copying is supported for this OS
  865. function! s:oPath.CopyingSupported() dict
  866. return exists('g:NERDTreeCopyCmd')
  867. endfunction
  868. "FUNCTION: oPath.CopyingWillOverwrite(dest) {{{3
  869. "
  870. "returns 1 if copy this path to the given location will cause files to
  871. "overwritten
  872. "
  873. "Args:
  874. "dest: the location this path will be copied to
  875. function! s:oPath.CopyingWillOverwrite(dest) dict
  876. if filereadable(a:dest)
  877. return 1
  878. endif
  879. if isdirectory(a:dest)
  880. let path = s:oPath.JoinPathStrings(a:dest, self.GetLastPathComponent(0))
  881. if filereadable(path)
  882. return 1
  883. endif
  884. endif
  885. endfunction
  886. "FUNCTION: oPath.Delete() {{{3
  887. "
  888. "Deletes the file represented by this path.
  889. "Deletion of directories is not supported
  890. "
  891. "Throws NERDTree.Path.Deletion exceptions
  892. function! s:oPath.Delete() dict
  893. if self.isDirectory
  894. let cmd = ""
  895. if s:running_windows
  896. "if we are runnnig windows then put quotes around the pathstring
  897. let cmd = g:NERDTreeRemoveDirCmd . self.StrForOS(1)
  898. else
  899. let cmd = g:NERDTreeRemoveDirCmd . self.StrForOS(1)
  900. endif
  901. let success = system(cmd)
  902. if v:shell_error != 0
  903. throw "NERDTree.Path.Deletion Exception: Could not delete directory: '" . self.StrForOS(0) . "'"
  904. endif
  905. else
  906. let success = delete(self.StrForOS(!s:running_windows))
  907. if success != 0
  908. throw "NERDTree.Path.Deletion Exception: Could not delete file: '" . self.Str(0) . "'"
  909. endif
  910. endif
  911. endfunction
  912. "FUNCTION: oPath.ExtractDriveLetter(fullpath) {{{3
  913. "
  914. "If running windows, cache the drive letter for this path
  915. function! s:oPath.ExtractDriveLetter(fullpath) dict
  916. if s:running_windows
  917. let self.drive = substitute(a:fullpath, '\(^[a-zA-Z]:\).*', '\1', '')
  918. else
  919. let self.drive = ''
  920. endif
  921. endfunction
  922. "FUNCTION: oPath.GetDir() {{{3
  923. "
  924. "Returns this path if it is a directory, else this paths parent.
  925. "
  926. "Return:
  927. "a Path object
  928. function! s:oPath.GetDir() dict
  929. if self.isDirectory
  930. return self
  931. else
  932. return self.GetParent()
  933. endif
  934. endfunction
  935. "FUNCTION: oPath.GetParent() {{{3
  936. "
  937. "Returns a new path object for this paths parent
  938. "
  939. "Return:
  940. "a new Path object
  941. function! s:oPath.GetParent() dict
  942. let path = '/'. join(self.pathSegments[0:-2], '/')
  943. return s:oPath.New(path)
  944. endfunction
  945. "FUNCTION: oPath.GetLastPathComponent(dirSlash) {{{3
  946. "
  947. "Gets the last part of this path.
  948. "
  949. "Args:
  950. "dirSlash: if 1 then a trailing slash will be added to the returned value for
  951. "directory nodes.
  952. function! s:oPath.GetLastPathComponent(dirSlash) dict
  953. if empty(self.pathSegments)
  954. return ''
  955. endif
  956. let toReturn = self.pathSegments[-1]
  957. if a:dirSlash && self.isDirectory
  958. let toReturn = toReturn . '/'
  959. endif
  960. return toReturn
  961. endfunction
  962. "FUNCTION: oPath.GetPathTrunk() {{{3
  963. "Gets the path without the last segment on the end.
  964. function! s:oPath.GetPathTrunk() dict
  965. return s:oPath.New(self.StrTrunk())
  966. endfunction
  967. "FUNCTION: oPath.GetSortOrderIndex() {{{3
  968. "returns the index of the pattern in g:NERDTreeSortOrder that this path matches
  969. function! s:oPath.GetSortOrderIndex() dict
  970. let i = 0
  971. while i < len(g:NERDTreeSortOrder)
  972. if self.GetLastPathComponent(1) =~ g:NERDTreeSortOrder[i]
  973. return i
  974. endif
  975. let i = i + 1
  976. endwhile
  977. return s:NERDTreeSortStarIndex
  978. endfunction
  979. "FUNCTION: oPath.Ignore() {{{3
  980. "returns true if this path should be ignored
  981. function! s:oPath.Ignore() dict
  982. let lastPathComponent = self.GetLastPathComponent(0)
  983. "filter out the user specified paths to ignore
  984. if t:NERDTreeIgnoreEnabled
  985. for i in g:NERDTreeIgnore
  986. if lastPathComponent =~ i
  987. return 1
  988. endif
  989. endfor
  990. endif
  991. "dont show hidden files unless instructed to
  992. if g:NERDTreeShowHidden == 0 && lastPathComponent =~ '^\.'
  993. return 1
  994. endif
  995. if g:NERDTreeShowFiles == 0 && self.isDirectory == 0
  996. return 1
  997. endif
  998. return 0
  999. endfunction
  1000. "FUNCTION: oPath.JoinPathStrings(...) {{{3
  1001. function! s:oPath.JoinPathStrings(...) dict
  1002. let components = []
  1003. for i in a:000
  1004. let components = extend(components, split(i, '/'))
  1005. endfor
  1006. return '/' . join(components, '/')
  1007. endfunction
  1008. "FUNCTION: oPath.Equals() {{{3
  1009. "
  1010. "Determines whether 2 path objects are "equal".
  1011. "They are equal if the paths they represent are the same
  1012. "
  1013. "Args:
  1014. "path: the other path obj to compare this with
  1015. function! s:oPath.Equals(path) dict
  1016. return self.Str(0) == a:path.Str(0)
  1017. endfunction
  1018. "FUNCTION: oPath.New() {{{3
  1019. "
  1020. "The Constructor for the Path object
  1021. "Throws NERDTree.Path.InvalidArguments exception.
  1022. function! s:oPath.New(fullpath) dict
  1023. let newPath = copy(self)
  1024. call newPath.ReadInfoFromDisk(a:fullpath)
  1025. return newPath
  1026. endfunction
  1027. "FUNCTION: oPath.ReadInfoFromDisk(fullpath) {{{3
  1028. "
  1029. "
  1030. "Throws NERDTree.Path.InvalidArguments exception.
  1031. function! s:oPath.ReadInfoFromDisk(fullpath) dict
  1032. call self.ExtractDriveLetter(a:fullpath)
  1033. let fullpath = s:oPath.WinToUnixPath(a:fullpath)
  1034. let self.pathSegments = split(fullpath, '/')
  1035. let self.isReadOnly = 0
  1036. if isdirectory(a:fullpath)
  1037. let self.isDirectory = 1
  1038. elseif filereadable(a:fullpath)
  1039. let self.isDirectory = 0
  1040. let self.isReadOnly = filewritable(a:fullpath) == 0
  1041. else
  1042. throw "NERDTree.Path.InvalidArguments Exception: Invalid path = " . a:fullpath
  1043. endif
  1044. "grab the last part of the path (minus the trailing slash)
  1045. let lastPathComponent = self.GetLastPathComponent(0)
  1046. "get the path to the new node with the parent dir fully resolved
  1047. let hardPath = resolve(self.StrTrunk()) . '/' . lastPathComponent
  1048. "if the last part of the path is a symlink then flag it as such
  1049. let self.isSymLink = (resolve(hardPath) != hardPath)
  1050. if self.isSymLink
  1051. let self.symLinkDest = resolve(fullpath)
  1052. "if the link is a dir then slap a / on the end of its dest
  1053. if isdirectory(self.symLinkDest)
  1054. "we always wanna treat MS windows shortcuts as files for
  1055. "simplicity
  1056. if hardPath !~ '\.lnk$'
  1057. let self.symLinkDest = self.symLinkDest . '/'
  1058. endif
  1059. endif
  1060. endif
  1061. endfunction
  1062. "FUNCTION: oPath.Refresh() {{{3
  1063. function! s:oPath.Refresh() dict
  1064. call self.ReadInfoFromDisk(self.StrForOS(0))
  1065. call self.CacheBookmarkNames()
  1066. endfunction
  1067. "FUNCTION: oPath.Rename() {{{3
  1068. "
  1069. "Renames this node on the filesystem
  1070. function! s:oPath.Rename(newPath) dict
  1071. if a:newPath == ''
  1072. throw "NERDTree.Path.InvalidArguments exception. Invalid newPath for renaming = ". a:newPath
  1073. endif
  1074. let success = rename(self.StrForOS(!s:running_windows), a:newPath)
  1075. if success != 0
  1076. throw "NERDTree.Path.Rename Exception: Could not rename: '" . self.StrForOS(0) . "'" . 'to:' . a:newPath
  1077. endif
  1078. call self.ReadInfoFromDisk(a:newPath)
  1079. endfunction
  1080. "FUNCTION: oPath.Str(esc) {{{3
  1081. "
  1082. "Gets the actual string path that this obj represents.
  1083. "
  1084. "Args:
  1085. "esc: if 1 then all the tricky chars in the returned string will be escaped
  1086. function! s:oPath.Str(esc) dict
  1087. let toReturn = '/' . join(self.pathSegments, '/')
  1088. if self.isDirectory && toReturn != '/'
  1089. let toReturn = toReturn . '/'
  1090. endif
  1091. if a:esc
  1092. let toReturn = escape(toReturn, s:escape_chars)
  1093. endif
  1094. return toReturn
  1095. endfunction
  1096. "FUNCTION: oPath.StrAbs() {{{3
  1097. "
  1098. "Returns a string representing this path with all the symlinks resolved
  1099. "
  1100. "Return:
  1101. "string
  1102. function! s:oPath.StrAbs() dict
  1103. return resolve(self.Str(1))
  1104. endfunction
  1105. "FUNCTION: oPath.StrForCd() {{{3
  1106. "
  1107. " returns a string that can be used with :cd
  1108. "
  1109. "Return:
  1110. "a string that can be used in the view to represent this path
  1111. function! s:oPath.StrForCd() dict
  1112. if s:running_windows
  1113. return self.StrForOS(0)
  1114. else
  1115. return self.StrForOS(1)
  1116. endif
  1117. endfunction
  1118. "FUNCTION: oPath.StrDisplay() {{{3
  1119. "
  1120. "Returns a string that specifies how the path should be represented as a
  1121. "string
  1122. "
  1123. "Return:
  1124. "a string that can be used in the view to represent this path
  1125. function! s:oPath.StrDisplay() dict
  1126. let toReturn = self.GetLastPathComponent(1)
  1127. let bookmarks = self.BookmarkNames()
  1128. if !empty(bookmarks)
  1129. let toReturn .= ' {' . join(bookmarks, ',') . '}'
  1130. endif
  1131. if self.isSymLink
  1132. let toReturn .= ' -> ' . self.symLinkDest
  1133. endif
  1134. if self.isReadOnly
  1135. let toReturn .= s:tree_RO_str
  1136. endif
  1137. return toReturn
  1138. endfunction
  1139. "FUNCTION: oPath.StrForEditCmd() {{{3
  1140. "
  1141. "Return: the string for this path that is suitable to be used with the :edit
  1142. "command
  1143. function! s:oPath.StrForEditCmd() dict
  1144. if s:running_windows
  1145. return self.StrForOS(0)
  1146. else
  1147. return self.Str(1)
  1148. endif
  1149. endfunction
  1150. "FUNCTION: oPath.StrForGlob() {{{3
  1151. function! s:oPath.StrForGlob() dict
  1152. let lead = s:os_slash
  1153. "if we are running windows then slap a drive letter on the front
  1154. if s:running_windows
  1155. let lead = self.drive . '\'
  1156. endif
  1157. let toReturn = lead . join(self.pathSegments, s:os_slash)
  1158. if !s:running_windows
  1159. let toReturn = escape(toReturn, s:escape_chars)
  1160. endif
  1161. return toReturn
  1162. endfunction
  1163. "FUNCTION: oPath.StrForOS(esc) {{{3
  1164. "
  1165. "Gets the string path for this path object that is appropriate for the OS.
  1166. "EG, in windows c:\foo\bar
  1167. " in *nix /foo/bar
  1168. "
  1169. "Args:
  1170. "esc: if 1 then all the tricky chars in the returned string will be
  1171. " escaped. If we are running windows then the str is double quoted instead.
  1172. function! s:oPath.StrForOS(esc) dict
  1173. let lead = s:os_slash
  1174. "if we are running windows then slap a drive letter on the front
  1175. if s:running_windows
  1176. let lead = self.drive . '\'
  1177. endif
  1178. let toReturn = lead . join(self.pathSegments, s:os_slash)
  1179. if a:esc
  1180. if s:running_windows
  1181. let toReturn = '"' . toReturn . '"'
  1182. else
  1183. let toReturn = escape(toReturn, s:escape_chars)
  1184. endif
  1185. endif
  1186. return toReturn
  1187. endfunction
  1188. "FUNCTION: oPath.StrTrunk() {{{3
  1189. "Gets the path without the last segment on the end.
  1190. function! s:oPath.StrTrunk() dict
  1191. return self.drive . '/' . join(self.pathSegments[0:-2], '/')
  1192. endfunction
  1193. "FUNCTION: oPath.UncacheBookmark(name){{{3
  1194. "remove the given bookmark from this paths cached bookmarks
  1195. function! s:oPath.UncacheBookmark(name) dict
  1196. let bookmarks = self.BookmarkNames()
  1197. let i = index(bookmarks, a:name)
  1198. if i != -1
  1199. echo remove(bookmarks, i)
  1200. endif
  1201. endfunction
  1202. "FUNCTION: oPath.WinToUnixPath(pathstr){{{3
  1203. "Takes in a windows path and returns the unix equiv
  1204. "
  1205. "A class level method
  1206. "
  1207. "Args:
  1208. "pathstr: the windows path to convert
  1209. function! s:oPath.WinToUnixPath(pathstr) dict
  1210. if !s:running_windows
  1211. return a:pathstr
  1212. endif
  1213. let toReturn = a:pathstr
  1214. "remove the x:\ of the front
  1215. let toReturn = substitute(toReturn, '^.*:\(\\\|/\)\?', '/', "")
  1216. "convert all \ chars to /
  1217. let toReturn = substitute(toReturn, '\', '/', "g")
  1218. return toReturn
  1219. endfunction
  1220. " SECTION: General Functions {{{1
  1221. "============================================================
  1222. "FUNCTION: s:Abs(num){{{2
  1223. "returns the absolute value of the input
  1224. function! s:Abs(num)
  1225. if a:num > 0
  1226. return a:num
  1227. else
  1228. return 0 - a:num
  1229. end
  1230. endfunction
  1231. "FUNCTION: s:AbsoluteTreeRoot(){{{2
  1232. " returns the highest cached ancestor of the current root
  1233. function! s:AbsoluteTreeRoot()
  1234. let currentNode = t:NERDTreeRoot
  1235. while currentNode.parent != {}
  1236. let currentNode = currentNode.parent
  1237. endwhile
  1238. return currentNode
  1239. endfunction
  1240. "FUNCTION: s:BufInWindows(bnum){{{2
  1241. "[[STOLEN FROM VTREEEXPLORER.VIM]]
  1242. "Determine the number of windows open to this buffer number.
  1243. "Care of Yegappan Lakshman. Thanks!
  1244. "
  1245. "Args:
  1246. "bnum: the subject buffers buffer number
  1247. function! s:BufInWindows(bnum)
  1248. let cnt = 0
  1249. let winnum = 1
  1250. while 1
  1251. let bufnum = winbufnr(winnum)
  1252. if bufnum < 0
  1253. break
  1254. endif
  1255. if bufnum == a:bnum
  1256. let cnt = cnt + 1
  1257. endif
  1258. let winnum = winnum + 1
  1259. endwhile
  1260. return cnt
  1261. endfunction " >>>
  1262. "FUNCTION: s:ClearAllBookmarks() {{{2
  1263. "delete all bookmarks
  1264. function! s:ClearAllBookmarks()
  1265. for name in keys(g:NERDTreeBookmarks)
  1266. let node = {}
  1267. try
  1268. let node = s:GetNodeForBookmark(name, 1)
  1269. catch /NERDTree/
  1270. endtry
  1271. call remove(g:NERDTreeBookmarks, name)
  1272. if !empty(node)
  1273. call node.path.CacheBookmarkNames()
  1274. endif
  1275. endfor
  1276. call s:WriteBookmarks()
  1277. endfunction
  1278. "FUNCTION: s:GetNodeForBookmark(name, searchFromAbsoluteRoot) {{{2
  1279. "get the treenode for the bookmark with the given name
  1280. "
  1281. "Args:
  1282. "name: name of bookmark
  1283. "searchFromAbsoluteRoot: specifies wheather we should search from the current
  1284. "tree root, or the highest cached node
  1285. function! s:GetNodeForBookmark(name, searchFromAbsoluteRoot)
  1286. try
  1287. let bookmark = s:GetBookmarks()[a:name]
  1288. catch /E716/ "key not in dictionary error
  1289. throw "NERDTree.BookmarkDoesntExist no bookmark found with name: " . a:name
  1290. endtry
  1291. let searchRoot = a:searchFromAbsoluteRoot ? s:AbsoluteTreeRoot() : t:NERDTreeRoot
  1292. let targetNode = searchRoot.FindNode(bookmark)
  1293. if empty(targetNode)
  1294. throw "NERDTree.BookmarkNotFound no node was found for bookmark: " . a:name
  1295. endif
  1296. return targetNode
  1297. endfunction
  1298. "FUNCTION: s:InitNerdTree(name) {{{2
  1299. "Initialise the nerd tree for this tab. The tree will start in either the
  1300. "given directory, or the directory associated with the given bookmark
  1301. "
  1302. "Args:
  1303. "name: the name of a bookmark or a directory
  1304. function! s:InitNerdTree(name)
  1305. let path = {}
  1306. if count(keys(s:GetBookmarks()), a:name)
  1307. let path = s:GetBookmarks()[a:name]
  1308. else
  1309. let dir = a:name == '' ? expand('%:p:h') : a:name
  1310. let dir = resolve(dir)
  1311. try
  1312. let path = s:oPath.New(dir)
  1313. catch /NERDTree.Path.InvalidArguments/
  1314. call s:Echo("No bookmark or directory found for: " . a:name)
  1315. return
  1316. endtry
  1317. endif
  1318. if !path.isDirectory
  1319. let path = path.GetParent()
  1320. endif
  1321. "if instructed to, then change the vim CWD to the dir the NERDTree is
  1322. "inited in
  1323. if g:NERDTreeChDirMode != 0
  1324. exec 'cd ' . path.StrForCd()
  1325. endif
  1326. let t:treeShowHelp = 0
  1327. let t:NERDTreeIgnoreEnabled = 1
  1328. if s:TreeExistsForTab()
  1329. if s:IsTreeOpen()
  1330. call s:CloseTree()
  1331. endif
  1332. unlet t:NERDTreeRoot
  1333. endif
  1334. let t:NERDTreeRoot = s:oTreeDirNode.New(path)
  1335. call t:NERDTreeRoot.Open()
  1336. call s:CreateTreeWin()
  1337. call s:RenderView()
  1338. call s:PutCursorOnNode(t:NERDTreeRoot, 0, 0)
  1339. endfunction
  1340. " Function: s:ReadBookmarks() {{{2
  1341. function! s:ReadBookmarks()
  1342. if filereadable(g:NERDTreeBookmarksFile)
  1343. let bookmarks = s:GetBookmarks()
  1344. let bookmarkStrings = readfile(g:NERDTreeBookmarksFile)
  1345. let invalidBookmarksFound = 0
  1346. for i in bookmarkStrings
  1347. let key = substitute(i, '^\(\w\{-}\) .*$', '\1', '')
  1348. let path = substitute(i, '^\w\{-} \(.*\)$', '\1', '')
  1349. try
  1350. let bookmarks[key] = s:oPath.New(path)
  1351. catch /NERDTree.Path.InvalidArguments/
  1352. let invalidBookmarksFound += 1
  1353. endtry
  1354. endfor
  1355. if invalidBookmarksFound
  1356. call s:Echo(invalidBookmarksFound . " invalid bookmarks were read and discarded")
  1357. call s:WriteBookmarks()
  1358. endif
  1359. endif
  1360. endfunction
  1361. " Function: s:TreeExistsForTab() {{{2
  1362. " Returns 1 if a nerd tree root exists in the current tab
  1363. function! s:TreeExistsForTab()
  1364. return exists("t:NERDTreeRoot")
  1365. endfunction
  1366. " Function: s:WriteBookmarks() {{{2
  1367. function! s:WriteBookmarks()
  1368. let bookmarks = s:GetBookmarks()
  1369. let bookmarkStrings = []
  1370. for k in keys(bookmarks)
  1371. call add(bookmarkStrings, k . ' ' . bookmarks[k].StrForOS(0))
  1372. endfor
  1373. call writefile(bookmarkStrings, g:NERDTreeBookmarksFile)
  1374. endfunction
  1375. " SECTION: Public Functions {{{1
  1376. "============================================================
  1377. "Returns the node that the cursor is currently on.
  1378. "
  1379. "If the cursor is not in the NERDTree window, it is temporarily put there.
  1380. "
  1381. "If no NERD tree window exists for the current tab, a NERDTree.NoTreeForTab
  1382. "exception is thrown.
  1383. "
  1384. "If the cursor is not on a node then an empty dictionary {} is returned.
  1385. function! NERDTreeGetCurrentNode()
  1386. if !s:TreeExistsForTab() || !s:IsTreeOpen()
  1387. throw "NERDTree.NoTreeForTab exception: there is no NERD tree open for the current tab"
  1388. endif
  1389. let winnr = winnr()
  1390. if winnr != s:GetTreeWinNum()
  1391. call s:PutCursorInTreeWin()
  1392. endif
  1393. let treenode = s:GetSelectedNode()
  1394. if winnr != winnr()
  1395. wincmd w
  1396. endif
  1397. return treenode
  1398. endfunction
  1399. "Returns the path object for the current node.
  1400. "
  1401. "Subject to the same conditions as NERDTreeGetCurrentNode
  1402. function! NERDTreeGetCurrentPath()
  1403. let node = NERDTreeGetCurrentNode()
  1404. if node != {}
  1405. return node.path
  1406. else
  1407. return {}
  1408. endif
  1409. endfunction
  1410. " SECTION: View Functions {{{1
  1411. "============================================================
  1412. "FUNCTION: s:CenterView() {{{2
  1413. "centers the nerd tree window around the cursor (provided the nerd tree
  1414. "options permit)
  1415. function! s:CenterView()
  1416. if g:NERDTreeAutoCenter
  1417. let current_line = winline()
  1418. let lines_to_top = current_line
  1419. let lines_to_bottom = winheight(s:GetTreeWinNum()) - current_line
  1420. if lines_to_top < g:NERDTreeAutoCenterThreshold || lines_to_bottom < g:NERDTreeAutoCenterThreshold
  1421. normal! zz
  1422. endif
  1423. endif
  1424. endfunction
  1425. "FUNCTION: s:CloseTreeIfOpen() {{{2
  1426. "Closes the NERD tree window if it is open
  1427. function! s:CloseTreeIfOpen()
  1428. if s:IsTreeOpen()
  1429. call s:CloseTree()
  1430. endif
  1431. endfunction
  1432. "FUNCTION: s:CloseTree() {{{2
  1433. "Closes the NERD tree window
  1434. function! s:CloseTree()
  1435. if !s:IsTreeOpen()
  1436. throw "NERDTree.view.CloseTree exception: no NERDTree is open"
  1437. endif
  1438. if winnr("$") != 1
  1439. execute s:GetTreeWinNum() . " wincmd w"
  1440. close
  1441. execute "wincmd p"
  1442. else
  1443. :q
  1444. endif
  1445. endfunction
  1446. "FUNCTION: s:CreateTreeWin() {{{2
  1447. "Inits the NERD tree window. ie. opens it, sizes it, sets all the local
  1448. "options etc
  1449. function! s:CreateTreeWin()
  1450. "create the nerd tree window
  1451. let splitLocation = g:NERDTreeWinPos ? "topleft " : "botright "
  1452. let splitMode = g:NERDTreeSplitVertical ? "vertical " : ""
  1453. let splitSize = g:NERDTreeWinSize
  1454. let t:NERDTreeWinName = localtime() . s:NERDTreeWinName
  1455. let cmd = splitLocation . splitMode . splitSize . ' new ' . t:NERDTreeWinName
  1456. silent! execute cmd
  1457. setlocal winfixwidth
  1458. "throwaway buffer options
  1459. setlocal noswapfile
  1460. setlocal buftype=nofile
  1461. setlocal bufhidden=delete
  1462. setlocal nowrap
  1463. setlocal foldcolumn=0
  1464. setlocal nobuflisted
  1465. setlocal nospell
  1466. if g:NERDTreeShowLineNumbers
  1467. setlocal nu
  1468. else
  1469. setlocal nonu
  1470. endif
  1471. iabc <buffer>
  1472. if g:NERDTreeHighlightCursorline
  1473. setlocal cursorline
  1474. endif
  1475. " for line continuation
  1476. let cpo_save1 = &cpo
  1477. set cpo&vim
  1478. call s:BindMappings()
  1479. setfiletype nerdtree
  1480. " syntax highlighting
  1481. if has("syntax") && exists("g:syntax_on") && !has("syntax_items")
  1482. call s:SetupSyntaxHighlighting()
  1483. endif
  1484. endfunction
  1485. "FUNCTION: s:DrawTree {{{2
  1486. "Draws the given node recursively
  1487. "
  1488. "Args:
  1489. "curNode: the node that is being rendered with this call
  1490. "depth: the current depth in the tree for this call
  1491. "drawText: 1 if we should actually draw the line for this node (if 0 then the
  1492. "child nodes are rendered only)
  1493. "vertMap: a binary array that indicates whether a vertical bar should be draw
  1494. "for each depth in the tree
  1495. "isLastChild:true if this curNode is the last child of its parent
  1496. function! s:DrawTree(curNode, depth, drawText, vertMap, isLastChild)
  1497. if a:drawText == 1
  1498. let treeParts = ''
  1499. "get all the leading spaces and vertical tree parts for this line
  1500. if a:depth > 1
  1501. for j in a:vertMap[0:-2]
  1502. if j == 1
  1503. let treeParts = treeParts . s:tree_vert . s:tree_wid_strM1
  1504. else
  1505. let treeParts = treeParts . s:tree_wid_str
  1506. endif
  1507. endfor
  1508. endif
  1509. "get the last vertical tree part for this line which will be different
  1510. "if this node is the last child of its parent
  1511. if a:isLastChild
  1512. let treeParts = treeParts . s:tree_vert_last
  1513. else
  1514. let treeParts = treeParts . s:tree_vert
  1515. endif
  1516. "smack the appropriate dir/file symbol on the line before the file/dir
  1517. "name itself
  1518. if a:curNode.path.isDirectory
  1519. if a:curNode.isOpen
  1520. let treeParts = treeParts . s:tree_dir_open
  1521. else
  1522. let treeParts = treeParts . s:tree_dir_closed
  1523. endif
  1524. else
  1525. let treeParts = treeParts . s:tree_file
  1526. endif
  1527. let line = treeParts . a:curNode.StrDisplay()
  1528. call setline(line(".")+1, line)
  1529. call cursor(line(".")+1, col("."))
  1530. endif
  1531. "if the node is an open dir, draw its children
  1532. if a:curNode.path.isDirectory == 1 && a:curNode.isOpen == 1
  1533. let childNodesToDraw = a:curNode.GetVisibleChildren()
  1534. if len(childNodesToDraw) > 0
  1535. "draw all the nodes children except the last
  1536. let lastIndx = len(childNodesToDraw)-1
  1537. if lastIndx > 0
  1538. for i in childNodesToDraw[0:lastIndx-1]
  1539. call s:DrawTree(i, a:depth + 1, 1, add(copy(a:vertMap), 1), 0)
  1540. endfor
  1541. endif
  1542. "draw the last child, indicating that it IS the last
  1543. call s:DrawTree(childNodesToDraw[lastIndx], a:depth + 1, 1, add(copy(a:vertMap), 0), 1)
  1544. endif
  1545. endif
  1546. endfunction
  1547. "FUNCTION: s:DumpHelp {{{2
  1548. "prints out the quick help
  1549. function! s:DumpHelp()
  1550. let old_h = @h
  1551. if t:treeShowHelp == 1
  1552. let @h= "\" NERD tree (" . s:NERD_tree_version . ") quickhelp~\n"
  1553. let @h=@h."\" ============================\n"
  1554. let @h=@h."\" File node mappings~\n"
  1555. let @h=@h."\" ". (g:NERDTreeMouseMode == 3 ? "single" : "double") ."-click,\n"
  1556. let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in prev window\n"
  1557. let @h=@h."\" ". g:NERDTreeMapPreview .": preview \n"
  1558. let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n"
  1559. let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n"
  1560. let @h=@h."\" middle-click,\n"
  1561. let @h=@h."\" ". g:NERDTreeMapOpenSplit .": open split\n"
  1562. let @h=@h."\" ". g:NERDTreeMapPreviewSplit .": preview split\n"
  1563. let @h=@h."\" ". g:NERDTreeMapExecute.": Execute file\n"
  1564. let @h=@h."\" \n\" ----------------------------\n"
  1565. let @h=@h."\" Directory node mappings~\n"
  1566. let @h=@h."\" ". (g:NERDTreeMouseMode == 1 ? "double" : "single") ."-click,\n"
  1567. let @h=@h."\" ". g:NERDTreeMapActivateNode .": open & close node\n"
  1568. let @h=@h."\" ". g:NERDTreeMapOpenRecursively .": recursively open node\n"
  1569. let @h=@h."\" ". g:NERDTreeMapCloseDir .": close parent of node\n"
  1570. let @h=@h."\" ". g:NERDTreeMapCloseChildren .": close all child nodes of\n"
  1571. let @h=@h."\" current node recursively\n"
  1572. let @h=@h."\" middle-click,\n"
  1573. let @h=@h."\" ". g:NERDTreeMapOpenExpl.": Open netrw for selected\n"
  1574. let @h=@h."\" node \n"
  1575. let @h=@h."\" \n\" ----------------------------\n"
  1576. let @h=@h."\" Tree navigation mappings~\n"
  1577. let @h=@h."\" ". g:NERDTreeMapJumpRoot .": go to root\n"
  1578. let @h=@h."\" ". g:NERDTreeMapJumpParent .": go to parent\n"
  1579. let @h=@h."\" ". g:NERDTreeMapJumpFirstChild .": go to first child\n"
  1580. let @h=@h."\" ". g:NERDTreeMapJumpLastChild .": go to last child\n"
  1581. let @h=@h."\" ". g:NERDTreeMapJumpNextSibling .": go to next sibling\n"
  1582. let @h=@h."\" ". g:NERDTreeMapJumpPrevSibling .": go to prev sibling\n"
  1583. let @h=@h."\" \n\" ----------------------------\n"
  1584. let @h=@h."\" Filesystem mappings~\n"
  1585. let @h=@h."\" ". g:NERDTreeMapChangeRoot .": change tree root to the\n"
  1586. let @h=@h."\" selected dir\n"
  1587. let @h=@h."\" ". g:NERDTreeMapUpdir .": move tree root up a dir\n"
  1588. let @h=@h."\" ". g:NERDTreeMapUpdirKeepOpen .": move tree root up a dir\n"
  1589. let @h=@h."\" but leave old root open\n"
  1590. let @h=@h."\" ". g:NERDTreeMapRefresh .": refresh cursor dir\n"
  1591. let @h=@h."\" ". g:NERDTreeMapRefreshRoot .": refresh current root\n"
  1592. let @h=@h."\" ". g:NERDTreeMapFilesystemMenu .": Show filesystem menu\n"
  1593. let @h=@h."\" ". g:NERDTreeMapChdir .":change the CWD to the\n"
  1594. let @h=@h."\" selected dir\n"
  1595. let @h=@h."\" \n\" ----------------------------\n"
  1596. let @h=@h."\" Tree filtering mappings~\n"
  1597. let @h=@h."\" ". g:NERDTreeMapToggleHidden .": hidden files (" . (g:NERDTreeShowHidden ? "on" : "off") . ")\n"
  1598. let @h=@h."\" ". g:NERDTreeMapToggleFilters .": file filters (" . (t:NERDTreeIgnoreEnabled ? "on" : "off") . ")\n"
  1599. let @h=@h."\" ". g:NERDTreeMapToggleFiles .": files (" . (g:NERDTreeShowFiles ? "on" : "off") . ")\n"
  1600. let @h=@h."\" \n\" ----------------------------\n"
  1601. let @h=@h."\" Other mappings~\n"
  1602. let @h=@h."\" ". g:NERDTreeMapQuit .": Close the NERDTree window\n"
  1603. let @h=@h."\" ". g:NERDTreeMapHelp .": toggle help\n"
  1604. let @h=@h."\" \n\" ----------------------------\n"
  1605. let @h=@h."\" Bookmark commands~\n"
  1606. let @h=@h."\" :Bookmark <name>\n"
  1607. let @h=@h."\" :BookmarkToRoot <name>\n"
  1608. let @h=@h."\" :RevealBookmark <name>\n"
  1609. let @h=@h."\" :OpenBookmark <name>\n"
  1610. let @h=@h."\" :ClearBookmarks [<names>]\n"
  1611. let @h=@h."\" :ClearAllBookmarks\n"
  1612. else
  1613. let @h="\" Press ". g:NERDTreeMapHelp ." for help\n"
  1614. endif
  1615. silent! put h
  1616. let @h = old_h
  1617. endfunction
  1618. "FUNCTION: s:Echo {{{2
  1619. "A wrapper for :echo. Appends 'NERDTree:' on the front of all messages
  1620. "
  1621. "Args:
  1622. "msg: the message to echo
  1623. function! s:Echo(msg)
  1624. redraw
  1625. echo "NERDTree: " . a:msg
  1626. endfunction
  1627. "FUNCTION: s:EchoWarning {{{2
  1628. "Wrapper for s:Echo, sets the message type to warningmsg for this message
  1629. "Args:
  1630. "msg: the message to echo
  1631. function! s:EchoWarning(msg)
  1632. echohl warningmsg
  1633. call s:Echo(a:msg)
  1634. echohl normal
  1635. endfunction
  1636. "FUNCTION: s:EchoError {{{2
  1637. "Wrapper for s:Echo, sets the message type to errormsg for this message
  1638. "Args:
  1639. "msg: the message to echo
  1640. function! s:EchoError(msg)
  1641. echohl errormsg
  1642. call s:Echo(a:msg)
  1643. echohl normal
  1644. endfunction
  1645. " FUNCTION: s:FindBookmarks(A,L,P) {{{2
  1646. " completion function for the bookmark commands
  1647. function! s:FindBookmarks(A,L,P)
  1648. let keys = keys(s:GetBookmarks())
  1649. return filter(keys, 'v:val =~ "^' . a:A . '"')
  1650. endfunction
  1651. "FUNCTION: s:FindNodeLineNumber(treenode){{{2
  1652. "Finds the line number for the given tree node
  1653. "
  1654. "Args:
  1655. "treenode: the node to find the line no. for
  1656. function! s:FindNodeLineNumber(treenode)
  1657. "if the node is the root then return the root line no.
  1658. if a:treenode.IsRoot()
  1659. return s:FindRootNodeLineNumber()
  1660. endif
  1661. let totalLines = line("$")
  1662. "the path components we have matched so far
  1663. let pathcomponents = [substitute(t:NERDTreeRoot.path.Str(0), '/ *$', '', '')]
  1664. "the index of the component we are searching for
  1665. let curPathComponent = 1
  1666. let fullpath = a:treenode.path.Str(0)
  1667. let lnum = s:FindRootNodeLineNumber()
  1668. while lnum > 0
  1669. let lnum = lnum + 1
  1670. "have we reached the bottom of the tree?
  1671. if lnum == totalLines+1
  1672. return -1
  1673. endif
  1674. let curLine = getline(lnum)
  1675. let indent = match(curLine,s:tree_markup_reg_neg) / s:tree_wid
  1676. if indent == curPathComponent
  1677. let curLine = s:StripMarkupFromLine(curLine, 1)
  1678. let curPath = join(pathcomponents, '/') . '/' . curLine
  1679. if stridx(fullpath, curPath, 0) == 0
  1680. if fullpath == curPath || strpart(fullpath, len(curPath)-1,1) == '/'
  1681. let curLine = substitute(curLine, '/ *$', '', '')
  1682. call add(pathcomponents, curLine)
  1683. let curPathComponent = curPathComponent + 1
  1684. if fullpath == curPath
  1685. return lnum
  1686. endif
  1687. endif
  1688. endif
  1689. endif
  1690. endwhile
  1691. return -1
  1692. endfunction
  1693. "FUNCTION: s:FindRootNodeLineNumber(){{{2
  1694. "Finds the line number of the root node
  1695. function! s:FindRootNodeLineNumber()
  1696. let rootLine = 1
  1697. while getline(rootLine) !~ '^/'
  1698. let rootLine = rootLine + 1
  1699. endwhile
  1700. return rootLine
  1701. endfunction
  1702. " FUNCTION: s:GetBookmarks(name) {{{2
  1703. " getter/lazy initializer for the g:NERDTreeBookmarks hash
  1704. function! s:GetBookmarks()
  1705. if !exists("g:NERDTreeBookmarks")
  1706. let g:NERDTreeBookmarks = {}
  1707. endif
  1708. return g:NERDTreeBookmarks
  1709. endfunction
  1710. "FUNCTION: s:GetPath(ln) {{{2
  1711. "Gets the full path to the node that is rendered on the given line number
  1712. "
  1713. "Args:
  1714. "ln: the line number to get the path for
  1715. "
  1716. "Return:
  1717. "A path if a node was selected, {} if nothing is selected.
  1718. "If the 'up a dir' line was selected then the path to the parent of the
  1719. "current root is returned
  1720. function! s:GetPath(ln)
  1721. let line = getline(a:ln)
  1722. "check to see if we have the root node
  1723. if line =~ '^\/'
  1724. return t:NERDTreeRoot.path
  1725. endif
  1726. " in case called from outside the tree
  1727. if line !~ '^ *[|`]' || line =~ '^$'
  1728. return {}
  1729. endif
  1730. if line == s:tree_up_dir_line
  1731. return t:NERDTreeRoot.path.GetParent()
  1732. endif
  1733. "get the indent level for the file (i.e. how deep in the tree it is)
  1734. "let indent = match(line,'[^-| `]') / s:tree_wid
  1735. let indent = match(line, s:tree_markup_reg_neg) / s:tree_wid
  1736. "remove the tree parts and the leading space
  1737. let curFile = s:StripMarkupFromLine(line, 0)
  1738. let wasdir = 0
  1739. if curFile =~ '/$'
  1740. let wasdir = 1
  1741. let curFile = substitute(curFile, '/\?$', '/', "")
  1742. endif
  1743. let dir = ""
  1744. let lnum = a:ln
  1745. while lnum > 0
  1746. let lnum = lnum - 1
  1747. let curLine = getline(lnum)
  1748. let curLineStripped = s:StripMarkupFromLine(curLine, 1)
  1749. "have we reached the top of the tree?
  1750. if curLine =~ '^/'
  1751. let dir = substitute (curLine, ' *$', "", "") . dir
  1752. break
  1753. endif
  1754. if curLineStripped =~ '/$'
  1755. let lpindent = match(curLine,s:tree_markup_reg_neg) / s:tree_wid
  1756. if lpindent < indent
  1757. let indent = indent - 1
  1758. let dir = substitute (curLineStripped,'^\\', "", "") . dir
  1759. continue
  1760. endif
  1761. endif
  1762. endwhile
  1763. let curFile = t:NERDTreeRoot.path.drive . dir . curFile
  1764. let toReturn = s:oPath.New(curFile)
  1765. return toReturn
  1766. endfunction
  1767. "FUNCTION: s:GetSelectedDir() {{{2
  1768. "Returns the current node if it is a dir node, or else returns the current
  1769. "nodes parent
  1770. function! s:GetSelectedDir()
  1771. let currentDir = s:GetSelectedNode()
  1772. if currentDir != {} && !currentDir.IsRoot()
  1773. if currentDir.path.isDirectory == 0
  1774. let currentDir = currentDir.parent
  1775. endif
  1776. endif
  1777. return currentDir
  1778. endfunction
  1779. "FUNCTION: s:GetSelectedNode() {{{2
  1780. "gets the treenode that the cursor is currently over
  1781. function! s:GetSelectedNode()
  1782. try
  1783. let path = s:GetPath(line("."))
  1784. if path == {}
  1785. return {}
  1786. endif
  1787. return t:NERDTreeRoot.FindNode(path)
  1788. catch /^NERDTree/
  1789. return {}
  1790. endtry
  1791. endfunction
  1792. "FUNCTION: s:GetTreeBufNum() {{{2
  1793. "gets the nerd tree buffer number for this tab
  1794. function! s:GetTreeBufNum()
  1795. if exists("t:NERDTreeWinName")
  1796. return bufnr(t:NERDTreeWinName)
  1797. else
  1798. return -1
  1799. endif
  1800. endfunction
  1801. "FUNCTION: s:GetTreeWinNum() {{{2
  1802. "gets the nerd tree window number for this tab
  1803. function! s:GetTreeWinNum()
  1804. if exists("t:NERDTreeWinName")
  1805. return bufwinnr(t:NERDTreeWinName)
  1806. else
  1807. return -1
  1808. endif
  1809. endfunction
  1810. "FUNCTION: s:IsTreeOpen() {{{2
  1811. function! s:IsTreeOpen()
  1812. return s:GetTreeWinNum() != -1
  1813. endfunction
  1814. " FUNCTION: s:JumpToChild(direction) {{{2
  1815. " Args:
  1816. " direction: 0 if going to first child, 1 if going to last
  1817. function! s:JumpToChild(direction)
  1818. let currentNode = s:GetSelectedNode()
  1819. if currentNode == {} || currentNode.IsRoot()
  1820. call s:Echo("cannot jump to " . (a:direction ? "last" : "first") . " child")
  1821. return
  1822. end
  1823. let dirNode = currentNode.parent
  1824. let childNodes = dirNode.GetVisibleChildren()
  1825. let targetNode = childNodes[0]
  1826. if a:direction
  1827. let targetNode = childNodes[len(childNodes) - 1]
  1828. endif
  1829. if targetNode.Equals(currentNode)
  1830. let siblingDir = currentNode.parent.FindOpenDirSiblingWithChildren(a:direction)
  1831. if siblingDir != {}
  1832. let indx = a:direction ? siblingDir.GetVisibleChildCount()-1 : 0
  1833. let targetNode = siblingDir.GetChildByIndex(indx, 1)
  1834. endif
  1835. endif
  1836. call s:PutCursorOnNode(targetNode, 1, 0)
  1837. call s:CenterView()
  1838. endfunction
  1839. "FUNCTION: s:OpenDirNodeSplit(treenode) {{{2
  1840. "Open the file represented by the given node in a new window.
  1841. "No action is taken for file nodes
  1842. "
  1843. "ARGS:
  1844. "treenode: file node to open
  1845. function! s:OpenDirNodeSplit(treenode)
  1846. if a:treenode.path.isDirectory == 1
  1847. call s:OpenNodeSplit(a:treenode)
  1848. endif
  1849. endfunction
  1850. " FUNCTION: s:OpenExplorerFor(treenode) {{{2
  1851. " opens a netrw window for the given dir treenode
  1852. function! s:OpenExplorerFor(treenode)
  1853. let oldwin = winnr()
  1854. wincmd p
  1855. if oldwin == winnr() || (&modified && s:BufInWindows(winbufnr(winnr())) < 2)
  1856. wincmd p
  1857. call s:OpenDirNodeSplit(a:treenode)
  1858. else
  1859. exec ("silent edit " . a:treenode.path.StrForEditCmd())
  1860. endif
  1861. endfunction
  1862. "FUNCTION: s:OpenFileNode(treenode) {{{2
  1863. "Open the file represented by the given node in the current window, splitting
  1864. "the window if needed
  1865. "
  1866. "ARGS:
  1867. "treenode: file node to open
  1868. function! s:OpenFileNode(treenode)
  1869. call s:PutCursorInTreeWin()
  1870. if s:ShouldSplitToOpen(winnr("#"))
  1871. call s:OpenFileNodeSplit(a:treenode)
  1872. else
  1873. try
  1874. wincmd p
  1875. silent exec ("edit " . a:treenode.path.StrForEditCmd())
  1876. catch /^Vim\%((\a\+)\)\=:E37/
  1877. call s:PutCursorInTreeWin()
  1878. call s:Echo("Cannot open file, it is already open and modified")
  1879. catch /^Vim\%((\a\+)\)\=:/
  1880. echo v:exception
  1881. endtry
  1882. endif
  1883. endfunction
  1884. "FUNCTION: s:OpenFileNodeSplit(treenode) {{{2
  1885. "Open the file represented by the given node in a new window.
  1886. "No action is taken for dir nodes
  1887. "
  1888. "ARGS:
  1889. "treenode: file node to open
  1890. function! s:OpenFileNodeSplit(treenode)
  1891. if a:treenode.path.isDirectory == 0
  1892. try
  1893. call s:OpenNodeSplit(a:treenode)
  1894. catch /^NERDTree.view.FileOpen/
  1895. call s:Echo("Cannot open file, it is already open and modified" )
  1896. endtry
  1897. endif
  1898. endfunction
  1899. "FUNCTION: s:OpenNodeSplit(treenode) {{{2
  1900. "Open the file/dir represented by the given node in a new window
  1901. "
  1902. "ARGS:
  1903. "treenode: file node to open
  1904. function! s:OpenNodeSplit(treenode)
  1905. call s:PutCursorInTreeWin()
  1906. " Save the user's settings for splitbelow and splitright
  1907. let savesplitbelow=&splitbelow
  1908. let savesplitright=&splitright
  1909. " Figure out how to do the split based on the user's preferences.
  1910. " We want to split to the (left,right,top,bottom) of the explorer
  1911. " window, but we want to extract the screen real-estate from the
  1912. " window next to the explorer if possible.
  1913. "
  1914. " 'there' will be set to a command to move from the split window
  1915. " back to the explorer window
  1916. "
  1917. " 'back' will be set to a command to move from the explorer window
  1918. " back to the newly split window
  1919. "
  1920. " 'right' and 'below' will be set to the settings needed for
  1921. " splitbelow and splitright IF the explorer is the only window.
  1922. "
  1923. if g:NERDTreeSplitVertical == 1
  1924. let there= g:NERDTreeWinPos ? "wincmd h" : "wincmd l"
  1925. let back= g:NERDTreeWinPos ? "wincmd l" : "wincmd h"
  1926. let right=g:NERDTreeWinPos ? 1 : 0
  1927. let below=0
  1928. else
  1929. let there= g:NERDTreeWinPos ? "wincmd k" : "wincmd j"
  1930. let back= g:NERDTreeWinPos ? "wincmd j" : "wincmd k"
  1931. let right=0
  1932. let below=g:NERDTreeWinPos ? 1 : 0
  1933. endif
  1934. " Attempt to go to adjacent window
  1935. exec(back)
  1936. let onlyOneWin = (winnr() == s:GetTreeWinNum())
  1937. " If no adjacent window, set splitright and splitbelow appropriately
  1938. if onlyOneWin
  1939. let &splitright=right
  1940. let &splitbelow=below
  1941. else
  1942. " found adjacent window - invert split direction
  1943. let &splitright=!right
  1944. let &splitbelow=!below
  1945. endif
  1946. " Create a variable to use if splitting vertically
  1947. let splitMode = ""
  1948. if (onlyOneWin && g:NERDTreeSplitVertical) || (!onlyOneWin && !g:NERDTreeSplitVertical)
  1949. let splitMode = "vertical"
  1950. endif
  1951. " Open the new window
  1952. try
  1953. exec("silent " . splitMode." sp " . a:treenode.path.StrForEditCmd())
  1954. catch /^Vim\%((\a\+)\)\=:E37/
  1955. call s:PutCursorInTreeWin()
  1956. throw "NERDTree.view.FileOpen exception: ". a:treenode.path.Str(0) ." is already open and modified."
  1957. catch /^Vim\%((\a\+)\)\=:/
  1958. do nothing
  1959. endtry
  1960. " resize the explorer window if it is larger than the requested size
  1961. exec(there)
  1962. if g:NERDTreeWinSize =~ '[0-9]\+' && winheight("") > g:NERDTreeWinSize
  1963. exec("silent vertical resize ".g:NERDTreeWinSize)
  1964. endif
  1965. wincmd p
  1966. " Restore splitmode settings
  1967. let &splitbelow=savesplitbelow
  1968. let &splitright=savesplitright
  1969. endfunction
  1970. "FUNCTION: s:PromptToDelBuffer(bufnum, msg){{{2
  1971. "prints out the given msg and, if the user responds by pushing 'y' then the
  1972. "buffer with the given bufnum is deleted
  1973. "
  1974. "Args:
  1975. "bufnum: the buffer that may be deleted
  1976. "msg: a message that will be echoed to the user asking them if they wish to
  1977. " del the buffer
  1978. function! s:PromptToDelBuffer(bufnum, msg)
  1979. echo a:msg
  1980. if nr2char(getchar()) == 'y'
  1981. exec "silent bdelete! " . a:bufnum
  1982. endif
  1983. endfunction
  1984. "FUNCTION: s:PutCursorOnNode(treenode, isJump, recurseUpward){{{2
  1985. "Places the cursor on the line number representing the given node
  1986. "
  1987. "Args:
  1988. "treenode: the node to put the cursor on
  1989. "isJump: 1 if this cursor movement should be counted as a jump by vim
  1990. "recurseUpward: try to put the cursor on the parent if the this node isnt
  1991. "visible
  1992. function! s:PutCursorOnNode(treenode, isJump, recurseUpward)
  1993. let ln = s:FindNodeLineNumber(a:treenode)
  1994. if ln != -1
  1995. if a:isJump
  1996. mark '
  1997. endif
  1998. call cursor(ln, col("."))
  1999. else
  2000. if a:recurseUpward
  2001. let node = a:treenode
  2002. while s:FindNodeLineNumber(node) == -1 && node != {}
  2003. let node = node.parent
  2004. call node.Open()
  2005. endwhile
  2006. call s:RenderView()
  2007. call s:PutCursorOnNode(a:treenode, a:isJump, 0)
  2008. endif
  2009. endif
  2010. endfunction
  2011. "FUNCTION: s:PutCursorInTreeWin(){{{2
  2012. "Places the cursor in the nerd tree window
  2013. function! s:PutCursorInTreeWin()
  2014. if !s:IsTreeOpen()
  2015. throw "NERDTree.view.InvalidOperation Exception: No NERD tree window exists"
  2016. endif
  2017. exec s:GetTreeWinNum() . "wincmd w"
  2018. endfunction
  2019. "FUNCTION: s:RenderView {{{2
  2020. "The entry function for rendering the tree. Renders the root then calls
  2021. "s:DrawTree to draw the children of the root
  2022. "
  2023. "Args:
  2024. function! s:RenderView()
  2025. execute s:GetTreeWinNum() . "wincmd w"
  2026. setlocal modifiable
  2027. "remember the top line of the buffer and the current line so we can
  2028. "restore the view exactly how it was
  2029. let curLine = line(".")
  2030. let curCol = col(".")
  2031. let topLine = line("w0")
  2032. "delete all lines in the buffer (being careful not to clobber a register)
  2033. :silent 1,$delete _
  2034. call s:DumpHelp()
  2035. "delete the blank line before the help and add one after it
  2036. call setline(line(".")+1, " ")
  2037. call cursor(line(".")+1, col("."))
  2038. "add the 'up a dir' line
  2039. call setline(line(".")+1, s:tree_up_dir_line)
  2040. call cursor(line(".")+1, col("."))
  2041. "draw the header line
  2042. call setline(line(".")+1, t:NERDTreeRoot.path.Str(0))
  2043. call cursor(line(".")+1, col("."))
  2044. "draw the tree
  2045. call s:DrawTree(t:NERDTreeRoot, 0, 0, [], t:NERDTreeRoot.GetChildCount() == 1)
  2046. "delete the blank line at the top of the buffer
  2047. :silent 1,1delete _
  2048. "restore the view
  2049. let old_scrolloff=&scrolloff
  2050. let &scrolloff=0
  2051. call cursor(topLine, 1)
  2052. normal! zt
  2053. call cursor(curLine, curCol)
  2054. let &scrolloff = old_scrolloff
  2055. setlocal nomodifiable
  2056. endfunction
  2057. "FUNCTION: s:RenderViewSavingPosition {{{2
  2058. "Renders the tree and ensures the cursor stays on the current node or the
  2059. "current nodes parent if it is no longer available upon re-rendering
  2060. function! s:RenderViewSavingPosition()
  2061. let currentNode = s:GetSelectedNode()
  2062. "go up the tree till we find a node that will be visible or till we run
  2063. "out of nodes
  2064. while currentNode != {} && !currentNode.IsVisible() && !currentNode.IsRoot()
  2065. let currentNode = currentNode.parent
  2066. endwhile
  2067. call s:RenderView()
  2068. if currentNode != {}
  2069. call s:PutCursorOnNode(currentNode, 0, 0)
  2070. endif
  2071. endfunction
  2072. "FUNCTION: s:RestoreScreenState() {{{2
  2073. "
  2074. "Sets the screen state back to what it was when s:SaveScreenState was last
  2075. "called.
  2076. "
  2077. "Assumes the cursor is in the NERDTree window
  2078. function! s:RestoreScreenState()
  2079. if !exists("t:NERDTreeOldTopLine") || !exists("t:NERDTreeOldPos")
  2080. return
  2081. endif
  2082. call cursor(t:NERDTreeOldTopLine, 0)
  2083. normal! zt
  2084. call setpos(".", t:NERDTreeOldPos)
  2085. endfunction
  2086. "FUNCTION: s:SaveScreenState() {{{2
  2087. "Saves the current cursor position in the current buffer and the window
  2088. "scroll position
  2089. "
  2090. "Assumes the cursor is in the NERDTree window
  2091. function! s:SaveScreenState()
  2092. let t:NERDTreeOldPos = getpos(".")
  2093. let t:NERDTreeOldTopLine = line("w0")
  2094. endfunction
  2095. "FUNCTION: s:SetupSyntaxHighlighting() {{{2
  2096. function! s:SetupSyntaxHighlighting()
  2097. "treeFlags are syntax items that should be invisible, but give clues as to
  2098. "how things should be highlighted
  2099. syn match treeFlag #\~#
  2100. syn match treeFlag #\[RO\]#
  2101. "highlighting for the .. (up dir) line at the top of the tree
  2102. execute "syn match treeUp #". s:tree_up_dir_line ."#"
  2103. "highlighting for the ~/+ symbols for the directory nodes
  2104. syn match treeClosable #\~\<#
  2105. syn match treeClosable #\~\.#
  2106. syn match treeOpenable #+\<#
  2107. syn match treeOpenable #+\.#he=e-1
  2108. "highlighting for the tree structural parts
  2109. syn match treePart #|#
  2110. syn match treePart #`#
  2111. syn match treePartFile #[|`]-#hs=s+1 contains=treePart
  2112. "quickhelp syntax elements
  2113. syn match treeHelpKey #" \{1,2\}[^ ]*:#hs=s+2,he=e-1
  2114. syn match treeHelpKey #" \{1,2\}[^ ]*,#hs=s+2,he=e-1
  2115. syn match treeHelpTitle #" .*\~#hs=s+2,he=e-1 contains=treeFlag
  2116. syn match treeToggleOn #".*(on)#hs=e-2,he=e-1 contains=treeHelpKey
  2117. syn match treeToggleOff #".*(off)#hs=e-3,he=e-1 contains=treeHelpKey
  2118. syn match treeHelpCommand #" :.\{-}\>#hs=s+3
  2119. syn match treeHelp #^" .*# contains=treeHelpKey,treeHelpTitle,treeFlag,treeToggleOff,treeToggleOn,treeHelpCommand
  2120. "highlighting for sym links
  2121. syn match treeLink #[^-| `].* -> # contains=treeBookmark
  2122. "highlighting for readonly files
  2123. syn match treeRO #[0-9a-zA-Z]\+.*\[RO\]# contains=treeFlag,treeBookmark
  2124. "highlighting for bookmarks
  2125. syn match treeBookmark # {.*}#hs=s+1
  2126. "highlighing for directory nodes and file nodes
  2127. syn match treeDirSlash #/#
  2128. syn match treeDir #[^-| `].*/# contains=treeLink,treeDirSlash,treeOpenable,treeClosable
  2129. syn match treeFile #|-.*# contains=treeLink,treePart,treeRO,treePartFile,treeBookmark
  2130. syn match treeFile #`-.*# contains=treeLink,treePart,treeRO,treePartFile,treeBookmark
  2131. syn match treeCWD #^/.*$#
  2132. if g:NERDChristmasTree
  2133. hi def link treePart Special
  2134. hi def link treePartFile Type
  2135. hi def link treeFile Macro
  2136. hi def link treeDirSlash Identifier
  2137. hi def link treeClosable Type
  2138. else
  2139. hi def link treePart Normal
  2140. hi def link treePartFile Normal
  2141. hi def link treeFile Normal
  2142. hi def link treeClosable Title
  2143. endif
  2144. hi def link treeHelp String
  2145. hi def link treeHelpKey Identifier
  2146. hi def link treeHelpCommand Identifier
  2147. hi def link treeHelpTitle Macro
  2148. hi def link treeToggleOn Question
  2149. hi def link treeToggleOff WarningMsg
  2150. hi def link treeDir Directory
  2151. hi def link treeUp Directory
  2152. hi def link treeCWD Statement
  2153. hi def link treeLink Title
  2154. hi def link treeOpenable Title
  2155. hi def link treeFlag ignore
  2156. hi def link treeRO WarningMsg
  2157. hi def link treeBookmark Statement
  2158. hi def link NERDTreeCurrentNode Search
  2159. endfunction
  2160. "FUNCTION: s:ShouldSplitToOpen() {{{2
  2161. "Returns 1 if opening a file from the tree in the given window requires it to
  2162. "be split
  2163. "
  2164. "Args:
  2165. "winnumber: the number of the window in question
  2166. function! s:ShouldSplitToOpen(winnumber)
  2167. if &hidden
  2168. return 0
  2169. endif
  2170. let oldwinnr = winnr()
  2171. exec a:winnumber . "wincmd p"
  2172. let modified = &modified
  2173. exec oldwinnr . "wincmd p"
  2174. return winnr("$") == 1 || (modified && s:BufInWindows(winbufnr(a:winnumber)) < 2)
  2175. endfunction
  2176. "FUNCTION: s:StripMarkupFromLine(line, removeLeadingSpaces){{{2
  2177. "returns the given line with all the tree parts stripped off
  2178. "
  2179. "Args:
  2180. "line: the subject line
  2181. "removeLeadingSpaces: 1 if leading spaces are to be removed (leading spaces =
  2182. "any spaces before the actual text of the node)
  2183. function! s:StripMarkupFromLine(line, removeLeadingSpaces)
  2184. let line = a:line
  2185. "remove the tree parts and the leading space
  2186. let line = substitute (line,"^" . s:tree_markup_reg . "*","","")
  2187. "strip off any read only flag
  2188. let line = substitute (line, s:tree_RO_str_reg, "","")
  2189. "strip off any bookmark flags
  2190. let line = substitute (line, ' {[^}]*}', "","")
  2191. let wasdir = 0
  2192. if line =~ '/$'
  2193. let wasdir = 1
  2194. endif
  2195. let line = substitute (line,' -> .*',"","") " remove link to
  2196. if wasdir == 1
  2197. let line = substitute (line, '/\?$', '/', "")
  2198. endif
  2199. if a:removeLeadingSpaces
  2200. let line = substitute (line, '^ *', '', '')
  2201. endif
  2202. return line
  2203. endfunction
  2204. "FUNCTION: s:Toggle(dir) {{{2
  2205. "Toggles the NERD tree. I.e the NERD tree is open, it is closed, if it is
  2206. "closed it is restored or initialized (if it doesnt exist)
  2207. "
  2208. "Args:
  2209. "dir: the full path for the root node (is only used if the NERD tree is being
  2210. "initialized.
  2211. function! s:Toggle(dir)
  2212. if s:TreeExistsForTab()
  2213. if !s:IsTreeOpen()
  2214. call s:CreateTreeWin()
  2215. call s:RenderView()
  2216. call s:RestoreScreenState()
  2217. else
  2218. call s:CloseTree()
  2219. endif
  2220. else
  2221. call s:InitNerdTree(a:dir)
  2222. endif
  2223. endfunction
  2224. "SECTION: Interface bindings {{{1
  2225. "============================================================
  2226. "FUNCTION: s:ActivateNode() {{{2
  2227. "If the current node is a file, open it in the previous window (or a new one
  2228. "if the previous is modified). If it is a directory then it is opened.
  2229. function! s:ActivateNode()
  2230. if getline(".") == s:tree_up_dir_line
  2231. return s:UpDir(0)
  2232. endif
  2233. let treenode = s:GetSelectedNode()
  2234. if treenode == {}
  2235. call s:EchoWarning("cannot open selected entry")
  2236. return
  2237. endif
  2238. if treenode.path.isDirectory
  2239. call treenode.ToggleOpen()
  2240. call s:RenderView()
  2241. call s:PutCursorOnNode(treenode, 0, 0)
  2242. else
  2243. call s:OpenFileNode(treenode)
  2244. endif
  2245. endfunction
  2246. "FUNCTION: s:BindMappings() {{{2
  2247. function! s:BindMappings()
  2248. " set up mappings and commands for this buffer
  2249. nnoremap <silent> <buffer> <middlerelease> :call <SID>HandleMiddleMouse()<cr>
  2250. nnoremap <silent> <buffer> <leftrelease> <leftrelease>:call <SID>CheckForActivate()<cr>
  2251. nnoremap <silent> <buffer> <2-leftmouse> :call <SID>ActivateNode()<cr>
  2252. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapActivateNode . " :call <SID>ActivateNode()<cr>"
  2253. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenSplit ." :call <SID>OpenEntrySplit()<cr>"
  2254. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapPreview ." :call <SID>PreviewNode(0)<cr>"
  2255. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapPreviewSplit ." :call <SID>PreviewNode(1)<cr>"
  2256. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapExecute ." :call <SID>ExecuteNode()<cr>"
  2257. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenRecursively ." :call <SID>OpenNodeRecursively()<cr>"
  2258. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapUpdirKeepOpen ." :call <SID>UpDir(1)<cr>"
  2259. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapUpdir ." :call <SID>UpDir(0)<cr>"
  2260. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapChangeRoot ." :call <SID>ChRoot()<cr>"
  2261. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapChdir ." :call <SID>ChCwd()<cr>"
  2262. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapQuit ." :NERDTreeToggle<cr>"
  2263. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapRefreshRoot ." :call <SID>RefreshRoot()<cr>"
  2264. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapRefresh ." :call <SID>RefreshCurrent()<cr>"
  2265. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapHelp ." :call <SID>DisplayHelp()<cr>"
  2266. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleHidden ." :call <SID>ToggleShowHidden()<cr>"
  2267. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleFilters ." :call <SID>ToggleIgnoreFilter()<cr>"
  2268. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleFiles ." :call <SID>ToggleShowFiles()<cr>"
  2269. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapCloseDir ." :call <SID>CloseCurrentDir()<cr>"
  2270. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapCloseChildren ." :call <SID>CloseChildren()<cr>"
  2271. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapFilesystemMenu ." :call <SID>ShowFileSystemMenu()<cr>"
  2272. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpParent ." :call <SID>JumpToParent()<cr>"
  2273. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpNextSibling ." :call <SID>JumpToSibling(1)<cr>"
  2274. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpPrevSibling ." :call <SID>JumpToSibling(0)<cr>"
  2275. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpFirstChild ." :call <SID>JumpToFirstChild()<cr>"
  2276. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpLastChild ." :call <SID>JumpToLastChild()<cr>"
  2277. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpRoot ." :call <SID>JumpToRoot()<cr>"
  2278. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenInTab ." :call <SID>OpenNodeNewTab(0)<cr>"
  2279. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenInTabSilent ." :call <SID>OpenNodeNewTab(1)<cr>"
  2280. exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenExpl ." :call <SID>OpenExplorer()<cr>"
  2281. command! -buffer -nargs=1 Bookmark :call <SID>BookmarkNode('<args>')
  2282. command! -buffer -complete=customlist,s:FindBookmarks -nargs=1 RevealBookmark :call <SID>RevealBookmark('<args>')
  2283. command! -buffer -complete=customlist,s:FindBookmarks -nargs=1 OpenBookmark :call <SID>OpenBookmark('<args>')
  2284. command! -buffer -complete=customlist,s:FindBookmarks -nargs=* ClearBookmarks call <SID>ClearBookmarks('<args>')
  2285. command! -buffer -complete=customlist,s:FindBookmarks -nargs=+ BookmarkToRoot call <SID>BookmarkToRoot('<args>')
  2286. command! -buffer -nargs=0 ClearAllBookmarks call <SID>ClearAllBookmarks() <bar> call <SID>RenderView()
  2287. command! -buffer -nargs=0 ReadBookmarks call <SID>ReadBookmarks() <bar> call <SID>RenderView()
  2288. command! -buffer -nargs=0 WriteBookmarks call <SID>WriteBookmarks()
  2289. endfunction
  2290. " FUNCTION: s:BookmarkNode(name) {{{2
  2291. " Associate the current node with the given name
  2292. function! s:BookmarkNode(name)
  2293. if a:name !~ '^[0-9a-zA-Z_]*$'
  2294. call s:Echo("Bookmarks must be named using numbers, letters and underscores only")
  2295. return
  2296. endif
  2297. let currentNode = s:GetSelectedNode()
  2298. if currentNode != {}
  2299. try
  2300. let oldMarkedNode = s:GetNodeForBookmark(a:name, 1)
  2301. call oldMarkedNode.path.UncacheBookmark(a:name)
  2302. catch /NERDTree.Bookmark\(DoesntExist\|NotFound\)/
  2303. endtry
  2304. let bookmarks = s:GetBookmarks()
  2305. let bookmarks[a:name] = currentNode.path
  2306. call currentNode.path.CacheBookmarkNames()
  2307. call s:WriteBookmarks()
  2308. call s:RenderView()
  2309. else
  2310. call s:Echo("select a node first")
  2311. endif
  2312. endfunction
  2313. " FUNCTION: s:BookmarkToRoot(name) {{{2
  2314. " Make the node for the given bookmark the new tree root
  2315. function! s:BookmarkToRoot(name)
  2316. try
  2317. let targetNode = s:GetNodeForBookmark(a:name, 1)
  2318. catch /NERDTree.BookmarkNotFound/
  2319. let bookmarks = s:GetBookmarks()
  2320. let targetNode = s:oTreeFileNode.New(bookmarks[a:name])
  2321. endtry
  2322. call targetNode.MakeRoot()
  2323. call s:RenderView()
  2324. call s:PutCursorOnNode(targetNode, 0, 0)
  2325. endfunction
  2326. "FUNCTION: s:CheckForActivate() {{{2
  2327. "Checks if the click should open the current node, if so then activate() is
  2328. "called (directories are automatically opened if the symbol beside them is
  2329. "clicked)
  2330. function! s:CheckForActivate()
  2331. let currentNode = s:GetSelectedNode()
  2332. if currentNode != {}
  2333. let startToCur = strpart(getline(line(".")), 0, col("."))
  2334. let char = strpart(startToCur, strlen(startToCur)-1, 1)
  2335. "if they clicked a dir, check if they clicked on the + or ~ sign
  2336. "beside it
  2337. if currentNode.path.isDirectory
  2338. let reg = '^' . s:tree_markup_reg .'*[' . s:tree_dir_open . s:tree_dir_closed . ']$'
  2339. if startToCur =~ reg
  2340. call s:ActivateNode()
  2341. return
  2342. endif
  2343. endif
  2344. if (g:NERDTreeMouseMode == 2 && currentNode.path.isDirectory) || g:NERDTreeMouseMode == 3
  2345. if char !~ s:tree_markup_reg && startToCur !~ '\/$'
  2346. call s:ActivateNode()
  2347. return
  2348. endif
  2349. endif
  2350. endif
  2351. endfunction
  2352. " FUNCTION: s:ChCwd() {{{2
  2353. function! s:ChCwd()
  2354. let treenode = s:GetSelectedNode()
  2355. if treenode == {}
  2356. call s:Echo("Select a node first")
  2357. return
  2358. endif
  2359. try
  2360. call treenode.path.ChangeToDir()
  2361. catch /^NERDTree.Path.Change/
  2362. call s:EchoWarning("could not change cwd")
  2363. endtry
  2364. endfunction
  2365. " FUNCTION: s:ChRoot() {{{2
  2366. " changes the current root to the selected one
  2367. function! s:ChRoot()
  2368. let treenode = s:GetSelectedNode()
  2369. if treenode == {}
  2370. call s:Echo("Select a node first")
  2371. return
  2372. endif
  2373. call treenode.MakeRoot()
  2374. call s:RenderView()
  2375. call s:PutCursorOnNode(t:NERDTreeRoot, 0, 0)
  2376. endfunction
  2377. " FUNCTION: s:ClearBookmarks(bookmarks) {{{2
  2378. function! s:ClearBookmarks(bookmarks)
  2379. let bookmarks = s:GetBookmarks()
  2380. if a:bookmarks == ''
  2381. let currentNode = s:GetSelectedNode()
  2382. if currentNode != {}
  2383. call currentNode.ClearBookmarks()
  2384. endif
  2385. else
  2386. for name in split(a:bookmarks, ' ')
  2387. if count(keys(bookmarks), name)
  2388. let node = {}
  2389. try
  2390. let node = s:GetNodeForBookmark(name, 1)
  2391. catch /NERDTree/
  2392. endtry
  2393. call remove(bookmarks, name)
  2394. if !empty(node)
  2395. call node.path.CacheBookmarkNames()
  2396. endif
  2397. endif
  2398. endfor
  2399. endif
  2400. call s:WriteBookmarks()
  2401. call s:RenderView()
  2402. endfunction
  2403. " FUNCTION: s:CloseChildren() {{{2
  2404. " closes all childnodes of the current node
  2405. function! s:CloseChildren()
  2406. let currentNode = s:GetSelectedDir()
  2407. if currentNode == {}
  2408. call s:Echo("Select a node first")
  2409. return
  2410. endif
  2411. call currentNode.CloseChildren()
  2412. call s:RenderView()
  2413. call s:PutCursorOnNode(currentNode, 0, 0)
  2414. endfunction
  2415. " FUNCTION: s:CloseCurrentDir() {{{2
  2416. " closes the parent dir of the current node
  2417. function! s:CloseCurrentDir()
  2418. let treenode = s:GetSelectedNode()
  2419. if treenode == {}
  2420. call s:Echo("Select a node first")
  2421. return
  2422. endif
  2423. let parent = treenode.parent
  2424. if parent.IsRoot()
  2425. call s:Echo("cannot close tree root")
  2426. else
  2427. call treenode.parent.Close()
  2428. call s:RenderView()
  2429. call s:PutCursorOnNode(treenode.parent, 0, 0)
  2430. endif
  2431. endfunction
  2432. " FUNCTION: s:CopyNode() {{{2
  2433. function! s:CopyNode()
  2434. let currentNode = s:GetSelectedNode()
  2435. if currentNode == {}
  2436. call s:Echo("Put the cursor on a file node first")
  2437. return
  2438. endif
  2439. let newNodePath = input("Copy the current node\n" .
  2440. \ "==========================================================\n" .
  2441. \ "Enter the new path to copy the node to: \n" .
  2442. \ "", currentNode.path.Str(0))
  2443. if newNodePath != ""
  2444. "strip trailing slash
  2445. let newNodePath = substitute(newNodePath, '\/$', '', '')
  2446. let confirmed = 1
  2447. if currentNode.path.CopyingWillOverwrite(newNodePath)
  2448. echo "\nWarning: copying may overwrite files! Continue? (yN)"
  2449. let choice = nr2char(getchar())
  2450. let confirmed = choice == 'y'
  2451. endif
  2452. if confirmed
  2453. try
  2454. let newNode = currentNode.Copy(newNodePath)
  2455. call s:RenderView()
  2456. call s:PutCursorOnNode(newNode, 0, 0)
  2457. catch /^NERDTree/
  2458. call s:EchoWarning("Could not copy node")
  2459. endtry
  2460. endif
  2461. else
  2462. call s:Echo("Copy aborted.")
  2463. endif
  2464. redraw
  2465. endfunction
  2466. " FUNCTION: s:DeleteNode() {{{2
  2467. " if the current node is a file, pops up a dialog giving the user the option
  2468. " to delete it
  2469. function! s:DeleteNode()
  2470. let currentNode = s:GetSelectedNode()
  2471. if currentNode == {}
  2472. call s:Echo("Put the cursor on a file node first")
  2473. return
  2474. endif
  2475. let confirmed = 0
  2476. if currentNode.path.isDirectory
  2477. let choice =input("Delete the current node\n" .
  2478. \ "==========================================================\n" .
  2479. \ "STOP! To delete this entire directory, type 'yes'\n" .
  2480. \ "" . currentNode.path.StrForOS(0) . ": ")
  2481. let confirmed = choice == 'yes'
  2482. else
  2483. echo "Delete the current node\n" .
  2484. \ "==========================================================\n".
  2485. \ "Are you sure you wish to delete the node:\n" .
  2486. \ "" . currentNode.path.StrForOS(0) . " (yN):"
  2487. let choice = nr2char(getchar())
  2488. let confirmed = choice == 'y'
  2489. endif
  2490. if confirmed
  2491. try
  2492. call currentNode.Delete()
  2493. call s:RenderView()
  2494. "if the node is open in a buffer, ask the user if they want to
  2495. "close that buffer
  2496. let bufnum = bufnr(currentNode.path.Str(0))
  2497. if buflisted(bufnum)
  2498. let prompt = "\nNode deleted.\n\nThe file is open in buffer ". bufnum . (bufwinnr(bufnum) == -1 ? " (hidden)" : "") .". Delete this buffer? (yN)"
  2499. call s:PromptToDelBuffer(bufnum, prompt)
  2500. endif
  2501. redraw
  2502. catch /^NERDTree/
  2503. call s:EchoWarning("Could not remove node")
  2504. endtry
  2505. else
  2506. call s:Echo("delete aborted" )
  2507. endif
  2508. endfunction
  2509. " FUNCTION: s:DisplayHelp() {{{2
  2510. " toggles the help display
  2511. function! s:DisplayHelp()
  2512. let t:treeShowHelp = t:treeShowHelp ? 0 : 1
  2513. call s:RenderView()
  2514. call s:CenterView()
  2515. endfunction
  2516. " FUNCTION: s:ExecuteNode() {{{2
  2517. function! s:ExecuteNode()
  2518. let treenode = s:GetSelectedNode()
  2519. if treenode == {} || treenode.path.isDirectory
  2520. call s:Echo("Select an executable file node first" )
  2521. else
  2522. echo "NERDTree executor\n" .
  2523. \ "==========================================================\n".
  2524. \ "Complete the command to execute (add arguments etc): \n\n"
  2525. let cmd = treenode.path.StrForOS(1)
  2526. let cmd = input(':!', cmd . ' ')
  2527. if cmd != ''
  2528. exec ':!' . cmd
  2529. else
  2530. call s:Echo("command aborted")
  2531. endif
  2532. endif
  2533. endfunction
  2534. " FUNCTION: s:HandleMiddleMouse() {{{2
  2535. function! s:HandleMiddleMouse()
  2536. let curNode = s:GetSelectedNode()
  2537. if curNode == {}
  2538. call s:Echo("Put the cursor on a node first" )
  2539. return
  2540. endif
  2541. if curNode.path.isDirectory
  2542. call s:OpenExplorer()
  2543. else
  2544. call s:OpenEntrySplit()
  2545. endif
  2546. endfunction
  2547. " FUNCTION: s:InsertNewNode() {{{2
  2548. " Adds a new node to the filesystem and then into the tree
  2549. function! s:InsertNewNode()
  2550. let curDirNode = s:GetSelectedDir()
  2551. if curDirNode == {}
  2552. call s:Echo("Put the cursor on a node first" )
  2553. return
  2554. endif
  2555. let newNodeName = input("Add a childnode\n".
  2556. \ "==========================================================\n".
  2557. \ "Enter the dir/file name to be created. Dirs end with a '/'\n" .
  2558. \ "", curDirNode.path.StrForGlob() . s:os_slash)
  2559. if newNodeName == ''
  2560. call s:Echo("Node Creation Aborted.")
  2561. return
  2562. endif
  2563. try
  2564. let newPath = s:oPath.Create(newNodeName)
  2565. let parentNode = t:NERDTreeRoot.FindNode(newPath.GetPathTrunk())
  2566. let newTreeNode = s:oTreeFileNode.New(newPath)
  2567. if parentNode.isOpen || !empty(parentNode.children)
  2568. call parentNode.AddChild(newTreeNode, 1)
  2569. call s:RenderView()
  2570. call s:PutCursorOnNode(newTreeNode, 1, 0)
  2571. endif
  2572. catch /^NERDTree/
  2573. call s:EchoWarning("Node Not Created.")
  2574. endtry
  2575. endfunction
  2576. " FUNCTION: s:JumpToFirstChild() {{{2
  2577. " wrapper for the jump to child method
  2578. function! s:JumpToFirstChild()
  2579. call s:JumpToChild(0)
  2580. endfunction
  2581. " FUNCTION: s:JumpToLastChild() {{{2
  2582. " wrapper for the jump to child method
  2583. function! s:JumpToLastChild()
  2584. call s:JumpToChild(1)
  2585. endfunction
  2586. " FUNCTION: s:JumpToParent() {{{2
  2587. " moves the cursor to the parent of the current node
  2588. function! s:JumpToParent()
  2589. let currentNode = s:GetSelectedNode()
  2590. if !empty(currentNode)
  2591. if !empty(currentNode.parent)
  2592. call s:PutCursorOnNode(currentNode.parent, 1, 0)
  2593. call s:CenterView()
  2594. else
  2595. call s:Echo("cannot jump to parent")
  2596. endif
  2597. else
  2598. call s:Echo("put the cursor on a node first")
  2599. endif
  2600. endfunction
  2601. " FUNCTION: s:JumpToRoot() {{{2
  2602. " moves the cursor to the root node
  2603. function! s:JumpToRoot()
  2604. call s:PutCursorOnNode(t:NERDTreeRoot, 1, 0)
  2605. call s:CenterView()
  2606. endfunction
  2607. " FUNCTION: s:JumpToSibling() {{{2
  2608. " moves the cursor to the sibling of the current node in the given direction
  2609. "
  2610. " Args:
  2611. " forward: 1 if the cursor should move to the next sibling, 0 if it should
  2612. " move back to the previous sibling
  2613. function! s:JumpToSibling(forward)
  2614. let currentNode = s:GetSelectedNode()
  2615. if !empty(currentNode)
  2616. if !currentNode.path.isDirectory
  2617. if a:forward
  2618. let sibling = currentNode.parent.FindSibling(1)
  2619. else
  2620. let sibling = currentNode.parent
  2621. endif
  2622. else
  2623. let sibling = currentNode.FindSibling(a:forward)
  2624. endif
  2625. if !empty(sibling)
  2626. call s:PutCursorOnNode(sibling, 1, 0)
  2627. call s:CenterView()
  2628. endif
  2629. else
  2630. call s:Echo("put the cursor on a node first")
  2631. endif
  2632. endfunction
  2633. " FUNCTION: s:OpenBookmark(name) {{{2
  2634. " put the cursor on the given bookmark and, if its a file, open it
  2635. function! s:OpenBookmark(name)
  2636. try
  2637. let targetNode = s:GetNodeForBookmark(a:name, 0)
  2638. call s:PutCursorOnNode(targetNode, 0, 1)
  2639. redraw!
  2640. catch /NERDTree.BookmarkNotFound/
  2641. call s:Echo("note - target node is not cached")
  2642. let bookmarks = s:GetBookmarks()
  2643. let targetNode = s:oTreeFileNode.New(bookmarks[a:name])
  2644. endtry
  2645. if targetNode.path.isDirectory
  2646. call s:OpenExplorerFor(targetNode)
  2647. else
  2648. call s:OpenFileNode(targetNode)
  2649. endif
  2650. endfunction
  2651. " FUNCTION: s:OpenEntrySplit() {{{2
  2652. " Opens the currently selected file from the explorer in a
  2653. " new window
  2654. function! s:OpenEntrySplit()
  2655. let treenode = s:GetSelectedNode()
  2656. if treenode != {}
  2657. call s:OpenFileNodeSplit(treenode)
  2658. else
  2659. call s:Echo("select a node first")
  2660. endif
  2661. endfunction
  2662. " FUNCTION: s:OpenExplorer() {{{2
  2663. function! s:OpenExplorer()
  2664. let treenode = s:GetSelectedDir()
  2665. if treenode != {}
  2666. call s:OpenExplorerFor(treenode)
  2667. else
  2668. call s:Echo("select a node first")
  2669. endif
  2670. endfunction
  2671. " FUNCTION: s:OpenNodeNewTab(stayCurrentTab) {{{2
  2672. " Opens the currently selected file from the explorer in a
  2673. " new tab
  2674. "
  2675. " Args:
  2676. " stayCurrentTab: if 1 then vim will stay in the current tab, if 0 then vim
  2677. " will go to the tab where the new file is opened
  2678. function! s:OpenNodeNewTab(stayCurrentTab)
  2679. let treenode = s:GetSelectedNode()
  2680. if treenode != {}
  2681. let curTabNr = tabpagenr()
  2682. exec "tabedit " . treenode.path.StrForEditCmd()
  2683. if a:stayCurrentTab
  2684. exec "tabnext " . curTabNr
  2685. endif
  2686. else
  2687. call s:Echo("select a node first")
  2688. endif
  2689. endfunction
  2690. " FUNCTION: s:OpenNodeRecursively() {{{2
  2691. function! s:OpenNodeRecursively()
  2692. let treenode = s:GetSelectedNode()
  2693. if treenode == {} || treenode.path.isDirectory == 0
  2694. call s:Echo("Select a directory node first" )
  2695. else
  2696. call s:Echo("Recursively opening node. Please wait...")
  2697. call treenode.OpenRecursively()
  2698. call s:RenderView()
  2699. redraw
  2700. call s:Echo("Recursively opening node. Please wait... DONE")
  2701. endif
  2702. endfunction
  2703. "FUNCTION: s:PreviewNode() {{{2
  2704. function! s:PreviewNode(openNewWin)
  2705. let treenode = s:GetSelectedNode()
  2706. if treenode == {} || treenode.path.isDirectory
  2707. call s:Echo("Select a file node first" )
  2708. return
  2709. endif
  2710. if a:openNewWin
  2711. call s:OpenEntrySplit()
  2712. else
  2713. call s:ActivateNode()
  2714. end
  2715. call s:PutCursorInTreeWin()
  2716. endfunction
  2717. " FUNCTION: s:RevealBookmark(name) {{{2
  2718. " put the cursor on the node associate with the given name
  2719. function! s:RevealBookmark(name)
  2720. try
  2721. let targetNode = s:GetNodeForBookmark(a:name, 0)
  2722. call s:PutCursorOnNode(targetNode, 0, 1)
  2723. catch /NERDTree.BookmarkDoesntExist/
  2724. call s:Echo("Bookmark isnt cached under the current root")
  2725. endtry
  2726. endfunction
  2727. " FUNCTION: s:RefreshRoot() {{{2
  2728. " Reloads the current root. All nodes below this will be lost and the root dir
  2729. " will be reloaded.
  2730. function! s:RefreshRoot()
  2731. call s:Echo("Refreshing the root node. This could take a while...")
  2732. call t:NERDTreeRoot.Refresh()
  2733. call s:RenderView()
  2734. redraw
  2735. call s:Echo("Refreshing the root node. This could take a while... DONE")
  2736. endfunction
  2737. " FUNCTION: s:RefreshCurrent() {{{2
  2738. " refreshes the root for the current node
  2739. function! s:RefreshCurrent()
  2740. let treenode = s:GetSelectedDir()
  2741. if treenode == {}
  2742. call s:Echo("Refresh failed. Select a node first")
  2743. return
  2744. endif
  2745. call s:Echo("Refreshing node. This could take a while...")
  2746. call treenode.Refresh()
  2747. call s:RenderView()
  2748. redraw
  2749. call s:Echo("Refreshing node. This could take a while... DONE")
  2750. endfunction
  2751. " FUNCTION: s:RenameCurrent() {{{2
  2752. " allows the user to rename the current node
  2753. function! s:RenameCurrent()
  2754. let curNode = s:GetSelectedNode()
  2755. if curNode == {}
  2756. call s:Echo("Put the cursor on a node first" )
  2757. return
  2758. endif
  2759. let newNodePath = input("Rename the current node\n" .
  2760. \ "==========================================================\n" .
  2761. \ "Enter the new path for the node: \n" .
  2762. \ "", curNode.path.StrForOS(0))
  2763. if newNodePath == ''
  2764. call s:Echo("Node Renaming Aborted.")
  2765. return
  2766. endif
  2767. try
  2768. let bufnum = bufnr(curNode.path.Str(0))
  2769. call curNode.Rename(newNodePath)
  2770. call s:RenderView()
  2771. "if the node is open in a buffer, ask the user if they want to
  2772. "close that buffer
  2773. if bufnum != -1
  2774. let prompt = "\nNode renamed.\n\nThe old file is open in buffer ". bufnum . (bufwinnr(bufnum) == -1 ? " (hidden)" : "") .". Delete this buffer? (yN)"
  2775. call s:PromptToDelBuffer(bufnum, prompt)
  2776. endif
  2777. call s:PutCursorOnNode(curNode, 1, 0)
  2778. redraw
  2779. catch /^NERDTree/
  2780. call s:EchoWarning("Node Not Renamed.")
  2781. endtry
  2782. endfunction
  2783. " FUNCTION: s:ShowFileSystemMenu() {{{2
  2784. function! s:ShowFileSystemMenu()
  2785. let curNode = s:GetSelectedNode()
  2786. if curNode == {}
  2787. call s:Echo("Put the cursor on a node first" )
  2788. return
  2789. endif
  2790. let prompt = "NERDTree Filesystem Menu\n" .
  2791. \ "==========================================================\n".
  2792. \ "Select the desired operation: \n" .
  2793. \ " (a)dd a childnode\n".
  2794. \ " (m)ove the current node\n".
  2795. \ " (d)elete the current node\n"
  2796. if s:oPath.CopyingSupported()
  2797. let prompt = prompt . " (c)opy the current node\n\n"
  2798. else
  2799. let prompt = prompt . " \n"
  2800. endif
  2801. echo prompt
  2802. let choice = nr2char(getchar())
  2803. if choice ==? "a"
  2804. call s:InsertNewNode()
  2805. elseif choice ==? "m"
  2806. call s:RenameCurrent()
  2807. elseif choice ==? "d"
  2808. call s:DeleteNode()
  2809. elseif choice ==? "c" && s:oPath.CopyingSupported()
  2810. call s:CopyNode()
  2811. endif
  2812. endfunction
  2813. " FUNCTION: s:ToggleIgnoreFilter() {{{2
  2814. " toggles the use of the NERDTreeIgnore option
  2815. function! s:ToggleIgnoreFilter()
  2816. let t:NERDTreeIgnoreEnabled = !t:NERDTreeIgnoreEnabled
  2817. call s:RenderViewSavingPosition()
  2818. call s:CenterView()
  2819. endfunction
  2820. " FUNCTION: s:ToggleShowFiles() {{{2
  2821. " toggles the display of hidden files
  2822. function! s:ToggleShowFiles()
  2823. let g:NERDTreeShowFiles = !g:NERDTreeShowFiles
  2824. call s:RenderViewSavingPosition()
  2825. call s:CenterView()
  2826. endfunction
  2827. " FUNCTION: s:ToggleShowHidden() {{{2
  2828. " toggles the display of hidden files
  2829. function! s:ToggleShowHidden()
  2830. let g:NERDTreeShowHidden = !g:NERDTreeShowHidden
  2831. call s:RenderViewSavingPosition()
  2832. call s:CenterView()
  2833. endfunction
  2834. "FUNCTION: s:UpDir(keepState) {{{2
  2835. "moves the tree up a level
  2836. "
  2837. "Args:
  2838. "keepState: 1 if the current root should be left open when the tree is
  2839. "re-rendered
  2840. function! s:UpDir(keepState)
  2841. let cwd = t:NERDTreeRoot.path.Str(0)
  2842. if cwd == "/" || cwd =~ '^[^/]..$'
  2843. call s:Echo("already at top dir")
  2844. else
  2845. if !a:keepState
  2846. call t:NERDTreeRoot.Close()
  2847. endif
  2848. let oldRoot = t:NERDTreeRoot
  2849. if empty(t:NERDTreeRoot.parent)
  2850. let path = t:NERDTreeRoot.path.GetPathTrunk()
  2851. let newRoot = s:oTreeDirNode.New(path)
  2852. call newRoot.Open()
  2853. call newRoot.TransplantChild(t:NERDTreeRoot)
  2854. let t:NERDTreeRoot = newRoot
  2855. else
  2856. let t:NERDTreeRoot = t:NERDTreeRoot.parent
  2857. endif
  2858. call s:RenderView()
  2859. call s:PutCursorOnNode(oldRoot, 0, 0)
  2860. endif
  2861. endfunction
  2862. " vim: set sw=4 sts=4 et fdm=marker: