From 3adcf542289a0883924ae9b9be8b898c36702c95 Mon Sep 17 00:00:00 2001 From: Sam Chudnick Date: Sun, 11 Jun 2023 07:54:59 -0400 Subject: Add some Vim plugins --- .../start/nerdtree/lib/nerdtree/bookmark.vim | 365 +++++++++ .../vendor/start/nerdtree/lib/nerdtree/creator.vim | 402 ++++++++++ .../vendor/start/nerdtree/lib/nerdtree/event.vim | 13 + .../start/nerdtree/lib/nerdtree/flag_set.vim | 58 ++ .../vendor/start/nerdtree/lib/nerdtree/key_map.vim | 164 ++++ .../nerdtree/lib/nerdtree/menu_controller.vim | 211 +++++ .../start/nerdtree/lib/nerdtree/menu_item.vim | 118 +++ .../start/nerdtree/lib/nerdtree/nerdtree.vim | 209 +++++ .../start/nerdtree/lib/nerdtree/notifier.vim | 35 + .../vendor/start/nerdtree/lib/nerdtree/opener.vim | 326 ++++++++ .../vendor/start/nerdtree/lib/nerdtree/path.vim | 852 +++++++++++++++++++++ .../start/nerdtree/lib/nerdtree/tree_dir_node.vim | 706 +++++++++++++++++ .../start/nerdtree/lib/nerdtree/tree_file_node.vim | 349 +++++++++ .../pack/vendor/start/nerdtree/lib/nerdtree/ui.vim | 532 +++++++++++++ 14 files changed, 4340 insertions(+) create mode 100644 .vim/pack/vendor/start/nerdtree/lib/nerdtree/bookmark.vim create mode 100644 .vim/pack/vendor/start/nerdtree/lib/nerdtree/creator.vim create mode 100644 .vim/pack/vendor/start/nerdtree/lib/nerdtree/event.vim create mode 100644 .vim/pack/vendor/start/nerdtree/lib/nerdtree/flag_set.vim create mode 100644 .vim/pack/vendor/start/nerdtree/lib/nerdtree/key_map.vim create mode 100644 .vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_controller.vim create mode 100644 .vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_item.vim create mode 100644 .vim/pack/vendor/start/nerdtree/lib/nerdtree/nerdtree.vim create mode 100644 .vim/pack/vendor/start/nerdtree/lib/nerdtree/notifier.vim create mode 100644 .vim/pack/vendor/start/nerdtree/lib/nerdtree/opener.vim create mode 100644 .vim/pack/vendor/start/nerdtree/lib/nerdtree/path.vim create mode 100644 .vim/pack/vendor/start/nerdtree/lib/nerdtree/tree_dir_node.vim create mode 100644 .vim/pack/vendor/start/nerdtree/lib/nerdtree/tree_file_node.vim create mode 100644 .vim/pack/vendor/start/nerdtree/lib/nerdtree/ui.vim (limited to '.vim/pack/vendor/start/nerdtree/lib') diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/bookmark.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/bookmark.vim new file mode 100644 index 0000000..37be451 --- /dev/null +++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/bookmark.vim @@ -0,0 +1,365 @@ +" ============================================================================ +" CLASS: Bookmark +" +" The Bookmark class serves two purposes: +" (1) It is the top-level prototype for new, concrete Bookmark objects. +" (2) It provides an interface for client code to query and manipulate the +" global list of Bookmark objects within the current Vim session. +" ============================================================================ + + +let s:Bookmark = {} +let g:NERDTreeBookmark = s:Bookmark + +" FUNCTION: Bookmark.activate(nerdtree) {{{1 +function! s:Bookmark.activate(nerdtree, ...) + call self.open(a:nerdtree, a:0 ? a:1 : {}) +endfunction + +" FUNCTION: Bookmark.AddBookmark(name, path) {{{1 +" Class method to add a new bookmark to the list, if a previous bookmark exists +" with the same name, just update the path for that bookmark +function! s:Bookmark.AddBookmark(name, path) + for i in s:Bookmark.Bookmarks() + if i.name ==# a:name + let i.path = a:path + return + endif + endfor + call add(s:Bookmark.Bookmarks(), s:Bookmark.New(a:name, a:path)) +endfunction + +" FUNCTION: Bookmark.Bookmarks() {{{1 +" Class method to get all bookmarks. Lazily initializes the bookmarks global +" variable +function! s:Bookmark.Bookmarks() + if !exists('g:NERDTreeBookmarks') + let g:NERDTreeBookmarks = [] + endif + return g:NERDTreeBookmarks +endfunction + +" FUNCTION: Bookmark.BookmarkExistsFor(name) {{{1 +" class method that returns 1 if a bookmark with the given name is found, 0 +" otherwise +function! s:Bookmark.BookmarkExistsFor(name) + try + call s:Bookmark.BookmarkFor(a:name) + return 1 + catch /^NERDTree.BookmarkNotFoundError/ + return 0 + endtry +endfunction + +" FUNCTION: Bookmark.BookmarkFor(name) {{{1 +" Class method that returns the Bookmark object having the specified name. +" Throws NERDTree.BookmarkNotFoundError if no Bookmark is found. +function! s:Bookmark.BookmarkFor(name) + let l:result = {} + for l:bookmark in s:Bookmark.Bookmarks() + if l:bookmark.name ==# a:name + let l:result = l:bookmark + break + endif + endfor + if empty(l:result) + throw 'NERDTree.BookmarkNotFoundError: "' . a:name . '" not found' + endif + return l:result +endfunction + +" FUNCTION: Bookmark.BookmarkNames() {{{1 +" Class method to return an array of all bookmark names +function! s:Bookmark.BookmarkNames() + let names = [] + for i in s:Bookmark.Bookmarks() + call add(names, i.name) + endfor + return names +endfunction + +" FUNCTION: Bookmark.CacheBookmarks(silent) {{{1 +" Class method to read all bookmarks from the bookmarks file initialize +" bookmark objects for each one. +" +" Args: +" silent - dont echo an error msg if invalid bookmarks are found +function! s:Bookmark.CacheBookmarks(silent) + if filereadable(g:NERDTreeBookmarksFile) + let g:NERDTreeBookmarks = [] + let g:NERDTreeInvalidBookmarks = [] + let bookmarkStrings = readfile(g:NERDTreeBookmarksFile) + let invalidBookmarksFound = 0 + for i in bookmarkStrings + + "ignore blank lines + if i !=# '' + + let name = substitute(i, '^\(.\{-}\) .*$', '\1', '') + let path = substitute(i, '^.\{-} \(.*\)$', '\1', '') + let path = fnamemodify(path, ':p') + + try + let bookmark = s:Bookmark.New(name, g:NERDTreePath.New(path)) + call add(g:NERDTreeBookmarks, bookmark) + catch /^NERDTree.InvalidArgumentsError/ + call add(g:NERDTreeInvalidBookmarks, i) + let invalidBookmarksFound += 1 + endtry + endif + endfor + if invalidBookmarksFound + call s:Bookmark.Write() + if !a:silent + call nerdtree#echo(invalidBookmarksFound . ' invalid bookmarks were read. See :help NERDTreeInvalidBookmarks for info.') + endif + endif + endif +endfunction + +" FUNCTION: Bookmark.CompareBookmarksByName(firstBookmark, secondBookmark) {{{1 +" Class method that indicates the relative position of two bookmarks when +" placed in alphabetical order by name. Case-sensitivity is determined by an +" option. Supports the s:Bookmark.SortBookmarksList() method. +function! s:Bookmark.CompareBookmarksByName(firstBookmark, secondBookmark) + let l:result = 0 + if g:NERDTreeBookmarksSort ==# 1 + if a:firstBookmark.name ? a:secondBookmark.name + let l:result = 1 + endif + elseif g:NERDTreeBookmarksSort ==# 2 + if a:firstBookmark.name <# a:secondBookmark.name + let l:result = -1 + elseif a:firstBookmark.name ># a:secondBookmark.name + let l:result = 1 + endif + endif + return l:result +endfunction + +" FUNCTION: Bookmark.ClearAll() {{{1 +" Class method to delete all bookmarks. +function! s:Bookmark.ClearAll() + for i in s:Bookmark.Bookmarks() + call i.delete() + endfor + call s:Bookmark.Write() +endfunction + +" FUNCTION: Bookmark.delete() {{{1 +" Delete this bookmark. If the node for this bookmark is under the current +" root, then recache bookmarks for its Path object +function! s:Bookmark.delete() + call remove(s:Bookmark.Bookmarks(), index(s:Bookmark.Bookmarks(), self)) + call s:Bookmark.Write() +endfunction + +" FUNCTION: s:Edit() {{{1 +" opens the NERDTreeBookmarks file for manual editing +function! s:Bookmark.Edit() + call nerdtree#exec('wincmd w', 1) + call nerdtree#exec('edit '.g:NERDTreeBookmarksFile, 1) +endfunction + +" FUNCTION: Bookmark.getNode(nerdtree, searchFromAbsoluteRoot) {{{1 +" Returns the tree node object associated with this Bookmark. +" Throws NERDTree.BookmarkedNodeNotFoundError if the node is not found. +" +" Args: +" searchFromAbsoluteRoot: boolean flag, search from the highest cached node +" if true and from the current tree root if false +function! s:Bookmark.getNode(nerdtree, searchFromAbsoluteRoot) + if a:searchFromAbsoluteRoot + let l:searchRoot = a:nerdtree.root.AbsoluteTreeRoot() + else + let l:searchRoot = a:nerdtree.root + endif + let l:targetNode = l:searchRoot.findNode(self.path) + if empty(l:targetNode) + throw 'NERDTree.BookmarkedNodeNotFoundError: node for bookmark "' . self.name . '" not found' + endif + return l:targetNode +endfunction + +" FUNCTION: Bookmark.GetNodeForName(name, searchFromAbsoluteRoot, nerdtree) {{{1 +" Class method that returns the tree node object for the Bookmark with the +" given name. Throws NERDTree.BookmarkNotFoundError if a Bookmark with the +" name does not exist. Throws NERDTree.BookmarkedNodeNotFoundError if a +" tree node for the named Bookmark could not be found. +function! s:Bookmark.GetNodeForName(name, searchFromAbsoluteRoot, nerdtree) + let l:bookmark = s:Bookmark.BookmarkFor(a:name) + return l:bookmark.getNode(a:nerdtree, a:searchFromAbsoluteRoot) +endfunction + +" FUNCTION: Bookmark.GetSelected() {{{1 +" returns the Bookmark the cursor is over, or {} +function! s:Bookmark.GetSelected() + let line = getline('.') + let name = substitute(line, '^>\(.\{-}\) .\+$', '\1', '') + if name !=# line + try + return s:Bookmark.BookmarkFor(name) + catch /^NERDTree.BookmarkNotFoundError/ + return {} + endtry + endif + return {} +endfunction + +" FUNCTION: Bookmark.InvalidBookmarks() {{{1 +" Class method to get all invalid bookmark strings read from the bookmarks +" file +function! s:Bookmark.InvalidBookmarks() + if !exists('g:NERDTreeInvalidBookmarks') + let g:NERDTreeInvalidBookmarks = [] + endif + return g:NERDTreeInvalidBookmarks +endfunction + +" FUNCTION: Bookmark.mustExist() {{{1 +function! s:Bookmark.mustExist() + if !self.path.exists() + call s:Bookmark.CacheBookmarks(1) + throw 'NERDTree.BookmarkPointsToInvalidLocationError: the bookmark "'. + \ self.name .'" points to a non existing location: "'. self.path.str() + endif +endfunction + +" FUNCTION: Bookmark.New(name, path) {{{1 +" Create a new bookmark object with the given name and path object +function! s:Bookmark.New(name, path) + if a:name =~# ' ' + throw 'NERDTree.IllegalBookmarkNameError: illegal name:' . a:name + endif + + let newBookmark = copy(self) + let newBookmark.name = a:name + let newBookmark.path = a:path + return newBookmark +endfunction + +" FUNCTION: Bookmark.open(nerdtree, [options]) {{{1 +"Args: +" +"nerdtree: the tree to load open the bookmark in +" +"A dictionary containing the following keys (all optional): +" 'where': Specifies whether the node should be opened in new split/tab or in +" the previous window. Can be either 'v' (vertical split), 'h' +" (horizontal split), 't' (new tab) or 'p' (previous window). +" 'reuse': if a window is displaying the file then jump the cursor there +" 'keepopen': dont close the tree window +" 'stay': open the file, but keep the cursor in the tree win +" +function! s:Bookmark.open(nerdtree, ...) + let opts = a:0 ? a:1 : {} + + if nerdtree#closeBookmarksOnOpen() + call a:nerdtree.ui.toggleShowBookmarks() + endif + + if self.path.isDirectory && !has_key(opts, 'where') + call self.toRoot(a:nerdtree) + else + let opener = g:NERDTreeOpener.New(self.path, opts) + call opener.open(self) + endif +endfunction + +" FUNCTION: Bookmark.openInNewTab(options) {{{1 +" Create a new bookmark object with the given name and path object +function! s:Bookmark.openInNewTab(options) + call nerdtree#deprecated('Bookmark.openInNewTab', 'is deprecated, use open() instead') + call self.open(a:options) +endfunction + +" FUNCTION: Bookmark.setPath(path) {{{1 +" makes this bookmark point to the given path +function! s:Bookmark.setPath(path) + let self.path = a:path +endfunction + +" FUNCTION: Bookmark.SortBookmarksList() {{{1 +" Class method that sorts the global list of bookmarks alphabetically by name. +" Note that case-sensitivity is determined by a user option. +function! s:Bookmark.SortBookmarksList() + call sort(s:Bookmark.Bookmarks(), s:Bookmark.CompareBookmarksByName, s:Bookmark) +endfunction + +" FUNCTION: Bookmark.str() {{{1 +" Get the string that should be rendered in the view for this bookmark +function! s:Bookmark.str() + let pathStrMaxLen = winwidth(g:NERDTree.GetWinNum()) - 4 - strdisplaywidth(self.name) + if &number + let pathStrMaxLen = pathStrMaxLen - &numberwidth + endif + + let pathStr = self.path.str({'format': 'UI'}) + if strdisplaywidth(pathStr) > pathStrMaxLen + while strdisplaywidth(pathStr) > pathStrMaxLen && strchars(pathStr) > 0 + let pathStr = substitute(pathStr, '^.', '', '') + endwhile + let pathStr = '<' . pathStr + endif + return '>' . self.name . ' ' . pathStr +endfunction + +" FUNCTION: Bookmark.toRoot(nerdtree) {{{1 +" Set the root of the given NERDTree to the node for this Bookmark. If a node +" for this Bookmark does not exist, a new one is initialized. +function! s:Bookmark.toRoot(nerdtree) + if self.validate() + try + let l:targetNode = self.getNode(a:nerdtree, 1) + call l:targetNode.closeChildren() + catch /^NERDTree.BookmarkedNodeNotFoundError/ + let l:targetNode = g:NERDTreeFileNode.New(s:Bookmark.BookmarkFor(self.name).path, a:nerdtree) + endtry + call a:nerdtree.changeRoot(l:targetNode) + endif +endfunction + +" FUNCTION: Bookmark.ToRoot(name, nerdtree) {{{1 +" Class method that makes the Bookmark with the given name the root of +" specified NERDTree. +function! s:Bookmark.ToRoot(name, nerdtree) + let l:bookmark = s:Bookmark.BookmarkFor(a:name) + call l:bookmark.toRoot(a:nerdtree) +endfunction + +" FUNCTION: Bookmark.validate() {{{1 +function! s:Bookmark.validate() + if self.path.exists() + return 1 + else + call s:Bookmark.CacheBookmarks(1) + call nerdtree#echo(self.name . 'now points to an invalid location. See :help NERDTreeInvalidBookmarks for info.') + return 0 + endif +endfunction + +" FUNCTION: Bookmark.Write() {{{1 +" Class method to write all bookmarks to the bookmarks file +function! s:Bookmark.Write() + let bookmarkStrings = [] + for i in s:Bookmark.Bookmarks() + call add(bookmarkStrings, i.name . ' ' . fnamemodify(i.path.str(), ':~')) + endfor + + "add a blank line before the invalid ones + call add(bookmarkStrings, '') + + for j in s:Bookmark.InvalidBookmarks() + call add(bookmarkStrings, j) + endfor + + try + call writefile(bookmarkStrings, g:NERDTreeBookmarksFile) + catch + call nerdtree#echoError('Failed to write bookmarks file. Make sure g:NERDTreeBookmarksFile points to a valid location.') + endtry +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/creator.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/creator.vim new file mode 100644 index 0000000..b9d45dc --- /dev/null +++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/creator.vim @@ -0,0 +1,402 @@ +" ============================================================================ +" CLASS: Creator +" +" This class is responsible for creating NERDTree instances. The new NERDTree +" may be a tab tree, a window tree, or a mirrored tree. In the process of +" creating a NERDTree, it sets up all of the window and buffer options and key +" mappings etc. +" ============================================================================ + + +let s:Creator = {} +let g:NERDTreeCreator = s:Creator + +" FUNCTION: s:Creator._bindMappings() {{{1 +function! s:Creator._bindMappings() + call g:NERDTreeKeyMap.BindAll() + + command! -buffer -nargs=? Bookmark :call nerdtree#ui_glue#bookmarkNode('') + command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=1 RevealBookmark :call nerdtree#ui_glue#revealBookmark('') + command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=1 OpenBookmark call nerdtree#ui_glue#openBookmark('') + command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=* ClearBookmarks call nerdtree#ui_glue#clearBookmarks('') + command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=+ BookmarkToRoot call g:NERDTreeBookmark.ToRoot('', b:NERDTree) + command! -buffer -nargs=0 ClearAllBookmarks call g:NERDTreeBookmark.ClearAll() call b:NERDTree.render() + command! -buffer -nargs=0 ReadBookmarks call g:NERDTreeBookmark.CacheBookmarks(0) call b:NERDTree.render() + command! -buffer -nargs=0 WriteBookmarks call g:NERDTreeBookmark.Write() + command! -buffer -nargs=0 EditBookmarks call g:NERDTreeBookmark.Edit() +endfunction + +" FUNCTION: s:Creator._broadcastInitEvent() {{{1 +function! s:Creator._broadcastInitEvent() + if exists('#User#NERDTreeInit') + doautocmd User NERDTreeInit + endif +endfunction + +" FUNCTION: s:Creator.BufNamePrefix() {{{1 +function! s:Creator.BufNamePrefix() + return 'NERD_tree_' +endfunction + +" FUNCTION: s:Creator.CreateTabTree(a:name) {{{1 +function! s:Creator.CreateTabTree(name) + let creator = s:Creator.New() + call creator.createTabTree(a:name) +endfunction + +" FUNCTION: s:Creator.createTabTree(a:name) {{{1 +" name: the name of a bookmark or a directory +function! s:Creator.createTabTree(name) + let l:path = self._pathForString(a:name) + + " Abort if an exception was thrown (i.e., if the bookmark or directory + " does not exist). + if empty(l:path) + return + endif + + " Obey the user's preferences for changing the working directory. + if g:NERDTreeChDirMode != 0 + call l:path.changeToDir() + endif + + if g:NERDTree.ExistsForTab() + call g:NERDTree.Close() + call self._removeTreeBufForTab() + endif + + call self._createTreeWin() + call self._createNERDTree(l:path, 'tab') + call b:NERDTree.render() + call b:NERDTree.root.putCursorHere(0, 0) + + call self._broadcastInitEvent() +endfunction + +" FUNCTION: s:Creator.CreateWindowTree(dir) {{{1 +function! s:Creator.CreateWindowTree(dir) + let creator = s:Creator.New() + call creator.createWindowTree(a:dir) +endfunction + +" FUNCTION: s:Creator.createWindowTree(dir) {{{1 +function! s:Creator.createWindowTree(dir) + try + let path = g:NERDTreePath.New(a:dir) + catch /^NERDTree.InvalidArgumentsError/ + call nerdtree#echo('Invalid directory name:' . a:dir) + return + endtry + + "we want the directory buffer to disappear when we do the :edit below + setlocal bufhidden=wipe + + let previousBuf = expand('#') + + "we need a unique name for each window tree buffer to ensure they are + "all independent + exec g:NERDTreeCreatePrefix . ' edit ' . self._nextBufferName() + + call self._createNERDTree(path, 'window') + let b:NERDTree._previousBuf = bufnr(previousBuf) + call self._setCommonBufOptions() + + call b:NERDTree.render() + + call self._broadcastInitEvent() +endfunction + +" FUNCTION: s:Creator._createNERDTree(path) {{{1 +function! s:Creator._createNERDTree(path, type) + let b:NERDTree = g:NERDTree.New(a:path, a:type) + + " TODO: This assignment is kept for compatibility reasons. Many other + " plugins use b:NERDTreeRoot instead of b:NERDTree.root. Remove this + " assignment in the future. + let b:NERDTreeRoot = b:NERDTree.root + + call b:NERDTree.root.open() +endfunction + +" FUNCTION: s:Creator.CreateMirror() {{{1 +function! s:Creator.CreateMirror() + let creator = s:Creator.New() + call creator.createMirror() +endfunction + +" FUNCTION: s:Creator.createMirror() {{{1 +function! s:Creator.createMirror() + "get the names off all the nerd tree buffers + let treeBufNames = [] + for i in range(1, tabpagenr('$')) + let nextName = self._tabpagevar(i, 'NERDTreeBufName') + if nextName != -1 && (!exists('t:NERDTreeBufName') || nextName != t:NERDTreeBufName) + call add(treeBufNames, nextName) + endif + endfor + let treeBufNames = self._uniq(treeBufNames) + + "map the option names (that the user will be prompted with) to the nerd + "tree buffer names + let options = {} + let i = 0 + while i < len(treeBufNames) + let bufName = treeBufNames[i] + let treeRoot = getbufvar(bufName, 'NERDTree').root + let options[i+1 . '. ' . treeRoot.path.str() . ' (buf name: ' . bufName . ')'] = bufName + let i = i + 1 + endwhile + + "work out which tree to mirror, if there is more than 1 then ask the user + let bufferName = '' + if len(keys(options)) > 1 + let choices = ['Choose a tree to mirror'] + let choices = extend(choices, sort(keys(options))) + let choice = inputlist(choices) + if choice < 1 || choice > len(options) || choice ==# '' + return + endif + + let bufferName = options[sort(keys(options))[choice-1]] + elseif len(keys(options)) ==# 1 + let bufferName = values(options)[0] + else + call nerdtree#echo('No trees to mirror') + return + endif + + if g:NERDTree.ExistsForTab() && g:NERDTree.IsOpen() + call g:NERDTree.Close() + endif + + let t:NERDTreeBufName = bufferName + call self._createTreeWin() + exec 'buffer ' . bufferName + call b:NERDTree.ui.restoreScreenState() + if !&hidden + call b:NERDTree.render() + endif +endfunction + +" FUNCTION: s:Creator._createTreeWin() {{{1 +" Initialize the NERDTree window. Open the window, size it properly, set all +" local options, etc. +function! s:Creator._createTreeWin() + let l:splitLocation = g:NERDTreeWinPos ==# 'left' ? 'topleft ' : 'botright ' + let l:splitSize = g:NERDTreeWinSize + + if !g:NERDTree.ExistsForTab() + let t:NERDTreeBufName = self._nextBufferName() + silent! execute l:splitLocation . 'vertical ' . l:splitSize . ' new' + silent! execute 'edit ' . t:NERDTreeBufName + silent! execute 'vertical resize '. l:splitSize + else + silent! execute l:splitLocation . 'vertical ' . l:splitSize . ' split' + silent! execute 'buffer ' . t:NERDTreeBufName + endif + + setlocal winfixwidth + + call self._setCommonBufOptions() + + if has('patch-7.4.1925') + clearjumps + endif + +endfunction + +" FUNCTION: s:Creator._isBufHidden(nr) {{{1 +function! s:Creator._isBufHidden(nr) + redir => bufs + silent ls! + redir END + + return bufs =~ a:nr . '..h' +endfunction + +" FUNCTION: s:Creator.New() {{{1 +function! s:Creator.New() + let newCreator = copy(self) + return newCreator +endfunction + +" FUNCTION: s:Creator._nextBufferName() {{{1 +" returns the buffer name for the next nerd tree +function! s:Creator._nextBufferName() + let name = s:Creator.BufNamePrefix() . self._nextBufferNumber() + return name +endfunction + +" FUNCTION: s:Creator._nextBufferNumber() {{{1 +" the number to add to the nerd tree buffer name to make the buf name unique +function! s:Creator._nextBufferNumber() + if !exists('s:Creator._NextBufNum') + let s:Creator._NextBufNum = 1 + else + let s:Creator._NextBufNum += 1 + endif + + return s:Creator._NextBufNum +endfunction + +" FUNCTION: s:Creator._pathForString(str) {{{1 +" find a bookmark or adirectory for the given string +function! s:Creator._pathForString(str) + let path = {} + if g:NERDTreeBookmark.BookmarkExistsFor(a:str) + let path = g:NERDTreeBookmark.BookmarkFor(a:str).path + else + let dir = a:str ==# '' ? getcwd() : a:str + + "hack to get an absolute path if a relative path is given + if dir =~# '^\.' + let dir = getcwd() . nerdtree#slash() . dir + endif + + "hack to prevent removing slash if dir is the root of the file system. + if dir !=# '/' + let dir = g:NERDTreePath.Resolve(dir) + endif + + try + let path = g:NERDTreePath.New(dir) + catch /^NERDTree.InvalidArgumentsError/ + call nerdtree#echo('No bookmark or directory found for: ' . a:str) + return {} + endtry + endif + if !path.isDirectory + let path = path.getParent() + endif + + return path +endfunction + +" Function: s:Creator._removeTreeBufForTab() {{{1 +function! s:Creator._removeTreeBufForTab() + let buf = bufnr(t:NERDTreeBufName) + + "if &hidden is not set then it will already be gone + if buf != -1 + + "nerdtree buf may be mirrored/displayed elsewhere + if self._isBufHidden(buf) + exec 'bwipeout ' . buf + endif + + endif + + unlet t:NERDTreeBufName +endfunction + +" FUNCTION: s:Creator._setCommonBufOptions() {{{1 +function! s:Creator._setCommonBufOptions() + + " Options for a non-file/control buffer. + setlocal bufhidden=hide + setlocal buftype=nofile + setlocal noswapfile + + " Options for controlling buffer/window appearance. + setlocal foldcolumn=0 + setlocal foldmethod=manual + setlocal nobuflisted + setlocal nofoldenable + setlocal nolist + setlocal nospell + setlocal nowrap + + if g:NERDTreeShowLineNumbers + setlocal number + else + setlocal nonumber + if v:version >= 703 + setlocal norelativenumber + endif + endif + + iabc + + if g:NERDTreeHighlightCursorline + setlocal cursorline + endif + + call self._setupStatusline() + call self._bindMappings() + + setlocal filetype=nerdtree +endfunction + +" FUNCTION: s:Creator._setupStatusline() {{{1 +function! s:Creator._setupStatusline() + if g:NERDTreeStatusline != -1 + let &l:statusline = g:NERDTreeStatusline + endif +endfunction + +" FUNCTION: s:Creator._tabpagevar(tabnr, var) {{{1 +function! s:Creator._tabpagevar(tabnr, var) + let currentTab = tabpagenr() + let old_ei = &eventignore + set eventignore=all + + try + exec 'tabnext ' . a:tabnr + let v = -1 + if exists('t:' . a:var) + exec 'let v = t:' . a:var + endif + exec 'tabnext ' . currentTab + + finally + let &eventignore = old_ei + endtry + + return v +endfunction + +" FUNCTION: s:Creator.ToggleTabTree(dir) {{{1 +function! s:Creator.ToggleTabTree(dir) + let creator = s:Creator.New() + call creator.toggleTabTree(a:dir) +endfunction + +" FUNCTION: s:Creator.toggleTabTree(dir) {{{1 +" Toggles the NERD tree. I.e if the NERD tree is open, it is closed. If it is +" closed, it is restored or initialized. If dir is not empty, it will be set +" as the new root. +" +" Args: +" dir: the full path for the root node (is used if the NERD tree is being +" initialized, or to change the root to a new dir.) +function! s:Creator.toggleTabTree(dir) + if g:NERDTree.ExistsForTab() + if !g:NERDTree.IsOpen() + call self._createTreeWin() + if !empty(a:dir) && a:dir !=# b:NERDTree.root.path.str() + call self.createTabTree(a:dir) + elseif !&hidden + call b:NERDTree.render() + endif + call b:NERDTree.ui.restoreScreenState() + else + call g:NERDTree.Close() + endif + else + call self.createTabTree(a:dir) + endif +endfunction + +" Function: s:Creator._uniq(list) {{{1 +" returns a:list without duplicates +function! s:Creator._uniq(list) + let uniqlist = [] + for elem in a:list + if index(uniqlist, elem) ==# -1 + let uniqlist += [elem] + endif + endfor + return uniqlist +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/event.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/event.vim new file mode 100644 index 0000000..964e8ff --- /dev/null +++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/event.vim @@ -0,0 +1,13 @@ +"CLASS: Event +"============================================================ +let s:Event = {} +let g:NERDTreeEvent = s:Event + +function! s:Event.New(nerdtree, subject, action, params) abort + let newObj = copy(self) + let newObj.nerdtree = a:nerdtree + let newObj.subject = a:subject + let newObj.action = a:action + let newObj.params = a:params + return newObj +endfunction diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/flag_set.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/flag_set.vim new file mode 100644 index 0000000..7552867 --- /dev/null +++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/flag_set.vim @@ -0,0 +1,58 @@ +"CLASS: FlagSet +"============================================================ +let s:FlagSet = {} +let g:NERDTreeFlagSet = s:FlagSet + +"FUNCTION: FlagSet.addFlag(scope, flag) {{{1 +function! s:FlagSet.addFlag(scope, flag) + let flags = self._flagsForScope(a:scope) + if index(flags, a:flag) == -1 + call add(flags, a:flag) + end +endfunction + +"FUNCTION: FlagSet.clearFlags(scope) {{{1 +function! s:FlagSet.clearFlags(scope) + let self._flags[a:scope] = [] +endfunction + +"FUNCTION: FlagSet._flagsForScope(scope) {{{1 +function! s:FlagSet._flagsForScope(scope) + if !has_key(self._flags, a:scope) + let self._flags[a:scope] = [] + endif + return self._flags[a:scope] +endfunction + +"FUNCTION: FlagSet.New() {{{1 +function! s:FlagSet.New() + let newObj = copy(self) + let newObj._flags = {} + return newObj +endfunction + +"FUNCTION: FlagSet.removeFlag(scope, flag) {{{1 +function! s:FlagSet.removeFlag(scope, flag) + let flags = self._flagsForScope(a:scope) + + let i = index(flags, a:flag) + if i >= 0 + call remove(flags, i) + endif +endfunction + +"FUNCTION: FlagSet.renderToString() {{{1 +function! s:FlagSet.renderToString() + let flagstring = '' + for i in values(self._flags) + let flagstring .= join(i) + endfor + + if len(flagstring) == 0 + return '' + endif + + return '[' . flagstring . ']' +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/key_map.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/key_map.vim new file mode 100644 index 0000000..ed79167 --- /dev/null +++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/key_map.vim @@ -0,0 +1,164 @@ +"CLASS: KeyMap +"============================================================ +let s:KeyMap = {} +let g:NERDTreeKeyMap = s:KeyMap +let s:keyMaps = {} + +"FUNCTION: KeyMap.All() {{{1 +function! s:KeyMap.All() + let sortedKeyMaps = values(s:keyMaps) + call sort(sortedKeyMaps, s:KeyMap.Compare, s:KeyMap) + + return sortedKeyMaps +endfunction + +"FUNCTION: KeyMap.Compare(keyMap1, keyMap2) {{{1 +function! s:KeyMap.Compare(keyMap1, keyMap2) + + if a:keyMap1.key >? a:keyMap2.key + return 1 + endif + + if a:keyMap1.key ' notation, we + " must replace each of the '<' characters with '' to ensure the string + " is not translated into its corresponding keycode during the later part + " of the map command below + " :he <> + let specialNotationRegex = '\m<\([[:alnum:]_-]\+>\)' + if self.key =~# specialNotationRegex + let keymapInvokeString = substitute(self.key, specialNotationRegex, '\1', 'g') + else + let keymapInvokeString = self.key + endif + let keymapInvokeString = escape(keymapInvokeString, '\"') + + let premap = self.key ==# '' ? ' ' : ' ' + + exec 'nnoremap '. self.key . premap . ':call nerdtree#ui_glue#invokeKeyMap("'. keymapInvokeString .'")' +endfunction + +"FUNCTION: KeyMap.Remove(key, scope) {{{1 +function! s:KeyMap.Remove(key, scope) + return remove(s:keyMaps, a:key . a:scope) +endfunction + +"FUNCTION: KeyMap.invoke() {{{1 +"Call the KeyMaps callback function +function! s:KeyMap.invoke(...) + let l:Callback = type(self.callback) ==# type(function('tr')) ? self.callback : function(self.callback) + if a:0 + call l:Callback(a:1) + else + call l:Callback() + endif +endfunction + +"FUNCTION: KeyMap.Invoke() {{{1 +"Find a keymapping for a:key and the current scope invoke it. +" +"Scope is determined as follows: +" * if the cursor is on a dir node then DirNode +" * if the cursor is on a file node then FileNode +" * if the cursor is on a bookmark then Bookmark +" +"If a keymap has the scope of 'all' then it will be called if no other keymap +"is found for a:key and the scope. +function! s:KeyMap.Invoke(key) + + "required because clicking the command window below another window still + "invokes the mapping - but changes the window cursor + "is in first + " + "TODO: remove this check when the vim bug is fixed + if !g:NERDTree.ExistsForBuf() + return {} + endif + + let node = g:NERDTreeFileNode.GetSelected() + if !empty(node) + + "try file node + if !node.path.isDirectory + let km = s:KeyMap.FindFor(a:key, 'FileNode') + if !empty(km) + return km.invoke(node) + endif + endif + + "try dir node + if node.path.isDirectory + let km = s:KeyMap.FindFor(a:key, 'DirNode') + if !empty(km) + return km.invoke(node) + endif + endif + + "try generic node + let km = s:KeyMap.FindFor(a:key, 'Node') + if !empty(km) + return km.invoke(node) + endif + + endif + + "try bookmark + let bm = g:NERDTreeBookmark.GetSelected() + if !empty(bm) + let km = s:KeyMap.FindFor(a:key, 'Bookmark') + if !empty(km) + return km.invoke(bm) + endif + endif + + "try all + let km = s:KeyMap.FindFor(a:key, 'all') + if !empty(km) + return km.invoke() + endif +endfunction + +"FUNCTION: KeyMap.Create(options) {{{1 +function! s:KeyMap.Create(options) + let opts = extend({'scope': 'all', 'quickhelpText': ''}, copy(a:options)) + + "dont override other mappings unless the 'override' option is given + if get(opts, 'override', 0) ==# 0 && !empty(s:KeyMap.FindFor(opts['key'], opts['scope'])) + return + end + + let newKeyMap = copy(self) + let newKeyMap.key = opts['key'] + let newKeyMap.quickhelpText = opts['quickhelpText'] + let newKeyMap.callback = opts['callback'] + let newKeyMap.scope = opts['scope'] + + call s:KeyMap.Add(newKeyMap) +endfunction + +"FUNCTION: KeyMap.Add(keymap) {{{1 +function! s:KeyMap.Add(keymap) + let s:keyMaps[a:keymap.key . a:keymap.scope] = a:keymap +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_controller.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_controller.vim new file mode 100644 index 0000000..952c67b --- /dev/null +++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_controller.vim @@ -0,0 +1,211 @@ +"CLASS: MenuController +"============================================================ +let s:MenuController = {} +let g:NERDTreeMenuController = s:MenuController + +"FUNCTION: MenuController.New(menuItems) {{{1 +"create a new menu controller that operates on the given menu items +function! s:MenuController.New(menuItems) + let newMenuController = copy(self) + if a:menuItems[0].isSeparator() + let newMenuController.menuItems = a:menuItems[1:-1] + else + let newMenuController.menuItems = a:menuItems + endif + return newMenuController +endfunction + +" FUNCTION: s:MenuController.isMinimal() {{{1 +function! s:MenuController.isMinimal() + return g:NERDTreeMinimalMenu +endfunction + +" FUNCTION: MenuController.showMenu() {{{1 +" Enter the main loop of the NERDTree menu, prompting the user to select +" a menu item. +function! s:MenuController.showMenu() + call self._saveOptions() + + try + let self.selection = 0 + let l:done = 0 + + while !l:done + if has('nvim') + mode + else + redraw! + endif + call self._echoPrompt() + + let l:key = nr2char(getchar()) + let l:done = self._handleKeypress(l:key) + endwhile + finally + call self._restoreOptions() + + " Redraw when Ctrl-C or Esc is received. + if !l:done || self.selection ==# -1 + redraw! + endif + endtry + + if self.selection !=# -1 + let l:m = self._current() + call l:m.execute() + endif +endfunction + +"FUNCTION: MenuController._echoPrompt() {{{1 +function! s:MenuController._echoPrompt() + let navHelp = 'Use ' . g:NERDTreeMenuDown . '/' . g:NERDTreeMenuUp . '/enter' + + if self.isMinimal() + let selection = self.menuItems[self.selection].text + let keyword = matchstr(selection, '[^ ]*([^ ]*') + + let shortcuts = map(copy(self.menuItems), "v:val['shortcut']") + let shortcuts[self.selection] = ' ' . keyword . ' ' + + echo 'Menu: [' . join(shortcuts, ',') . '] (' . navHelp . ' or shortcut): ' + else + echo 'NERDTree Menu. ' . navHelp . ', or the shortcuts indicated' + echo '=========================================================' + + for i in range(0, len(self.menuItems)-1) + if self.selection ==# i + echo '> ' . self.menuItems[i].text + else + echo ' ' . self.menuItems[i].text + endif + endfor + endif +endfunction + +"FUNCTION: MenuController._current(key) {{{1 +"get the MenuItem that is currently selected +function! s:MenuController._current() + return self.menuItems[self.selection] +endfunction + +"FUNCTION: MenuController._handleKeypress(key) {{{1 +"change the selection (if appropriate) and return 1 if the user has made +"their choice, 0 otherwise +function! s:MenuController._handleKeypress(key) + if a:key ==# g:NERDTreeMenuDown + call self._cursorDown() + elseif a:key ==# g:NERDTreeMenuUp + call self._cursorUp() + elseif a:key ==# nr2char(27) "escape + let self.selection = -1 + return 1 + elseif a:key ==# "\r" || a:key ==# "\n" "enter and ctrl-j + return 1 + else + let index = self._nextIndexFor(a:key) + if index !=# -1 + let self.selection = index + if len(self._allIndexesFor(a:key)) ==# 1 + return 1 + endif + endif + endif + + return 0 +endfunction + +"FUNCTION: MenuController._allIndexesFor(shortcut) {{{1 +"get indexes to all menu items with the given shortcut +function! s:MenuController._allIndexesFor(shortcut) + let toReturn = [] + + for i in range(0, len(self.menuItems)-1) + if self.menuItems[i].shortcut ==# a:shortcut + call add(toReturn, i) + endif + endfor + + return toReturn +endfunction + +"FUNCTION: MenuController._nextIndexFor(shortcut) {{{1 +"get the index to the next menu item with the given shortcut, starts from the +"current cursor location and wraps around to the top again if need be +function! s:MenuController._nextIndexFor(shortcut) + for i in range(self.selection+1, len(self.menuItems)-1) + if self.menuItems[i].shortcut ==# a:shortcut + return i + endif + endfor + + for i in range(0, self.selection) + if self.menuItems[i].shortcut ==# a:shortcut + return i + endif + endfor + + return -1 +endfunction + +"FUNCTION: MenuController._setCmdheight() {{{1 +"sets &cmdheight to whatever is needed to display the menu +function! s:MenuController._setCmdheight() + if self.isMinimal() + let &cmdheight = 1 + else + let &cmdheight = len(self.menuItems) + 3 + endif +endfunction + +"FUNCTION: MenuController._saveOptions() {{{1 +"set any vim options that are required to make the menu work (saving their old +"values) +function! s:MenuController._saveOptions() + let self._oldLazyredraw = &lazyredraw + let self._oldCmdheight = &cmdheight + set nolazyredraw + call self._setCmdheight() +endfunction + +"FUNCTION: MenuController._restoreOptions() {{{1 +"restore the options we saved in _saveOptions() +function! s:MenuController._restoreOptions() + let &cmdheight = self._oldCmdheight + let &lazyredraw = self._oldLazyredraw +endfunction + +"FUNCTION: MenuController._cursorDown() {{{1 +"move the cursor to the next menu item, skipping separators +function! s:MenuController._cursorDown() + let done = 0 + while !done + if self.selection < len(self.menuItems)-1 + let self.selection += 1 + else + let self.selection = 0 + endif + + if !self._current().isSeparator() + let done = 1 + endif + endwhile +endfunction + +"FUNCTION: MenuController._cursorUp() {{{1 +"move the cursor to the previous menu item, skipping separators +function! s:MenuController._cursorUp() + let done = 0 + while !done + if self.selection > 0 + let self.selection -= 1 + else + let self.selection = len(self.menuItems)-1 + endif + + if !self._current().isSeparator() + let done = 1 + endif + endwhile +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_item.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_item.vim new file mode 100644 index 0000000..7f25917 --- /dev/null +++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/menu_item.vim @@ -0,0 +1,118 @@ +"CLASS: MenuItem +"============================================================ +let s:MenuItem = {} +let g:NERDTreeMenuItem = s:MenuItem + +"FUNCTION: MenuItem.All() {{{1 +"get all top level menu items +function! s:MenuItem.All() + if !exists('s:menuItems') + let s:menuItems = [] + endif + return s:menuItems +endfunction + +"FUNCTION: MenuItem.AllEnabled() {{{1 +"get all top level menu items that are currently enabled +function! s:MenuItem.AllEnabled() + let toReturn = [] + for i in s:MenuItem.All() + if i.enabled() + call add(toReturn, i) + endif + endfor + return toReturn +endfunction + +"FUNCTION: MenuItem.Create(options) {{{1 +"make a new menu item and add it to the global list +function! s:MenuItem.Create(options) + let newMenuItem = copy(self) + + let newMenuItem.text = a:options['text'] + let newMenuItem.shortcut = a:options['shortcut'] + let newMenuItem.children = [] + + let newMenuItem.isActiveCallback = -1 + if has_key(a:options, 'isActiveCallback') + let newMenuItem.isActiveCallback = a:options['isActiveCallback'] + endif + + let newMenuItem.callback = -1 + if has_key(a:options, 'callback') + let newMenuItem.callback = a:options['callback'] + endif + + if has_key(a:options, 'parent') + call add(a:options['parent'].children, newMenuItem) + else + call add(s:MenuItem.All(), newMenuItem) + endif + + return newMenuItem +endfunction + +"FUNCTION: MenuItem.CreateSeparator(options) {{{1 +"make a new separator menu item and add it to the global list +function! s:MenuItem.CreateSeparator(options) + let standard_options = { 'text': '--------------------', + \ 'shortcut': -1, + \ 'callback': -1 } + let options = extend(a:options, standard_options, 'force') + + return s:MenuItem.Create(options) +endfunction + +"FUNCTION: MenuItem.CreateSubmenu(options) {{{1 +"make a new submenu and add it to global list +function! s:MenuItem.CreateSubmenu(options) + let standard_options = { 'callback': -1 } + let options = extend(a:options, standard_options, 'force') + + return s:MenuItem.Create(options) +endfunction + +"FUNCTION: MenuItem.enabled() {{{1 +"return 1 if this menu item should be displayed +" +"delegates off to the isActiveCallback, and defaults to 1 if no callback was +"specified +function! s:MenuItem.enabled() + if self.isActiveCallback != -1 + return type(self.isActiveCallback) == type(function('tr')) ? self.isActiveCallback() : {self.isActiveCallback}() + endif + return 1 +endfunction + +"FUNCTION: MenuItem.execute() {{{1 +"perform the action behind this menu item, if this menuitem has children then +"display a new menu for them, otherwise deletegate off to the menuitem's +"callback +function! s:MenuItem.execute() + if len(self.children) + let mc = g:NERDTreeMenuController.New(self.children) + call mc.showMenu() + else + if self.callback != -1 + if type(self.callback) == type(function('tr')) + call self.callback() + else + call {self.callback}() + endif + endif + endif +endfunction + +"FUNCTION: MenuItem.isSeparator() {{{1 +"return 1 if this menuitem is a separator +function! s:MenuItem.isSeparator() + return self.callback == -1 && self.children == [] +endfunction + +"FUNCTION: MenuItem.isSubmenu() {{{1 +"return 1 if this menuitem is a submenu +function! s:MenuItem.isSubmenu() + return self.callback == -1 && !empty(self.children) +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/nerdtree.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/nerdtree.vim new file mode 100644 index 0000000..61a11a9 --- /dev/null +++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/nerdtree.vim @@ -0,0 +1,209 @@ +"CLASS: NERDTree +"============================================================ +let s:NERDTree = {} +let g:NERDTree = s:NERDTree + +"FUNCTION: s:NERDTree.AddPathFilter() {{{1 +function! s:NERDTree.AddPathFilter(callback) + call add(s:NERDTree.PathFilters(), a:callback) +endfunction + +"FUNCTION: s:NERDTree.changeRoot(node) {{{1 +function! s:NERDTree.changeRoot(node) + if a:node.path.isDirectory + let self.root = a:node + else + call a:node.cacheParent() + let self.root = a:node.parent + endif + + call self.root.open() + + "change dir to the dir of the new root if instructed to + if g:NERDTreeChDirMode >= 2 + call self.root.path.changeToDir() + endif + + call self.render() + call self.root.putCursorHere(0, 0) + + if exists('#User#NERDTreeNewRoot') + doautocmd User NERDTreeNewRoot + endif +endfunction + +"FUNCTION: s:NERDTree.Close() {{{1 +"Closes the tab tree window for this tab +function! s:NERDTree.Close() + if !s:NERDTree.IsOpen() + return + endif + + if winnr('$') !=# 1 + " Use the window ID to identify the currently active window or fall + " back on the buffer ID if win_getid/win_gotoid are not available, in + " which case we'll focus an arbitrary window showing the buffer. + let l:useWinId = exists('*win_getid') && exists('*win_gotoid') + + if winnr() ==# s:NERDTree.GetWinNum() + call nerdtree#exec('wincmd p', 1) + let l:activeBufOrWin = l:useWinId ? win_getid() : bufnr('') + call nerdtree#exec('wincmd p', 1) + else + let l:activeBufOrWin = l:useWinId ? win_getid() : bufnr('') + endif + + call nerdtree#exec(s:NERDTree.GetWinNum() . ' wincmd w', 1) + call nerdtree#exec('close', 0) + if l:useWinId + call nerdtree#exec('call win_gotoid(' . l:activeBufOrWin . ')', 0) + else + call nerdtree#exec(bufwinnr(l:activeBufOrWin) . ' wincmd w', 0) + endif + else + close + endif +endfunction + +"FUNCTION: s:NERDTree.CursorToBookmarkTable(){{{1 +"Places the cursor at the top of the bookmarks table +function! s:NERDTree.CursorToBookmarkTable() + if !b:NERDTree.ui.getShowBookmarks() + throw 'NERDTree.IllegalOperationError: cant find bookmark table, bookmarks arent active' + endif + + if g:NERDTreeMinimalUI + return cursor(1, 2) + endif + + let rootNodeLine = b:NERDTree.ui.getRootLineNum() + + let line = 1 + while getline(line) !~# '^>-\+Bookmarks-\+$' + let line = line + 1 + if line >= rootNodeLine + throw 'NERDTree.BookmarkTableNotFoundError: didnt find the bookmarks table' + endif + endwhile + call cursor(line, 2) +endfunction + +"FUNCTION: s:NERDTree.CursorToTreeWin(){{{1 +"Places the cursor in the nerd tree window +function! s:NERDTree.CursorToTreeWin(...) + call g:NERDTree.MustBeOpen() + call nerdtree#exec(g:NERDTree.GetWinNum() . 'wincmd w', a:0 >0 ? a:1 : 1) +endfunction + +" Function: s:NERDTree.ExistsForBuffer() {{{1 +" Returns 1 if a nerd tree root exists in the current buffer +function! s:NERDTree.ExistsForBuf() + return exists('b:NERDTree') +endfunction + +" Function: s:NERDTree.ExistsForTab() {{{1 +" Returns 1 if a nerd tree root exists in the current tab +function! s:NERDTree.ExistsForTab() + if !exists('t:NERDTreeBufName') + return + end + + "check b:NERDTree is still there and hasn't been e.g. :bdeleted + return !empty(getbufvar(bufnr(t:NERDTreeBufName), 'NERDTree')) +endfunction + +function! s:NERDTree.ForCurrentBuf() + if s:NERDTree.ExistsForBuf() + return b:NERDTree + else + return {} + endif +endfunction + +"FUNCTION: s:NERDTree.ForCurrentTab() {{{1 +function! s:NERDTree.ForCurrentTab() + if !s:NERDTree.ExistsForTab() + return + endif + + let bufnr = bufnr(t:NERDTreeBufName) + return getbufvar(bufnr, 'NERDTree') +endfunction + +"FUNCTION: s:NERDTree.getRoot() {{{1 +function! s:NERDTree.getRoot() + return self.root +endfunction + +"FUNCTION: s:NERDTree.GetWinNum() {{{1 +"gets the nerd tree window number for this tab +function! s:NERDTree.GetWinNum() + if exists('t:NERDTreeBufName') + return bufwinnr(t:NERDTreeBufName) + endif + + " If WindowTree, there is no t:NERDTreeBufName variable. Search all windows. + for w in range(1,winnr('$')) + if bufname(winbufnr(w)) =~# '^' . g:NERDTreeCreator.BufNamePrefix() . '\d\+$' + return w + endif + endfor + + return -1 +endfunction + +"FUNCTION: s:NERDTree.IsOpen() {{{1 +function! s:NERDTree.IsOpen() + return s:NERDTree.GetWinNum() !=# -1 +endfunction + +"FUNCTION: s:NERDTree.isTabTree() {{{1 +function! s:NERDTree.isTabTree() + return self._type ==# 'tab' +endfunction + +"FUNCTION: s:NERDTree.isWinTree() {{{1 +function! s:NERDTree.isWinTree() + return self._type ==# 'window' +endfunction + +"FUNCTION: s:NERDTree.MustBeOpen() {{{1 +function! s:NERDTree.MustBeOpen() + if !s:NERDTree.IsOpen() + throw 'NERDTree.TreeNotOpen' + endif +endfunction + +"FUNCTION: s:NERDTree.New() {{{1 +function! s:NERDTree.New(path, type) + let newObj = copy(self) + let newObj.ui = g:NERDTreeUI.New(newObj) + let newObj.root = g:NERDTreeDirNode.New(a:path, newObj) + let newObj._type = a:type + return newObj +endfunction + +"FUNCTION: s:NERDTree.PathFilters() {{{1 +function! s:NERDTree.PathFilters() + if !exists('s:NERDTree._PathFilters') + let s:NERDTree._PathFilters = [] + endif + return s:NERDTree._PathFilters +endfunction + +"FUNCTION: s:NERDTree.previousBuf() {{{1 +function! s:NERDTree.previousBuf() + return self._previousBuf +endfunction + +function! s:NERDTree.setPreviousBuf(bnum) + let self._previousBuf = a:bnum +endfunction + +"FUNCTION: s:NERDTree.render() {{{1 +"A convenience function - since this is called often +function! s:NERDTree.render() + call self.ui.render() +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/notifier.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/notifier.vim new file mode 100644 index 0000000..ffa2853 --- /dev/null +++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/notifier.vim @@ -0,0 +1,35 @@ +"CLASS: Notifier +"============================================================ +let s:Notifier = {} + +function! s:Notifier.AddListener(event, funcname) + let listeners = s:Notifier.GetListenersForEvent(a:event) + if listeners == [] + let listenersMap = s:Notifier.GetListenersMap() + let listenersMap[a:event] = listeners + endif + call add(listeners, a:funcname) +endfunction + +function! s:Notifier.NotifyListeners(event, path, nerdtree, params) + let event = g:NERDTreeEvent.New(a:nerdtree, a:path, a:event, a:params) + + for Listener in s:Notifier.GetListenersForEvent(a:event) + let l:Callback = type(Listener) == type(function('tr')) ? Listener : function(Listener) + call l:Callback(event) + endfor +endfunction + +function! s:Notifier.GetListenersMap() + if !exists('s:refreshListenersMap') + let s:refreshListenersMap = {} + endif + return s:refreshListenersMap +endfunction + +function! s:Notifier.GetListenersForEvent(name) + let listenersMap = s:Notifier.GetListenersMap() + return get(listenersMap, a:name, []) +endfunction + +let g:NERDTreePathNotifier = deepcopy(s:Notifier) diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/opener.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/opener.vim new file mode 100644 index 0000000..27993ac --- /dev/null +++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/opener.vim @@ -0,0 +1,326 @@ +" ============================================================================ +" CLASS: Opener +" +" The Opener class defines an API for 'opening' operations. +" ============================================================================ + + +let s:Opener = {} +let g:NERDTreeOpener = s:Opener + +" FUNCTION: s:Opener._bufInWindows(bnum) {{{1 +" [[STOLEN FROM VTREEEXPLORER.VIM]] +" Determine the number of windows open to this buffer number. +" Care of Yegappan Lakshman. Thanks! +" +" Args: +" bnum: the subject buffers buffer number +function! s:Opener._bufInWindows(bnum) + let cnt = 0 + let winnum = 1 + while 1 + let bufnum = winbufnr(winnum) + if bufnum < 0 + break + endif + if bufnum ==# a:bnum + let cnt = cnt + 1 + endif + let winnum = winnum + 1 + endwhile + + return cnt +endfunction + +" FUNCTION: Opener._checkToCloseTree(newtab) {{{1 +" Check the class options to see if the tree should be closed now. +" +" Args: +" a:newtab - boolean. If set, only close the tree now if we are opening the +" target in a new tab. This is needed because we have to close tree before we +" leave the tab +function! s:Opener._checkToCloseTree(newtab) + if self._keepopen + return + endif + + if (a:newtab && self._where ==# 't') || !a:newtab + call g:NERDTree.Close() + endif +endfunction + +" FUNCTION: s:Opener._firstUsableWindow() {{{1 +" find the window number of the first normal window +function! s:Opener._firstUsableWindow() + let i = 1 + while i <= winnr('$') + let bnum = winbufnr(i) + if bnum !=# -1 && getbufvar(bnum, '&buftype') ==# '' + \ && !getwinvar(i, '&previewwindow') + \ && (!getbufvar(bnum, '&modified') || &hidden) + return i + endif + + let i += 1 + endwhile + return -1 +endfunction + +" FUNCTION: Opener._gotoTargetWin() {{{1 +function! s:Opener._gotoTargetWin() + if b:NERDTree.isWinTree() + if self._where ==# 'v' + call self._newVSplit() + elseif self._where ==# 'h' + call self._newSplit() + elseif self._where ==# 't' + tabnew + endif + else + call self._checkToCloseTree(1) + + if self._where ==# 'v' + call self._newVSplit() + elseif self._where ==# 'h' + call self._newSplit() + elseif self._where ==# 't' + tabnew + elseif self._where ==# 'p' + call self._previousWindow() + endif + + call self._checkToCloseTree(0) + endif +endfunction + +" FUNCTION: s:Opener._isWindowUsable(winnumber) {{{1 +" Returns 0 if opening a file from the tree in the given window requires it to +" be split, 1 otherwise +" +" Args: +" winnumber: the number of the window in question +function! s:Opener._isWindowUsable(winnumber) + "gotta split if theres only one window (i.e. the NERD tree) + if winnr('$') ==# 1 + return 0 + endif + + let oldwinnr = winnr() + call nerdtree#exec(a:winnumber . 'wincmd p', 1) + let specialWindow = getbufvar('%', '&buftype') !=# '' || getwinvar('%', '&previewwindow') + let modified = &modified + call nerdtree#exec(oldwinnr . 'wincmd p', 1) + + "if its a special window e.g. quickfix or another explorer plugin then we + "have to split + if specialWindow + return 0 + endif + + if &hidden + return 1 + endif + + return !modified || self._bufInWindows(winbufnr(a:winnumber)) >= 2 +endfunction + +" FUNCTION: Opener.New(path, opts) {{{1 +" Instantiate a new NERDTreeOpener object. +" Args: +" a:path: the path object that is to be opened +" a:opts: a dictionary containing the following optional keys... +" 'where': specifies whether the node should be opened in new split, in +" a new tab or, in the last window; takes values 'v', 'h', or 't' +" 'reuse': if file is already shown in a window, jump there; takes values +" 'all', 'currenttab', or empty +" 'keepopen': boolean (0 or 1); if true, the tree window will not be closed +" 'stay': boolean (0 or 1); if true, remain in tree window after opening +function! s:Opener.New(path, opts) + let l:newOpener = copy(self) + + let l:newOpener._keepopen = nerdtree#has_opt(a:opts, 'keepopen') + let l:newOpener._nerdtree = b:NERDTree + let l:newOpener._path = a:path + let l:newOpener._reuse = has_key(a:opts, 'reuse') ? a:opts['reuse'] : '' + let l:newOpener._stay = nerdtree#has_opt(a:opts, 'stay') + let l:newOpener._where = has_key(a:opts, 'where') ? a:opts['where'] : '' + + call l:newOpener._saveCursorPos() + + return l:newOpener +endfunction + +" FUNCTION: Opener._newSplit() {{{1 +function! s:Opener._newSplit() + let onlyOneWin = (winnr('$') ==# 1) + let savesplitright = &splitright + if onlyOneWin + let &splitright = (g:NERDTreeWinPos ==# 'left') + endif + " If only one window (ie. NERDTree), split vertically instead. + let splitMode = onlyOneWin ? 'vertical' : '' + + " Open the new window + try + call nerdtree#exec('wincmd p', 1) + call nerdtree#exec(splitMode . ' split',1) + catch /^Vim\%((\a\+)\)\=:E37/ + call g:NERDTree.CursorToTreeWin() + throw 'NERDTree.FileAlreadyOpenAndModifiedError: '. self._path.str() .' is already open and modified.' + catch /^Vim\%((\a\+)\)\=:/ + "do nothing + endtry + + "resize the tree window if no other window was open before + if onlyOneWin + call nerdtree#exec('wincmd p', 1) + call nerdtree#exec('silent '. splitMode .' resize '. g:NERDTreeWinSize, 1) + call nerdtree#exec('wincmd p', 0) + endif + + let &splitright=savesplitright +endfunction + +" FUNCTION: Opener._newVSplit() {{{1 +function! s:Opener._newVSplit() + let l:winwidth = winwidth('.') + + let onlyOneWin = (winnr('$') ==# 1) + let savesplitright = &splitright + if onlyOneWin + let &splitright = (g:NERDTreeWinPos ==# 'left') + let l:winwidth = g:NERDTreeWinSize + endif + + call nerdtree#exec('wincmd p', 1) + call nerdtree#exec('vsplit', 1) + + let l:currentWindowNumber = winnr() + + " Restore the NERDTree to its original width. + call g:NERDTree.CursorToTreeWin() + execute 'silent vertical resize ' . l:winwidth + + call nerdtree#exec(l:currentWindowNumber . 'wincmd w', 0) + let &splitright=savesplitright +endfunction + +" FUNCTION: Opener.open(target) {{{1 +function! s:Opener.open(target) + if self._path.isDirectory + call self._openDirectory(a:target) + return + endif + + call self._openFile() +endfunction + +" FUNCTION: Opener._openFile() {{{1 +function! s:Opener._openFile() + if !self._stay && self._keepopen && get(b:, 'NERDTreeZoomed', 0) + call b:NERDTree.ui.toggleZoom() + endif + + if self._reuseWindow() + return + endif + + call self._gotoTargetWin() + + if self._stay + silent call self._path.edit() + call self._restoreCursorPos() + return + endif + + call self._path.edit() +endfunction + +" FUNCTION: Opener._openDirectory(node) {{{1 +function! s:Opener._openDirectory(node) + call self._gotoTargetWin() + + if self._nerdtree.isWinTree() + call g:NERDTreeCreator.CreateWindowTree(a:node.path.str()) + else + if empty(self._where) + call b:NERDTree.changeRoot(a:node) + elseif self._where ==# 't' + call g:NERDTreeCreator.CreateTabTree(a:node.path.str()) + else + call g:NERDTreeCreator.CreateWindowTree(a:node.path.str()) + endif + endif + + if self._stay + call self._restoreCursorPos() + endif +endfunction + +" FUNCTION: Opener._previousWindow() {{{1 +function! s:Opener._previousWindow() + if !self._isWindowUsable(winnr('#')) && self._firstUsableWindow() ==# -1 + call self._newSplit() + else + try + if !self._isWindowUsable(winnr('#')) + call nerdtree#exec(self._firstUsableWindow() . 'wincmd w', 1) + else + call nerdtree#exec('wincmd p', 1) + endif + catch /^Vim\%((\a\+)\)\=:E37/ + call g:NERDTree.CursorToTreeWin() + throw 'NERDTree.FileAlreadyOpenAndModifiedError: '. self._path.str() .' is already open and modified.' + catch /^Vim\%((\a\+)\)\=:/ + echo v:exception + endtry + endif +endfunction + +" FUNCTION: Opener._restoreCursorPos() {{{1 +function! s:Opener._restoreCursorPos() + call nerdtree#exec(self._tabnr . 'tabnext', 1) + call nerdtree#exec(bufwinnr(self._bufnr) . 'wincmd w', 1) +endfunction + +" FUNCTION: Opener._reuseWindow() {{{1 +" put the cursor in the first window we find for this file +" +" return 1 if we were successful +function! s:Opener._reuseWindow() + if empty(self._reuse) + return 0 + endif + + "check the current tab for the window + let winnr = bufwinnr('^' . self._path.str() . '$') + if winnr !=# -1 + call nerdtree#exec(winnr . 'wincmd w', 0) + call self._checkToCloseTree(0) + return 1 + endif + + if self._reuse ==# 'currenttab' + return 0 + endif + + "check other tabs + let tabnr = self._path.tabnr() + if tabnr + call self._checkToCloseTree(1) + call nerdtree#exec(tabnr . 'tabnext', 1) + let winnr = bufwinnr('^' . self._path.str() . '$') + call nerdtree#exec(winnr . 'wincmd w', 0) + return 1 + endif + + return 0 +endfunction + +" FUNCTION: Opener._saveCursorPos() {{{1 +function! s:Opener._saveCursorPos() + let self._bufnr = bufnr('') + let self._tabnr = tabpagenr() +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/path.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/path.vim new file mode 100644 index 0000000..997abf3 --- /dev/null +++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/path.vim @@ -0,0 +1,852 @@ +" ============================================================================ +" CLASS: Path +" +" The Path class provides an abstracted representation of a file system +" pathname. Various operations on pathnames are provided and a number of +" representations of a given path name can be accessed here. +" ============================================================================ + + +let s:Path = {} +let g:NERDTreePath = s:Path + +" FUNCTION: Path.AbsolutePathFor(pathStr) {{{1 +function! s:Path.AbsolutePathFor(pathStr) + let l:prependWorkingDir = 0 + + if nerdtree#runningWindows() + let l:prependWorkingDir = a:pathStr !~# '^.:\(\\\|\/\)\?' && a:pathStr !~# '^\(\\\\\|\/\/\)' + else + let l:prependWorkingDir = a:pathStr !~# '^/' + endif + + let l:result = a:pathStr + + if l:prependWorkingDir + let l:result = getcwd() + + if l:result[-1:] == nerdtree#slash() + let l:result = l:result . a:pathStr + else + let l:result = l:result . nerdtree#slash() . a:pathStr + endif + endif + + return l:result +endfunction + +" FUNCTION: Path.bookmarkNames() {{{1 +function! s:Path.bookmarkNames() + if !exists('self._bookmarkNames') + call self.cacheDisplayString() + endif + return self._bookmarkNames +endfunction + +" FUNCTION: Path.cacheDisplayString() {{{1 +function! s:Path.cacheDisplayString() abort + let self.cachedDisplayString = g:NERDTreeNodeDelimiter . self.getLastPathComponent(1) + + if self.isExecutable + let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . '*' + endif + + let self._bookmarkNames = [] + for i in g:NERDTreeBookmark.Bookmarks() + if i.path.equals(self) + call add(self._bookmarkNames, i.name) + endif + endfor + if !empty(self._bookmarkNames) && g:NERDTreeMarkBookmarks ==# 1 + let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . ' {' . join(self._bookmarkNames) . '}' + endif + + if self.isSymLink + let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . ' -> ' . self.symLinkDest + endif + + if self.isReadOnly + let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . ' ['.g:NERDTreeGlyphReadOnly.']' + endif +endfunction + +" FUNCTION: Path.addDelimiter() {{{1 +function! s:Path.addDelimiter(line) + if a:line =~# '\(.*' . g:NERDTreeNodeDelimiter . '\)\{2}' + return a:line + else + return a:line . g:NERDTreeNodeDelimiter + endif +endfunction + +" FUNCTION: Path.changeToDir() {{{1 +function! s:Path.changeToDir() + let dir = self.str({'format': 'Cd'}) + if self.isDirectory ==# 0 + let dir = self.getParent().str({'format': 'Cd'}) + endif + + try + if g:NERDTreeUseTCD && exists(':tcd') ==# 2 + execute 'tcd ' . dir + call nerdtree#echo("Tab's CWD is now: " . getcwd()) + else + execute 'cd ' . dir + call nerdtree#echo('CWD is now: ' . getcwd()) + endif + catch + throw 'NERDTree.PathChangeError: cannot change CWD to ' . dir + endtry +endfunction + +" FUNCTION: Path.Create(fullpath) {{{1 +" +" Factory method. +" +" Creates a path object with the given path. The path is also created on the +" filesystem. If the path already exists, a NERDTree.Path.Exists exception is +" thrown. If any other errors occur, a NERDTree.Path exception is thrown. +" +" Args: +" fullpath: the full filesystem path to the file/dir to create +function! s:Path.Create(fullpath) + "bail if the a:fullpath already exists + if isdirectory(a:fullpath) || filereadable(a:fullpath) + throw "NERDTree.CreatePathError: Directory Exists: '" . a:fullpath . "'" + endif + + try + + "if it ends with a slash, assume its a dir create it + if a:fullpath =~# '\(\\\|\/\)$' + "whack the trailing slash off the end if it exists + let fullpath = substitute(a:fullpath, '\(\\\|\/\)$', '', '') + + call mkdir(fullpath, 'p') + + "assume its a file and create + else + call s:Path.createParentDirectories(a:fullpath) + call writefile([], a:fullpath) + endif + catch + throw "NERDTree.CreatePathError: Could not create path: '" . a:fullpath . "'" + endtry + + return s:Path.New(a:fullpath) +endfunction + +" FUNCTION: Path.copy(dest) {{{1 +" +" Copies the file/dir represented by this Path to the given location +" +" Args: +" dest: the location to copy this dir/file to +function! s:Path.copy(dest) + if !s:Path.CopyingSupported() + throw 'NERDTree.CopyingNotSupportedError: Copying is not supported on this OS' + endif + + call s:Path.createParentDirectories(a:dest) + + if exists('g:NERDTreeCopyCmd') + let cmd_prefix = g:NERDTreeCopyCmd + else + let cmd_prefix = (self.isDirectory ? g:NERDTreeCopyDirCmd : g:NERDTreeCopyFileCmd) + endif + + let cmd = cmd_prefix . ' ' . shellescape(self.str()) . ' ' . shellescape(a:dest) + let success = system(cmd) + if v:shell_error !=# 0 + throw "NERDTree.CopyError: Could not copy '". self.str() ."' to: '" . a:dest . "'" + endif +endfunction + +" FUNCTION: Path.CopyingSupported() {{{1 +" +" returns 1 if copying is supported for this OS +function! s:Path.CopyingSupported() + return exists('g:NERDTreeCopyCmd') || (exists('g:NERDTreeCopyDirCmd') && exists('g:NERDTreeCopyFileCmd')) +endfunction + +" FUNCTION: Path.copyingWillOverwrite(dest) {{{1 +" +" returns 1 if copy this path to the given location will cause files to +" overwritten +" +" Args: +" dest: the location this path will be copied to +function! s:Path.copyingWillOverwrite(dest) + if filereadable(a:dest) + return 1 + endif + + if isdirectory(a:dest) + let path = s:Path.JoinPathStrings(a:dest, self.getLastPathComponent(0)) + if filereadable(path) + return 1 + endif + endif +endfunction + +" FUNCTION: Path.createParentDirectories(path) {{{1 +" +" create parent directories for this path if needed +" without throwing any errors if those directories already exist +" +" Args: +" path: full path of the node whose parent directories may need to be created +function! s:Path.createParentDirectories(path) + let dir_path = fnamemodify(a:path, ':h') + if !isdirectory(dir_path) + call mkdir(dir_path, 'p') + endif +endfunction + +" FUNCTION: Path.delete() {{{1 +" +" Deletes the file or directory represented by this path. +" +" Throws NERDTree.Path.Deletion exceptions +function! s:Path.delete() + if self.isDirectory + + let cmd = g:NERDTreeRemoveDirCmd . self.str({'escape': 1}) + let success = system(cmd) + + if v:shell_error !=# 0 + throw "NERDTree.PathDeletionError: Could not delete directory: '" . self.str() . "'" + endif + else + if exists('g:NERDTreeRemoveFileCmd') + let cmd = g:NERDTreeRemoveFileCmd . self.str({'escape': 1}) + let success = system(cmd) + else + let success = delete(self.str()) + endif + + if success !=# 0 + throw "NERDTree.PathDeletionError: Could not delete file: '" . self.str() . "'" + endif + endif + + "delete all bookmarks for this path + for i in self.bookmarkNames() + let bookmark = g:NERDTreeBookmark.BookmarkFor(i) + call bookmark.delete() + endfor +endfunction + +" FUNCTION: Path.displayString() {{{1 +" +" Returns a string that specifies how the path should be represented as a +" string +function! s:Path.displayString() + if self.cachedDisplayString ==# '' + call self.cacheDisplayString() + endif + + return self.cachedDisplayString +endfunction + +" FUNCTION: Path.edit() {{{1 +function! s:Path.edit() + let l:bufname = self.str({'format': 'Edit'}) + if bufname('%') !=# l:bufname + exec 'edit ' . l:bufname + endif +endfunction + +" FUNCTION: Path.extractDriveLetter(fullpath) {{{1 +" +" If running windows, cache the drive letter for this path +function! s:Path.extractDriveLetter(fullpath) + if nerdtree#runningWindows() + if a:fullpath =~# '^\(\\\\\|\/\/\)' + "For network shares, the 'drive' consists of the first two parts of the path, i.e. \\boxname\share + let self.drive = substitute(a:fullpath, '^\(\(\\\\\|\/\/\)[^\\\/]*\(\\\|\/\)[^\\\/]*\).*', '\1', '') + let self.drive = substitute(self.drive, '/', '\', 'g') + else + let self.drive = substitute(a:fullpath, '\(^[a-zA-Z]:\).*', '\1', '') + endif + else + let self.drive = '' + endif + +endfunction + +" FUNCTION: Path.exists() {{{1 +" return 1 if this path points to a location that is readable or is a directory +function! s:Path.exists() + let p = self.str() + return filereadable(p) || isdirectory(p) +endfunction + +" FUNCTION: Path._escChars() {{{1 +function! s:Path._escChars() + if nerdtree#runningWindows() + return " `\|\"#%&,?()\*^<>$" + endif + + return " \\`\|\"#%&,?()\*^<>[]{}$" +endfunction + +" FUNCTION: Path.getDir() {{{1 +" +" Returns this path if it is a directory, else this paths parent. +" +" Return: +" a Path object +function! s:Path.getDir() + if self.isDirectory + return self + else + return self.getParent() + endif +endfunction + +" FUNCTION: Path.getParent() {{{1 +" +" Returns a new path object for this paths parent +" +" Return: +" a new Path object +function! s:Path.getParent() + if nerdtree#runningWindows() + let path = self.drive . '\' . join(self.pathSegments[0:-2], '\') + else + let path = '/'. join(self.pathSegments[0:-2], '/') + endif + + return s:Path.New(path) +endfunction + +" FUNCTION: Path.getLastPathComponent(dirSlash) {{{1 +" +" Gets the last part of this path. +" +" Args: +" dirSlash: if 1 then a trailing slash will be added to the returned value for +" directory nodes. +function! s:Path.getLastPathComponent(dirSlash) + if empty(self.pathSegments) + return '' + endif + let toReturn = self.pathSegments[-1] + if a:dirSlash && self.isDirectory + let toReturn = toReturn . '/' + endif + return toReturn +endfunction + +" FUNCTION: Path.getSortOrderIndex() {{{1 +" returns the index of the pattern in g:NERDTreeSortOrder that this path matches +function! s:Path.getSortOrderIndex() + let i = 0 + while i < len(g:NERDTreeSortOrder) + if g:NERDTreeSortOrder[i] !~? '\[\[-\?\(timestamp\|size\|extension\)\]\]' && + \ self.getLastPathComponent(1) =~# g:NERDTreeSortOrder[i] + return i + endif + let i = i + 1 + endwhile + + return index(g:NERDTreeSortOrder, '*') +endfunction + +" FUNCTION: Path._splitChunks(path) {{{1 +" returns a list of path chunks +function! s:Path._splitChunks(path) + let chunks = split(a:path, '\(\D\+\|\d\+\)\zs') + let i = 0 + while i < len(chunks) + "convert number literals to numbers + if match(chunks[i], '^\d\+$') ==# 0 + let chunks[i] = str2nr(chunks[i]) + endif + let i = i + 1 + endwhile + return chunks +endfunction + +" FUNCTION: Path.getSortKey() {{{1 +" returns a key used in compare function for sorting +function! s:Path.getSortKey() + if !exists('self._sortKey') || g:NERDTreeSortOrder !=# g:NERDTreeOldSortOrder + " Look for file metadata tags: [[timestamp]], [[extension]], [[size]] + let metadata = [] + for tag in g:NERDTreeSortOrder + if tag =~? '\[\[-\?timestamp\]\]' + let metadata += [self.isDirectory ? 0 : getftime(self.str()) * (tag =~# '-' ? -1 : 1)] + elseif tag =~? '\[\[-\?size\]\]' + let metadata += [self.isDirectory ? 0 : getfsize(self.str()) * (tag =~# '-' ? -1 : 1)] + elseif tag =~? '\[\[extension\]\]' + let extension = matchstr(self.getLastPathComponent(0), '[^.]\+\.\zs[^.]\+$') + let metadata += [self.isDirectory ? '' : (extension ==# '' ? nr2char(str2nr('0x10ffff',16)) : extension)] + endif + endfor + + if g:NERDTreeSortOrder[0] =~# '\[\[.*\]\]' + " Apply tags' sorting first if specified first. + let self._sortKey = metadata + [self.getSortOrderIndex()] + else + " Otherwise, do regex grouping first. + let self._sortKey = [self.getSortOrderIndex()] + metadata + endif + + let path = self.getLastPathComponent(0) + if !g:NERDTreeSortHiddenFirst + let path = substitute(path, '^[._]', '', '') + endif + if !g:NERDTreeCaseSensitiveSort + let path = tolower(path) + endif + + call extend(self._sortKey, (g:NERDTreeNaturalSort ? self._splitChunks(path) : [path])) + endif + return self._sortKey +endfunction + +" FUNCTION: Path.isHiddenUnder(path) {{{1 +function! s:Path.isHiddenUnder(path) + + if !self.isUnder(a:path) + return 0 + endif + + let l:startIndex = len(a:path.pathSegments) + let l:segments = self.pathSegments[l:startIndex : ] + + for l:segment in l:segments + + if l:segment =~# '^\.' + return 1 + endif + endfor + + return 0 +endfunction + +" FUNCTION: Path.isUnixHiddenFile() {{{1 +" check for unix hidden files +function! s:Path.isUnixHiddenFile() + return self.getLastPathComponent(0) =~# '^\.' +endfunction + +" FUNCTION: Path.isUnixHiddenPath() {{{1 +" check for unix path with hidden components +function! s:Path.isUnixHiddenPath() + if self.getLastPathComponent(0) =~# '^\.' + return 1 + else + for segment in self.pathSegments + if segment =~# '^\.' + return 1 + endif + endfor + return 0 + endif +endfunction + +" FUNCTION: Path.ignore(nerdtree) {{{1 +" returns true if this path should be ignored +function! s:Path.ignore(nerdtree) + "filter out the user specified paths to ignore + if a:nerdtree.ui.isIgnoreFilterEnabled() + for i in g:NERDTreeIgnore + if self._ignorePatternMatches(i) + return 1 + endif + endfor + + for l:Callback in g:NERDTree.PathFilters() + let l:Callback = type(l:Callback) ==# type(function('tr')) ? l:Callback : function(l:Callback) + if l:Callback({'path': self, 'nerdtree': a:nerdtree}) + return 1 + endif + endfor + endif + + "dont show hidden files unless instructed to + if !a:nerdtree.ui.getShowHidden() && self.isUnixHiddenFile() + return 1 + endif + + if a:nerdtree.ui.getShowFiles() ==# 0 && self.isDirectory ==# 0 + return 1 + endif + + return 0 +endfunction + +" FUNCTION: Path._ignorePatternMatches(pattern) {{{1 +" returns true if this path matches the given ignore pattern +function! s:Path._ignorePatternMatches(pattern) + let pat = a:pattern + if strpart(pat,len(pat)-8) ==# '[[path]]' + let pat = strpart(pat,0, len(pat)-8) + return self.str() =~# pat + elseif strpart(pat,len(pat)-7) ==# '[[dir]]' + if !self.isDirectory + return 0 + endif + let pat = strpart(pat,0, len(pat)-7) + elseif strpart(pat,len(pat)-8) ==# '[[file]]' + if self.isDirectory + return 0 + endif + let pat = strpart(pat,0, len(pat)-8) + endif + + return self.getLastPathComponent(0) =~# pat +endfunction + +" FUNCTION: Path.isAncestor(path) {{{1 +" return 1 if this path is somewhere above the given path in the filesystem. +" +" a:path should be a dir +function! s:Path.isAncestor(child) + return a:child.isUnder(self) +endfunction + +" FUNCTION: Path.isUnder(path) {{{1 +" return 1 if this path is somewhere under the given path in the filesystem. +function! s:Path.isUnder(parent) + if a:parent.isDirectory ==# 0 + return 0 + endif + if nerdtree#runningWindows() && a:parent.drive !=# self.drive + return 0 + endif + let l:this_count = len(self.pathSegments) + if l:this_count ==# 0 + return 0 + endif + let l:that_count = len(a:parent.pathSegments) + if l:that_count ==# 0 + return 1 + endif + if l:that_count >= l:this_count + return 0 + endif + for i in range(0, l:that_count-1) + if self.pathSegments[i] !=# a:parent.pathSegments[i] + return 0 + endif + endfor + return 1 +endfunction + +" FUNCTION: Path.JoinPathStrings(...) {{{1 +function! s:Path.JoinPathStrings(...) + let components = [] + for i in a:000 + let components = extend(components, split(i, '/')) + endfor + return '/' . join(components, '/') +endfunction + +" FUNCTION: Path.equals() {{{1 +" +" Determines whether 2 path objects are "equal". +" They are equal if the paths they represent are the same +" +" Args: +" path: the other path obj to compare this with +function! s:Path.equals(path) + if nerdtree#runningWindows() + return self.str() ==? a:path.str() + else + return self.str() ==# a:path.str() + endif +endfunction + +" FUNCTION: Path.New(pathStr) {{{1 +function! s:Path.New(pathStr) + let l:newPath = copy(self) + + call l:newPath.readInfoFromDisk(s:Path.AbsolutePathFor(a:pathStr)) + + let l:newPath.cachedDisplayString = '' + let l:newPath.flagSet = g:NERDTreeFlagSet.New() + + return l:newPath +endfunction + +" FUNCTION: Path.Resolve() {{{1 +" Invoke the vim resolve() function and return the result +" This is necessary because in some versions of vim resolve() removes trailing +" slashes while in other versions it doesn't. This always removes the trailing +" slash +function! s:Path.Resolve(path) + let tmp = resolve(a:path) + return tmp =~# '.\+/$' ? substitute(tmp, '/$', '', '') : tmp +endfunction + +" FUNCTION: Path.readInfoFromDisk(fullpath) {{{1 +" +" +" Throws NERDTree.Path.InvalidArguments exception. +function! s:Path.readInfoFromDisk(fullpath) + call self.extractDriveLetter(a:fullpath) + + let fullpath = s:Path.WinToUnixPath(a:fullpath) + + if getftype(fullpath) ==# 'fifo' + throw 'NERDTree.InvalidFiletypeError: Cant handle FIFO files: ' . a:fullpath + endif + + let self.pathSegments = filter(split(fullpath, '/'), '!empty(v:val)') + + let self.isReadOnly = 0 + if isdirectory(a:fullpath) + let self.isDirectory = 1 + elseif filereadable(a:fullpath) + let self.isDirectory = 0 + let self.isReadOnly = filewritable(a:fullpath) ==# 0 + else + throw 'NERDTree.InvalidArgumentsError: Invalid path = ' . a:fullpath + endif + + let self.isExecutable = 0 + if !self.isDirectory + let self.isExecutable = getfperm(a:fullpath) =~# 'x' + endif + + "grab the last part of the path (minus the trailing slash) + let lastPathComponent = self.getLastPathComponent(0) + + "get the path to the new node with the parent dir fully resolved + let hardPath = s:Path.Resolve(self.strTrunk()) . '/' . lastPathComponent + + "if the last part of the path is a symlink then flag it as such + let self.isSymLink = (s:Path.Resolve(hardPath) !=# hardPath) + if self.isSymLink + let self.symLinkDest = s:Path.Resolve(fullpath) + + "if the link is a dir then slap a / on the end of its dest + if isdirectory(self.symLinkDest) + + "we always wanna treat MS windows shortcuts as files for + "simplicity + if hardPath !~# '\.lnk$' + + let self.symLinkDest = self.symLinkDest . '/' + endif + endif + endif +endfunction + +" FUNCTION: Path.refresh(nerdtree) {{{1 +function! s:Path.refresh(nerdtree) + call self.readInfoFromDisk(self.str()) + call g:NERDTreePathNotifier.NotifyListeners('refresh', self, a:nerdtree, {}) + call self.cacheDisplayString() +endfunction + +" FUNCTION: Path.refreshFlags(nerdtree) {{{1 +function! s:Path.refreshFlags(nerdtree) + call g:NERDTreePathNotifier.NotifyListeners('refreshFlags', self, a:nerdtree, {}) + call self.cacheDisplayString() +endfunction + +" FUNCTION: Path.rename() {{{1 +" +" Renames this node on the filesystem +function! s:Path.rename(newPath) + if a:newPath ==# '' + throw 'NERDTree.InvalidArgumentsError: Invalid newPath for renaming = '. a:newPath + endif + + call s:Path.createParentDirectories(a:newPath) + + let success = rename(self.str(), a:newPath) + if success !=# 0 + throw "NERDTree.PathRenameError: Could not rename: '" . self.str() . "'" . 'to:' . a:newPath + endif + call self.readInfoFromDisk(a:newPath) + + for i in self.bookmarkNames() + let b = g:NERDTreeBookmark.BookmarkFor(i) + call b.setPath(copy(self)) + endfor + call g:NERDTreeBookmark.Write() +endfunction + +" FUNCTION: Path.str() {{{1 +" Return a string representation of this Path object. +" +" Args: +" This function takes a single dictionary (optional) with keys and values that +" specify how the returned pathname should be formatted. +" +" The dictionary may have the following keys: +" 'format' +" 'escape' +" 'truncateTo' +" +" The 'format' key may have a value of: +" 'Cd' - a string to be used with ":cd" and similar commands +" 'Edit' - a string to be used with ":edit" and similar commands +" 'UI' - a string to be displayed in the NERDTree user interface +" +" The 'escape' key, if specified, will cause the output to be escaped with +" Vim's internal "shellescape()" function. +" +" The 'truncateTo' key shortens the length of the path to that given by the +" value associated with 'truncateTo'. A '<' is prepended. +function! s:Path.str(...) + let options = a:0 ? a:1 : {} + let toReturn = '' + + if has_key(options, 'format') + let format = options['format'] + if has_key(self, '_strFor' . format) + exec 'let toReturn = self._strFor' . format . '()' + else + throw 'NERDTree.UnknownFormatError: unknown format "'. format .'"' + endif + else + let toReturn = self._str() + endif + + if nerdtree#has_opt(options, 'escape') + let toReturn = shellescape(toReturn) + endif + + if has_key(options, 'truncateTo') + let limit = options['truncateTo'] + if strdisplaywidth(toReturn) > limit-1 + while strdisplaywidth(toReturn) > limit-1 && strchars(toReturn) > 0 + let toReturn = substitute(toReturn, '^.', '', '') + endwhile + if len(split(toReturn, '/')) > 1 + let toReturn = ' 0) ? a:1 : {} + + call self.toggleOpen(l:options) + + " Note that we only re-render the NERDTree for this node if we did NOT + " create a new node and render it in a new window or tab. In the latter + " case, rendering the NERDTree for this node could overwrite the text of + " the new NERDTree! + if !has_key(l:options, 'where') || empty(l:options['where']) + call self.getNerdtree().render() + call self.putCursorHere(0, 0) + endif +endfunction + +" FUNCTION: TreeDirNode.addChild(treenode, inOrder) {{{1 +" Adds the given treenode to the list of children for this node +" +" Args: +" -treenode: the node to add +" -inOrder: 1 if the new node should be inserted in sorted order +function! s:TreeDirNode.addChild(treenode, inOrder) + call add(self.children, a:treenode) + let a:treenode.parent = self + + if a:inOrder + call self.sortChildren() + endif +endfunction + +" FUNCTION: TreeDirNode.close() {{{1 +" Mark this TreeDirNode as closed. +function! s:TreeDirNode.close() + + " Close all directories in this directory node's cascade. This is + " necessary to ensure consistency when cascades are rendered. + for l:dirNode in self.getCascade() + let l:dirNode.isOpen = 0 + endfor +endfunction + +" FUNCTION: TreeDirNode.closeChildren() {{{1 +" Recursively close any directory nodes that are descendants of this node. +function! s:TreeDirNode.closeChildren() + for l:child in self.children + if l:child.path.isDirectory + call l:child.close() + call l:child.closeChildren() + endif + endfor +endfunction + +" FUNCTION: TreeDirNode.createChild(path, inOrder) {{{1 +" Instantiates a new child node for this node with the given path. The new +" nodes parent is set to this node. +" +" Args: +" path: a Path object that this node will represent/contain +" inOrder: 1 if the new node should be inserted in sorted order +" +" Returns: +" the newly created node +function! s:TreeDirNode.createChild(path, inOrder) + let newTreeNode = g:NERDTreeFileNode.New(a:path, self.getNerdtree()) + call self.addChild(newTreeNode, a:inOrder) + return newTreeNode +endfunction + +" FUNCTION: TreeDirNode.displayString() {{{1 +" Assemble and return a string that can represent this TreeDirNode object in +" the NERDTree window. +function! s:TreeDirNode.displayString() + let l:result = '' + + " Build a label that identifies this TreeDirNode. + let l:label = '' + let l:cascade = self.getCascade() + for l:dirNode in l:cascade + let l:next = l:dirNode.path.displayString() + let l:label .= l:label ==# '' ? l:next : substitute(l:next,'^.','','') + endfor + + " Select the appropriate open/closed status indicator symbol. + let l:symbol = (l:cascade[-1].isOpen ? g:NERDTreeDirArrowCollapsible : g:NERDTreeDirArrowExpandable ) + let l:symbol .= (g:NERDTreeDirArrowExpandable ==# '' ? '' : ' ') + let l:flags = l:cascade[-1].path.flagSet.renderToString() + + return l:symbol . l:flags . l:label +endfunction + +" FUNCTION: TreeDirNode.findNode(path) {{{1 +" Will find one of the children (recursively) that has the given path +" +" Args: +" path: a path object +unlet s:TreeDirNode.findNode +function! s:TreeDirNode.findNode(path) + if a:path.equals(self.path) + return self + endif + if stridx(a:path.str(), self.path.str(), 0) ==# -1 + return {} + endif + + if self.path.isDirectory + for i in self.children + let retVal = i.findNode(a:path) + if retVal !=# {} + return retVal + endif + endfor + endif + return {} +endfunction + +" FUNCTION: TreeDirNode.getCascade() {{{1 +" Return an array of dir nodes (starting from self) that can be cascade opened. +function! s:TreeDirNode.getCascade() + if !self.isCascadable() + return [self] + endif + + let vc = self.getVisibleChildren() + let visChild = vc[0] + + return [self] + visChild.getCascade() +endfunction + +" FUNCTION: TreeDirNode.getCascadeRoot() {{{1 +" Return the first directory node in the cascade in which this directory node +" is rendered. +function! s:TreeDirNode.getCascadeRoot() + + " Don't search above the current NERDTree root node. + if self.isRoot() + return self + endif + + let l:cascadeRoot = self + let l:parent = self.parent + + while !empty(l:parent) && !l:parent.isRoot() + + if index(l:parent.getCascade(), self) ==# -1 + break + endif + + let l:cascadeRoot = l:parent + let l:parent = l:parent.parent + endwhile + + return l:cascadeRoot +endfunction + +" FUNCTION: TreeDirNode.getChildCount() {{{1 +" Returns the number of children this node has +function! s:TreeDirNode.getChildCount() + return len(self.children) +endfunction + +" FUNCTION: TreeDirNode.getChild(path) {{{1 +" Returns child node of this node that has the given path or {} if no such node +" exists. +" +" This function doesnt not recurse into child dir nodes +" +" Args: +" path: a path object +function! s:TreeDirNode.getChild(path) + if stridx(a:path.str(), self.path.str(), 0) ==# -1 + return {} + endif + + let index = self.getChildIndex(a:path) + if index ==# -1 + return {} + else + return self.children[index] + endif + +endfunction + +" FUNCTION: TreeDirNode.getChildByIndex(indx, visible) {{{1 +" returns the child at the given index +" +" Args: +" indx: the index to get the child from +" visible: 1 if only the visible children array should be used, 0 if all the +" children should be searched. +function! s:TreeDirNode.getChildByIndex(indx, visible) + let array_to_search = a:visible? self.getVisibleChildren() : self.children + if a:indx > len(array_to_search) + throw 'NERDTree.InvalidArgumentsError: Index is out of bounds.' + endif + return array_to_search[a:indx] +endfunction + +" FUNCTION: TreeDirNode.getChildIndex(path) {{{1 +" Returns the index of the child node of this node that has the given path or +" -1 if no such node exists. +" +" This function doesnt not recurse into child dir nodes +" +" Args: +" path: a path object +function! s:TreeDirNode.getChildIndex(path) + if stridx(a:path.str(), self.path.str(), 0) ==# -1 + return -1 + endif + + "do a binary search for the child + let a = 0 + let z = self.getChildCount() + while a < z + let mid = (a+z)/2 + let diff = nerdtree#compareNodePaths(a:path, self.children[mid].path) + + if diff ==# -1 + let z = mid + elseif diff ==# 1 + let a = mid+1 + else + return mid + endif + endwhile + return -1 +endfunction + +" FUNCTION: TreeDirNode.getDirChildren() {{{1 +" Return a list of all child nodes from 'self.children' that are of type +" TreeDirNode. This function supports http://github.com/scrooloose/nerdtree-project-plugin.git. +function! s:TreeDirNode.getDirChildren() + return filter(copy(self.children), 'v:val.path.isDirectory ==# 1') +endfunction + +" FUNCTION: TreeDirNode._glob(pattern, all) {{{1 +" Return a list of strings naming the descendants of the directory in this +" TreeDirNode object that match the specified glob pattern. +" +" Args: +" pattern: (string) the glob pattern to apply +" all: (0 or 1) if 1, include '.' and '..' if they match 'pattern'; if 0, +" always exclude them +" +" Note: If the pathnames in the result list are below the working directory, +" they are returned as pathnames relative to that directory. This is because +" this function, internally, attempts to obey 'wildignore' rules that use +" relative paths. +function! s:TreeDirNode._glob(pattern, all) + + " Construct a path specification such that globpath() will return + " relative pathnames, if possible. + if self.path.str() ==# getcwd() + let l:pathSpec = ',' + else + let l:pathSpec = escape(fnamemodify(self.path.str({'format': 'Glob'}), ':.'), ',') + + " On Windows, the drive letter may be removed by "fnamemodify()". + if nerdtree#runningWindows() && l:pathSpec[0] == nerdtree#slash() + let l:pathSpec = self.path.drive . l:pathSpec + endif + endif + + let l:globList = [] + + " See ':h version7.txt' and ':h version8.txt' for details on the + " development of the glob() and globpath() functions. + if v:version > 704 || (v:version ==# 704 && has('patch654')) + let l:globList = globpath(l:pathSpec, a:pattern, !g:NERDTreeRespectWildIgnore, 1, 0) + elseif v:version ==# 704 && has('patch279') + let l:globList = globpath(l:pathSpec, a:pattern, !g:NERDTreeRespectWildIgnore, 1) + elseif v:version > 702 || (v:version ==# 702 && has('patch051')) + let l:globString = globpath(l:pathSpec, a:pattern, !g:NERDTreeRespectWildIgnore) + let l:globList = split(l:globString, "\n") + else + let l:globString = globpath(l:pathSpec, a:pattern) + let l:globList = split(l:globString, "\n") + endif + + " If a:all is false, filter '.' and '..' from the output. + if !a:all + let l:toRemove = [] + + for l:file in l:globList + let l:tail = fnamemodify(l:file, ':t') + + " If l:file has a trailing slash, then its :tail will be ''. Use + " :h to drop the slash and the empty string after it; then use :t + " to get the directory name. + if l:tail ==# '' + let l:tail = fnamemodify(l:file, ':h:t') + endif + + if l:tail ==# '.' || l:tail ==# '..' + call add(l:toRemove, l:file) + if len(l:toRemove) ==# 2 + break + endif + endif + endfor + + for l:file in l:toRemove + call remove(l:globList, index(l:globList, l:file)) + endfor + endif + + return l:globList +endfunction + +" FUNCTION: TreeDirNode.GetSelected() {{{1 +" Returns the current node if it is a dir node, or else returns the current +" nodes parent +unlet s:TreeDirNode.GetSelected +function! s:TreeDirNode.GetSelected() + let currentDir = g:NERDTreeFileNode.GetSelected() + if currentDir !=# {} && !currentDir.isRoot() + if currentDir.path.isDirectory ==# 0 + let currentDir = currentDir.parent + endif + endif + return currentDir +endfunction + +" FUNCTION: TreeDirNode.getVisibleChildCount() {{{1 +" Returns the number of visible children this node has +function! s:TreeDirNode.getVisibleChildCount() + return len(self.getVisibleChildren()) +endfunction + +" FUNCTION: TreeDirNode.getVisibleChildren() {{{1 +" Returns a list of children to display for this node, in the correct order +" +" Return: +" an array of treenodes +function! s:TreeDirNode.getVisibleChildren() + let toReturn = [] + for i in self.children + if i.path.ignore(self.getNerdtree()) ==# 0 + call add(toReturn, i) + endif + endfor + return toReturn +endfunction + +" FUNCTION: TreeDirNode.hasVisibleChildren() {{{1 +" returns 1 if this node has any childre, 0 otherwise.. +function! s:TreeDirNode.hasVisibleChildren() + return self.getVisibleChildCount() !=# 0 +endfunction + +" FUNCTION: TreeDirNode.isCascadable() {{{1 +" true if this dir has only one visible child that is also a dir +" false if this dir is bookmarked or symlinked. Why? Two reasons: +" 1. If cascaded, we don't know which dir is bookmarked or is a symlink. +" 2. If the parent is a symlink or is bookmarked, you end up with unparsable +" text, and NERDTree cannot get the path of any child node. +" Also, return false if this directory is the tree root, which should never be +" part of a cascade. +function! s:TreeDirNode.isCascadable() + if g:NERDTreeCascadeSingleChildDir ==# 0 + return 0 + endif + + if self.isRoot() + return 0 + endif + + if self.path.isSymLink + return 0 + endif + + for i in g:NERDTreeBookmark.Bookmarks() + if i.path.equals(self.path) + return 0 + endif + endfor + + let c = self.getVisibleChildren() + return len(c) ==# 1 && c[0].path.isDirectory +endfunction + +" FUNCTION: TreeDirNode._initChildren() {{{1 +" Removes all childen from this node and re-reads them +" +" Args: +" silent: 1 if the function should not echo any 'please wait' messages for +" large directories +" +" Return: the number of child nodes read +function! s:TreeDirNode._initChildren(silent) + "remove all the current child nodes + let self.children = [] + + let files = self._glob('*', 1) + self._glob('.*', 0) + + if !a:silent && len(files) > g:NERDTreeNotificationThreshold + call nerdtree#echo('Please wait, caching a large dir ...') + endif + + let invalidFilesFound = 0 + for i in files + try + let path = g:NERDTreePath.New(i) + call self.createChild(path, 0) + call g:NERDTreePathNotifier.NotifyListeners('init', path, self.getNerdtree(), {}) + catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/ + let invalidFilesFound += 1 + endtry + endfor + + let g:NERDTreeOldSortOrder = g:NERDTreeSortOrder + call self.sortChildren() + + call nerdtree#echo('') + + if invalidFilesFound + call nerdtree#echoWarning(invalidFilesFound . ' file(s) could not be loaded into the NERD tree') + endif + return self.getChildCount() +endfunction + +" FUNCTION: TreeDirNode.New(path, nerdtree) {{{1 +" Return a new TreeDirNode object with the given path and parent. +" +" Args: +" path: dir that the node represents +" nerdtree: the tree the node belongs to +function! s:TreeDirNode.New(path, nerdtree) + if a:path.isDirectory !=# 1 + throw 'NERDTree.InvalidArgumentsError: A TreeDirNode object must be instantiated with a directory Path object.' + endif + + let newTreeNode = copy(self) + let newTreeNode.path = a:path + + let newTreeNode.isOpen = 0 + let newTreeNode.children = [] + + let newTreeNode.parent = {} + let newTreeNode._nerdtree = a:nerdtree + + return newTreeNode +endfunction + +" FUNCTION: TreeDirNode.open([options]) {{{1 +" Open this directory node in the current tree or elsewhere if special options +" are provided. Return 0 if options were processed. Otherwise, return the +" number of new cached nodes. +function! s:TreeDirNode.open(...) + let l:options = a:0 ? a:1 : {} + + " If special options were specified, process them and return. + if has_key(l:options, 'where') && !empty(l:options['where']) + let l:opener = g:NERDTreeOpener.New(self.path, l:options) + call l:opener.open(self) + return 0 + endif + + " Open any ancestors of this node that render within the same cascade. + let l:parent = self.parent + while !empty(l:parent) && !l:parent.isRoot() + if index(l:parent.getCascade(), self) >= 0 + let l:parent.isOpen = 1 + let l:parent = l:parent.parent + else + break + endif + endwhile + + let self.isOpen = 1 + + let l:numChildrenCached = 0 + if empty(self.children) + let l:numChildrenCached = self._initChildren(0) + endif + + return l:numChildrenCached +endfunction + +" FUNCTION: TreeDirNode.openAlong([opts]) {{{1 +" recursive open the dir if it has only one directory child. +" +" return the level of opened directories. +function! s:TreeDirNode.openAlong(...) + let opts = a:0 ? a:1 : {} + let level = 0 + + let node = self + while node.path.isDirectory + call node.open(opts) + let level += 1 + if node.getVisibleChildCount() ==# 1 + let node = node.getChildByIndex(0, 1) + else + break + endif + endwhile + return level +endfunction + +" FUNCTION: TreeDirNode.openExplorer() {{{1 +" Open an explorer window for this node in the previous window. The explorer +" can be a NERDTree window or a netrw window. +function! s:TreeDirNode.openExplorer() + execute 'wincmd p' + execute 'edit '.self.path.str({'format':'Edit'}) +endfunction + +" FUNCTION: TreeDirNode.openInNewTab(options) {{{1 +unlet s:TreeDirNode.openInNewTab +function! s:TreeDirNode.openInNewTab(options) + call nerdtree#deprecated('TreeDirNode.openInNewTab', 'is deprecated, use open() instead') + call self.open({'where': 't'}) +endfunction + +" FUNCTION: TreeDirNode._openInNewTab() {{{1 +function! s:TreeDirNode._openInNewTab() + tabnew + call g:NERDTreeCreator.CreateTabTree(self.path.str()) +endfunction + +" FUNCTION: TreeDirNode.openRecursively() {{{1 +" Open this directory node and any descendant directory nodes whose pathnames +" are not ignored. +function! s:TreeDirNode.openRecursively() + silent call self.open() + + for l:child in self.children + if l:child.path.isDirectory && !l:child.path.ignore(l:child.getNerdtree()) + call l:child.openRecursively() + endif + endfor +endfunction + +" FUNCTION: TreeDirNode.refresh() {{{1 +function! s:TreeDirNode.refresh() + call self.path.refresh(self.getNerdtree()) + + "if this node was ever opened, refresh its children + if self.isOpen || !empty(self.children) + let files = self._glob('*', 1) + self._glob('.*', 0) + let newChildNodes = [] + let invalidFilesFound = 0 + for i in files + try + "create a new path and see if it exists in this nodes children + let path = g:NERDTreePath.New(i) + let newNode = self.getChild(path) + if newNode !=# {} + call newNode.refresh() + call add(newChildNodes, newNode) + + "the node doesnt exist so create it + else + let newNode = g:NERDTreeFileNode.New(path, self.getNerdtree()) + let newNode.parent = self + call add(newChildNodes, newNode) + endif + catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/ + let invalidFilesFound = 1 + endtry + endfor + + "swap this nodes children out for the children we just read/refreshed + let self.children = newChildNodes + call self.sortChildren() + + if invalidFilesFound + call nerdtree#echoWarning('some files could not be loaded into the NERD tree') + endif + endif +endfunction + +" FUNCTION: TreeDirNode.refreshFlags() {{{1 +unlet s:TreeDirNode.refreshFlags +function! s:TreeDirNode.refreshFlags() + call self.path.refreshFlags(self.getNerdtree()) + for i in self.children + call i.refreshFlags() + endfor +endfunction + +" FUNCTION: TreeDirNode.refreshDirFlags() {{{1 +function! s:TreeDirNode.refreshDirFlags() + call self.path.refreshFlags(self.getNerdtree()) +endfunction + +" FUNCTION: TreeDirNode.reveal(path) {{{1 +" reveal the given path, i.e. cache and open all treenodes needed to display it +" in the UI +" Returns the revealed node +function! s:TreeDirNode.reveal(path, ...) + let opts = a:0 ? a:1 : {} + + if !a:path.isUnder(self.path) + throw 'NERDTree.InvalidArgumentsError: ' . a:path.str() . ' should be under ' . self.path.str() + endif + + call self.open() + + if self.path.equals(a:path.getParent()) + let n = self.findNode(a:path) + " We may be looking for a newly-saved file that isn't in the tree yet. + if n ==# {} + call self.refresh() + let n = self.findNode(a:path) + endif + if has_key(opts, 'open') + call n.open() + endif + return n + endif + + let p = a:path + while !p.getParent().equals(self.path) + let p = p.getParent() + endwhile + + let n = self.findNode(p) + return n.reveal(a:path, opts) +endfunction + +" FUNCTION: TreeDirNode.removeChild(treenode) {{{1 +" Remove the given treenode from self.children. +" Throws NERDTree.ChildNotFoundError if the node is not found. +" +" Args: +" treenode: the node object to remove +function! s:TreeDirNode.removeChild(treenode) + for i in range(0, self.getChildCount()-1) + if self.children[i].equals(a:treenode) + call remove(self.children, i) + return + endif + endfor + + throw 'NERDTree.ChildNotFoundError: child node was not found' +endfunction + +" FUNCTION: TreeDirNode.sortChildren() {{{1 +" Sort self.children by alphabetical order and directory priority. +function! s:TreeDirNode.sortChildren() + if count(g:NERDTreeSortOrder, '*') < 1 + call add(g:NERDTreeSortOrder, '*') + endif + let CompareFunc = function('nerdtree#compareNodes') + call sort(self.children, CompareFunc) + let g:NERDTreeOldSortOrder = g:NERDTreeSortOrder +endfunction + +" FUNCTION: TreeDirNode.toggleOpen([options]) {{{1 +" Opens this directory if it is closed and vice versa +function! s:TreeDirNode.toggleOpen(...) + let opts = a:0 ? a:1 : {} + if self.isOpen ==# 1 + call self.close() + else + if g:NERDTreeCascadeOpenSingleChildDir ==# 0 + call self.open(opts) + else + call self.openAlong(opts) + endif + endif +endfunction + +" FUNCTION: TreeDirNode.transplantChild(newNode) {{{1 +" Replaces the child of this with the given node (where the child node's full +" path matches a:newNode's fullpath). The search for the matching node is +" non-recursive +" +" Arg: +" newNode: the node to graft into the tree +function! s:TreeDirNode.transplantChild(newNode) + for i in range(0, self.getChildCount()-1) + if self.children[i].equals(a:newNode) + let self.children[i] = a:newNode + let a:newNode.parent = self + break + endif + endfor +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/tree_file_node.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/tree_file_node.vim new file mode 100644 index 0000000..957b98a --- /dev/null +++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/tree_file_node.vim @@ -0,0 +1,349 @@ +" ============================================================================ +" CLASS: TreeFileNode +" +" This class is the parent of the TreeDirNode class and is the 'Component' +" part of the composite design pattern between the NERDTree node classes. +" ============================================================================ + + +let s:TreeFileNode = {} +let g:NERDTreeFileNode = s:TreeFileNode + +" FUNCTION: TreeFileNode.activate(...) {{{1 +function! s:TreeFileNode.activate(...) + call self.open(a:0 ? a:1 : {}) +endfunction + +" FUNCTION: TreeFileNode.bookmark(name) {{{1 +" bookmark this node with a:name +function! s:TreeFileNode.bookmark(name) + + " if a bookmark exists with the same name and the node is cached then save + " it so we can update its display string + let oldMarkedNode = {} + try + let oldMarkedNode = g:NERDTreeBookmark.GetNodeForName(a:name, 1, self.getNerdtree()) + catch /^NERDTree.BookmarkNotFoundError/ + catch /^NERDTree.BookmarkedNodeNotFoundError/ + endtry + + call g:NERDTreeBookmark.AddBookmark(a:name, self.path) + call self.path.cacheDisplayString() + call g:NERDTreeBookmark.Write() + + if !empty(oldMarkedNode) + call oldMarkedNode.path.cacheDisplayString() + endif +endfunction + +" FUNCTION: TreeFileNode.cacheParent() {{{1 +" initializes self.parent if it isnt already +function! s:TreeFileNode.cacheParent() + if empty(self.parent) + let parentPath = self.path.getParent() + if parentPath.equals(self.path) + throw 'NERDTree.CannotCacheParentError: already at root' + endif + let self.parent = s:TreeFileNode.New(parentPath, self.getNerdtree()) + endif +endfunction + +" FUNCTION: TreeFileNode.clearBookmarks() {{{1 +function! s:TreeFileNode.clearBookmarks() + for i in g:NERDTreeBookmark.Bookmarks() + if i.path.equals(self.path) + call i.delete() + end + endfor + call self.path.cacheDisplayString() +endfunction + +" FUNCTION: TreeFileNode.copy(dest) {{{1 +function! s:TreeFileNode.copy(dest) + call self.path.copy(a:dest) + let newPath = g:NERDTreePath.New(a:dest) + let parent = self.getNerdtree().root.findNode(newPath.getParent()) + if !empty(parent) + call parent.refresh() + return parent.findNode(newPath) + else + return {} + endif +endfunction + +" FUNCTION: TreeFileNode.delete {{{1 +" Removes this node from the tree and calls the Delete method for its path obj +function! s:TreeFileNode.delete() + call self.path.delete() + call self.parent.removeChild(self) +endfunction + +" FUNCTION: TreeFileNode.displayString() {{{1 +" +" Returns a string that specifies how the node should be represented as a +" string +" +" Return: +" a string that can be used in the view to represent this node +function! s:TreeFileNode.displayString() + return self.path.flagSet.renderToString() . self.path.displayString() +endfunction + +" FUNCTION: TreeFileNode.equals(treenode) {{{1 +" +" Compares this treenode to the input treenode and returns 1 if they are the +" same node. +" +" Use this method instead of == because sometimes when the treenodes contain +" many children, vim seg faults when doing == +" +" Args: +" treenode: the other treenode to compare to +function! s:TreeFileNode.equals(treenode) + return self.path.str() ==# a:treenode.path.str() +endfunction + +" FUNCTION: TreeFileNode.findNode(path) {{{1 +" Returns self if this node.path.Equals the given path. +" Returns {} if not equal. +" +" Args: +" path: the path object to compare against +function! s:TreeFileNode.findNode(path) + if a:path.equals(self.path) + return self + endif + return {} +endfunction + +" FUNCTION: TreeFileNode.findSibling(direction) {{{1 +" Find the next or previous sibling of this node. +" +" Args: +" direction: 0 for previous, 1 for next +" +" Return: +" The next/previous TreeFileNode object or an empty dictionary if not found. +function! s:TreeFileNode.findSibling(direction) + + " There can be no siblings if there is no parent. + if empty(self.parent) + return {} + endif + + let l:nodeIndex = self.parent.getChildIndex(self.path) + + if l:nodeIndex == -1 + return {} + endif + + " Get the next index to begin the search. + let l:nodeIndex += a:direction ? 1 : -1 + + while 0 <= l:nodeIndex && l:nodeIndex < self.parent.getChildCount() + + " Return the next node if it is not ignored. + if !self.parent.children[l:nodeIndex].path.ignore(self.getNerdtree()) + return self.parent.children[l:nodeIndex] + endif + + let l:nodeIndex += a:direction ? 1 : -1 + endwhile + + return {} +endfunction + +" FUNCTION: TreeFileNode.getNerdtree(){{{1 +function! s:TreeFileNode.getNerdtree() + return self._nerdtree +endfunction + +" FUNCTION: TreeFileNode.GetRootForTab(){{{1 +" get the root node for this tab +function! s:TreeFileNode.GetRootForTab() + if g:NERDTree.ExistsForTab() + return getbufvar(t:NERDTreeBufName, 'NERDTree').root + end + return {} +endfunction + +" FUNCTION: TreeFileNode.GetSelected() {{{1 +" If the cursor is currently positioned on a tree node, return the node. +" Otherwise, return the empty dictionary. +function! s:TreeFileNode.GetSelected() + + try + let l:path = b:NERDTree.ui.getPath(line('.')) + + if empty(l:path) + return {} + endif + + return b:NERDTree.root.findNode(l:path) + catch + return {} + endtry +endfunction + +" FUNCTION: TreeFileNode.isVisible() {{{1 +" returns 1 if this node should be visible according to the tree filters and +" hidden file filters (and their on/off status) +function! s:TreeFileNode.isVisible() + return !self.path.ignore(self.getNerdtree()) +endfunction + +" FUNCTION: TreeFileNode.isRoot() {{{1 +function! s:TreeFileNode.isRoot() + if !g:NERDTree.ExistsForBuf() + throw 'NERDTree.NoTreeError: No tree exists for the current buffer' + endif + + return self.equals(self.getNerdtree().root) +endfunction + +" FUNCTION: TreeFileNode.New(path, nerdtree) {{{1 +" Returns a new TreeNode object with the given path and parent +" +" Args: +" path: file/dir that the node represents +" nerdtree: the tree the node belongs to +function! s:TreeFileNode.New(path, nerdtree) + if a:path.isDirectory + return g:NERDTreeDirNode.New(a:path, a:nerdtree) + else + let newTreeNode = copy(self) + let newTreeNode.path = a:path + let newTreeNode.parent = {} + let newTreeNode._nerdtree = a:nerdtree + return newTreeNode + endif +endfunction + +" FUNCTION: TreeFileNode.open() {{{1 +function! s:TreeFileNode.open(...) + let opts = a:0 ? a:1 : {} + let opener = g:NERDTreeOpener.New(self.path, opts) + call opener.open(self) +endfunction + +" FUNCTION: TreeFileNode.openSplit() {{{1 +" Open this node in a new window +function! s:TreeFileNode.openSplit() + call nerdtree#deprecated('TreeFileNode.openSplit', 'is deprecated, use .open() instead.') + call self.open({'where': 'h'}) +endfunction + +" FUNCTION: TreeFileNode.openVSplit() {{{1 +" Open this node in a new vertical window +function! s:TreeFileNode.openVSplit() + call nerdtree#deprecated('TreeFileNode.openVSplit', 'is deprecated, use .open() instead.') + call self.open({'where': 'v'}) +endfunction + +" FUNCTION: TreeFileNode.openInNewTab(options) {{{1 +function! s:TreeFileNode.openInNewTab(options) + call nerdtree#deprecated('TreeFileNode.openinNewTab', 'is deprecated, use .open() instead.') + call self.open(extend({'where': 't'}, a:options)) +endfunction + +" FUNCTION: TreeFileNode.openExplorer() +function! s:TreeFileNode.openExplorer() + execute 'wincmd p' + execute 'edit '.self.path.getParent().str({'format':'Edit'}) +endfunction + +" FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{1 +" Places the cursor on the line number this node is rendered on +" +" Args: +" isJump: 1 if this cursor movement should be counted as a jump by vim +" recurseUpward: try to put the cursor on the parent if the this node isnt +" visible +function! s:TreeFileNode.putCursorHere(isJump, recurseUpward) + let ln = self.getNerdtree().ui.getLineNum(self) + if ln != -1 + if a:isJump + mark ' + endif + call cursor(ln, col('.')) + else + if a:recurseUpward + let node = self + while node != {} && self.getNerdtree().ui.getLineNum(node) ==# -1 + let node = node.parent + call node.open() + endwhile + call self._nerdtree.render() + call node.putCursorHere(a:isJump, 0) + endif + endif +endfunction + +" FUNCTION: TreeFileNode.refresh() {{{1 +function! s:TreeFileNode.refresh() + call self.path.refresh(self.getNerdtree()) +endfunction + +" FUNCTION: TreeFileNode.refreshFlags() {{{1 +function! s:TreeFileNode.refreshFlags() + call self.path.refreshFlags(self.getNerdtree()) +endfunction + +" FUNCTION: TreeFileNode.rename() {{{1 +" Calls the rename method for this nodes path obj +function! s:TreeFileNode.rename(newName) + let newName = substitute(a:newName, '\(\\\|\/\)$', '', '') + call self.path.rename(newName) + call self.parent.removeChild(self) + + let parentPath = self.path.getParent() + let newParent = self.getNerdtree().root.findNode(parentPath) + + if newParent != {} + call newParent.createChild(self.path, 1) + call newParent.refresh() + endif +endfunction + +" FUNCTION: TreeFileNode.renderToString {{{1 +" returns a string representation for this tree to be rendered in the view +function! s:TreeFileNode.renderToString() + return self._renderToString(0, 0) +endfunction + +" Args: +" depth: the current depth in the tree for this call +" drawText: 1 if we should actually draw the line for this node (if 0 then the +" child nodes are rendered only) +" for each depth in the tree +function! s:TreeFileNode._renderToString(depth, drawText) + let output = '' + if a:drawText ==# 1 + + let treeParts = repeat(' ', a:depth - 1) + let treeParts .= (self.path.isDirectory || g:NERDTreeDirArrowExpandable ==# '' ? '' : ' ') + + let line = treeParts . self.displayString() + let output = output . line . "\n" + endif + + " if the node is an open dir, draw its children + if self.path.isDirectory ==# 1 && self.isOpen ==# 1 + + let childNodesToDraw = self.getVisibleChildren() + + if self.isCascadable() && a:depth > 0 + + let output = output . childNodesToDraw[0]._renderToString(a:depth, 0) + + elseif len(childNodesToDraw) > 0 + for i in childNodesToDraw + let output = output . i._renderToString(a:depth + 1, 1) + endfor + endif + endif + + return output +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/.vim/pack/vendor/start/nerdtree/lib/nerdtree/ui.vim b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/ui.vim new file mode 100644 index 0000000..a481ba4 --- /dev/null +++ b/.vim/pack/vendor/start/nerdtree/lib/nerdtree/ui.vim @@ -0,0 +1,532 @@ +" ============================================================================ +" CLASS: UI +" ============================================================================ + + +let s:UI = {} +let g:NERDTreeUI = s:UI + +" FUNCTION: s:UI.centerView() {{{1 +" centers the nerd tree window around the cursor (provided the nerd tree +" options permit) +function! s:UI.centerView() + if g:NERDTreeAutoCenter + let current_line = winline() + let lines_to_top = current_line + let lines_to_bottom = winheight(g:NERDTree.GetWinNum()) - current_line + if lines_to_top < g:NERDTreeAutoCenterThreshold || lines_to_bottom < g:NERDTreeAutoCenterThreshold + normal! zz + endif + endif +endfunction + +" FUNCTION: s:UI._dumpHelp {{{1 +" prints out the quick help +function! s:UI._dumpHelp() + if self.getShowHelp() + let help = "\" NERDTree (" . nerdtree#version() . ") quickhelp~\n" + let help .= "\" ============================\n" + let help .= "\" File node mappings~\n" + let help .= '" '. (g:NERDTreeMouseMode ==# 3 ? 'single' : 'double') ."-click,\n" + if self.nerdtree.isTabTree() + let help .= '" '. g:NERDTreeMapActivateNode .": open in prev window\n" + else + let help .= '" '. g:NERDTreeMapActivateNode .": open in current window\n" + endif + if self.nerdtree.isTabTree() + let help .= '" '. g:NERDTreeMapPreview .": preview\n" + endif + let help .= '" '. g:NERDTreeMapOpenInTab.": open in new tab\n" + let help .= '" '. g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" + let help .= "\" middle-click,\n" + let help .= '" '. g:NERDTreeMapOpenSplit .": open split\n" + let help .= '" '. g:NERDTreeMapPreviewSplit .": preview split\n" + let help .= '" '. g:NERDTreeMapOpenVSplit .": open vsplit\n" + let help .= '" '. g:NERDTreeMapPreviewVSplit .": preview vsplit\n" + let help .= '" '. g:NERDTreeMapCustomOpen .": custom open\n" + + let help .= "\"\n\" ----------------------------\n" + let help .= "\" Directory node mappings~\n" + let help .= '" '. (g:NERDTreeMouseMode ==# 1 ? 'double' : 'single') ."-click,\n" + let help .= '" '. g:NERDTreeMapActivateNode .": open & close node\n" + let help .= '" '. g:NERDTreeMapOpenRecursively .": recursively open node\n" + let help .= '" '. g:NERDTreeMapOpenInTab.": open in new tab\n" + let help .= '" '. g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" + let help .= '" '. g:NERDTreeMapCustomOpen .": custom open\n" + let help .= '" '. g:NERDTreeMapCloseDir .": close parent of node\n" + let help .= '" '. g:NERDTreeMapCloseChildren .": close all child nodes of\n" + let help .= "\" current node recursively\n" + let help .= "\" middle-click,\n" + let help .= '" '. g:NERDTreeMapOpenExpl.": explore selected dir\n" + + let help .= "\"\n\" ----------------------------\n" + let help .= "\" Bookmark table mappings~\n" + let help .= "\" double-click,\n" + let help .= '" '. g:NERDTreeMapActivateNode .": open bookmark\n" + let help .= '" '. g:NERDTreeMapPreview .": preview file\n" + let help .= '" '. g:NERDTreeMapPreview .": find dir in tree\n" + let help .= '" '. g:NERDTreeMapOpenInTab.": open in new tab\n" + let help .= '" '. g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" + let help .= '" '. g:NERDTreeMapOpenSplit .": open split\n" + let help .= '" '. g:NERDTreeMapPreviewSplit .": preview split\n" + let help .= '" '. g:NERDTreeMapOpenVSplit .": open vsplit\n" + let help .= '" '. g:NERDTreeMapPreviewVSplit .": preview vsplit\n" + let help .= '" '. g:NERDTreeMapCustomOpen .": custom open\n" + let help .= '" '. g:NERDTreeMapDeleteBookmark .": delete bookmark\n" + + let help .= "\"\n\" ----------------------------\n" + let help .= "\" Tree navigation mappings~\n" + let help .= '" '. g:NERDTreeMapJumpRoot .": go to root\n" + let help .= '" '. g:NERDTreeMapJumpParent .": go to parent\n" + let help .= '" '. g:NERDTreeMapJumpFirstChild .": go to first child\n" + let help .= '" '. g:NERDTreeMapJumpLastChild .": go to last child\n" + let help .= '" '. g:NERDTreeMapJumpNextSibling .": go to next sibling\n" + let help .= '" '. g:NERDTreeMapJumpPrevSibling .": go to prev sibling\n" + + let help .= "\"\n\" ----------------------------\n" + let help .= "\" Filesystem mappings~\n" + let help .= '" '. g:NERDTreeMapChangeRoot .": change tree root to the\n" + let help .= "\" selected dir\n" + let help .= '" '. g:NERDTreeMapUpdir .": move tree root up a dir\n" + let help .= '" '. g:NERDTreeMapUpdirKeepOpen .": move tree root up a dir\n" + let help .= "\" but leave old root open\n" + let help .= '" '. g:NERDTreeMapRefresh .": refresh cursor dir\n" + let help .= '" '. g:NERDTreeMapRefreshRoot .": refresh current root\n" + let help .= '" '. g:NERDTreeMapMenu .": Show menu\n" + let help .= '" '. g:NERDTreeMapChdir .":change the CWD to the\n" + let help .= "\" selected dir\n" + let help .= '" '. g:NERDTreeMapCWD .":change tree root to CWD\n" + + let help .= "\"\n\" ----------------------------\n" + let help .= "\" Tree filtering mappings~\n" + let help .= '" '. g:NERDTreeMapToggleHidden .': hidden files (' . (self.getShowHidden() ? 'on' : 'off') . ")\n" + let help .= '" '. g:NERDTreeMapToggleFilters .': file filters (' . (self.isIgnoreFilterEnabled() ? 'on' : 'off') . ")\n" + let help .= '" '. g:NERDTreeMapToggleFiles .': files (' . (self.getShowFiles() ? 'on' : 'off') . ")\n" + let help .= '" '. g:NERDTreeMapToggleBookmarks .': bookmarks (' . (self.getShowBookmarks() ? 'on' : 'off') . ")\n" + + " add quickhelp entries for each custom key map + let help .= "\"\n\" ----------------------------\n" + let help .= "\" Custom mappings~\n" + for i in g:NERDTreeKeyMap.All() + if !empty(i.quickhelpText) + let help .= '" '. i.key .': '. i.quickhelpText ."\n" + endif + endfor + + let help .= "\"\n\" ----------------------------\n" + let help .= "\" Other mappings~\n" + let help .= '" '. g:NERDTreeMapQuit .": Close the NERDTree window\n" + let help .= '" '. g:NERDTreeMapToggleZoom .": Zoom (maximize-minimize)\n" + let help .= "\" the NERDTree window\n" + let help .= '" '. g:NERDTreeMapHelp .": toggle help\n" + let help .= "\"\n\" ----------------------------\n" + let help .= "\" Bookmark commands~\n" + let help .= "\" :Bookmark []\n" + let help .= "\" :BookmarkToRoot \n" + let help .= "\" :RevealBookmark \n" + let help .= "\" :OpenBookmark \n" + let help .= "\" :ClearBookmarks []\n" + let help .= "\" :ClearAllBookmarks\n" + let help .= "\" :ReadBookmarks\n" + let help .= "\" :WriteBookmarks\n" + let help .= "\" :EditBookmarks\n" + silent! put =help + elseif !self.isMinimal() + let help ='" Press '. g:NERDTreeMapHelp ." for help\n" + silent! put =help + endif +endfunction + + +" FUNCTION: s:UI.new(nerdtree) {{{1 +function! s:UI.New(nerdtree) + let newObj = copy(self) + let newObj.nerdtree = a:nerdtree + let newObj._showHelp = 0 + let newObj._ignoreEnabled = 1 + let newObj._showFiles = g:NERDTreeShowFiles + let newObj._showHidden = g:NERDTreeShowHidden + let newObj._showBookmarks = g:NERDTreeShowBookmarks + + return newObj +endfunction + +" FUNCTION: s:UI.getPath(ln) {{{1 +" Return the Path object for the node that is rendered on the given line +" number. If the 'up a dir' line is selected, return the Path object for +" the parent of the root. Return the empty dictionary if the given line +" does not reference a tree node. +function! s:UI.getPath(ln) + let line = getline(a:ln) + + let rootLine = self.getRootLineNum() + + if a:ln ==# rootLine + return self.nerdtree.root.path + endif + + if line ==# s:UI.UpDirLine() + return self.nerdtree.root.path.getParent() + endif + + if a:ln < rootLine + return {} + endif + + let indent = self._indentLevelFor(line) + + " remove the tree parts and the leading space + let curFile = self._stripMarkup(line) + + let dir = '' + let lnum = a:ln + while lnum > 0 + let lnum = lnum - 1 + let curLine = getline(lnum) + let curLineStripped = self._stripMarkup(curLine) + + " have we reached the top of the tree? + if lnum ==# rootLine + let dir = self.nerdtree.root.path.str({'format': 'UI'}) . dir + break + endif + if curLineStripped =~# '/$' + let lpindent = self._indentLevelFor(curLine) + if lpindent < indent + let indent = indent - 1 + + let dir = substitute (curLineStripped,'^\\', '', '') . dir + continue + endif + endif + endwhile + let curFile = self.nerdtree.root.path.drive . dir . curFile + let toReturn = g:NERDTreePath.New(curFile) + return toReturn +endfunction + +" FUNCTION: s:UI.getLineNum(node) {{{1 +" Return the line number where the given node is rendered. Return -1 if the +" given node is not visible. +function! s:UI.getLineNum(node) + + if a:node.isRoot() + return self.getRootLineNum() + endif + + let l:pathComponents = [substitute(self.nerdtree.root.path.str({'format': 'UI'}), '/\s*$', '', '')] + let l:currentPathComponent = 1 + + let l:fullPath = a:node.path.str({'format': 'UI'}) + + for l:lineNumber in range(self.getRootLineNum() + 1, line('$')) + let l:currentLine = getline(l:lineNumber) + let l:indentLevel = self._indentLevelFor(l:currentLine) + + if l:indentLevel !=# l:currentPathComponent + continue + endif + + let l:currentLine = self._stripMarkup(l:currentLine) + let l:currentPath = join(l:pathComponents, '/') . '/' . l:currentLine + + " Directories: If the current path 'starts with' the full path, then + " either the paths are equal or the line is a cascade containing the + " full path. + if l:fullPath[-1:] ==# '/' && stridx(l:currentPath, l:fullPath) ==# 0 + return l:lineNumber + endif + + " Files: The paths must exactly match. + if l:fullPath ==# l:currentPath + return l:lineNumber + endif + + " Otherwise: If the full path starts with the current path and the + " current path is a directory, we add a new path component. + if stridx(l:fullPath, l:currentPath) ==# 0 && l:currentPath[-1:] ==# '/' + let l:currentLine = substitute(l:currentLine, '/\s*$', '', '') + call add(l:pathComponents, l:currentLine) + let l:currentPathComponent += 1 + endif + endfor + + return -1 +endfunction + +" FUNCTION: s:UI.getRootLineNum(){{{1 +" gets the line number of the root node +function! s:UI.getRootLineNum() + let rootLine = 1 + while rootLine <= line('$') && getline(rootLine) !~# '^\(/\|<\)' + let rootLine = rootLine + 1 + endwhile + return rootLine +endfunction + +" FUNCTION: s:UI.getShowBookmarks() {{{1 +function! s:UI.getShowBookmarks() + return self._showBookmarks +endfunction + +" FUNCTION: s:UI.getShowFiles() {{{1 +function! s:UI.getShowFiles() + return self._showFiles +endfunction + +" FUNCTION: s:UI.getShowHelp() {{{1 +function! s:UI.getShowHelp() + return self._showHelp +endfunction + +" FUNCTION: s:UI.getShowHidden() {{{1 +function! s:UI.getShowHidden() + return self._showHidden +endfunction + +" FUNCTION: s:UI._indentLevelFor(line) {{{1 +function! s:UI._indentLevelFor(line) + " Replace multi-character DirArrows with a single space so the + " indentation calculation doesn't get messed up. + if g:NERDTreeDirArrowExpandable ==# '' + let l:line = ' '.a:line + else + let l:line = substitute(substitute(a:line, '\V'.g:NERDTreeDirArrowExpandable, ' ', ''), '\V'.g:NERDTreeDirArrowCollapsible, ' ', '') + endif + let leadChars = match(l:line, '\M\[^ ]') + return leadChars / s:UI.IndentWid() +endfunction + +" FUNCTION: s:UI.IndentWid() {{{1 +function! s:UI.IndentWid() + return 2 +endfunction + +" FUNCTION: s:UI.isIgnoreFilterEnabled() {{{1 +function! s:UI.isIgnoreFilterEnabled() + return self._ignoreEnabled ==# 1 +endfunction + +" FUNCTION: s:UI.isMinimal() {{{1 +function! s:UI.isMinimal() + return g:NERDTreeMinimalUI +endfunction + +" FUNCTION: s:UI.MarkupReg() {{{1 +function! s:UI.MarkupReg() + return '^ *['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.']\? ' +endfunction + +" FUNCTION: s:UI._renderBookmarks {{{1 +function! s:UI._renderBookmarks() + + if !self.isMinimal() + call setline(line('.')+1, '>----------Bookmarks----------') + call cursor(line('.')+1, col('.')) + endif + + if g:NERDTreeBookmarksSort ==# 1 || g:NERDTreeBookmarksSort ==# 2 + call g:NERDTreeBookmark.SortBookmarksList() + endif + + for i in g:NERDTreeBookmark.Bookmarks() + call setline(line('.')+1, i.str()) + call cursor(line('.')+1, col('.')) + endfor + + call setline(line('.')+1, '') + call cursor(line('.')+1, col('.')) +endfunction + +" FUNCTION: s:UI.restoreScreenState() {{{1 +" +" Sets the screen state back to what it was when nerdtree#saveScreenState was last +" called. +" +" Assumes the cursor is in the NERDTree window +function! s:UI.restoreScreenState() + if !has_key(self, '_screenState') + return + endif + call nerdtree#exec('silent vertical resize ' . self._screenState['oldWindowSize'], 1) + + let old_scrolloff=&scrolloff + let &scrolloff=0 + call cursor(self._screenState['oldTopLine'], 0) + normal! zt + call setpos('.', self._screenState['oldPos']) + let &scrolloff=old_scrolloff +endfunction + +" FUNCTION: s:UI.saveScreenState() {{{1 +" Saves the current cursor position in the current buffer and the window +" scroll position +function! s:UI.saveScreenState() + let win = winnr() + let self._screenState = {} + try + call g:NERDTree.CursorToTreeWin() + let self._screenState['oldPos'] = getpos('.') + let self._screenState['oldTopLine'] = line('w0') + let self._screenState['oldWindowSize'] = winnr('$')==1 ? g:NERDTreeWinSize : winwidth('') + call nerdtree#exec(win . 'wincmd w', 1) + catch + endtry +endfunction + +" FUNCTION: s:UI.setShowHidden(val) {{{1 +function! s:UI.setShowHidden(val) + let self._showHidden = a:val +endfunction + +" FUNCTION: s:UI._stripMarkup(line){{{1 +" find the filename in the given line, and return it. +" +" Args: +" line: the subject line +function! s:UI._stripMarkup(line) + let l:line = substitute(a:line, '^.\{-}' . g:NERDTreeNodeDelimiter, '', '') + return substitute(l:line, g:NERDTreeNodeDelimiter.'.*$', '', '') +endfunction + +" FUNCTION: s:UI.render() {{{1 +function! s:UI.render() + setlocal noreadonly modifiable + + " remember the top line of the buffer and the current line so we can + " restore the view exactly how it was + let curLine = line('.') + let curCol = col('.') + let topLine = line('w0') + + " delete all lines in the buffer (being careful not to clobber a register) + silent 1,$delete _ + + call self._dumpHelp() + + " delete the blank line before the help and add one after it + if !self.isMinimal() + call setline(line('.')+1, '') + call cursor(line('.')+1, col('.')) + endif + + if self.getShowBookmarks() + call self._renderBookmarks() + endif + + " add the 'up a dir' line + if !self.isMinimal() + call setline(line('.')+1, s:UI.UpDirLine()) + call cursor(line('.')+1, col('.')) + endif + + " draw the header line + let header = self.nerdtree.root.path.str({'format': 'UI', 'truncateTo': winwidth(0)}) + call setline(line('.')+1, header) + call cursor(line('.')+1, col('.')) + + " draw the tree + silent put =self.nerdtree.root.renderToString() + + " delete the blank line at the top of the buffer + silent 1,1delete _ + + " restore the view + let old_scrolloff=&scrolloff + let &scrolloff=0 + call cursor(topLine, 1) + normal! zt + call cursor(curLine, curCol) + let &scrolloff = old_scrolloff + + setlocal readonly nomodifiable +endfunction + + +" FUNCTION: UI.renderViewSavingPosition {{{1 +" Renders the tree and ensures the cursor stays on the current node or the +" current nodes parent if it is no longer available upon re-rendering +function! s:UI.renderViewSavingPosition() + let currentNode = g:NERDTreeFileNode.GetSelected() + + " go up the tree till we find a node that will be visible or till we run + " out of nodes + while currentNode !=# {} && !currentNode.isVisible() && !currentNode.isRoot() + let currentNode = currentNode.parent + endwhile + + call self.render() + + if currentNode !=# {} + call currentNode.putCursorHere(0, 0) + endif +endfunction + +" FUNCTION: s:UI.toggleHelp() {{{1 +function! s:UI.toggleHelp() + let self._showHelp = !self._showHelp +endfunction + +" FUNCTION: s:UI.toggleIgnoreFilter() {{{1 +" toggles the use of the NERDTreeIgnore option +function! s:UI.toggleIgnoreFilter() + let self._ignoreEnabled = !self._ignoreEnabled + call self.renderViewSavingPosition() + call self.centerView() +endfunction + +" FUNCTION: s:UI.toggleShowBookmarks() {{{1 +" Toggle the visibility of the Bookmark table. +function! s:UI.toggleShowBookmarks() + let self._showBookmarks = !self._showBookmarks + + if self.getShowBookmarks() + call self.nerdtree.render() + call g:NERDTree.CursorToBookmarkTable() + else + + if empty(g:NERDTreeFileNode.GetSelected()) + call b:NERDTree.root.putCursorHere(0, 0) + normal! 0 + endif + + call self.renderViewSavingPosition() + endif + + call self.centerView() +endfunction + +" FUNCTION: s:UI.toggleShowFiles() {{{1 +" toggles the display of hidden files +function! s:UI.toggleShowFiles() + let self._showFiles = !self._showFiles + call self.renderViewSavingPosition() + call self.centerView() +endfunction + +" FUNCTION: s:UI.toggleShowHidden() {{{1 +" toggles the display of hidden files +function! s:UI.toggleShowHidden() + let self._showHidden = !self._showHidden + call self.renderViewSavingPosition() + call self.centerView() +endfunction + +" FUNCTION: s:UI.toggleZoom() {{{1 +" zoom (maximize/minimize) the NERDTree window +function! s:UI.toggleZoom() + if exists('b:NERDTreeZoomed') && b:NERDTreeZoomed + call nerdtree#exec('silent vertical resize '. g:NERDTreeWinSize, 1) + let b:NERDTreeZoomed = 0 + else + call nerdtree#exec('vertical resize '. get(g:, 'NERDTreeWinSizeMax', ''), 1) + let b:NERDTreeZoomed = 1 + endif +endfunction + +" FUNCTION: s:UI.UpDirLine() {{{1 +function! s:UI.UpDirLine() + return '.. (up a dir)' +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: -- cgit v1.2.3