├── .gitignore ├── CHANGELOG ├── LICENCE ├── README ├── README.markdown ├── autoload ├── nerdtree.vim └── nerdtree │ └── ui_glue.vim ├── doc └── NERD_tree.txt ├── lib └── nerdtree │ ├── bookmark.vim │ ├── creator.vim │ ├── event.vim │ ├── flag_set.vim │ ├── key_map.vim │ ├── menu_controller.vim │ ├── menu_item.vim │ ├── nerdtree.vim │ ├── notifier.vim │ ├── opener.vim │ ├── path.vim │ ├── tree_dir_node.vim │ ├── tree_file_node.vim │ └── ui.vim ├── nerdtree_plugin ├── exec_menuitem.vim └── fs_menu.vim ├── plugin └── NERD_tree.vim └── syntax └── nerdtree.vim /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | tags 4 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 5.0.0 2 | - Refactor the code significantly: 3 | * Break the classes out into their own files. 4 | * Make the majority of the code OO - previously large parts were 5 | effectively a tangle of "global" methods. 6 | - Add an API to assign flags to nodes. This allows VCS plugins like 7 | https://github.com/Xuyuanp/nerdtree-git-plugin to exist. Thanks to 8 | Xuyuanp for helping design/test/build said API. 9 | - add 'scope' argument to the key map API see :help NERDTreeAddKeyMap() 10 | - add magic [[dir]] and [[file]] flags to NERDTreeIgnore 11 | - add support for custom path filters. See :help NERDTreeAddPathFilter() 12 | - add path listener API. See :help NERDTreePathListenerAPI. 13 | - expand the fs menu functionality to list file properties (PhilRunninger, 14 | apbarrero, JESii) 15 | - make bookmarks work with `~` home shortcuts (hiberabyss) 16 | - show OSX specific fsmenu options in regular vim on mac (evindor) 17 | - make dir arrow icons configurable (PickRelated) 18 | - optimise node sorting performance when opening large dirs (vtsang) 19 | - make the root note render prettier by truncating it at a path slash (gcmt) 20 | - remove NERDChristmasTree option - its always christmas now 21 | - add "cascade" open and closing for dirs containing only another single 22 | dir. See :help NERDTreeCascadeOpenSingleChildDir (pendulm) 23 | 24 | Many other fixes, doc updates and contributions from: 25 | actionshrimp 26 | SchDen 27 | egalpin 28 | cperl82 - many small fixes 29 | toiffel 30 | WoLpH 31 | handcraftedbits 32 | devmanhinton 33 | xiaodili 34 | zhangoose 35 | gastropoda 36 | mixvin 37 | alvan 38 | lucascaton 39 | kelaban 40 | shanesmith 41 | staeff 42 | pendulm 43 | stephenprater 44 | franksort 45 | agrussellknives 46 | AndrewRadev 47 | Twinside 48 | 49 | 4.2.0 50 | - Add NERDTreeDirArrows option to make the UI use pretty arrow chars 51 | instead of the old +~| chars to define the tree structure (sickill) 52 | - shift the syntax highlighting out into its own syntax file (gnap) 53 | - add some mac specific options to the filesystem menu - for macvim 54 | only (andersonfreitas) 55 | - Add NERDTreeMinimalUI option to remove some non functional parts of the 56 | nerdtree ui (camthompson) 57 | - tweak the behaviour of :NERDTreeFind - see :help :NERDTreeFind for the 58 | new behaviour (benjamingeiger) 59 | - if no name is given to :Bookmark, make it default to the name of the 60 | target file/dir (minyoung) 61 | - use 'file' completion when doing copying, create, and move 62 | operations (EvanDotPro) 63 | - lots of misc bug fixes (paddyoloughlin, sdewald, camthompson, Vitaly 64 | Bogdanov, AndrewRadev, mathias, scottstvnsn, kml, wycats, me RAWR!) 65 | 66 | 4.1.0 67 | features: 68 | - NERDTreeFind to reveal the node for the current buffer in the tree, 69 | see |NERDTreeFind|. This effectively merges the FindInNERDTree plugin (by 70 | Doug McInnes) into the script. 71 | - make NERDTreeQuitOnOpen apply to the t/T keymaps too. Thanks to Stefan 72 | Ritter and Rémi Prévost. 73 | - truncate the root node if wider than the tree window. Thanks to Victor 74 | Gonzalez. 75 | 76 | bugfixes: 77 | - really fix window state restoring 78 | - fix some win32 path escaping issues. Thanks to Stephan Baumeister, Ricky, 79 | jfilip1024, and Chris Chambers 80 | 81 | 4.0.0 82 | - add a new programmable menu system (see :help NERDTreeMenu). 83 | - add new APIs to add menus/menu-items to the menu system as well as 84 | custom key mappings to the NERD tree buffer (see :help NERDTreeAPI). 85 | - removed the old API functions 86 | - added a mapping to maximize/restore the size of nerd tree window, thanks 87 | to Guillaume Duranceau for the patch. See :help NERDTree-A for details. 88 | 89 | - fix a bug where secondary nerd trees (netrw hijacked trees) and 90 | NERDTreeQuitOnOpen didnt play nicely, thanks to Curtis Harvey. 91 | - fix a bug where the script ignored directories whose name ended in a dot, 92 | thanks to Aggelos Orfanakos for the patch. 93 | - fix a bug when using the x mapping on the tree root, thanks to Bryan 94 | Venteicher for the patch. 95 | - fix a bug where the cursor position/window size of the nerd tree buffer 96 | wasnt being stored on closing the window, thanks to Richard Hart. 97 | - fix a bug where NERDTreeMirror would mirror the wrong tree 98 | 99 | 3.1.1 100 | - fix a bug where a non-listed no-name buffer was getting created every 101 | time the tree windows was created, thanks to Derek Wyatt and owen1 102 | - make behave the same as the 'o' mapping 103 | - some helptag fixes in the doc, thanks strull 104 | - fix a bug when using :set nohidden and opening a file where the previous 105 | buf was modified. Thanks iElectric 106 | - other minor fixes 107 | 108 | 3.1.0 109 | New features: 110 | - add mappings to open files in a vsplit, see :help NERDTree-s and :help 111 | NERDTree-gs 112 | - make the statusline for the nerd tree window default to something 113 | hopefully more useful. See :help 'NERDTreeStatusline' 114 | Bugfixes: 115 | - make the hijack netrw functionality work when vim is started with "vim 116 | " (thanks to Alf Mikula for the patch). 117 | - fix a bug where the CWD wasnt being changed for some operations even when 118 | NERDTreeChDirMode==2 (thanks to Lucas S. Buchala) 119 | - add -bar to all the nerd tree :commands so they can chain with other 120 | :commands (thanks to tpope) 121 | - fix bugs when ignorecase was set (thanks to nach) 122 | - fix a bug with the relative path code (thanks to nach) 123 | - fix a bug where doing a :cd would cause :NERDTreeToggle to fail (thanks nach) 124 | 125 | 126 | 3.0.1 127 | Bugfixes: 128 | - fix bugs with :NERDTreeToggle and :NERDTreeMirror when 'hidden 129 | was not set 130 | - fix a bug where :NERDTree would fail if was relative and 131 | didnt start with a ./ or ../ Thanks to James Kanze. 132 | - make the q mapping work with secondary (:e style) trees, 133 | thanks to jamessan 134 | - fix a bunch of small bugs with secondary trees 135 | 136 | More insane refactoring. 137 | 138 | 3.0.0 139 | - hijack netrw so that doing an :edit will put a NERD tree in 140 | the window rather than a netrw browser. See :help 'NERDTreeHijackNetrw' 141 | - allow sharing of trees across tabs, see :help :NERDTreeMirror 142 | - remove "top" and "bottom" as valid settings for NERDTreeWinPos 143 | - change the '' mapping to 'i' 144 | - change the 'H' mapping to 'I' 145 | - lots of refactoring 146 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is a mirror of http://www.vim.org/scripts/script.php?script_id=1658 2 | 3 | Grab the latest dev version from github: https://github.com/scrooloose/nerdtree. 4 | 5 | What is this "NERD tree"?? 6 | 7 | Check out this demo http://www.flickr.com/photos/30496122@N07/2862367534/sizes/o/ 8 | 9 | The NERD tree allows you to explore your filesystem and to open files and 10 | directories. It presents the filesystem to you in the form of a tree which you 11 | manipulate with the keyboard and/or mouse. It also allows you to perform 12 | simple filesystem operations. 13 | 14 | The following features and functionality are provided by the NERD tree: 15 | * Files and directories are displayed in a hierarchical tree structure 16 | * Different highlighting is provided for the following types of nodes: 17 | * files 18 | * directories 19 | * sym-links 20 | * windows .lnk files 21 | * read-only files 22 | * executable files 23 | * Many (customisable) mappings are provided to manipulate the tree: 24 | * Mappings to open/close/explore directory nodes 25 | * Mappings to open files in new/existing windows/tabs 26 | * Mappings to change the current root of the tree 27 | * Mappings to navigate around the tree 28 | * ... 29 | * Directories and files can be bookmarked. 30 | * Most NERD tree navigation can also be done with the mouse 31 | * Filtering of tree content (can be toggled at runtime) 32 | * custom file filters to prevent e.g. vim backup files being displayed 33 | * optional displaying of hidden files (. files) 34 | * files can be "turned off" so that only directories are displayed 35 | * A textual filesystem menu is provided which allows you to 36 | create/delete/move file and directory nodes as well as copy (for 37 | supported OSs) 38 | * The position and size of the NERD tree window can be customised 39 | * The order in which the nodes in the tree are listed can be customised. 40 | * A model of your filesystem is created/maintained as you explore it. This 41 | has several advantages: 42 | * All filesystem information is cached and is only re-read on demand 43 | * If you revisit a part of the tree that you left earlier in your 44 | session, the directory nodes will be opened/closed as you left them 45 | * The script remembers the cursor position and window position in the NERD 46 | tree so you can toggle it off (or just close the tree window) and then 47 | reopen it (with NERDTreeToggle) the NERD tree window will appear exactly 48 | as you left it 49 | * You can have a separate NERD tree for each tab, share trees across tabs, 50 | or a mix of both. 51 | * By default the script overrides the default file browser (netw), so if 52 | you :edit a directory a (slighly modified) NERD tree will appear in the 53 | current window 54 | 55 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | The NERD Tree 2 | ============= 3 | 4 | Intro 5 | ----- 6 | 7 | The NERD tree allows you to explore your filesystem and to open files and 8 | directories. It presents the filesystem to you in the form of a tree which you 9 | manipulate with the keyboard and/or mouse. It also allows you to perform 10 | simple filesystem operations. 11 | 12 | The following features and functionality are provided by the NERD tree: 13 | 14 | * Files and directories are displayed in a hierarchical tree structure 15 | * Different highlighting is provided for the following types of nodes: 16 | * files 17 | * directories 18 | * sym-links 19 | * windows .lnk files 20 | * read-only files 21 | * executable files 22 | * Many (customisable) mappings are provided to manipulate the tree: 23 | * Mappings to open/close/explore directory nodes 24 | * Mappings to open files in new/existing windows/tabs 25 | * Mappings to change the current root of the tree 26 | * Mappings to navigate around the tree 27 | * ... 28 | * Directories and files can be bookmarked. 29 | * Most NERD tree navigation can also be done with the mouse 30 | * Filtering of tree content (can be toggled at runtime) 31 | * custom file filters to prevent e.g. vim backup files being displayed 32 | * optional displaying of hidden files (. files) 33 | * files can be "turned off" so that only directories are displayed 34 | * The position and size of the NERD tree window can be customised 35 | * The order in which the nodes in the tree are listed can be customised. 36 | * A model of your filesystem is created/maintained as you explore it. This 37 | has several advantages: 38 | * All filesystem information is cached and is only re-read on demand 39 | * If you revisit a part of the tree that you left earlier in your 40 | session, the directory nodes will be opened/closed as you left them 41 | * The script remembers the cursor position and window position in the NERD 42 | tree so you can toggle it off (or just close the tree window) and then 43 | reopen it (with NERDTreeToggle) the NERD tree window will appear exactly 44 | as you left it 45 | * You can have a separate NERD tree for each tab, share trees across tabs, 46 | or a mix of both. 47 | * By default the script overrides the default file browser (netrw), so if 48 | you :edit a directory a (slightly modified) NERD tree will appear in the 49 | current window 50 | * A programmable menu system is provided (simulates right clicking on a node) 51 | * one default menu plugin is provided to perform basic filesystem 52 | operations (create/delete/move/copy files/directories) 53 | * There's an API for adding your own keymappings 54 | 55 | Installation 56 | ------------ 57 | 58 | ####[pathogen.vim](https://github.com/tpope/vim-pathogen) 59 | 60 | cd ~/.vim/bundle 61 | git clone https://github.com/scrooloose/nerdtree.git 62 | 63 | Then reload vim, run `:Helptags`, and check out `:help NERD_tree.txt`. 64 | 65 | 66 | ####[apt-vim](https://github.com/egalpin/apt-vim) 67 | 68 | apt-vim install -y https://github.com/scrooloose/nerdtree.git 69 | 70 | 71 | 72 | Faq 73 | --- 74 | 75 | > Is there any support for `git` flags? 76 | 77 | Yes, install [nerdtree-git-plugin](https://github.com/Xuyuanp/nerdtree-git-plugin). 78 | 79 | 80 | > Can I have the nerdtree on every tab automatically? 81 | 82 | Nope. If this is something you want then chances are you aren't using tabs and 83 | buffers as they were intended to be used. Read this 84 | http://stackoverflow.com/questions/102384/using-vims-tabs-like-buffers 85 | 86 | If you are interested in this behaviour then consider [vim-nerdtree-tabs](https://github.com/jistr/vim-nerdtree-tabs) 87 | 88 | > How can I open a NERDTree automatically when vim starts up? 89 | 90 | Stick this in your vimrc: `autocmd vimenter * NERDTree` 91 | 92 | > How can I open a NERDTree automatically when vim starts up if no files were specified? 93 | 94 | Stick this in your vimrc 95 | 96 | autocmd StdinReadPre * let s:std_in=1 97 | autocmd VimEnter * if argc() == 0 && !exists("s:std_in") | NERDTree | endif 98 | 99 | > How can I map a specific key or shortcut to open NERDTree? 100 | 101 | Stick this in your vimrc to open NERDTree with `Ctrl+n` (you can set whatever key you want): 102 | 103 | map :NERDTreeToggle 104 | 105 | > How can I close vim if the only window left open is a NERDTree? 106 | 107 | Stick this in your vimrc: 108 | 109 | autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTreeType") && b:NERDTreeType == "primary") | q | endif 110 | 111 | > Can I have different highlighting for different file extensions? 112 | 113 | See here: https://github.com/scrooloose/nerdtree/issues/433#issuecomment-92590696 114 | 115 | > How can I change default arrows? 116 | 117 | Use these variables in your vimrc. Note that below are default arrow symbols 118 | 119 | let g:NERDTreeDirArrows = 1 120 | let g:NERDTreeDirArrowExpandable = '▸' 121 | let g:NERDTreeDirArrowCollapsible = '▾' 122 | -------------------------------------------------------------------------------- /autoload/nerdtree.vim: -------------------------------------------------------------------------------- 1 | if exists("g:loaded_nerdtree_autoload") 2 | finish 3 | endif 4 | let g:loaded_nerdtree_autoload = 1 5 | 6 | function! nerdtree#version() 7 | return '5.0.0' 8 | endfunction 9 | 10 | " SECTION: General Functions {{{1 11 | "============================================================ 12 | 13 | "FUNCTION: nerdtree#checkForBrowse(dir) {{{2 14 | "inits a secondary nerd tree in the current buffer if appropriate 15 | function! nerdtree#checkForBrowse(dir) 16 | if a:dir != '' && isdirectory(a:dir) 17 | call g:NERDTreeCreator.CreateSecondary(a:dir) 18 | endif 19 | endfunction 20 | 21 | " FUNCTION: nerdtree#completeBookmarks(A,L,P) {{{2 22 | " completion function for the bookmark commands 23 | function! nerdtree#completeBookmarks(A,L,P) 24 | return filter(g:NERDTreeBookmark.BookmarkNames(), 'v:val =~# "^' . a:A . '"') 25 | endfunction 26 | 27 | "FUNCTION: nerdtree#compareBookmarks(dir) {{{2 28 | function! nerdtree#compareBookmarks(first, second) 29 | return a:first.compareTo(a:second) 30 | endfunction 31 | 32 | "FUNCTION: nerdtree#compareNodes(dir) {{{2 33 | function! nerdtree#compareNodes(n1, n2) 34 | return a:n1.path.compareTo(a:n2.path) 35 | endfunction 36 | 37 | "FUNCTION: nerdtree#compareNodesBySortKey(n1, n2) {{{2 38 | function! nerdtree#compareNodesBySortKey(n1, n2) 39 | if a:n1.path.getSortKey() <# a:n2.path.getSortKey() 40 | return -1 41 | elseif a:n1.path.getSortKey() ># a:n2.path.getSortKey() 42 | return 1 43 | else 44 | return 0 45 | endif 46 | endfunction 47 | 48 | " FUNCTION: nerdtree#deprecated(func, [msg]) {{{2 49 | " Issue a deprecation warning for a:func. If a second arg is given, use this 50 | " as the deprecation message 51 | function! nerdtree#deprecated(func, ...) 52 | let msg = a:0 ? a:func . ' ' . a:1 : a:func . ' is deprecated' 53 | 54 | if !exists('s:deprecationWarnings') 55 | let s:deprecationWarnings = {} 56 | endif 57 | if !has_key(s:deprecationWarnings, a:func) 58 | let s:deprecationWarnings[a:func] = 1 59 | echomsg msg 60 | endif 61 | endfunction 62 | 63 | " FUNCTION: nerdtree#exec(cmd) {{{2 64 | " same as :exec cmd but eventignore=all is set for the duration 65 | function! nerdtree#exec(cmd) 66 | let old_ei = &ei 67 | set ei=all 68 | exec a:cmd 69 | let &ei = old_ei 70 | endfunction 71 | 72 | " FUNCTION: nerdtree#has_opt(options, name) {{{2 73 | function! nerdtree#has_opt(options, name) 74 | return has_key(a:options, a:name) && a:options[a:name] == 1 75 | endfunction 76 | 77 | " FUNCTION: nerdtree#loadClassFiles() {{{2 78 | function! nerdtree#loadClassFiles() 79 | runtime lib/nerdtree/path.vim 80 | runtime lib/nerdtree/menu_controller.vim 81 | runtime lib/nerdtree/menu_item.vim 82 | runtime lib/nerdtree/key_map.vim 83 | runtime lib/nerdtree/bookmark.vim 84 | runtime lib/nerdtree/tree_file_node.vim 85 | runtime lib/nerdtree/tree_dir_node.vim 86 | runtime lib/nerdtree/opener.vim 87 | runtime lib/nerdtree/creator.vim 88 | runtime lib/nerdtree/flag_set.vim 89 | runtime lib/nerdtree/nerdtree.vim 90 | runtime lib/nerdtree/ui.vim 91 | runtime lib/nerdtree/event.vim 92 | runtime lib/nerdtree/notifier.vim 93 | endfunction 94 | 95 | " FUNCTION: nerdtree#postSourceActions() {{{2 96 | function! nerdtree#postSourceActions() 97 | call g:NERDTreeBookmark.CacheBookmarks(0) 98 | call nerdtree#ui_glue#createDefaultBindings() 99 | 100 | "load all nerdtree plugins 101 | runtime! nerdtree_plugin/**/*.vim 102 | endfunction 103 | 104 | "FUNCTION: nerdtree#runningWindows(dir) {{{2 105 | function! nerdtree#runningWindows() 106 | return has("win16") || has("win32") || has("win64") 107 | endfunction 108 | 109 | " SECTION: View Functions {{{1 110 | "============================================================ 111 | 112 | "FUNCTION: nerdtree#echo {{{2 113 | "A wrapper for :echo. Appends 'NERDTree:' on the front of all messages 114 | " 115 | "Args: 116 | "msg: the message to echo 117 | function! nerdtree#echo(msg) 118 | redraw 119 | echomsg "NERDTree: " . a:msg 120 | endfunction 121 | 122 | "FUNCTION: nerdtree#echoError {{{2 123 | "Wrapper for nerdtree#echo, sets the message type to errormsg for this message 124 | "Args: 125 | "msg: the message to echo 126 | function! nerdtree#echoError(msg) 127 | echohl errormsg 128 | call nerdtree#echo(a:msg) 129 | echohl normal 130 | endfunction 131 | 132 | "FUNCTION: nerdtree#echoWarning {{{2 133 | "Wrapper for nerdtree#echo, sets the message type to warningmsg for this message 134 | "Args: 135 | "msg: the message to echo 136 | function! nerdtree#echoWarning(msg) 137 | echohl warningmsg 138 | call nerdtree#echo(a:msg) 139 | echohl normal 140 | endfunction 141 | 142 | "FUNCTION: nerdtree#renderView {{{2 143 | function! nerdtree#renderView() 144 | call b:NERDTree.render() 145 | endfunction 146 | 147 | " vim: set sw=4 sts=4 et fdm=marker: 148 | -------------------------------------------------------------------------------- /autoload/nerdtree/ui_glue.vim: -------------------------------------------------------------------------------- 1 | if exists("g:loaded_nerdtree_ui_glue_autoload") 2 | finish 3 | endif 4 | let g:loaded_nerdtree_ui_glue_autoload = 1 5 | 6 | " FUNCTION: nerdtree#ui_glue#createDefaultBindings() {{{1 7 | function! nerdtree#ui_glue#createDefaultBindings() 8 | let s = '' . s:SID() . '_' 9 | 10 | call NERDTreeAddKeyMap({ 'key': '', 'scope': "all", 'callback': s."handleMiddleMouse" }) 11 | call NERDTreeAddKeyMap({ 'key': '', 'scope': "all", 'callback': s."handleLeftClick" }) 12 | call NERDTreeAddKeyMap({ 'key': '<2-LeftMouse>', 'scope': "DirNode", 'callback': s."activateDirNode" }) 13 | call NERDTreeAddKeyMap({ 'key': '<2-LeftMouse>', 'scope': "FileNode", 'callback': s."activateFileNode" }) 14 | call NERDTreeAddKeyMap({ 'key': '<2-LeftMouse>', 'scope': "Bookmark", 'callback': s."activateBookmark" }) 15 | call NERDTreeAddKeyMap({ 'key': '<2-LeftMouse>', 'scope': "all", 'callback': s."activateAll" }) 16 | 17 | 18 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "DirNode", 'callback': s."activateDirNode" }) 19 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "FileNode", 'callback': s."activateFileNode" }) 20 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "Bookmark", 'callback': s."activateBookmark" }) 21 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "all", 'callback': s."activateAll" }) 22 | 23 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenSplit, 'scope': "Node", 'callback': s."openHSplit" }) 24 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenVSplit, 'scope': "Node", 'callback': s."openVSplit" }) 25 | 26 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenSplit, 'scope': "Bookmark", 'callback': s."openHSplit" }) 27 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenVSplit, 'scope': "Bookmark", 'callback': s."openVSplit" }) 28 | 29 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreview, 'scope': "Node", 'callback': s."previewNodeCurrent" }) 30 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreviewVSplit, 'scope': "Node", 'callback': s."previewNodeVSplit" }) 31 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreviewSplit, 'scope': "Node", 'callback': s."previewNodeHSplit" }) 32 | 33 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreview, 'scope': "Bookmark", 'callback': s."previewNodeCurrent" }) 34 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreviewVSplit, 'scope': "Bookmark", 'callback': s."previewNodeVSplit" }) 35 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreviewSplit, 'scope': "Bookmark", 'callback': s."previewNodeHSplit" }) 36 | 37 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenRecursively, 'scope': "DirNode", 'callback': s."openNodeRecursively" }) 38 | 39 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapUpdir, 'scope': "all", 'callback': s."upDirCurrentRootClosed" }) 40 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapUpdirKeepOpen, 'scope': "all", 'callback': s."upDirCurrentRootOpen" }) 41 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapChangeRoot, 'scope': "Node", 'callback': s."chRoot" }) 42 | 43 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapChdir, 'scope': "Node", 'callback': s."chCwd" }) 44 | 45 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapQuit, 'scope': "all", 'callback': s."closeTreeWindow" }) 46 | 47 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCWD, 'scope': "all", 'callback': "nerdtree#ui_glue#chRootCwd" }) 48 | 49 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapRefreshRoot, 'scope': "all", 'callback': s."refreshRoot" }) 50 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapRefresh, 'scope': "Node", 'callback': s."refreshCurrent" }) 51 | 52 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapHelp, 'scope': "all", 'callback': s."displayHelp" }) 53 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleZoom, 'scope': "all", 'callback': s."toggleZoom" }) 54 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleHidden, 'scope': "all", 'callback': s."toggleShowHidden" }) 55 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleFilters, 'scope': "all", 'callback': s."toggleIgnoreFilter" }) 56 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleFiles, 'scope': "all", 'callback': s."toggleShowFiles" }) 57 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleBookmarks, 'scope': "all", 'callback': s."toggleShowBookmarks" }) 58 | 59 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCloseDir, 'scope': "Node", 'callback': s."closeCurrentDir" }) 60 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCloseChildren, 'scope': "DirNode", 'callback': s."closeChildren" }) 61 | 62 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapMenu, 'scope': "Node", 'callback': s."showMenu" }) 63 | 64 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpParent, 'scope': "Node", 'callback': s."jumpToParent" }) 65 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpFirstChild, 'scope': "Node", 'callback': s."jumpToFirstChild" }) 66 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpLastChild, 'scope': "Node", 'callback': s."jumpToLastChild" }) 67 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpRoot, 'scope': "all", 'callback': s."jumpToRoot" }) 68 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpNextSibling, 'scope': "Node", 'callback': s."jumpToNextSibling" }) 69 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpPrevSibling, 'scope': "Node", 'callback': s."jumpToPrevSibling" }) 70 | 71 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenInTab, 'scope': "Node", 'callback': s."openInNewTab" }) 72 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenInTabSilent, 'scope': "Node", 'callback': s."openInNewTabSilent" }) 73 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenInTab, 'scope': "Bookmark", 'callback': s."openInNewTab" }) 74 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenInTabSilent, 'scope': "Bookmark", 'callback': s."openInNewTabSilent" }) 75 | 76 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenExpl, 'scope': "DirNode", 'callback': s."openExplorer" }) 77 | 78 | call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapDeleteBookmark, 'scope': "Bookmark", 'callback': s."deleteBookmark" }) 79 | endfunction 80 | 81 | 82 | "SECTION: Interface bindings {{{1 83 | "============================================================ 84 | 85 | "FUNCTION: s:activateAll() {{{1 86 | "handle the user activating the updir line 87 | function! s:activateAll() 88 | if getline(".") ==# g:NERDTreeUI.UpDirLine() 89 | return nerdtree#ui_glue#upDir(0) 90 | endif 91 | endfunction 92 | 93 | "FUNCTION: s:activateDirNode() {{{1 94 | "handle the user activating a tree node 95 | function! s:activateDirNode(node) 96 | call a:node.activate() 97 | endfunction 98 | 99 | "FUNCTION: s:activateFileNode() {{{1 100 | "handle the user activating a tree node 101 | function! s:activateFileNode(node) 102 | call a:node.activate({'reuse': 'all', 'where': 'p'}) 103 | endfunction 104 | 105 | "FUNCTION: s:activateBookmark() {{{1 106 | "handle the user activating a bookmark 107 | function! s:activateBookmark(bm) 108 | call a:bm.activate(!a:bm.path.isDirectory ? {'where': 'p'} : {}) 109 | endfunction 110 | 111 | " FUNCTION: nerdtree#ui_glue#bookmarkNode(name) {{{1 112 | " Associate the current node with the given name 113 | function! nerdtree#ui_glue#bookmarkNode(...) 114 | let currentNode = g:NERDTreeFileNode.GetSelected() 115 | if currentNode != {} 116 | let name = a:1 117 | if empty(name) 118 | let name = currentNode.path.getLastPathComponent(0) 119 | endif 120 | try 121 | call currentNode.bookmark(name) 122 | call b:NERDTree.render() 123 | catch /^NERDTree.IllegalBookmarkNameError/ 124 | call nerdtree#echo("bookmark names must not contain spaces") 125 | endtry 126 | else 127 | call nerdtree#echo("select a node first") 128 | endif 129 | endfunction 130 | 131 | " FUNCTION: s:chCwd(node) {{{1 132 | function! s:chCwd(node) 133 | try 134 | call a:node.path.changeToDir() 135 | catch /^NERDTree.PathChangeError/ 136 | call nerdtree#echoWarning("could not change cwd") 137 | endtry 138 | endfunction 139 | 140 | " FUNCTION: s:chRoot(node) {{{1 141 | " changes the current root to the selected one 142 | function! s:chRoot(node) 143 | call a:node.makeRoot() 144 | call b:NERDTree.render() 145 | call b:NERDTreeRoot.putCursorHere(0, 0) 146 | endfunction 147 | 148 | " FUNCTION: s:nerdtree#ui_glue#chRootCwd() {{{1 149 | " changes the current root to CWD 150 | function! nerdtree#ui_glue#chRootCwd() 151 | try 152 | let cwd = g:NERDTreePath.New(getcwd()) 153 | catch /^NERDTree.InvalidArgumentsError/ 154 | call nerdtree#echo("current directory does not exist.") 155 | return 156 | endtry 157 | if cwd.str() == g:NERDTreeFileNode.GetRootForTab().path.str() 158 | return 159 | endif 160 | call s:chRoot(g:NERDTreeDirNode.New(cwd)) 161 | endfunction 162 | 163 | " FUNCTION: nnerdtree#ui_glue#clearBookmarks(bookmarks) {{{1 164 | function! nerdtree#ui_glue#clearBookmarks(bookmarks) 165 | if a:bookmarks ==# '' 166 | let currentNode = g:NERDTreeFileNode.GetSelected() 167 | if currentNode != {} 168 | call currentNode.clearBookmarks() 169 | endif 170 | else 171 | for name in split(a:bookmarks, ' ') 172 | let bookmark = g:NERDTreeBookmark.BookmarkFor(name) 173 | call bookmark.delete() 174 | endfor 175 | endif 176 | call b:NERDTree.render() 177 | endfunction 178 | 179 | " FUNCTION: s:closeChildren(node) {{{1 180 | " closes all childnodes of the current node 181 | function! s:closeChildren(node) 182 | call a:node.closeChildren() 183 | call b:NERDTree.render() 184 | call a:node.putCursorHere(0, 0) 185 | endfunction 186 | 187 | " FUNCTION: s:closeCurrentDir(node) {{{1 188 | " closes the parent dir of the current node 189 | function! s:closeCurrentDir(node) 190 | let parent = a:node.parent 191 | if parent ==# {} || parent.isRoot() 192 | call nerdtree#echo("cannot close tree root") 193 | else 194 | while g:NERDTreeCascadeOpenSingleChildDir && !parent.parent.isRoot() 195 | if parent.parent.getVisibleChildCount() == 1 196 | call parent.close() 197 | let parent = parent.parent 198 | else 199 | break 200 | endif 201 | endwhile 202 | call parent.close() 203 | call b:NERDTree.render() 204 | call parent.putCursorHere(0, 0) 205 | endif 206 | endfunction 207 | 208 | " FUNCTION: s:closeTreeWindow() {{{1 209 | " close the tree window 210 | function! s:closeTreeWindow() 211 | if b:NERDTreeType ==# "secondary" && b:NERDTreePreviousBuf != -1 212 | exec "buffer " . b:NERDTreePreviousBuf 213 | else 214 | if winnr("$") > 1 215 | call g:NERDTree.Close() 216 | else 217 | call nerdtree#echo("Cannot close last window") 218 | endif 219 | endif 220 | endfunction 221 | 222 | " FUNCTION: s:deleteBookmark(bm) {{{1 223 | " if the cursor is on a bookmark, prompt to delete 224 | function! s:deleteBookmark(bm) 225 | echo "Are you sure you wish to delete the bookmark:\n\"" . a:bm.name . "\" (yN):" 226 | 227 | if nr2char(getchar()) ==# 'y' 228 | try 229 | call a:bm.delete() 230 | call b:NERDTree.render() 231 | redraw 232 | catch /^NERDTree/ 233 | call nerdtree#echoWarning("Could not remove bookmark") 234 | endtry 235 | else 236 | call nerdtree#echo("delete aborted" ) 237 | endif 238 | 239 | endfunction 240 | 241 | " FUNCTION: s:displayHelp() {{{1 242 | " toggles the help display 243 | function! s:displayHelp() 244 | let b:treeShowHelp = b:treeShowHelp ? 0 : 1 245 | call b:NERDTree.render() 246 | call b:NERDTree.ui.centerView() 247 | endfunction 248 | 249 | " FUNCTION: s:findAndRevealPath() {{{1 250 | function! s:findAndRevealPath() 251 | try 252 | let p = g:NERDTreePath.New(expand("%:p")) 253 | catch /^NERDTree.InvalidArgumentsError/ 254 | call nerdtree#echo("no file for the current buffer") 255 | return 256 | endtry 257 | 258 | if p.isUnixHiddenPath() 259 | let showhidden=g:NERDTreeShowHidden 260 | let g:NERDTreeShowHidden = 1 261 | endif 262 | 263 | if !g:NERDTree.ExistsForTab() 264 | try 265 | let cwd = g:NERDTreePath.New(getcwd()) 266 | catch /^NERDTree.InvalidArgumentsError/ 267 | call nerdtree#echo("current directory does not exist.") 268 | let cwd = p.getParent() 269 | endtry 270 | 271 | if p.isUnder(cwd) 272 | call g:NERDTreeCreator.CreatePrimary(cwd.str()) 273 | else 274 | call g:NERDTreeCreator.CreatePrimary(p.getParent().str()) 275 | endif 276 | else 277 | if !p.isUnder(g:NERDTreeFileNode.GetRootForTab().path) 278 | if !g:NERDTree.IsOpen() 279 | call g:NERDTreeCreator.TogglePrimary('') 280 | else 281 | call g:NERDTree.CursorToTreeWin() 282 | endif 283 | let b:NERDTreeShowHidden = g:NERDTreeShowHidden 284 | call s:chRoot(g:NERDTreeDirNode.New(p.getParent())) 285 | else 286 | if !g:NERDTree.IsOpen() 287 | call g:NERDTreeCreator.TogglePrimary("") 288 | endif 289 | endif 290 | endif 291 | call g:NERDTree.CursorToTreeWin() 292 | call b:NERDTreeRoot.reveal(p) 293 | 294 | if p.isUnixHiddenFile() 295 | let g:NERDTreeShowHidden = showhidden 296 | endif 297 | endfunction 298 | 299 | "FUNCTION: s:handleLeftClick() {{{1 300 | "Checks if the click should open the current node 301 | function! s:handleLeftClick() 302 | let currentNode = g:NERDTreeFileNode.GetSelected() 303 | if currentNode != {} 304 | 305 | "the dir arrows are multibyte chars, and vim's string functions only 306 | "deal with single bytes - so split the line up with the hack below and 307 | "take the line substring manually 308 | let line = split(getline(line(".")), '\zs') 309 | let startToCur = "" 310 | for i in range(0,len(line)-1) 311 | let startToCur .= line[i] 312 | endfor 313 | 314 | if currentNode.path.isDirectory 315 | if startToCur =~# g:NERDTreeUI.MarkupReg() && startToCur =~# '[+~'.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'] \?$' 316 | call currentNode.activate() 317 | return 318 | endif 319 | endif 320 | 321 | if (g:NERDTreeMouseMode ==# 2 && currentNode.path.isDirectory) || g:NERDTreeMouseMode ==# 3 322 | let char = strpart(startToCur, strlen(startToCur)-1, 1) 323 | if char !~# g:NERDTreeUI.MarkupReg() 324 | if currentNode.path.isDirectory 325 | call currentNode.activate() 326 | else 327 | call currentNode.activate({'reuse': 'all', 'where': 'p'}) 328 | endif 329 | return 330 | endif 331 | endif 332 | endif 333 | endfunction 334 | 335 | " FUNCTION: s:handleMiddleMouse() {{{1 336 | function! s:handleMiddleMouse() 337 | let curNode = g:NERDTreeFileNode.GetSelected() 338 | if curNode ==# {} 339 | call nerdtree#echo("Put the cursor on a node first" ) 340 | return 341 | endif 342 | 343 | if curNode.path.isDirectory 344 | call nerdtree#openExplorer(curNode) 345 | else 346 | call curNode.open({'where': 'h'}) 347 | endif 348 | endfunction 349 | 350 | " FUNCTION: s:jumpToChild(direction) {{{2 351 | " Args: 352 | " direction: 0 if going to first child, 1 if going to last 353 | function! s:jumpToChild(currentNode, direction) 354 | if a:currentNode.isRoot() 355 | return nerdtree#echo("cannot jump to " . (a:direction ? "last" : "first") . " child") 356 | end 357 | let dirNode = a:currentNode.parent 358 | let childNodes = dirNode.getVisibleChildren() 359 | 360 | let targetNode = childNodes[0] 361 | if a:direction 362 | let targetNode = childNodes[len(childNodes) - 1] 363 | endif 364 | 365 | if targetNode.equals(a:currentNode) 366 | let siblingDir = a:currentNode.parent.findOpenDirSiblingWithVisibleChildren(a:direction) 367 | if siblingDir != {} 368 | let indx = a:direction ? siblingDir.getVisibleChildCount()-1 : 0 369 | let targetNode = siblingDir.getChildByIndex(indx, 1) 370 | endif 371 | endif 372 | 373 | call targetNode.putCursorHere(1, 0) 374 | 375 | call b:NERDTree.ui.centerView() 376 | endfunction 377 | 378 | 379 | " FUNCTION: nerdtree#ui_glue#invokeKeyMap(key) {{{1 380 | "this is needed since I cant figure out how to invoke dict functions from a 381 | "key map 382 | function! nerdtree#ui_glue#invokeKeyMap(key) 383 | call g:NERDTreeKeyMap.Invoke(a:key) 384 | endfunction 385 | 386 | " FUNCTION: s:jumpToFirstChild() {{{1 387 | " wrapper for the jump to child method 388 | function! s:jumpToFirstChild(node) 389 | call s:jumpToChild(a:node, 0) 390 | endfunction 391 | 392 | " FUNCTION: s:jumpToLastChild() {{{1 393 | " wrapper for the jump to child method 394 | function! s:jumpToLastChild(node) 395 | call s:jumpToChild(a:node, 1) 396 | endfunction 397 | 398 | " FUNCTION: s:jumpToParent(node) {{{1 399 | " moves the cursor to the parent of the current node 400 | function! s:jumpToParent(node) 401 | if !empty(a:node.parent) 402 | call a:node.parent.putCursorHere(1, 0) 403 | call b:NERDTree.ui.centerView() 404 | else 405 | call nerdtree#echo("cannot jump to parent") 406 | endif 407 | endfunction 408 | 409 | " FUNCTION: s:jumpToRoot() {{{1 410 | " moves the cursor to the root node 411 | function! s:jumpToRoot() 412 | call b:NERDTreeRoot.putCursorHere(1, 0) 413 | call b:NERDTree.ui.centerView() 414 | endfunction 415 | 416 | " FUNCTION: s:jumpToNextSibling(node) {{{1 417 | function! s:jumpToNextSibling(node) 418 | call s:jumpToSibling(a:node, 1) 419 | endfunction 420 | 421 | " FUNCTION: s:jumpToPrevSibling(node) {{{1 422 | function! s:jumpToPrevSibling(node) 423 | call s:jumpToSibling(a:node, 0) 424 | endfunction 425 | 426 | " FUNCTION: s:jumpToSibling(currentNode, forward) {{{2 427 | " moves the cursor to the sibling of the current node in the given direction 428 | " 429 | " Args: 430 | " forward: 1 if the cursor should move to the next sibling, 0 if it should 431 | " move back to the previous sibling 432 | function! s:jumpToSibling(currentNode, forward) 433 | let sibling = a:currentNode.findSibling(a:forward) 434 | 435 | if !empty(sibling) 436 | call sibling.putCursorHere(1, 0) 437 | call b:NERDTree.ui.centerView() 438 | endif 439 | endfunction 440 | 441 | " FUNCTION: nerdtree#ui_glue#openBookmark(name) {{{1 442 | " put the cursor on the given bookmark and, if its a file, open it 443 | function! nerdtree#ui_glue#openBookmark(name) 444 | try 445 | let targetNode = g:NERDTreeBookmark.GetNodeForName(a:name, 0) 446 | call targetNode.putCursorHere(0, 1) 447 | redraw! 448 | catch /^NERDTree.BookmarkedNodeNotFoundError/ 449 | call nerdtree#echo("note - target node is not cached") 450 | let bookmark = g:NERDTreeBookmark.BookmarkFor(a:name) 451 | let targetNode = g:NERDTreeFileNode.New(bookmark.path) 452 | endtry 453 | if targetNode.path.isDirectory 454 | call targetNode.openExplorer() 455 | else 456 | call targetNode.open({'where': 'p'}) 457 | endif 458 | endfunction 459 | 460 | " FUNCTION: s:openHSplit(target) {{{1 461 | function! s:openHSplit(target) 462 | call a:target.activate({'where': 'h'}) 463 | endfunction 464 | 465 | " FUNCTION: s:openVSplit(target) {{{1 466 | function! s:openVSplit(target) 467 | call a:target.activate({'where': 'v'}) 468 | endfunction 469 | 470 | " FUNCTION: s:openExplorer(node) {{{1 471 | function! s:openExplorer(node) 472 | call a:node.openExplorer() 473 | endfunction 474 | 475 | " FUNCTION: s:openInNewTab(target) {{{1 476 | function! s:openInNewTab(target) 477 | call a:target.activate({'where': 't'}) 478 | endfunction 479 | 480 | " FUNCTION: s:openInNewTabSilent(target) {{{1 481 | function! s:openInNewTabSilent(target) 482 | call a:target.activate({'where': 't', 'stay': 1}) 483 | endfunction 484 | 485 | " FUNCTION: s:openNodeRecursively(node) {{{1 486 | function! s:openNodeRecursively(node) 487 | call nerdtree#echo("Recursively opening node. Please wait...") 488 | call a:node.openRecursively() 489 | call b:NERDTree.render() 490 | redraw 491 | call nerdtree#echo("Recursively opening node. Please wait... DONE") 492 | endfunction 493 | 494 | "FUNCTION: s:previewNodeCurrent(node) {{{1 495 | function! s:previewNodeCurrent(node) 496 | call a:node.open({'stay': 1, 'where': 'p', 'keepopen': 1}) 497 | endfunction 498 | 499 | "FUNCTION: s:previewNodeHSplit(node) {{{1 500 | function! s:previewNodeHSplit(node) 501 | call a:node.open({'stay': 1, 'where': 'h', 'keepopen': 1}) 502 | endfunction 503 | 504 | "FUNCTION: s:previewNodeVSplit(node) {{{1 505 | function! s:previewNodeVSplit(node) 506 | call a:node.open({'stay': 1, 'where': 'v', 'keepopen': 1}) 507 | endfunction 508 | 509 | " FUNCTION: nerdtree#ui_glue#revealBookmark(name) {{{1 510 | " put the cursor on the node associate with the given name 511 | function! nerdtree#ui_glue#revealBookmark(name) 512 | try 513 | let targetNode = g:NERDTreeBookmark.GetNodeForName(a:name, 0) 514 | call targetNode.putCursorHere(0, 1) 515 | catch /^NERDTree.BookmarkNotFoundError/ 516 | call nerdtree#echo("Bookmark isnt cached under the current root") 517 | endtry 518 | endfunction 519 | 520 | " FUNCTION: s:refreshRoot() {{{1 521 | " Reloads the current root. All nodes below this will be lost and the root dir 522 | " will be reloaded. 523 | function! s:refreshRoot() 524 | call nerdtree#echo("Refreshing the root node. This could take a while...") 525 | call b:NERDTreeRoot.refresh() 526 | call b:NERDTree.render() 527 | redraw 528 | call nerdtree#echo("Refreshing the root node. This could take a while... DONE") 529 | endfunction 530 | 531 | " FUNCTION: s:refreshCurrent(node) {{{1 532 | " refreshes the root for the current node 533 | function! s:refreshCurrent(node) 534 | let node = a:node 535 | if !node.path.isDirectory 536 | let node = node.parent 537 | endif 538 | 539 | call nerdtree#echo("Refreshing node. This could take a while...") 540 | call node.refresh() 541 | call b:NERDTree.render() 542 | redraw 543 | call nerdtree#echo("Refreshing node. This could take a while... DONE") 544 | endfunction 545 | 546 | " FUNCTION: nerdtree#ui_glue#setupCommands() {{{1 547 | function! nerdtree#ui_glue#setupCommands() 548 | command! -n=? -complete=dir -bar NERDTree :call g:NERDTreeCreator.CreatePrimary('') 549 | command! -n=? -complete=dir -bar NERDTreeToggle :call g:NERDTreeCreator.TogglePrimary('') 550 | command! -n=0 -bar NERDTreeClose :call g:NERDTree.Close() 551 | command! -n=1 -complete=customlist,nerdtree#completeBookmarks -bar NERDTreeFromBookmark call g:NERDTreeCreator.CreatePrimary('') 552 | command! -n=0 -bar NERDTreeMirror call g:NERDTreeCreator.CreateMirror() 553 | command! -n=0 -bar NERDTreeFind call s:findAndRevealPath() 554 | command! -n=0 -bar NERDTreeFocus call NERDTreeFocus() 555 | command! -n=0 -bar NERDTreeCWD call NERDTreeCWD() 556 | endfunction 557 | 558 | " Function: s:SID() {{{1 559 | function s:SID() 560 | if !exists("s:sid") 561 | let s:sid = matchstr(expand(''), '\zs\d\+\ze_SID$') 562 | endif 563 | return s:sid 564 | endfun 565 | 566 | " FUNCTION: s:showMenu(node) {{{1 567 | function! s:showMenu(node) 568 | let mc = g:NERDTreeMenuController.New(g:NERDTreeMenuItem.AllEnabled()) 569 | call mc.showMenu() 570 | endfunction 571 | 572 | " FUNCTION: s:toggleIgnoreFilter() {{{1 573 | function! s:toggleIgnoreFilter() 574 | call b:NERDTree.ui.toggleIgnoreFilter() 575 | endfunction 576 | 577 | " FUNCTION: s:toggleShowBookmarks() {{{1 578 | function! s:toggleShowBookmarks() 579 | call b:NERDTree.ui.toggleShowBookmarks() 580 | endfunction 581 | 582 | " FUNCTION: s:toggleShowFiles() {{{1 583 | function! s:toggleShowFiles() 584 | call b:NERDTree.ui.toggleShowFiles() 585 | endfunction 586 | 587 | " FUNCTION: s:toggleShowHidden() {{{1 588 | " toggles the display of hidden files 589 | function! s:toggleShowHidden() 590 | call b:NERDTree.ui.toggleShowHidden() 591 | endfunction 592 | 593 | " FUNCTION: s:toggleZoom() {{{1 594 | function! s:toggleZoom() 595 | call b:NERDTree.ui.toggleZoom() 596 | endfunction 597 | 598 | "FUNCTION: nerdtree#ui_glue#upDir(keepState) {{{1 599 | "moves the tree up a level 600 | " 601 | "Args: 602 | "keepState: 1 if the current root should be left open when the tree is 603 | "re-rendered 604 | function! nerdtree#ui_glue#upDir(keepState) 605 | let cwd = b:NERDTreeRoot.path.str({'format': 'UI'}) 606 | if cwd ==# "/" || cwd =~# '^[^/]..$' 607 | call nerdtree#echo("already at top dir") 608 | else 609 | if !a:keepState 610 | call b:NERDTreeRoot.close() 611 | endif 612 | 613 | let oldRoot = b:NERDTreeRoot 614 | 615 | if empty(b:NERDTreeRoot.parent) 616 | let path = b:NERDTreeRoot.path.getParent() 617 | let newRoot = g:NERDTreeDirNode.New(path) 618 | call newRoot.open() 619 | call newRoot.transplantChild(b:NERDTreeRoot) 620 | let b:NERDTreeRoot = newRoot 621 | else 622 | let b:NERDTreeRoot = b:NERDTreeRoot.parent 623 | endif 624 | 625 | if g:NERDTreeChDirMode ==# 2 626 | call b:NERDTreeRoot.path.changeToDir() 627 | endif 628 | 629 | call b:NERDTree.render() 630 | call oldRoot.putCursorHere(0, 0) 631 | endif 632 | endfunction 633 | 634 | " FUNCTION: s:upDirCurrentRootOpen() {{{1 635 | function! s:upDirCurrentRootOpen() 636 | call nerdtree#ui_glue#upDir(1) 637 | endfunction 638 | 639 | " FUNCTION: s:upDirCurrentRootClosed() {{{1 640 | function! s:upDirCurrentRootClosed() 641 | call nerdtree#ui_glue#upDir(0) 642 | endfunction 643 | 644 | " vim: set sw=4 sts=4 et fdm=marker: 645 | -------------------------------------------------------------------------------- /lib/nerdtree/bookmark.vim: -------------------------------------------------------------------------------- 1 | "CLASS: Bookmark 2 | "============================================================ 3 | let s:Bookmark = {} 4 | let g:NERDTreeBookmark = s:Bookmark 5 | 6 | " FUNCTION: Bookmark.activate() {{{1 7 | function! s:Bookmark.activate(...) 8 | call self.open(a:0 ? a:1 : {}) 9 | endfunction 10 | 11 | " FUNCTION: Bookmark.AddBookmark(name, path) {{{1 12 | " Class method to add a new bookmark to the list, if a previous bookmark exists 13 | " with the same name, just update the path for that bookmark 14 | function! s:Bookmark.AddBookmark(name, path) 15 | for i in s:Bookmark.Bookmarks() 16 | if i.name ==# a:name 17 | let i.path = a:path 18 | return 19 | endif 20 | endfor 21 | call add(s:Bookmark.Bookmarks(), s:Bookmark.New(a:name, a:path)) 22 | if g:NERDTreeBookmarksSort ==# 1 23 | call s:Bookmark.Sort() 24 | endif 25 | endfunction 26 | 27 | " FUNCTION: Bookmark.Bookmarks() {{{1 28 | " Class method to get all bookmarks. Lazily initializes the bookmarks global 29 | " variable 30 | function! s:Bookmark.Bookmarks() 31 | if !exists("g:NERDTreeBookmarks") 32 | let g:NERDTreeBookmarks = [] 33 | endif 34 | return g:NERDTreeBookmarks 35 | endfunction 36 | 37 | " FUNCTION: Bookmark.BookmarkExistsFor(name) {{{1 38 | " class method that returns 1 if a bookmark with the given name is found, 0 39 | " otherwise 40 | function! s:Bookmark.BookmarkExistsFor(name) 41 | try 42 | call s:Bookmark.BookmarkFor(a:name) 43 | return 1 44 | catch /^NERDTree.BookmarkNotFoundError/ 45 | return 0 46 | endtry 47 | endfunction 48 | 49 | " FUNCTION: Bookmark.BookmarkFor(name) {{{1 50 | " Class method to get the bookmark that has the given name. {} is return if no 51 | " bookmark is found 52 | function! s:Bookmark.BookmarkFor(name) 53 | for i in s:Bookmark.Bookmarks() 54 | if i.name ==# a:name 55 | return i 56 | endif 57 | endfor 58 | throw "NERDTree.BookmarkNotFoundError: no bookmark found for name: \"". a:name .'"' 59 | endfunction 60 | 61 | " FUNCTION: Bookmark.BookmarkNames() {{{1 62 | " Class method to return an array of all bookmark names 63 | function! s:Bookmark.BookmarkNames() 64 | let names = [] 65 | for i in s:Bookmark.Bookmarks() 66 | call add(names, i.name) 67 | endfor 68 | return names 69 | endfunction 70 | 71 | " FUNCTION: Bookmark.CacheBookmarks(silent) {{{1 72 | " Class method to read all bookmarks from the bookmarks file initialize 73 | " bookmark objects for each one. 74 | " 75 | " Args: 76 | " silent - dont echo an error msg if invalid bookmarks are found 77 | function! s:Bookmark.CacheBookmarks(silent) 78 | if filereadable(g:NERDTreeBookmarksFile) 79 | let g:NERDTreeBookmarks = [] 80 | let g:NERDTreeInvalidBookmarks = [] 81 | let bookmarkStrings = readfile(g:NERDTreeBookmarksFile) 82 | let invalidBookmarksFound = 0 83 | for i in bookmarkStrings 84 | 85 | "ignore blank lines 86 | if i != '' 87 | 88 | let name = substitute(i, '^\(.\{-}\) .*$', '\1', '') 89 | let path = substitute(i, '^.\{-} \(.*\)$', '\1', '') 90 | let path = fnamemodify(path, ':p') 91 | 92 | try 93 | let bookmark = s:Bookmark.New(name, g:NERDTreePath.New(path)) 94 | call add(g:NERDTreeBookmarks, bookmark) 95 | catch /^NERDTree.InvalidArgumentsError/ 96 | call add(g:NERDTreeInvalidBookmarks, i) 97 | let invalidBookmarksFound += 1 98 | endtry 99 | endif 100 | endfor 101 | if invalidBookmarksFound 102 | call s:Bookmark.Write() 103 | if !a:silent 104 | call nerdtree#echo(invalidBookmarksFound . " invalid bookmarks were read. See :help NERDTreeInvalidBookmarks for info.") 105 | endif 106 | endif 107 | if g:NERDTreeBookmarksSort ==# 1 108 | call s:Bookmark.Sort() 109 | endif 110 | endif 111 | endfunction 112 | 113 | " FUNCTION: Bookmark.compareTo(otherbookmark) {{{1 114 | " Compare these two bookmarks for sorting purposes 115 | function! s:Bookmark.compareTo(otherbookmark) 116 | return a:otherbookmark.name < self.name 117 | endfunction 118 | " FUNCTION: Bookmark.ClearAll() {{{1 119 | " Class method to delete all bookmarks. 120 | function! s:Bookmark.ClearAll() 121 | for i in s:Bookmark.Bookmarks() 122 | call i.delete() 123 | endfor 124 | call s:Bookmark.Write() 125 | endfunction 126 | 127 | " FUNCTION: Bookmark.delete() {{{1 128 | " Delete this bookmark. If the node for this bookmark is under the current 129 | " root, then recache bookmarks for its Path object 130 | function! s:Bookmark.delete() 131 | let node = {} 132 | try 133 | let node = self.getNode(1) 134 | catch /^NERDTree.BookmarkedNodeNotFoundError/ 135 | endtry 136 | call remove(s:Bookmark.Bookmarks(), index(s:Bookmark.Bookmarks(), self)) 137 | if !empty(node) 138 | call node.path.cacheDisplayString() 139 | endif 140 | call s:Bookmark.Write() 141 | endfunction 142 | 143 | " FUNCTION: Bookmark.getNode(searchFromAbsoluteRoot) {{{1 144 | " Gets the treenode for this bookmark 145 | " 146 | " Args: 147 | " searchFromAbsoluteRoot: specifies whether we should search from the current 148 | " tree root, or the highest cached node 149 | function! s:Bookmark.getNode(searchFromAbsoluteRoot) 150 | let searchRoot = a:searchFromAbsoluteRoot ? g:NERDTreeDirNode.AbsoluteTreeRoot() : b:NERDTreeRoot 151 | let targetNode = searchRoot.findNode(self.path) 152 | if empty(targetNode) 153 | throw "NERDTree.BookmarkedNodeNotFoundError: no node was found for bookmark: " . self.name 154 | endif 155 | return targetNode 156 | endfunction 157 | 158 | " FUNCTION: Bookmark.GetNodeForName(name, searchFromAbsoluteRoot) {{{1 159 | " Class method that finds the bookmark with the given name and returns the 160 | " treenode for it. 161 | function! s:Bookmark.GetNodeForName(name, searchFromAbsoluteRoot) 162 | let bookmark = s:Bookmark.BookmarkFor(a:name) 163 | return bookmark.getNode(a:searchFromAbsoluteRoot) 164 | endfunction 165 | 166 | " FUNCTION: Bookmark.GetSelected() {{{1 167 | " returns the Bookmark the cursor is over, or {} 168 | function! s:Bookmark.GetSelected() 169 | let line = getline(".") 170 | let name = substitute(line, '^>\(.\{-}\) .\+$', '\1', '') 171 | if name != line 172 | try 173 | return s:Bookmark.BookmarkFor(name) 174 | catch /^NERDTree.BookmarkNotFoundError/ 175 | return {} 176 | endtry 177 | endif 178 | return {} 179 | endfunction 180 | 181 | " FUNCTION: Bookmark.InvalidBookmarks() {{{1 182 | " Class method to get all invalid bookmark strings read from the bookmarks 183 | " file 184 | function! s:Bookmark.InvalidBookmarks() 185 | if !exists("g:NERDTreeInvalidBookmarks") 186 | let g:NERDTreeInvalidBookmarks = [] 187 | endif 188 | return g:NERDTreeInvalidBookmarks 189 | endfunction 190 | 191 | " FUNCTION: Bookmark.mustExist() {{{1 192 | function! s:Bookmark.mustExist() 193 | if !self.path.exists() 194 | call s:Bookmark.CacheBookmarks(1) 195 | throw "NERDTree.BookmarkPointsToInvalidLocationError: the bookmark \"". 196 | \ self.name ."\" points to a non existing location: \"". self.path.str() 197 | endif 198 | endfunction 199 | 200 | " FUNCTION: Bookmark.New(name, path) {{{1 201 | " Create a new bookmark object with the given name and path object 202 | function! s:Bookmark.New(name, path) 203 | if a:name =~# ' ' 204 | throw "NERDTree.IllegalBookmarkNameError: illegal name:" . a:name 205 | endif 206 | 207 | let newBookmark = copy(self) 208 | let newBookmark.name = a:name 209 | let newBookmark.path = a:path 210 | return newBookmark 211 | endfunction 212 | 213 | " FUNCTION: Bookmark.open([options]) {{{1 214 | "Args: 215 | "A dictionary containing the following keys (all optional): 216 | " 'where': Specifies whether the node should be opened in new split/tab or in 217 | " the previous window. Can be either 'v' (vertical split), 'h' 218 | " (horizontal split), 't' (new tab) or 'p' (previous window). 219 | " 'reuse': if a window is displaying the file then jump the cursor there 220 | " 'keepopen': dont close the tree window 221 | " 'stay': open the file, but keep the cursor in the tree win 222 | " 223 | function! s:Bookmark.open(...) 224 | let opts = a:0 ? a:1 : {} 225 | 226 | if self.path.isDirectory && !has_key(opts, 'where') 227 | call self.toRoot() 228 | else 229 | let opener = g:NERDTreeOpener.New(self.path, opts) 230 | call opener.open(self) 231 | endif 232 | endfunction 233 | 234 | " FUNCTION: Bookmark.openInNewTab(options) {{{1 235 | " Create a new bookmark object with the given name and path object 236 | function! s:Bookmark.openInNewTab(options) 237 | call nerdtree#deprecated('Bookmark.openInNewTab', 'is deprecated, use open() instead') 238 | call self.open(a:options) 239 | endfunction 240 | 241 | " FUNCTION: Bookmark.setPath(path) {{{1 242 | " makes this bookmark point to the given path 243 | function! s:Bookmark.setPath(path) 244 | let self.path = a:path 245 | endfunction 246 | 247 | " FUNCTION: Bookmark.Sort() {{{1 248 | " Class method that sorts all bookmarks 249 | function! s:Bookmark.Sort() 250 | let CompareFunc = function("nerdtree#compareBookmarks") 251 | call sort(s:Bookmark.Bookmarks(), CompareFunc) 252 | endfunction 253 | 254 | " FUNCTION: Bookmark.str() {{{1 255 | " Get the string that should be rendered in the view for this bookmark 256 | function! s:Bookmark.str() 257 | let pathStrMaxLen = winwidth(g:NERDTree.GetWinNum()) - 4 - len(self.name) 258 | if &nu 259 | let pathStrMaxLen = pathStrMaxLen - &numberwidth 260 | endif 261 | 262 | let pathStr = self.path.str({'format': 'UI'}) 263 | if len(pathStr) > pathStrMaxLen 264 | let pathStr = '<' . strpart(pathStr, len(pathStr) - pathStrMaxLen) 265 | endif 266 | return '>' . self.name . ' ' . pathStr 267 | endfunction 268 | 269 | " FUNCTION: Bookmark.toRoot() {{{1 270 | " Make the node for this bookmark the new tree root 271 | function! s:Bookmark.toRoot() 272 | if self.validate() 273 | try 274 | let targetNode = self.getNode(1) 275 | catch /^NERDTree.BookmarkedNodeNotFoundError/ 276 | let targetNode = g:NERDTreeFileNode.New(s:Bookmark.BookmarkFor(self.name).path) 277 | endtry 278 | call targetNode.makeRoot() 279 | call b:NERDTree.render() 280 | call targetNode.putCursorHere(0, 0) 281 | endif 282 | endfunction 283 | 284 | " FUNCTION: Bookmark.ToRoot(name) {{{1 285 | " Make the node for this bookmark the new tree root 286 | function! s:Bookmark.ToRoot(name) 287 | let bookmark = s:Bookmark.BookmarkFor(a:name) 288 | call bookmark.toRoot() 289 | endfunction 290 | 291 | " FUNCTION: Bookmark.validate() {{{1 292 | function! s:Bookmark.validate() 293 | if self.path.exists() 294 | return 1 295 | else 296 | call s:Bookmark.CacheBookmarks(1) 297 | call b:NERDTree.render() 298 | call nerdtree#echo(self.name . "now points to an invalid location. See :help NERDTreeInvalidBookmarks for info.") 299 | return 0 300 | endif 301 | endfunction 302 | 303 | " FUNCTION: Bookmark.Write() {{{1 304 | " Class method to write all bookmarks to the bookmarks file 305 | function! s:Bookmark.Write() 306 | let bookmarkStrings = [] 307 | for i in s:Bookmark.Bookmarks() 308 | call add(bookmarkStrings, i.name . ' ' . fnamemodify(i.path.str(), ':~')) 309 | endfor 310 | 311 | "add a blank line before the invalid ones 312 | call add(bookmarkStrings, "") 313 | 314 | for j in s:Bookmark.InvalidBookmarks() 315 | call add(bookmarkStrings, j) 316 | endfor 317 | call writefile(bookmarkStrings, g:NERDTreeBookmarksFile) 318 | endfunction 319 | 320 | " vim: set sw=4 sts=4 et fdm=marker: 321 | -------------------------------------------------------------------------------- /lib/nerdtree/creator.vim: -------------------------------------------------------------------------------- 1 | "CLASS: Creator 2 | "Creates primary/secondary/mirror nerdtree windows. Sets up all the window and 3 | "buffer options and key mappings etc. 4 | "============================================================ 5 | let s:Creator = {} 6 | let g:NERDTreeCreator = s:Creator 7 | 8 | "FUNCTION: s:Creator._bindMappings() {{{1 9 | function! s:Creator._bindMappings() 10 | "make do the same as the activate node mapping 11 | nnoremap :call nerdtree#ui_glue#invokeKeyMap(g:NERDTreeMapActivateNode) 12 | 13 | call g:NERDTreeKeyMap.BindAll() 14 | 15 | command! -buffer -nargs=? Bookmark :call nerdtree#ui_glue#bookmarkNode('') 16 | command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=1 RevealBookmark :call nerdtree#ui_glue#revealBookmark('') 17 | command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=1 OpenBookmark :call nerdtree#ui_glue#openBookmark('') 18 | command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=* ClearBookmarks call nerdtree#ui_glue#clearBookmarks('') 19 | command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=+ BookmarkToRoot call g:NERDTreeBookmark.ToRoot('') 20 | command! -buffer -nargs=0 ClearAllBookmarks call g:NERDTreeBookmark.ClearAll() call b:NERDTree.render() 21 | command! -buffer -nargs=0 ReadBookmarks call g:NERDTreeBookmark.CacheBookmarks(0) call b:NERDTree.render() 22 | command! -buffer -nargs=0 WriteBookmarks call g:NERDTreeBookmark.Write() 23 | endfunction 24 | 25 | "FUNCTION: s:Creator._broadcastInitEvent() {{{1 26 | function! s:Creator._broadcastInitEvent() 27 | silent doautocmd User NERDTreeInit 28 | endfunction 29 | 30 | " FUNCTION: s:Creator.BufNamePrefix() {{{2 31 | function! s:Creator.BufNamePrefix() 32 | return 'NERD_tree_' 33 | endfunction 34 | 35 | "FUNCTION: s:Creator.CreatePrimary(a:name) {{{1 36 | function! s:Creator.CreatePrimary(name) 37 | let creator = s:Creator.New() 38 | call creator.createPrimary(a:name) 39 | endfunction 40 | 41 | "FUNCTION: s:Creator.createPrimary(a:name) {{{1 42 | "name: the name of a bookmark or a directory 43 | function! s:Creator.createPrimary(name) 44 | let path = self._pathForString(a:name) 45 | 46 | "abort if exception was thrown (bookmark/dir doesn't exist) 47 | if empty(path) 48 | return 49 | endif 50 | 51 | if path == {} 52 | return 53 | endif 54 | 55 | "if instructed to, then change the vim CWD to the dir the NERDTree is 56 | "inited in 57 | if g:NERDTreeChDirMode != 0 58 | call path.changeToDir() 59 | endif 60 | 61 | if g:NERDTree.ExistsForTab() 62 | if g:NERDTree.IsOpen() 63 | call g:NERDTree.Close() 64 | endif 65 | unlet t:NERDTreeBufName 66 | endif 67 | 68 | call self._createTreeWin() 69 | call self._createNERDTree(path) 70 | let b:NERDTreeType = "primary" 71 | let b:treeShowHelp = 0 72 | let b:NERDTreeIgnoreEnabled = 1 73 | let b:NERDTreeShowFiles = g:NERDTreeShowFiles 74 | let b:NERDTreeShowHidden = g:NERDTreeShowHidden 75 | let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks 76 | 77 | call b:NERDTree.render() 78 | call b:NERDTreeRoot.putCursorHere(0, 0) 79 | 80 | call self._broadcastInitEvent() 81 | endfunction 82 | 83 | "FUNCTION: s:Creator.CreateSecondary(dir) {{{1 84 | function! s:Creator.CreateSecondary(dir) 85 | let creator = s:Creator.New() 86 | call creator.createSecondary(a:dir) 87 | endfunction 88 | 89 | "FUNCTION: s:Creator.createSecondary(dir) {{{1 90 | function! s:Creator.createSecondary(dir) 91 | try 92 | let path = g:NERDTreePath.New(a:dir) 93 | catch /^NERDTree.InvalidArgumentsError/ 94 | call nerdtree#echo("Invalid directory name:" . a:name) 95 | return 96 | endtry 97 | 98 | "we want the directory buffer to disappear when we do the :edit below 99 | setlocal bufhidden=wipe 100 | 101 | let previousBuf = expand("#") 102 | 103 | "we need a unique name for each secondary tree buffer to ensure they are 104 | "all independent 105 | exec "silent edit " . self._nextBufferName() 106 | 107 | let b:NERDTreePreviousBuf = bufnr(previousBuf) 108 | call self._createNERDTree(path) 109 | call self._setCommonBufOptions() 110 | let b:NERDTreeType = "secondary" 111 | 112 | call b:NERDTree.render() 113 | 114 | call self._broadcastInitEvent() 115 | endfunction 116 | 117 | " FUNCTION: s:Creator._createNERDTree(path) {{{1 118 | function! s:Creator._createNERDTree(path) 119 | let b:NERDTree = g:NERDTree.New(a:path) 120 | "TODO: This is kept for compatability only since many things use 121 | "b:NERDTreeRoot instead of the new NERDTree.root 122 | "Remove this one day 123 | let b:NERDTreeRoot = b:NERDTree.root 124 | 125 | call b:NERDTree.root.open() 126 | endfunction 127 | 128 | " FUNCTION: s:Creator.CreateMirror() {{{1 129 | function! s:Creator.CreateMirror() 130 | let creator = s:Creator.New() 131 | call creator.createMirror() 132 | endfunction 133 | 134 | " FUNCTION: s:Creator.createMirror() {{{1 135 | function! s:Creator.createMirror() 136 | "get the names off all the nerd tree buffers 137 | let treeBufNames = [] 138 | for i in range(1, tabpagenr("$")) 139 | let nextName = self._tabpagevar(i, 'NERDTreeBufName') 140 | if nextName != -1 && (!exists("t:NERDTreeBufName") || nextName != t:NERDTreeBufName) 141 | call add(treeBufNames, nextName) 142 | endif 143 | endfor 144 | let treeBufNames = self._uniq(treeBufNames) 145 | 146 | "map the option names (that the user will be prompted with) to the nerd 147 | "tree buffer names 148 | let options = {} 149 | let i = 0 150 | while i < len(treeBufNames) 151 | let bufName = treeBufNames[i] 152 | let treeRoot = getbufvar(bufName, "NERDTreeRoot") 153 | let options[i+1 . '. ' . treeRoot.path.str() . ' (buf name: ' . bufName . ')'] = bufName 154 | let i = i + 1 155 | endwhile 156 | 157 | "work out which tree to mirror, if there is more than 1 then ask the user 158 | let bufferName = '' 159 | if len(keys(options)) > 1 160 | let choices = ["Choose a tree to mirror"] 161 | let choices = extend(choices, sort(keys(options))) 162 | let choice = inputlist(choices) 163 | if choice < 1 || choice > len(options) || choice ==# '' 164 | return 165 | endif 166 | 167 | let bufferName = options[sort(keys(options))[choice-1]] 168 | elseif len(keys(options)) ==# 1 169 | let bufferName = values(options)[0] 170 | else 171 | call nerdtree#echo("No trees to mirror") 172 | return 173 | endif 174 | 175 | if g:NERDTree.ExistsForTab() && g:NERDTree.IsOpen() 176 | call g:NERDTree.Close() 177 | endif 178 | 179 | let t:NERDTreeBufName = bufferName 180 | call self._createTreeWin() 181 | exec 'buffer ' . bufferName 182 | if !&hidden 183 | call b:NERDTree.render() 184 | endif 185 | endfunction 186 | 187 | "FUNCTION: s:Creator._createTreeWin() {{{1 188 | "Inits the NERD tree window. ie. opens it, sizes it, sets all the local 189 | "options etc 190 | function! s:Creator._createTreeWin() 191 | "create the nerd tree window 192 | let splitLocation = g:NERDTreeWinPos ==# "left" ? "topleft " : "botright " 193 | let splitSize = g:NERDTreeWinSize 194 | 195 | if !exists('t:NERDTreeBufName') 196 | let t:NERDTreeBufName = self._nextBufferName() 197 | silent! exec splitLocation . 'vertical ' . splitSize . ' new' 198 | silent! exec "edit " . t:NERDTreeBufName 199 | else 200 | silent! exec splitLocation . 'vertical ' . splitSize . ' split' 201 | silent! exec "buffer " . t:NERDTreeBufName 202 | endif 203 | 204 | setlocal winfixwidth 205 | call self._setCommonBufOptions() 206 | endfunction 207 | 208 | "FUNCTION: s:Creator.New() {{{1 209 | function! s:Creator.New() 210 | let newCreator = copy(self) 211 | return newCreator 212 | endfunction 213 | 214 | " FUNCTION: s:Creator._nextBufferName() {{{2 215 | " returns the buffer name for the next nerd tree 216 | function! s:Creator._nextBufferName() 217 | let name = s:Creator.BufNamePrefix() . self._nextBufferNumber() 218 | return name 219 | endfunction 220 | 221 | " FUNCTION: s:Creator._nextBufferNumber() {{{2 222 | " the number to add to the nerd tree buffer name to make the buf name unique 223 | function! s:Creator._nextBufferNumber() 224 | if !exists("s:Creator._NextBufNum") 225 | let s:Creator._NextBufNum = 1 226 | else 227 | let s:Creator._NextBufNum += 1 228 | endif 229 | 230 | return s:Creator._NextBufNum 231 | endfunction 232 | 233 | "FUNCTION: s:Creator._pathForString(str) {{{1 234 | "find a bookmark or adirectory for the given string 235 | function! s:Creator._pathForString(str) 236 | let path = {} 237 | if g:NERDTreeBookmark.BookmarkExistsFor(a:str) 238 | let path = g:NERDTreeBookmark.BookmarkFor(a:str).path 239 | else 240 | let dir = a:str ==# '' ? getcwd() : a:str 241 | 242 | "hack to get an absolute path if a relative path is given 243 | if dir =~# '^\.' 244 | let dir = getcwd() . g:NERDTreePath.Slash() . dir 245 | endif 246 | let dir = g:NERDTreePath.Resolve(dir) 247 | 248 | try 249 | let path = g:NERDTreePath.New(dir) 250 | catch /^NERDTree.InvalidArgumentsError/ 251 | call nerdtree#echo("No bookmark or directory found for: " . a:str) 252 | return {} 253 | endtry 254 | endif 255 | if !path.isDirectory 256 | let path = path.getParent() 257 | endif 258 | 259 | return path 260 | endfunction 261 | 262 | "FUNCTION: s:Creator._setCommonBufOptions() {{{1 263 | function! s:Creator._setCommonBufOptions() 264 | "throwaway buffer options 265 | setlocal noswapfile 266 | setlocal buftype=nofile 267 | setlocal bufhidden=hide 268 | setlocal nowrap 269 | setlocal foldcolumn=0 270 | setlocal foldmethod=manual 271 | setlocal nofoldenable 272 | setlocal nobuflisted 273 | setlocal nospell 274 | if g:NERDTreeShowLineNumbers 275 | setlocal nu 276 | else 277 | setlocal nonu 278 | if v:version >= 703 279 | setlocal nornu 280 | endif 281 | endif 282 | 283 | iabc 284 | 285 | if g:NERDTreeHighlightCursorline 286 | setlocal cursorline 287 | endif 288 | 289 | call self._setupStatusline() 290 | 291 | let b:treeShowHelp = 0 292 | let b:NERDTreeIgnoreEnabled = 1 293 | let b:NERDTreeShowFiles = g:NERDTreeShowFiles 294 | let b:NERDTreeShowHidden = g:NERDTreeShowHidden 295 | let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks 296 | call self._bindMappings() 297 | setlocal filetype=nerdtree 298 | endfunction 299 | 300 | "FUNCTION: s:Creator._setupStatusline() {{{1 301 | function! s:Creator._setupStatusline() 302 | if g:NERDTreeStatusline != -1 303 | let &l:statusline = g:NERDTreeStatusline 304 | endif 305 | endfunction 306 | 307 | " FUNCTION: s:Creator._tabpagevar(tabnr, var) {{{1 308 | function! s:Creator._tabpagevar(tabnr, var) 309 | let currentTab = tabpagenr() 310 | let old_ei = &ei 311 | set ei=all 312 | 313 | exec "tabnext " . a:tabnr 314 | let v = -1 315 | if exists('t:' . a:var) 316 | exec 'let v = t:' . a:var 317 | endif 318 | exec "tabnext " . currentTab 319 | 320 | let &ei = old_ei 321 | 322 | return v 323 | endfunction 324 | 325 | "FUNCTION: s:Creator.TogglePrimary(dir) {{{1 326 | function! s:Creator.TogglePrimary(dir) 327 | let creator = s:Creator.New() 328 | call creator.togglePrimary(a:dir) 329 | endfunction 330 | 331 | "FUNCTION: s:Creator.togglePrimary(dir) {{{1 332 | "Toggles the NERD tree. I.e the NERD tree is open, it is closed, if it is 333 | "closed it is restored or initialized (if it doesnt exist) 334 | " 335 | "Args: 336 | "dir: the full path for the root node (is only used if the NERD tree is being 337 | "initialized. 338 | function! s:Creator.togglePrimary(dir) 339 | if g:NERDTree.ExistsForTab() 340 | if !g:NERDTree.IsOpen() 341 | call self._createTreeWin() 342 | if !&hidden 343 | call b:NERDTree.render() 344 | endif 345 | call b:NERDTree.ui.restoreScreenState() 346 | else 347 | call g:NERDTree.Close() 348 | endif 349 | else 350 | call self.createPrimary(a:dir) 351 | endif 352 | endfunction 353 | 354 | " Function: s:Creator._uniq(list) {{{1 355 | " returns a:list without duplicates 356 | function! s:Creator._uniq(list) 357 | let uniqlist = [] 358 | for elem in a:list 359 | if index(uniqlist, elem) ==# -1 360 | let uniqlist += [elem] 361 | endif 362 | endfor 363 | return uniqlist 364 | endfunction 365 | 366 | " vim: set sw=4 sts=4 et fdm=marker: 367 | -------------------------------------------------------------------------------- /lib/nerdtree/event.vim: -------------------------------------------------------------------------------- 1 | "CLASS: Event 2 | "============================================================ 3 | let s:Event = {} 4 | let g:NERDTreeEvent = s:Event 5 | 6 | function! s:Event.New(nerdtree, subject, action, params) abort 7 | let newObj = copy(self) 8 | let newObj.nerdtree = a:nerdtree 9 | let newObj.subject = a:subject 10 | let newObj.action = a:action 11 | let newObj.params = a:params 12 | return newObj 13 | endfunction 14 | -------------------------------------------------------------------------------- /lib/nerdtree/flag_set.vim: -------------------------------------------------------------------------------- 1 | "CLASS: FlagSet 2 | "============================================================ 3 | let s:FlagSet = {} 4 | let g:NERDTreeFlagSet = s:FlagSet 5 | 6 | "FUNCTION: FlagSet.addFlag(scope, flag) {{{1 7 | function! s:FlagSet.addFlag(scope, flag) 8 | let flags = self._flagsForScope(a:scope) 9 | if index(flags, a:flag) == -1 10 | call add(flags, a:flag) 11 | end 12 | endfunction 13 | 14 | "FUNCTION: FlagSet.clearFlags(scope) {{{1 15 | function! s:FlagSet.clearFlags(scope) 16 | let self._flags[a:scope] = [] 17 | endfunction 18 | 19 | "FUNCTION: FlagSet._flagsForScope(scope) {{{1 20 | function! s:FlagSet._flagsForScope(scope) 21 | if !has_key(self._flags, a:scope) 22 | let self._flags[a:scope] = [] 23 | endif 24 | return self._flags[a:scope] 25 | endfunction 26 | 27 | "FUNCTION: FlagSet.New() {{{1 28 | function! s:FlagSet.New() 29 | let newObj = copy(self) 30 | let newObj._flags = {} 31 | return newObj 32 | endfunction 33 | 34 | "FUNCTION: FlagSet.removeFlag(scope, flag) {{{1 35 | function! s:FlagSet.removeFlag(scope, flag) 36 | let flags = self._flagsForScope(a:scope) 37 | 38 | let i = index(flags, a:flag) 39 | if i >= 0 40 | call remove(flags, i) 41 | endif 42 | endfunction 43 | 44 | "FUNCTION: FlagSet.renderToString() {{{1 45 | function! s:FlagSet.renderToString() 46 | let flagstring = "" 47 | for i in values(self._flags) 48 | let flagstring .= join(i) 49 | endfor 50 | 51 | if len(flagstring) == 0 52 | return "" 53 | endif 54 | 55 | return '[' . flagstring . ']' 56 | endfunction 57 | -------------------------------------------------------------------------------- /lib/nerdtree/key_map.vim: -------------------------------------------------------------------------------- 1 | "CLASS: KeyMap 2 | "============================================================ 3 | let s:KeyMap = {} 4 | let g:NERDTreeKeyMap = s:KeyMap 5 | 6 | "FUNCTION: KeyMap.All() {{{1 7 | function! s:KeyMap.All() 8 | if !exists("s:keyMaps") 9 | let s:keyMaps = [] 10 | endif 11 | return s:keyMaps 12 | endfunction 13 | 14 | "FUNCTION: KeyMap.FindFor(key, scope) {{{1 15 | function! s:KeyMap.FindFor(key, scope) 16 | for i in s:KeyMap.All() 17 | if i.key ==# a:key && i.scope ==# a:scope 18 | return i 19 | endif 20 | endfor 21 | return {} 22 | endfunction 23 | 24 | "FUNCTION: KeyMap.BindAll() {{{1 25 | function! s:KeyMap.BindAll() 26 | for i in s:KeyMap.All() 27 | call i.bind() 28 | endfor 29 | endfunction 30 | 31 | "FUNCTION: KeyMap.bind() {{{1 32 | function! s:KeyMap.bind() 33 | " If the key sequence we're trying to map contains any '<>' notation, we 34 | " must replace each of the '<' characters with '' to ensure the string 35 | " is not translated into its corresponding keycode during the later part 36 | " of the map command below 37 | " :he <> 38 | let specialNotationRegex = '\m<\([[:alnum:]_-]\+>\)' 39 | if self.key =~# specialNotationRegex 40 | let keymapInvokeString = substitute(self.key, specialNotationRegex, '\1', 'g') 41 | else 42 | let keymapInvokeString = self.key 43 | endif 44 | 45 | let premap = self.key == "" ? " " : " " 46 | 47 | exec 'nnoremap '. self.key . premap . ':call nerdtree#ui_glue#invokeKeyMap("'. keymapInvokeString .'")' 48 | endfunction 49 | 50 | "FUNCTION: KeyMap.Remove(key, scope) {{{1 51 | function! s:KeyMap.Remove(key, scope) 52 | let maps = s:KeyMap.All() 53 | for i in range(len(maps)) 54 | if maps[i].key ==# a:key && maps[i].scope ==# a:scope 55 | return remove(maps, i) 56 | endif 57 | endfor 58 | endfunction 59 | 60 | "FUNCTION: KeyMap.invoke() {{{1 61 | "Call the KeyMaps callback function 62 | function! s:KeyMap.invoke(...) 63 | let Callback = function(self.callback) 64 | if a:0 65 | call Callback(a:1) 66 | else 67 | call Callback() 68 | endif 69 | endfunction 70 | 71 | "FUNCTION: KeyMap.Invoke() {{{1 72 | "Find a keymapping for a:key and the current scope invoke it. 73 | " 74 | "Scope is determined as follows: 75 | " * if the cursor is on a dir node then "DirNode" 76 | " * if the cursor is on a file node then "FileNode" 77 | " * if the cursor is on a bookmark then "Bookmark" 78 | " 79 | "If a keymap has the scope of "all" then it will be called if no other keymap 80 | "is found for a:key and the scope. 81 | function! s:KeyMap.Invoke(key) 82 | 83 | "required because clicking the command window below another window still 84 | "invokes the mapping - but changes the window cursor 85 | "is in first 86 | " 87 | "TODO: remove this check when the vim bug is fixed 88 | if !g:NERDTree.ExistsForBuf() 89 | return {} 90 | endif 91 | 92 | let node = g:NERDTreeFileNode.GetSelected() 93 | if !empty(node) 94 | 95 | "try file node 96 | if !node.path.isDirectory 97 | let km = s:KeyMap.FindFor(a:key, "FileNode") 98 | if !empty(km) 99 | return km.invoke(node) 100 | endif 101 | endif 102 | 103 | "try dir node 104 | if node.path.isDirectory 105 | let km = s:KeyMap.FindFor(a:key, "DirNode") 106 | if !empty(km) 107 | return km.invoke(node) 108 | endif 109 | endif 110 | 111 | "try generic node 112 | let km = s:KeyMap.FindFor(a:key, "Node") 113 | if !empty(km) 114 | return km.invoke(node) 115 | endif 116 | 117 | endif 118 | 119 | "try bookmark 120 | let bm = g:NERDTreeBookmark.GetSelected() 121 | if !empty(bm) 122 | let km = s:KeyMap.FindFor(a:key, "Bookmark") 123 | if !empty(km) 124 | return km.invoke(bm) 125 | endif 126 | endif 127 | 128 | "try all 129 | let km = s:KeyMap.FindFor(a:key, "all") 130 | if !empty(km) 131 | return km.invoke() 132 | endif 133 | endfunction 134 | 135 | "FUNCTION: KeyMap.Create(options) {{{1 136 | function! s:KeyMap.Create(options) 137 | let opts = extend({'scope': 'all', 'quickhelpText': ''}, copy(a:options)) 138 | 139 | "dont override other mappings unless the 'override' option is given 140 | if get(opts, 'override', 0) == 0 && !empty(s:KeyMap.FindFor(opts['key'], opts['scope'])) 141 | return 142 | end 143 | 144 | let newKeyMap = copy(self) 145 | let newKeyMap.key = opts['key'] 146 | let newKeyMap.quickhelpText = opts['quickhelpText'] 147 | let newKeyMap.callback = opts['callback'] 148 | let newKeyMap.scope = opts['scope'] 149 | 150 | call s:KeyMap.Add(newKeyMap) 151 | endfunction 152 | 153 | "FUNCTION: KeyMap.Add(keymap) {{{1 154 | function! s:KeyMap.Add(keymap) 155 | call s:KeyMap.Remove(a:keymap.key, a:keymap.scope) 156 | call add(s:KeyMap.All(), a:keymap) 157 | endfunction 158 | 159 | " vim: set sw=4 sts=4 et fdm=marker: 160 | -------------------------------------------------------------------------------- /lib/nerdtree/menu_controller.vim: -------------------------------------------------------------------------------- 1 | "CLASS: MenuController 2 | "============================================================ 3 | let s:MenuController = {} 4 | let g:NERDTreeMenuController = s:MenuController 5 | 6 | "FUNCTION: MenuController.New(menuItems) {{{1 7 | "create a new menu controller that operates on the given menu items 8 | function! s:MenuController.New(menuItems) 9 | let newMenuController = copy(self) 10 | if a:menuItems[0].isSeparator() 11 | let newMenuController.menuItems = a:menuItems[1:-1] 12 | else 13 | let newMenuController.menuItems = a:menuItems 14 | endif 15 | return newMenuController 16 | endfunction 17 | 18 | "FUNCTION: MenuController.showMenu() {{{1 19 | "start the main loop of the menu and get the user to choose/execute a menu 20 | "item 21 | function! s:MenuController.showMenu() 22 | call self._saveOptions() 23 | 24 | try 25 | let self.selection = 0 26 | 27 | let done = 0 28 | while !done 29 | redraw! 30 | call self._echoPrompt() 31 | let key = nr2char(getchar()) 32 | let done = self._handleKeypress(key) 33 | endwhile 34 | finally 35 | call self._restoreOptions() 36 | endtry 37 | 38 | if self.selection != -1 39 | let m = self._current() 40 | call m.execute() 41 | endif 42 | endfunction 43 | 44 | "FUNCTION: MenuController._echoPrompt() {{{1 45 | function! s:MenuController._echoPrompt() 46 | echo "NERDTree Menu. Use j/k/enter and the shortcuts indicated" 47 | echo "==========================================================" 48 | 49 | for i in range(0, len(self.menuItems)-1) 50 | if self.selection == i 51 | echo "> " . self.menuItems[i].text 52 | else 53 | echo " " . self.menuItems[i].text 54 | endif 55 | endfor 56 | endfunction 57 | 58 | "FUNCTION: MenuController._current(key) {{{1 59 | "get the MenuItem that is currently selected 60 | function! s:MenuController._current() 61 | return self.menuItems[self.selection] 62 | endfunction 63 | 64 | "FUNCTION: MenuController._handleKeypress(key) {{{1 65 | "change the selection (if appropriate) and return 1 if the user has made 66 | "their choice, 0 otherwise 67 | function! s:MenuController._handleKeypress(key) 68 | if a:key == 'j' 69 | call self._cursorDown() 70 | elseif a:key == 'k' 71 | call self._cursorUp() 72 | elseif a:key == nr2char(27) "escape 73 | let self.selection = -1 74 | return 1 75 | elseif a:key == "\r" || a:key == "\n" "enter and ctrl-j 76 | return 1 77 | else 78 | let index = self._nextIndexFor(a:key) 79 | if index != -1 80 | let self.selection = index 81 | if len(self._allIndexesFor(a:key)) == 1 82 | return 1 83 | endif 84 | endif 85 | endif 86 | 87 | return 0 88 | endfunction 89 | 90 | "FUNCTION: MenuController._allIndexesFor(shortcut) {{{1 91 | "get indexes to all menu items with the given shortcut 92 | function! s:MenuController._allIndexesFor(shortcut) 93 | let toReturn = [] 94 | 95 | for i in range(0, len(self.menuItems)-1) 96 | if self.menuItems[i].shortcut == a:shortcut 97 | call add(toReturn, i) 98 | endif 99 | endfor 100 | 101 | return toReturn 102 | endfunction 103 | 104 | "FUNCTION: MenuController._nextIndexFor(shortcut) {{{1 105 | "get the index to the next menu item with the given shortcut, starts from the 106 | "current cursor location and wraps around to the top again if need be 107 | function! s:MenuController._nextIndexFor(shortcut) 108 | for i in range(self.selection+1, len(self.menuItems)-1) 109 | if self.menuItems[i].shortcut == a:shortcut 110 | return i 111 | endif 112 | endfor 113 | 114 | for i in range(0, self.selection) 115 | if self.menuItems[i].shortcut == a:shortcut 116 | return i 117 | endif 118 | endfor 119 | 120 | return -1 121 | endfunction 122 | 123 | "FUNCTION: MenuController._setCmdheight() {{{1 124 | "sets &cmdheight to whatever is needed to display the menu 125 | function! s:MenuController._setCmdheight() 126 | let &cmdheight = len(self.menuItems) + 3 127 | endfunction 128 | 129 | "FUNCTION: MenuController._saveOptions() {{{1 130 | "set any vim options that are required to make the menu work (saving their old 131 | "values) 132 | function! s:MenuController._saveOptions() 133 | let self._oldLazyredraw = &lazyredraw 134 | let self._oldCmdheight = &cmdheight 135 | set nolazyredraw 136 | call self._setCmdheight() 137 | endfunction 138 | 139 | "FUNCTION: MenuController._restoreOptions() {{{1 140 | "restore the options we saved in _saveOptions() 141 | function! s:MenuController._restoreOptions() 142 | let &cmdheight = self._oldCmdheight 143 | let &lazyredraw = self._oldLazyredraw 144 | endfunction 145 | 146 | "FUNCTION: MenuController._cursorDown() {{{1 147 | "move the cursor to the next menu item, skipping separators 148 | function! s:MenuController._cursorDown() 149 | let done = 0 150 | while !done 151 | if self.selection < len(self.menuItems)-1 152 | let self.selection += 1 153 | else 154 | let self.selection = 0 155 | endif 156 | 157 | if !self._current().isSeparator() 158 | let done = 1 159 | endif 160 | endwhile 161 | endfunction 162 | 163 | "FUNCTION: MenuController._cursorUp() {{{1 164 | "move the cursor to the previous menu item, skipping separators 165 | function! s:MenuController._cursorUp() 166 | let done = 0 167 | while !done 168 | if self.selection > 0 169 | let self.selection -= 1 170 | else 171 | let self.selection = len(self.menuItems)-1 172 | endif 173 | 174 | if !self._current().isSeparator() 175 | let done = 1 176 | endif 177 | endwhile 178 | endfunction 179 | 180 | " vim: set sw=4 sts=4 et fdm=marker: 181 | -------------------------------------------------------------------------------- /lib/nerdtree/menu_item.vim: -------------------------------------------------------------------------------- 1 | "CLASS: MenuItem 2 | "============================================================ 3 | let s:MenuItem = {} 4 | let g:NERDTreeMenuItem = s:MenuItem 5 | 6 | "FUNCTION: MenuItem.All() {{{1 7 | "get all top level menu items 8 | function! s:MenuItem.All() 9 | if !exists("s:menuItems") 10 | let s:menuItems = [] 11 | endif 12 | return s:menuItems 13 | endfunction 14 | 15 | "FUNCTION: MenuItem.AllEnabled() {{{1 16 | "get all top level menu items that are currently enabled 17 | function! s:MenuItem.AllEnabled() 18 | let toReturn = [] 19 | for i in s:MenuItem.All() 20 | if i.enabled() 21 | call add(toReturn, i) 22 | endif 23 | endfor 24 | return toReturn 25 | endfunction 26 | 27 | "FUNCTION: MenuItem.Create(options) {{{1 28 | "make a new menu item and add it to the global list 29 | function! s:MenuItem.Create(options) 30 | let newMenuItem = copy(self) 31 | 32 | let newMenuItem.text = a:options['text'] 33 | let newMenuItem.shortcut = a:options['shortcut'] 34 | let newMenuItem.children = [] 35 | 36 | let newMenuItem.isActiveCallback = -1 37 | if has_key(a:options, 'isActiveCallback') 38 | let newMenuItem.isActiveCallback = a:options['isActiveCallback'] 39 | endif 40 | 41 | let newMenuItem.callback = -1 42 | if has_key(a:options, 'callback') 43 | let newMenuItem.callback = a:options['callback'] 44 | endif 45 | 46 | if has_key(a:options, 'parent') 47 | call add(a:options['parent'].children, newMenuItem) 48 | else 49 | call add(s:MenuItem.All(), newMenuItem) 50 | endif 51 | 52 | return newMenuItem 53 | endfunction 54 | 55 | "FUNCTION: MenuItem.CreateSeparator(options) {{{1 56 | "make a new separator menu item and add it to the global list 57 | function! s:MenuItem.CreateSeparator(options) 58 | let standard_options = { 'text': '--------------------', 59 | \ 'shortcut': -1, 60 | \ 'callback': -1 } 61 | let options = extend(a:options, standard_options, "force") 62 | 63 | return s:MenuItem.Create(options) 64 | endfunction 65 | 66 | "FUNCTION: MenuItem.CreateSubmenu(options) {{{1 67 | "make a new submenu and add it to global list 68 | function! s:MenuItem.CreateSubmenu(options) 69 | let standard_options = { 'callback': -1 } 70 | let options = extend(a:options, standard_options, "force") 71 | 72 | return s:MenuItem.Create(options) 73 | endfunction 74 | 75 | "FUNCTION: MenuItem.enabled() {{{1 76 | "return 1 if this menu item should be displayed 77 | " 78 | "delegates off to the isActiveCallback, and defaults to 1 if no callback was 79 | "specified 80 | function! s:MenuItem.enabled() 81 | if self.isActiveCallback != -1 82 | return {self.isActiveCallback}() 83 | endif 84 | return 1 85 | endfunction 86 | 87 | "FUNCTION: MenuItem.execute() {{{1 88 | "perform the action behind this menu item, if this menuitem has children then 89 | "display a new menu for them, otherwise deletegate off to the menuitem's 90 | "callback 91 | function! s:MenuItem.execute() 92 | if len(self.children) 93 | let mc = g:NERDTreeMenuController.New(self.children) 94 | call mc.showMenu() 95 | else 96 | if self.callback != -1 97 | call {self.callback}() 98 | endif 99 | endif 100 | endfunction 101 | 102 | "FUNCTION: MenuItem.isSeparator() {{{1 103 | "return 1 if this menuitem is a separator 104 | function! s:MenuItem.isSeparator() 105 | return self.callback == -1 && self.children == [] 106 | endfunction 107 | 108 | "FUNCTION: MenuItem.isSubmenu() {{{1 109 | "return 1 if this menuitem is a submenu 110 | function! s:MenuItem.isSubmenu() 111 | return self.callback == -1 && !empty(self.children) 112 | endfunction 113 | 114 | " vim: set sw=4 sts=4 et fdm=marker: 115 | -------------------------------------------------------------------------------- /lib/nerdtree/nerdtree.vim: -------------------------------------------------------------------------------- 1 | "CLASS: NERDTree 2 | "============================================================ 3 | let s:NERDTree = {} 4 | let g:NERDTree = s:NERDTree 5 | 6 | "FUNCTION: s:NERDTree.AddPathFilter() {{{1 7 | function! s:NERDTree.AddPathFilter(callback) 8 | call add(s:NERDTree.PathFilters(), a:callback) 9 | endfunction 10 | 11 | "FUNCTION: s:NERDTree.Close() {{{1 12 | "Closes the primary NERD tree window for this tab 13 | function! s:NERDTree.Close() 14 | if !s:NERDTree.IsOpen() 15 | return 16 | endif 17 | 18 | if winnr("$") != 1 19 | if winnr() == s:NERDTree.GetWinNum() 20 | call nerdtree#exec("wincmd p") 21 | let bufnr = bufnr("") 22 | call nerdtree#exec("wincmd p") 23 | else 24 | let bufnr = bufnr("") 25 | endif 26 | 27 | call nerdtree#exec(s:NERDTree.GetWinNum() . " wincmd w") 28 | close 29 | call nerdtree#exec(bufwinnr(bufnr) . " wincmd w") 30 | else 31 | close 32 | endif 33 | endfunction 34 | 35 | "FUNCTION: s:NERDTree.CloseIfQuitOnOpen() {{{1 36 | "Closes the NERD tree window if the close on open option is set 37 | function! s:NERDTree.CloseIfQuitOnOpen() 38 | if g:NERDTreeQuitOnOpen && s:NERDTree.IsOpen() 39 | call s:NERDTree.Close() 40 | endif 41 | endfunction 42 | 43 | "FUNCTION: s:NERDTree.CursorToBookmarkTable(){{{1 44 | "Places the cursor at the top of the bookmarks table 45 | function! s:NERDTree.CursorToBookmarkTable() 46 | if !b:NERDTreeShowBookmarks 47 | throw "NERDTree.IllegalOperationError: cant find bookmark table, bookmarks arent active" 48 | endif 49 | 50 | if g:NERDTreeMinimalUI 51 | return cursor(1, 2) 52 | endif 53 | 54 | let rootNodeLine = b:NERDTree.ui.getRootLineNum() 55 | 56 | let line = 1 57 | while getline(line) !~# '^>-\+Bookmarks-\+$' 58 | let line = line + 1 59 | if line >= rootNodeLine 60 | throw "NERDTree.BookmarkTableNotFoundError: didnt find the bookmarks table" 61 | endif 62 | endwhile 63 | call cursor(line, 2) 64 | endfunction 65 | 66 | "FUNCTION: s:NERDTree.CursorToTreeWin(){{{1 67 | "Places the cursor in the nerd tree window 68 | function! s:NERDTree.CursorToTreeWin() 69 | call g:NERDTree.MustBeOpen() 70 | call nerdtree#exec(g:NERDTree.GetWinNum() . "wincmd w") 71 | endfunction 72 | 73 | " Function: s:NERDTree.ExistsForBuffer() {{{1 74 | " Returns 1 if a nerd tree root exists in the current buffer 75 | function! s:NERDTree.ExistsForBuf() 76 | return exists("b:NERDTreeRoot") 77 | endfunction 78 | 79 | " Function: s:NERDTree.ExistsForTab() {{{1 80 | " Returns 1 if a nerd tree root exists in the current tab 81 | function! s:NERDTree.ExistsForTab() 82 | return exists("t:NERDTreeBufName") 83 | endfunction 84 | 85 | function! s:NERDTree.ForCurrentBuf() 86 | if s:NERDTree.ExistsForBuf() 87 | return b:NERDTree 88 | else 89 | return {} 90 | endif 91 | endfunction 92 | 93 | "FUNCTION: s:NERDTree.GetWinNum() {{{1 94 | "gets the nerd tree window number for this tab 95 | function! s:NERDTree.GetWinNum() 96 | if exists("t:NERDTreeBufName") 97 | return bufwinnr(t:NERDTreeBufName) 98 | else 99 | return -1 100 | endif 101 | endfunction 102 | 103 | "FUNCTION: s:NERDTree.IsOpen() {{{1 104 | function! s:NERDTree.IsOpen() 105 | return s:NERDTree.GetWinNum() != -1 106 | endfunction 107 | 108 | "FUNCTION: s:NERDTree.MustBeOpen() {{{1 109 | function! s:NERDTree.MustBeOpen() 110 | if !s:NERDTree.IsOpen() 111 | throw "NERDTree.TreeNotOpen" 112 | endif 113 | endfunction 114 | 115 | "FUNCTION: s:NERDTree.New() {{{1 116 | function! s:NERDTree.New(path) 117 | let newObj = copy(self) 118 | let newObj.ui = g:NERDTreeUI.New(newObj) 119 | let newObj.root = g:NERDTreeDirNode.New(a:path) 120 | 121 | return newObj 122 | endfunction 123 | 124 | "FUNCTION: s:NERDTree.PathFilters() {{{1 125 | function! s:NERDTree.PathFilters() 126 | if !exists('s:NERDTree._PathFilters') 127 | let s:NERDTree._PathFilters = [] 128 | endif 129 | return s:NERDTree._PathFilters 130 | endfunction 131 | 132 | 133 | "FUNCTION: s:NERDTree.render() {{{1 134 | "A convenience function - since this is called often 135 | function! s:NERDTree.render() 136 | call self.ui.render() 137 | endfunction 138 | -------------------------------------------------------------------------------- /lib/nerdtree/notifier.vim: -------------------------------------------------------------------------------- 1 | "CLASS: Notifier 2 | "============================================================ 3 | let s:Notifier = {} 4 | 5 | function! s:Notifier.AddListener(event, funcname) 6 | let listeners = s:Notifier.GetListenersForEvent(a:event) 7 | if listeners == [] 8 | let listenersMap = s:Notifier.GetListenersMap() 9 | let listenersMap[a:event] = listeners 10 | endif 11 | call add(listeners, a:funcname) 12 | endfunction 13 | 14 | function! s:Notifier.NotifyListeners(event, path, params) 15 | let event = g:NERDTreeEvent.New(b:NERDTree, a:path, a:event, a:params) 16 | 17 | for listener in s:Notifier.GetListenersForEvent(a:event) 18 | call {listener}(event) 19 | endfor 20 | endfunction 21 | 22 | function! s:Notifier.GetListenersMap() 23 | if !exists("s:refreshListenersMap") 24 | let s:refreshListenersMap = {} 25 | endif 26 | return s:refreshListenersMap 27 | endfunction 28 | 29 | function! s:Notifier.GetListenersForEvent(name) 30 | let listenersMap = s:Notifier.GetListenersMap() 31 | return get(listenersMap, a:name, []) 32 | endfunction 33 | 34 | let g:NERDTreePathNotifier = deepcopy(s:Notifier) 35 | 36 | -------------------------------------------------------------------------------- /lib/nerdtree/opener.vim: -------------------------------------------------------------------------------- 1 | "CLASS: Opener 2 | "============================================================ 3 | let s:Opener = {} 4 | let g:NERDTreeOpener = s:Opener 5 | 6 | "FUNCTION: s:Opener._bufInWindows(bnum){{{1 7 | "[[STOLEN FROM VTREEEXPLORER.VIM]] 8 | "Determine the number of windows open to this buffer number. 9 | "Care of Yegappan Lakshman. Thanks! 10 | " 11 | "Args: 12 | "bnum: the subject buffers buffer number 13 | function! s:Opener._bufInWindows(bnum) 14 | let cnt = 0 15 | let winnum = 1 16 | while 1 17 | let bufnum = winbufnr(winnum) 18 | if bufnum < 0 19 | break 20 | endif 21 | if bufnum ==# a:bnum 22 | let cnt = cnt + 1 23 | endif 24 | let winnum = winnum + 1 25 | endwhile 26 | 27 | return cnt 28 | endfunction 29 | "FUNCTION: Opener._checkToCloseTree(newtab) {{{1 30 | "Check the class options and global options (i.e. NERDTreeQuitOnOpen) to see 31 | "if the tree should be closed now. 32 | " 33 | "Args: 34 | "a:newtab - boolean. If set, only close the tree now if we are opening the 35 | "target in a new tab. This is needed because we have to close tree before we 36 | "leave the tab 37 | function! s:Opener._checkToCloseTree(newtab) 38 | if self._keepopen 39 | return 40 | endif 41 | 42 | if (a:newtab && self._where == 't') || !a:newtab 43 | call g:NERDTree.CloseIfQuitOnOpen() 44 | endif 45 | endfunction 46 | 47 | 48 | "FUNCTION: s:Opener._firstUsableWindow(){{{1 49 | "find the window number of the first normal window 50 | function! s:Opener._firstUsableWindow() 51 | let i = 1 52 | while i <= winnr("$") 53 | let bnum = winbufnr(i) 54 | if bnum != -1 && getbufvar(bnum, '&buftype') ==# '' 55 | \ && !getwinvar(i, '&previewwindow') 56 | \ && (!getbufvar(bnum, '&modified') || &hidden) 57 | return i 58 | endif 59 | 60 | let i += 1 61 | endwhile 62 | return -1 63 | endfunction 64 | 65 | "FUNCTION: Opener._gotoTargetWin() {{{1 66 | function! s:Opener._gotoTargetWin() 67 | if b:NERDTreeType ==# "secondary" 68 | if self._where == 'v' 69 | vsplit 70 | elseif self._where == 'h' 71 | split 72 | elseif self._where == 't' 73 | tabnew 74 | endif 75 | else 76 | call self._checkToCloseTree(1) 77 | 78 | if self._where == 'v' 79 | call self._newVSplit() 80 | elseif self._where == 'h' 81 | call self._newSplit() 82 | elseif self._where == 't' 83 | tabnew 84 | elseif self._where == 'p' 85 | call self._previousWindow() 86 | endif 87 | 88 | call self._checkToCloseTree(0) 89 | endif 90 | endfunction 91 | 92 | "FUNCTION: s:Opener._isWindowUsable(winnumber) {{{1 93 | "Returns 0 if opening a file from the tree in the given window requires it to 94 | "be split, 1 otherwise 95 | " 96 | "Args: 97 | "winnumber: the number of the window in question 98 | function! s:Opener._isWindowUsable(winnumber) 99 | "gotta split if theres only one window (i.e. the NERD tree) 100 | if winnr("$") ==# 1 101 | return 0 102 | endif 103 | 104 | let oldwinnr = winnr() 105 | call nerdtree#exec(a:winnumber . "wincmd p") 106 | let specialWindow = getbufvar("%", '&buftype') != '' || getwinvar('%', '&previewwindow') 107 | let modified = &modified 108 | call nerdtree#exec(oldwinnr . "wincmd p") 109 | 110 | "if its a special window e.g. quickfix or another explorer plugin then we 111 | "have to split 112 | if specialWindow 113 | return 0 114 | endif 115 | 116 | if &hidden 117 | return 1 118 | endif 119 | 120 | return !modified || self._bufInWindows(winbufnr(a:winnumber)) >= 2 121 | endfunction 122 | 123 | "FUNCTION: Opener.New(path, opts) {{{1 124 | "Args: 125 | " 126 | "a:path: The path object that is to be opened. 127 | " 128 | "a:opts: 129 | " 130 | "A dictionary containing the following keys (all optional): 131 | " 'where': Specifies whether the node should be opened in new split/tab or in 132 | " the previous window. Can be either 'v' or 'h' or 't' (for open in 133 | " new tab) 134 | " 'reuse': if a window is displaying the file then jump the cursor there. Can 135 | " 'all', 'currenttab' or empty to not reuse. 136 | " 'keepopen': dont close the tree window 137 | " 'stay': open the file, but keep the cursor in the tree win 138 | function! s:Opener.New(path, opts) 139 | let newObj = copy(self) 140 | 141 | let newObj._path = a:path 142 | let newObj._stay = nerdtree#has_opt(a:opts, 'stay') 143 | 144 | if has_key(a:opts, 'reuse') 145 | let newObj._reuse = a:opts['reuse'] 146 | else 147 | let newObj._reuse = '' 148 | endif 149 | 150 | let newObj._keepopen = nerdtree#has_opt(a:opts, 'keepopen') 151 | let newObj._where = has_key(a:opts, 'where') ? a:opts['where'] : '' 152 | let newObj._treetype = b:NERDTreeType 153 | call newObj._saveCursorPos() 154 | 155 | return newObj 156 | endfunction 157 | 158 | "FUNCTION: Opener._newSplit() {{{1 159 | function! s:Opener._newSplit() 160 | " Save the user's settings for splitbelow and splitright 161 | let savesplitbelow=&splitbelow 162 | let savesplitright=&splitright 163 | 164 | " 'there' will be set to a command to move from the split window 165 | " back to the explorer window 166 | " 167 | " 'back' will be set to a command to move from the explorer window 168 | " back to the newly split window 169 | " 170 | " 'right' and 'below' will be set to the settings needed for 171 | " splitbelow and splitright IF the explorer is the only window. 172 | " 173 | let there= g:NERDTreeWinPos ==# "left" ? "wincmd h" : "wincmd l" 174 | let back = g:NERDTreeWinPos ==# "left" ? "wincmd l" : "wincmd h" 175 | let right= g:NERDTreeWinPos ==# "left" 176 | let below=0 177 | 178 | " Attempt to go to adjacent window 179 | call nerdtree#exec(back) 180 | 181 | let onlyOneWin = (winnr("$") ==# 1) 182 | 183 | " If no adjacent window, set splitright and splitbelow appropriately 184 | if onlyOneWin 185 | let &splitright=right 186 | let &splitbelow=below 187 | else 188 | " found adjacent window - invert split direction 189 | let &splitright=!right 190 | let &splitbelow=!below 191 | endif 192 | 193 | let splitMode = onlyOneWin ? "vertical" : "" 194 | 195 | " Open the new window 196 | try 197 | exec(splitMode." sp ") 198 | catch /^Vim\%((\a\+)\)\=:E37/ 199 | call g:NERDTree.CursorToTreeWin() 200 | throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self._path.str() ." is already open and modified." 201 | catch /^Vim\%((\a\+)\)\=:/ 202 | "do nothing 203 | endtry 204 | 205 | "resize the tree window if no other window was open before 206 | if onlyOneWin 207 | let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize 208 | call nerdtree#exec(there) 209 | exec("silent ". splitMode ." resize ". size) 210 | call nerdtree#exec('wincmd p') 211 | endif 212 | 213 | " Restore splitmode settings 214 | let &splitbelow=savesplitbelow 215 | let &splitright=savesplitright 216 | endfunction 217 | 218 | "FUNCTION: Opener._newVSplit() {{{1 219 | function! s:Opener._newVSplit() 220 | let winwidth = winwidth(".") 221 | if winnr("$")==#1 222 | let winwidth = g:NERDTreeWinSize 223 | endif 224 | 225 | call nerdtree#exec("wincmd p") 226 | vnew 227 | 228 | "resize the nerd tree back to the original size 229 | call g:NERDTree.CursorToTreeWin() 230 | exec("silent vertical resize ". winwidth) 231 | call nerdtree#exec('wincmd p') 232 | endfunction 233 | 234 | "FUNCTION: Opener.open(target) {{{1 235 | function! s:Opener.open(target) 236 | if self._path.isDirectory 237 | call self._openDirectory(a:target) 238 | else 239 | call self._openFile() 240 | endif 241 | endfunction 242 | 243 | "FUNCTION: Opener._openFile() {{{1 244 | function! s:Opener._openFile() 245 | if self._reuseWindow() 246 | return 247 | endif 248 | 249 | call self._gotoTargetWin() 250 | 251 | if self._treetype ==# "secondary" 252 | call self._path.edit() 253 | else 254 | call self._path.edit() 255 | 256 | 257 | if self._stay 258 | call self._restoreCursorPos() 259 | endif 260 | endif 261 | endfunction 262 | 263 | "FUNCTION: Opener._openDirectory(node) {{{1 264 | function! s:Opener._openDirectory(node) 265 | if self._treetype ==# "secondary" 266 | call self._gotoTargetWin() 267 | call g:NERDTreeCreator.CreateSecondary(a:node.path.str()) 268 | else 269 | call self._gotoTargetWin() 270 | if empty(self._where) 271 | call a:node.makeRoot() 272 | call b:NERDTree.render() 273 | call a:node.putCursorHere(0, 0) 274 | elseif self._where == 't' 275 | call g:NERDTreeCreator.CreatePrimary(a:node.path.str()) 276 | else 277 | call g:NERDTreeCreator.CreateSecondary(a:node.path.str()) 278 | endif 279 | endif 280 | 281 | if self._stay 282 | call self._restoreCursorPos() 283 | endif 284 | endfunction 285 | 286 | "FUNCTION: Opener._previousWindow() {{{1 287 | function! s:Opener._previousWindow() 288 | if !self._isWindowUsable(winnr("#")) && self._firstUsableWindow() ==# -1 289 | call self._newSplit() 290 | else 291 | try 292 | if !self._isWindowUsable(winnr("#")) 293 | call nerdtree#exec(self._firstUsableWindow() . "wincmd w") 294 | else 295 | call nerdtree#exec('wincmd p') 296 | endif 297 | catch /^Vim\%((\a\+)\)\=:E37/ 298 | call g:NERDTree.CursorToTreeWin() 299 | throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self._path.str() ." is already open and modified." 300 | catch /^Vim\%((\a\+)\)\=:/ 301 | echo v:exception 302 | endtry 303 | endif 304 | endfunction 305 | 306 | "FUNCTION: Opener._restoreCursorPos(){{{1 307 | function! s:Opener._restoreCursorPos() 308 | call nerdtree#exec('normal ' . self._tabnr . 'gt') 309 | call nerdtree#exec(bufwinnr(self._bufnr) . 'wincmd w') 310 | endfunction 311 | 312 | "FUNCTION: Opener._reuseWindow(){{{1 313 | "put the cursor in the first window we find for this file 314 | " 315 | "return 1 if we were successful 316 | function! s:Opener._reuseWindow() 317 | if empty(self._reuse) 318 | return 0 319 | endif 320 | 321 | "check the current tab for the window 322 | let winnr = bufwinnr('^' . self._path.str() . '$') 323 | if winnr != -1 324 | call nerdtree#exec(winnr . "wincmd w") 325 | call self._checkToCloseTree(0) 326 | return 1 327 | endif 328 | 329 | if self._reuse == 'currenttab' 330 | return 0 331 | endif 332 | 333 | "check other tabs 334 | let tabnr = self._path.tabnr() 335 | if tabnr 336 | call self._checkToCloseTree(1) 337 | call nerdtree#exec('normal! ' . tabnr . 'gt') 338 | let winnr = bufwinnr('^' . self._path.str() . '$') 339 | call nerdtree#exec(winnr . "wincmd w") 340 | return 1 341 | endif 342 | 343 | return 0 344 | endfunction 345 | 346 | "FUNCTION: Opener._saveCursorPos(){{{1 347 | function! s:Opener._saveCursorPos() 348 | let self._bufnr = bufnr("") 349 | let self._tabnr = tabpagenr() 350 | endfunction 351 | 352 | " vim: set sw=4 sts=4 et fdm=marker: 353 | -------------------------------------------------------------------------------- /lib/nerdtree/path.vim: -------------------------------------------------------------------------------- 1 | "we need to use this number many times for sorting... so we calculate it only 2 | "once here 3 | let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*') 4 | " used in formating sortKey, e.g. '%04d' 5 | if exists("log10") 6 | let s:sortKeyFormat = "%0" . float2nr(ceil(log10(len(g:NERDTreeSortOrder)))) . "d" 7 | else 8 | let s:sortKeyFormat = "%04d" 9 | endif 10 | 11 | "CLASS: Path 12 | "============================================================ 13 | let s:Path = {} 14 | let g:NERDTreePath = s:Path 15 | 16 | "FUNCTION: Path.AbsolutePathFor(str) {{{1 17 | function! s:Path.AbsolutePathFor(str) 18 | let prependCWD = 0 19 | if nerdtree#runningWindows() 20 | let prependCWD = a:str !~# '^.:\(\\\|\/\)' && a:str !~# '^\(\\\\\|\/\/\)' 21 | else 22 | let prependCWD = a:str !~# '^/' 23 | endif 24 | 25 | let toReturn = a:str 26 | if prependCWD 27 | let toReturn = getcwd() . s:Path.Slash() . a:str 28 | endif 29 | 30 | return toReturn 31 | endfunction 32 | 33 | "FUNCTION: Path.bookmarkNames() {{{1 34 | function! s:Path.bookmarkNames() 35 | if !exists("self._bookmarkNames") 36 | call self.cacheDisplayString() 37 | endif 38 | return self._bookmarkNames 39 | endfunction 40 | 41 | "FUNCTION: Path.cacheDisplayString() {{{1 42 | function! s:Path.cacheDisplayString() abort 43 | let self.cachedDisplayString = self.flagSet.renderToString() 44 | 45 | let self.cachedDisplayString .= self.getLastPathComponent(1) 46 | 47 | if self.isExecutable 48 | let self.cachedDisplayString = self.cachedDisplayString . '*' 49 | endif 50 | 51 | let self._bookmarkNames = [] 52 | for i in g:NERDTreeBookmark.Bookmarks() 53 | if i.path.equals(self) 54 | call add(self._bookmarkNames, i.name) 55 | endif 56 | endfor 57 | if !empty(self._bookmarkNames) 58 | let self.cachedDisplayString .= ' {' . join(self._bookmarkNames) . '}' 59 | endif 60 | 61 | if self.isSymLink 62 | let self.cachedDisplayString .= ' -> ' . self.symLinkDest 63 | endif 64 | 65 | if self.isReadOnly 66 | let self.cachedDisplayString .= ' [RO]' 67 | endif 68 | endfunction 69 | 70 | "FUNCTION: Path.changeToDir() {{{1 71 | function! s:Path.changeToDir() 72 | let dir = self.str({'format': 'Cd'}) 73 | if self.isDirectory ==# 0 74 | let dir = self.getParent().str({'format': 'Cd'}) 75 | endif 76 | 77 | try 78 | execute "cd " . dir 79 | call nerdtree#echo("CWD is now: " . getcwd()) 80 | catch 81 | throw "NERDTree.PathChangeError: cannot change CWD to " . dir 82 | endtry 83 | endfunction 84 | 85 | "FUNCTION: Path.compareTo() {{{1 86 | " 87 | "Compares this Path to the given path and returns 0 if they are equal, -1 if 88 | "this Path is "less than" the given path, or 1 if it is "greater". 89 | " 90 | "Args: 91 | "path: the path object to compare this to 92 | " 93 | "Return: 94 | "1, -1 or 0 95 | function! s:Path.compareTo(path) 96 | let thisPath = self.getLastPathComponent(1) 97 | let thatPath = a:path.getLastPathComponent(1) 98 | 99 | "if the paths are the same then clearly we return 0 100 | if thisPath ==# thatPath 101 | return 0 102 | endif 103 | 104 | let thisSS = self.getSortOrderIndex() 105 | let thatSS = a:path.getSortOrderIndex() 106 | 107 | "compare the sort sequences, if they are different then the return 108 | "value is easy 109 | if thisSS < thatSS 110 | return -1 111 | elseif thisSS > thatSS 112 | return 1 113 | else 114 | if !g:NERDTreeSortHiddenFirst 115 | let thisPath = substitute(thisPath, '^[._]', '', '') 116 | let thatPath = substitute(thatPath, '^[._]', '', '') 117 | endif 118 | "if the sort sequences are the same then compare the paths 119 | "alphabetically 120 | let pathCompare = g:NERDTreeCaseSensitiveSort ? thisPath <# thatPath : thisPath " 304 | endif 305 | 306 | return " \\`\|\"#%&,?()\*^<>[]" 307 | endfunction 308 | 309 | "FUNCTION: Path.getDir() {{{1 310 | " 311 | "Returns this path if it is a directory, else this paths parent. 312 | " 313 | "Return: 314 | "a Path object 315 | function! s:Path.getDir() 316 | if self.isDirectory 317 | return self 318 | else 319 | return self.getParent() 320 | endif 321 | endfunction 322 | 323 | "FUNCTION: Path.getParent() {{{1 324 | " 325 | "Returns a new path object for this paths parent 326 | " 327 | "Return: 328 | "a new Path object 329 | function! s:Path.getParent() 330 | if nerdtree#runningWindows() 331 | let path = self.drive . '\' . join(self.pathSegments[0:-2], '\') 332 | else 333 | let path = '/'. join(self.pathSegments[0:-2], '/') 334 | endif 335 | 336 | return s:Path.New(path) 337 | endfunction 338 | 339 | "FUNCTION: Path.getLastPathComponent(dirSlash) {{{1 340 | " 341 | "Gets the last part of this path. 342 | " 343 | "Args: 344 | "dirSlash: if 1 then a trailing slash will be added to the returned value for 345 | "directory nodes. 346 | function! s:Path.getLastPathComponent(dirSlash) 347 | if empty(self.pathSegments) 348 | return '' 349 | endif 350 | let toReturn = self.pathSegments[-1] 351 | if a:dirSlash && self.isDirectory 352 | let toReturn = toReturn . '/' 353 | endif 354 | return toReturn 355 | endfunction 356 | 357 | "FUNCTION: Path.getSortOrderIndex() {{{1 358 | "returns the index of the pattern in g:NERDTreeSortOrder that this path matches 359 | function! s:Path.getSortOrderIndex() 360 | let i = 0 361 | while i < len(g:NERDTreeSortOrder) 362 | if self.getLastPathComponent(1) =~# g:NERDTreeSortOrder[i] 363 | return i 364 | endif 365 | let i = i + 1 366 | endwhile 367 | return s:NERDTreeSortStarIndex 368 | endfunction 369 | 370 | "FUNCTION: Path.getSortKey() {{{1 371 | "returns a string used in compare function for sorting 372 | function! s:Path.getSortKey() 373 | if !exists("self._sortKey") 374 | let path = self.getLastPathComponent(1) 375 | if !g:NERDTreeSortHiddenFirst 376 | let path = substitute(path, '^[._]', '', '') 377 | endif 378 | if !g:NERDTreeCaseSensitiveSort 379 | let path = tolower(path) 380 | endif 381 | let self._sortKey = printf(s:sortKeyFormat, self.getSortOrderIndex()) . path 382 | endif 383 | 384 | return self._sortKey 385 | endfunction 386 | 387 | 388 | "FUNCTION: Path.isUnixHiddenFile() {{{1 389 | "check for unix hidden files 390 | function! s:Path.isUnixHiddenFile() 391 | return self.getLastPathComponent(0) =~# '^\.' 392 | endfunction 393 | 394 | "FUNCTION: Path.isUnixHiddenPath() {{{1 395 | "check for unix path with hidden components 396 | function! s:Path.isUnixHiddenPath() 397 | if self.getLastPathComponent(0) =~# '^\.' 398 | return 1 399 | else 400 | for segment in self.pathSegments 401 | if segment =~# '^\.' 402 | return 1 403 | endif 404 | endfor 405 | return 0 406 | endif 407 | endfunction 408 | 409 | "FUNCTION: Path.ignore() {{{1 410 | "returns true if this path should be ignored 411 | function! s:Path.ignore() 412 | "filter out the user specified paths to ignore 413 | if b:NERDTreeIgnoreEnabled 414 | for i in g:NERDTreeIgnore 415 | if self._ignorePatternMatches(i) 416 | return 1 417 | endif 418 | endfor 419 | 420 | for callback in g:NERDTree.PathFilters() 421 | if {callback}({'path': self, 'nerdtree': b:NERDTree}) 422 | return 1 423 | endif 424 | endfor 425 | endif 426 | 427 | "dont show hidden files unless instructed to 428 | if b:NERDTreeShowHidden ==# 0 && self.isUnixHiddenFile() 429 | return 1 430 | endif 431 | 432 | if b:NERDTreeShowFiles ==# 0 && self.isDirectory ==# 0 433 | return 1 434 | endif 435 | 436 | return 0 437 | endfunction 438 | 439 | "FUNCTION: Path._ignorePatternMatches(pattern) {{{1 440 | "returns true if this path matches the given ignore pattern 441 | function! s:Path._ignorePatternMatches(pattern) 442 | let pat = a:pattern 443 | if strpart(pat,len(pat)-7) == '[[dir]]' 444 | if !self.isDirectory 445 | return 0 446 | endif 447 | let pat = strpart(pat,0, len(pat)-7) 448 | elseif strpart(pat,len(pat)-8) == '[[file]]' 449 | if self.isDirectory 450 | return 0 451 | endif 452 | let pat = strpart(pat,0, len(pat)-8) 453 | endif 454 | 455 | return self.getLastPathComponent(0) =~# pat 456 | endfunction 457 | 458 | "FUNCTION: Path.isUnder(path) {{{1 459 | "return 1 if this path is somewhere under the given path in the filesystem. 460 | " 461 | "a:path should be a dir 462 | function! s:Path.isUnder(path) 463 | if a:path.isDirectory == 0 464 | return 0 465 | endif 466 | 467 | let this = self.str() 468 | let that = a:path.str() 469 | return stridx(this, that . s:Path.Slash()) == 0 470 | endfunction 471 | 472 | "FUNCTION: Path.JoinPathStrings(...) {{{1 473 | function! s:Path.JoinPathStrings(...) 474 | let components = [] 475 | for i in a:000 476 | let components = extend(components, split(i, '/')) 477 | endfor 478 | return '/' . join(components, '/') 479 | endfunction 480 | 481 | "FUNCTION: Path.equals() {{{1 482 | " 483 | "Determines whether 2 path objects are "equal". 484 | "They are equal if the paths they represent are the same 485 | " 486 | "Args: 487 | "path: the other path obj to compare this with 488 | function! s:Path.equals(path) 489 | return self.str() ==# a:path.str() 490 | endfunction 491 | 492 | "FUNCTION: Path.New() {{{1 493 | "The Constructor for the Path object 494 | function! s:Path.New(path) 495 | let newPath = copy(self) 496 | 497 | call newPath.readInfoFromDisk(s:Path.AbsolutePathFor(a:path)) 498 | 499 | let newPath.cachedDisplayString = "" 500 | let newPath.flagSet = g:NERDTreeFlagSet.New() 501 | 502 | return newPath 503 | endfunction 504 | 505 | "FUNCTION: Path.Slash() {{{1 506 | "return the slash to use for the current OS 507 | function! s:Path.Slash() 508 | return nerdtree#runningWindows() ? '\' : '/' 509 | endfunction 510 | 511 | "FUNCTION: Path.Resolve() {{{1 512 | "Invoke the vim resolve() function and return the result 513 | "This is necessary because in some versions of vim resolve() removes trailing 514 | "slashes while in other versions it doesn't. This always removes the trailing 515 | "slash 516 | function! s:Path.Resolve(path) 517 | let tmp = resolve(a:path) 518 | return tmp =~# '.\+/$' ? substitute(tmp, '/$', '', '') : tmp 519 | endfunction 520 | 521 | "FUNCTION: Path.readInfoFromDisk(fullpath) {{{1 522 | " 523 | " 524 | "Throws NERDTree.Path.InvalidArguments exception. 525 | function! s:Path.readInfoFromDisk(fullpath) 526 | call self.extractDriveLetter(a:fullpath) 527 | 528 | let fullpath = s:Path.WinToUnixPath(a:fullpath) 529 | 530 | if getftype(fullpath) ==# "fifo" 531 | throw "NERDTree.InvalidFiletypeError: Cant handle FIFO files: " . a:fullpath 532 | endif 533 | 534 | let self.pathSegments = split(fullpath, '/') 535 | 536 | let self.isReadOnly = 0 537 | if isdirectory(a:fullpath) 538 | let self.isDirectory = 1 539 | elseif filereadable(a:fullpath) 540 | let self.isDirectory = 0 541 | let self.isReadOnly = filewritable(a:fullpath) ==# 0 542 | else 543 | throw "NERDTree.InvalidArgumentsError: Invalid path = " . a:fullpath 544 | endif 545 | 546 | let self.isExecutable = 0 547 | if !self.isDirectory 548 | let self.isExecutable = getfperm(a:fullpath) =~# 'x' 549 | endif 550 | 551 | "grab the last part of the path (minus the trailing slash) 552 | let lastPathComponent = self.getLastPathComponent(0) 553 | 554 | "get the path to the new node with the parent dir fully resolved 555 | let hardPath = s:Path.Resolve(self.strTrunk()) . '/' . lastPathComponent 556 | 557 | "if the last part of the path is a symlink then flag it as such 558 | let self.isSymLink = (s:Path.Resolve(hardPath) != hardPath) 559 | if self.isSymLink 560 | let self.symLinkDest = s:Path.Resolve(fullpath) 561 | 562 | "if the link is a dir then slap a / on the end of its dest 563 | if isdirectory(self.symLinkDest) 564 | 565 | "we always wanna treat MS windows shortcuts as files for 566 | "simplicity 567 | if hardPath !~# '\.lnk$' 568 | 569 | let self.symLinkDest = self.symLinkDest . '/' 570 | endif 571 | endif 572 | endif 573 | endfunction 574 | 575 | "FUNCTION: Path.refresh() {{{1 576 | function! s:Path.refresh() 577 | call self.readInfoFromDisk(self.str()) 578 | call g:NERDTreePathNotifier.NotifyListeners('refresh', self, {}) 579 | call self.cacheDisplayString() 580 | endfunction 581 | 582 | "FUNCTION: Path.refreshFlags() {{{1 583 | function! s:Path.refreshFlags() 584 | call g:NERDTreePathNotifier.NotifyListeners('refreshFlags', self, {}) 585 | call self.cacheDisplayString() 586 | endfunction 587 | 588 | "FUNCTION: Path.rename() {{{1 589 | " 590 | "Renames this node on the filesystem 591 | function! s:Path.rename(newPath) 592 | if a:newPath ==# '' 593 | throw "NERDTree.InvalidArgumentsError: Invalid newPath for renaming = ". a:newPath 594 | endif 595 | 596 | let success = rename(self.str(), a:newPath) 597 | if success != 0 598 | throw "NERDTree.PathRenameError: Could not rename: '" . self.str() . "'" . 'to:' . a:newPath 599 | endif 600 | call self.readInfoFromDisk(a:newPath) 601 | 602 | for i in self.bookmarkNames() 603 | let b = g:NERDTreeBookmark.BookmarkFor(i) 604 | call b.setPath(copy(self)) 605 | endfor 606 | call g:NERDTreeBookmark.Write() 607 | endfunction 608 | 609 | "FUNCTION: Path.str() {{{1 610 | " 611 | "Returns a string representation of this Path 612 | " 613 | "Takes an optional dictionary param to specify how the output should be 614 | "formatted. 615 | " 616 | "The dict may have the following keys: 617 | " 'format' 618 | " 'escape' 619 | " 'truncateTo' 620 | " 621 | "The 'format' key may have a value of: 622 | " 'Cd' - a string to be used with the :cd command 623 | " 'Edit' - a string to be used with :e :sp :new :tabedit etc 624 | " 'UI' - a string used in the NERD tree UI 625 | " 626 | "The 'escape' key, if specified will cause the output to be escaped with 627 | "shellescape() 628 | " 629 | "The 'truncateTo' key causes the resulting string to be truncated to the value 630 | "'truncateTo' maps to. A '<' char will be prepended. 631 | function! s:Path.str(...) 632 | let options = a:0 ? a:1 : {} 633 | let toReturn = "" 634 | 635 | if has_key(options, 'format') 636 | let format = options['format'] 637 | if has_key(self, '_strFor' . format) 638 | exec 'let toReturn = self._strFor' . format . '()' 639 | else 640 | throw 'NERDTree.UnknownFormatError: unknown format "'. format .'"' 641 | endif 642 | else 643 | let toReturn = self._str() 644 | endif 645 | 646 | if nerdtree#has_opt(options, 'escape') 647 | let toReturn = shellescape(toReturn) 648 | endif 649 | 650 | if has_key(options, 'truncateTo') 651 | let limit = options['truncateTo'] 652 | if len(toReturn) > limit-1 653 | let toReturn = toReturn[(len(toReturn)-limit+1):] 654 | if len(split(toReturn, '/')) > 1 655 | let toReturn = ' len(array_to_search) 138 | throw "NERDTree.InvalidArgumentsError: Index is out of bounds." 139 | endif 140 | return array_to_search[a:indx] 141 | endfunction 142 | 143 | "FUNCTION: TreeDirNode.getChildIndex(path) {{{1 144 | "Returns the index of the child node of this node that has the given path or 145 | "-1 if no such node exists. 146 | " 147 | "This function doesnt not recurse into child dir nodes 148 | " 149 | "Args: 150 | "path: a path object 151 | function! s:TreeDirNode.getChildIndex(path) 152 | if stridx(a:path.str(), self.path.str(), 0) ==# -1 153 | return -1 154 | endif 155 | 156 | "do a binary search for the child 157 | let a = 0 158 | let z = self.getChildCount() 159 | while a < z 160 | let mid = (a+z)/2 161 | let diff = a:path.compareTo(self.children[mid].path) 162 | 163 | if diff ==# -1 164 | let z = mid 165 | elseif diff ==# 1 166 | let a = mid+1 167 | else 168 | return mid 169 | endif 170 | endwhile 171 | return -1 172 | endfunction 173 | 174 | "FUNCTION: TreeDirNode.GetSelected() {{{1 175 | "Returns the current node if it is a dir node, or else returns the current 176 | "nodes parent 177 | unlet s:TreeDirNode.GetSelected 178 | function! s:TreeDirNode.GetSelected() 179 | let currentDir = g:NERDTreeFileNode.GetSelected() 180 | if currentDir != {} && !currentDir.isRoot() 181 | if currentDir.path.isDirectory ==# 0 182 | let currentDir = currentDir.parent 183 | endif 184 | endif 185 | return currentDir 186 | endfunction 187 | 188 | "FUNCTION: TreeDirNode.getVisibleChildCount() {{{1 189 | "Returns the number of visible children this node has 190 | function! s:TreeDirNode.getVisibleChildCount() 191 | return len(self.getVisibleChildren()) 192 | endfunction 193 | 194 | "FUNCTION: TreeDirNode.getVisibleChildren() {{{1 195 | "Returns a list of children to display for this node, in the correct order 196 | " 197 | "Return: 198 | "an array of treenodes 199 | function! s:TreeDirNode.getVisibleChildren() 200 | let toReturn = [] 201 | for i in self.children 202 | if i.path.ignore() ==# 0 203 | call add(toReturn, i) 204 | endif 205 | endfor 206 | return toReturn 207 | endfunction 208 | 209 | "FUNCTION: TreeDirNode.hasVisibleChildren() {{{1 210 | "returns 1 if this node has any childre, 0 otherwise.. 211 | function! s:TreeDirNode.hasVisibleChildren() 212 | return self.getVisibleChildCount() != 0 213 | endfunction 214 | 215 | "FUNCTION: TreeDirNode._initChildren() {{{1 216 | "Removes all childen from this node and re-reads them 217 | " 218 | "Args: 219 | "silent: 1 if the function should not echo any "please wait" messages for 220 | "large directories 221 | " 222 | "Return: the number of child nodes read 223 | function! s:TreeDirNode._initChildren(silent) 224 | "remove all the current child nodes 225 | let self.children = [] 226 | 227 | "get an array of all the files in the nodes dir 228 | let dir = self.path 229 | let globDir = dir.str({'format': 'Glob'}) 230 | 231 | if version >= 703 232 | let filesStr = globpath(globDir, '*', !g:NERDTreeRespectWildIgnore) . "\n" . globpath(globDir, '.*', !g:NERDTreeRespectWildIgnore) 233 | else 234 | let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*') 235 | endif 236 | 237 | let files = split(filesStr, "\n") 238 | 239 | if !a:silent && len(files) > g:NERDTreeNotificationThreshold 240 | call nerdtree#echo("Please wait, caching a large dir ...") 241 | endif 242 | 243 | let invalidFilesFound = 0 244 | for i in files 245 | 246 | "filter out the .. and . directories 247 | "Note: we must match .. AND ../ since sometimes the globpath returns 248 | "../ for path with strange chars (eg $) 249 | if i[len(i)-3:2] != ".." && i[len(i)-2:2] != ".." && 250 | \ i[len(i)-2:1] != "." && i[len(i)-1] != "." 251 | "put the next file in a new node and attach it 252 | try 253 | let path = g:NERDTreePath.New(i) 254 | call self.createChild(path, 0) 255 | call g:NERDTreePathNotifier.NotifyListeners('init', path, {}) 256 | catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/ 257 | let invalidFilesFound += 1 258 | endtry 259 | endif 260 | endfor 261 | 262 | call self.sortChildren() 263 | 264 | if !a:silent && len(files) > g:NERDTreeNotificationThreshold 265 | call nerdtree#echo("Please wait, caching a large dir ... DONE (". self.getChildCount() ." nodes cached).") 266 | endif 267 | 268 | if invalidFilesFound 269 | call nerdtree#echoWarning(invalidFilesFound . " file(s) could not be loaded into the NERD tree") 270 | endif 271 | return self.getChildCount() 272 | endfunction 273 | 274 | "FUNCTION: TreeDirNode.New(path) {{{1 275 | "Returns a new TreeNode object with the given path and parent 276 | " 277 | "Args: 278 | "path: a path object representing the full filesystem path to the file/dir that the node represents 279 | unlet s:TreeDirNode.New 280 | function! s:TreeDirNode.New(path) 281 | if a:path.isDirectory != 1 282 | throw "NERDTree.InvalidArgumentsError: A TreeDirNode object must be instantiated with a directory Path object." 283 | endif 284 | 285 | let newTreeNode = copy(self) 286 | let newTreeNode.path = a:path 287 | 288 | let newTreeNode.isOpen = 0 289 | let newTreeNode.children = [] 290 | 291 | let newTreeNode.parent = {} 292 | 293 | return newTreeNode 294 | endfunction 295 | 296 | "FUNCTION: TreeDirNode.open([opts]) {{{1 297 | "Open the dir in the current tree or in a new tree elsewhere. 298 | " 299 | "If opening in the current tree, return the number of cached nodes. 300 | unlet s:TreeDirNode.open 301 | function! s:TreeDirNode.open(...) 302 | let opts = a:0 ? a:1 : {} 303 | 304 | if has_key(opts, 'where') && !empty(opts['where']) 305 | let opener = g:NERDTreeOpener.New(self.path, opts) 306 | call opener.open(self) 307 | else 308 | let self.isOpen = 1 309 | if self.children ==# [] 310 | return self._initChildren(0) 311 | else 312 | return 0 313 | endif 314 | endif 315 | endfunction 316 | 317 | "FUNCTION: TreeDirNode.openAlong([opts]) {{{1 318 | "recursive open the dir if it has only one directory child. 319 | " 320 | "return the level of opened directories. 321 | function! s:TreeDirNode.openAlong(...) 322 | let opts = a:0 ? a:1 : {} 323 | let level = 0 324 | 325 | let node = self 326 | while node.path.isDirectory 327 | call node.open(opts) 328 | let level += 1 329 | if node.getVisibleChildCount() == 1 330 | let node = node.getChildByIndex(0, 1) 331 | else 332 | break 333 | endif 334 | endwhile 335 | return level 336 | endfunction 337 | 338 | " FUNCTION: TreeDirNode.openExplorer() {{{1 339 | " opens an explorer window for this node in the previous window (could be a 340 | " nerd tree or a netrw) 341 | function! s:TreeDirNode.openExplorer() 342 | call self.open({'where': 'p'}) 343 | endfunction 344 | 345 | "FUNCTION: TreeDirNode.openInNewTab(options) {{{1 346 | unlet s:TreeDirNode.openInNewTab 347 | function! s:TreeDirNode.openInNewTab(options) 348 | call nerdtree#deprecated('TreeDirNode.openInNewTab', 'is deprecated, use open() instead') 349 | call self.open({'where': 't'}) 350 | endfunction 351 | 352 | "FUNCTION: TreeDirNode._openInNewTab() {{{1 353 | function! s:TreeDirNode._openInNewTab() 354 | tabnew 355 | call g:NERDTreeCreator.CreatePrimary(self.path.str()) 356 | endfunction 357 | 358 | "FUNCTION: TreeDirNode.openRecursively() {{{1 359 | "Opens this treenode and all of its children whose paths arent 'ignored' 360 | "because of the file filters. 361 | " 362 | "This method is actually a wrapper for the OpenRecursively2 method which does 363 | "the work. 364 | function! s:TreeDirNode.openRecursively() 365 | call self._openRecursively2(1) 366 | endfunction 367 | 368 | "FUNCTION: TreeDirNode._openRecursively2() {{{1 369 | "Opens this all children of this treenode recursively if either: 370 | " *they arent filtered by file filters 371 | " *a:forceOpen is 1 372 | " 373 | "Args: 374 | "forceOpen: 1 if this node should be opened regardless of file filters 375 | function! s:TreeDirNode._openRecursively2(forceOpen) 376 | if self.path.ignore() ==# 0 || a:forceOpen 377 | let self.isOpen = 1 378 | if self.children ==# [] 379 | call self._initChildren(1) 380 | endif 381 | 382 | for i in self.children 383 | if i.path.isDirectory ==# 1 384 | call i._openRecursively2(0) 385 | endif 386 | endfor 387 | endif 388 | endfunction 389 | 390 | "FUNCTION: TreeDirNode.refresh() {{{1 391 | unlet s:TreeDirNode.refresh 392 | function! s:TreeDirNode.refresh() 393 | call self.path.refresh() 394 | 395 | "if this node was ever opened, refresh its children 396 | if self.isOpen || !empty(self.children) 397 | "go thru all the files/dirs under this node 398 | let newChildNodes = [] 399 | let invalidFilesFound = 0 400 | let dir = self.path 401 | let globDir = dir.str({'format': 'Glob'}) 402 | let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*') 403 | let files = split(filesStr, "\n") 404 | for i in files 405 | "filter out the .. and . directories 406 | "Note: we must match .. AND ../ cos sometimes the globpath returns 407 | "../ for path with strange chars (eg $) 408 | "if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' 409 | 410 | " Regular expression is too expensive. Use simply string comparison 411 | " instead 412 | if i[len(i)-3:2] != ".." && i[len(i)-2:2] != ".." && 413 | \ i[len(i)-2:1] != "." && i[len(i)-1] != "." 414 | try 415 | "create a new path and see if it exists in this nodes children 416 | let path = g:NERDTreePath.New(i) 417 | let newNode = self.getChild(path) 418 | if newNode != {} 419 | call newNode.refresh() 420 | call add(newChildNodes, newNode) 421 | 422 | "the node doesnt exist so create it 423 | else 424 | let newNode = g:NERDTreeFileNode.New(path) 425 | let newNode.parent = self 426 | call add(newChildNodes, newNode) 427 | endif 428 | 429 | 430 | catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/ 431 | let invalidFilesFound = 1 432 | endtry 433 | endif 434 | endfor 435 | 436 | "swap this nodes children out for the children we just read/refreshed 437 | let self.children = newChildNodes 438 | call self.sortChildren() 439 | 440 | if invalidFilesFound 441 | call nerdtree#echoWarning("some files could not be loaded into the NERD tree") 442 | endif 443 | endif 444 | endfunction 445 | 446 | "FUNCTION: TreeDirNode.refreshFlags() {{{1 447 | unlet s:TreeDirNode.refreshFlags 448 | function! s:TreeDirNode.refreshFlags() 449 | call self.path.refreshFlags() 450 | for i in self.children 451 | call i.refreshFlags() 452 | endfor 453 | endfunction 454 | 455 | "FUNCTION: TreeDirNode.refreshDirFlags() {{{1 456 | function! s:TreeDirNode.refreshDirFlags() 457 | call self.path.refreshFlags() 458 | endfunction 459 | 460 | "FUNCTION: TreeDirNode.reveal(path) {{{1 461 | "reveal the given path, i.e. cache and open all treenodes needed to display it 462 | "in the UI 463 | function! s:TreeDirNode.reveal(path) 464 | if !a:path.isUnder(self.path) 465 | throw "NERDTree.InvalidArgumentsError: " . a:path.str() . " should be under " . self.path.str() 466 | endif 467 | 468 | call self.open() 469 | 470 | if self.path.equals(a:path.getParent()) 471 | let n = self.findNode(a:path) 472 | call b:NERDTree.render() 473 | call n.putCursorHere(1,0) 474 | return 475 | endif 476 | 477 | let p = a:path 478 | while !p.getParent().equals(self.path) 479 | let p = p.getParent() 480 | endwhile 481 | 482 | let n = self.findNode(p) 483 | call n.reveal(a:path) 484 | endfunction 485 | 486 | "FUNCTION: TreeDirNode.removeChild(treenode) {{{1 487 | " 488 | "Removes the given treenode from this nodes set of children 489 | " 490 | "Args: 491 | "treenode: the node to remove 492 | " 493 | "Throws a NERDTree.ChildNotFoundError if the given treenode is not found 494 | function! s:TreeDirNode.removeChild(treenode) 495 | for i in range(0, self.getChildCount()-1) 496 | if self.children[i].equals(a:treenode) 497 | call remove(self.children, i) 498 | return 499 | endif 500 | endfor 501 | 502 | throw "NERDTree.ChildNotFoundError: child node was not found" 503 | endfunction 504 | 505 | "FUNCTION: TreeDirNode.sortChildren() {{{1 506 | " 507 | "Sorts the children of this node according to alphabetical order and the 508 | "directory priority. 509 | " 510 | function! s:TreeDirNode.sortChildren() 511 | let CompareFunc = function("nerdtree#compareNodesBySortKey") 512 | call sort(self.children, CompareFunc) 513 | endfunction 514 | 515 | "FUNCTION: TreeDirNode.toggleOpen([options]) {{{1 516 | "Opens this directory if it is closed and vice versa 517 | function! s:TreeDirNode.toggleOpen(...) 518 | let opts = a:0 ? a:1 : {} 519 | if self.isOpen ==# 1 520 | call self.close() 521 | else 522 | if g:NERDTreeCascadeOpenSingleChildDir == 0 523 | call self.open(opts) 524 | else 525 | call self.openAlong(opts) 526 | endif 527 | endif 528 | endfunction 529 | 530 | "FUNCTION: TreeDirNode.transplantChild(newNode) {{{1 531 | "Replaces the child of this with the given node (where the child node's full 532 | "path matches a:newNode's fullpath). The search for the matching node is 533 | "non-recursive 534 | " 535 | "Arg: 536 | "newNode: the node to graft into the tree 537 | function! s:TreeDirNode.transplantChild(newNode) 538 | for i in range(0, self.getChildCount()-1) 539 | if self.children[i].equals(a:newNode) 540 | let self.children[i] = a:newNode 541 | let a:newNode.parent = self 542 | break 543 | endif 544 | endfor 545 | endfunction 546 | 547 | " vim: set sw=4 sts=4 et fdm=marker: 548 | -------------------------------------------------------------------------------- /lib/nerdtree/tree_file_node.vim: -------------------------------------------------------------------------------- 1 | "CLASS: TreeFileNode 2 | "This class is the parent of the TreeDirNode class and is the 3 | "'Component' part of the composite design pattern between the treenode 4 | "classes. 5 | "============================================================ 6 | let s:TreeFileNode = {} 7 | let g:NERDTreeFileNode = s:TreeFileNode 8 | 9 | "FUNCTION: TreeFileNode.activate(...) {{{1 10 | function! s:TreeFileNode.activate(...) 11 | call self.open(a:0 ? a:1 : {}) 12 | endfunction 13 | 14 | "FUNCTION: TreeFileNode.bookmark(name) {{{1 15 | "bookmark this node with a:name 16 | function! s:TreeFileNode.bookmark(name) 17 | 18 | "if a bookmark exists with the same name and the node is cached then save 19 | "it so we can update its display string 20 | let oldMarkedNode = {} 21 | try 22 | let oldMarkedNode = g:NERDTreeBookmark.GetNodeForName(a:name, 1) 23 | catch /^NERDTree.BookmarkNotFoundError/ 24 | catch /^NERDTree.BookmarkedNodeNotFoundError/ 25 | endtry 26 | 27 | call g:NERDTreeBookmark.AddBookmark(a:name, self.path) 28 | call self.path.cacheDisplayString() 29 | call g:NERDTreeBookmark.Write() 30 | 31 | if !empty(oldMarkedNode) 32 | call oldMarkedNode.path.cacheDisplayString() 33 | endif 34 | endfunction 35 | 36 | "FUNCTION: TreeFileNode.cacheParent() {{{1 37 | "initializes self.parent if it isnt already 38 | function! s:TreeFileNode.cacheParent() 39 | if empty(self.parent) 40 | let parentPath = self.path.getParent() 41 | if parentPath.equals(self.path) 42 | throw "NERDTree.CannotCacheParentError: already at root" 43 | endif 44 | let self.parent = s:TreeFileNode.New(parentPath) 45 | endif 46 | endfunction 47 | 48 | "FUNCTION: TreeFileNode.clearBookmarks() {{{1 49 | function! s:TreeFileNode.clearBookmarks() 50 | for i in g:NERDTreeBookmark.Bookmarks() 51 | if i.path.equals(self.path) 52 | call i.delete() 53 | end 54 | endfor 55 | call self.path.cacheDisplayString() 56 | endfunction 57 | 58 | "FUNCTION: TreeFileNode.copy(dest) {{{1 59 | function! s:TreeFileNode.copy(dest) 60 | call self.path.copy(a:dest) 61 | let newPath = g:NERDTreePath.New(a:dest) 62 | let parent = b:NERDTreeRoot.findNode(newPath.getParent()) 63 | if !empty(parent) 64 | call parent.refresh() 65 | return parent.findNode(newPath) 66 | else 67 | return {} 68 | endif 69 | endfunction 70 | 71 | "FUNCTION: TreeFileNode.delete {{{1 72 | "Removes this node from the tree and calls the Delete method for its path obj 73 | function! s:TreeFileNode.delete() 74 | call self.path.delete() 75 | call self.parent.removeChild(self) 76 | endfunction 77 | 78 | "FUNCTION: TreeFileNode.displayString() {{{1 79 | " 80 | "Returns a string that specifies how the node should be represented as a 81 | "string 82 | " 83 | "Return: 84 | "a string that can be used in the view to represent this node 85 | function! s:TreeFileNode.displayString() 86 | return self.path.displayString() 87 | endfunction 88 | 89 | "FUNCTION: TreeFileNode.equals(treenode) {{{1 90 | " 91 | "Compares this treenode to the input treenode and returns 1 if they are the 92 | "same node. 93 | " 94 | "Use this method instead of == because sometimes when the treenodes contain 95 | "many children, vim seg faults when doing == 96 | " 97 | "Args: 98 | "treenode: the other treenode to compare to 99 | function! s:TreeFileNode.equals(treenode) 100 | return self.path.str() ==# a:treenode.path.str() 101 | endfunction 102 | 103 | "FUNCTION: TreeFileNode.findNode(path) {{{1 104 | "Returns self if this node.path.Equals the given path. 105 | "Returns {} if not equal. 106 | " 107 | "Args: 108 | "path: the path object to compare against 109 | function! s:TreeFileNode.findNode(path) 110 | if a:path.equals(self.path) 111 | return self 112 | endif 113 | return {} 114 | endfunction 115 | 116 | "FUNCTION: TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) {{{1 117 | " 118 | "Finds the next sibling for this node in the indicated direction. This sibling 119 | "must be a directory and may/may not have children as specified. 120 | " 121 | "Args: 122 | "direction: 0 if you want to find the previous sibling, 1 for the next sibling 123 | " 124 | "Return: 125 | "a treenode object or {} if no appropriate sibling could be found 126 | function! s:TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) 127 | "if we have no parent then we can have no siblings 128 | if self.parent != {} 129 | let nextSibling = self.findSibling(a:direction) 130 | 131 | while nextSibling != {} 132 | if nextSibling.path.isDirectory && nextSibling.hasVisibleChildren() && nextSibling.isOpen 133 | return nextSibling 134 | endif 135 | let nextSibling = nextSibling.findSibling(a:direction) 136 | endwhile 137 | endif 138 | 139 | return {} 140 | endfunction 141 | 142 | "FUNCTION: TreeFileNode.findSibling(direction) {{{1 143 | " 144 | "Finds the next sibling for this node in the indicated direction 145 | " 146 | "Args: 147 | "direction: 0 if you want to find the previous sibling, 1 for the next sibling 148 | " 149 | "Return: 150 | "a treenode object or {} if no sibling could be found 151 | function! s:TreeFileNode.findSibling(direction) 152 | "if we have no parent then we can have no siblings 153 | if self.parent != {} 154 | 155 | "get the index of this node in its parents children 156 | let siblingIndx = self.parent.getChildIndex(self.path) 157 | 158 | if siblingIndx != -1 159 | "move a long to the next potential sibling node 160 | let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1 161 | 162 | "keep moving along to the next sibling till we find one that is valid 163 | let numSiblings = self.parent.getChildCount() 164 | while siblingIndx >= 0 && siblingIndx < numSiblings 165 | 166 | "if the next node is not an ignored node (i.e. wont show up in the 167 | "view) then return it 168 | if self.parent.children[siblingIndx].path.ignore() ==# 0 169 | return self.parent.children[siblingIndx] 170 | endif 171 | 172 | "go to next node 173 | let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1 174 | endwhile 175 | endif 176 | endif 177 | 178 | return {} 179 | endfunction 180 | 181 | "FUNCTION: TreeFileNode.GetRootForTab(){{{1 182 | "get the root node for this tab 183 | function! s:TreeFileNode.GetRootForTab() 184 | if g:NERDTree.ExistsForTab() 185 | return getbufvar(t:NERDTreeBufName, 'NERDTreeRoot') 186 | end 187 | return {} 188 | endfunction 189 | 190 | "FUNCTION: TreeFileNode.GetSelected() {{{1 191 | "gets the treenode that the cursor is currently over 192 | function! s:TreeFileNode.GetSelected() 193 | try 194 | let path = b:NERDTree.ui.getPath(line(".")) 195 | if path ==# {} 196 | return {} 197 | endif 198 | return b:NERDTreeRoot.findNode(path) 199 | catch /^NERDTree/ 200 | return {} 201 | endtry 202 | endfunction 203 | 204 | "FUNCTION: TreeFileNode.isVisible() {{{1 205 | "returns 1 if this node should be visible according to the tree filters and 206 | "hidden file filters (and their on/off status) 207 | function! s:TreeFileNode.isVisible() 208 | return !self.path.ignore() 209 | endfunction 210 | 211 | "FUNCTION: TreeFileNode.isRoot() {{{1 212 | "returns 1 if this node is b:NERDTreeRoot 213 | function! s:TreeFileNode.isRoot() 214 | if !g:NERDTree.ExistsForBuf() 215 | throw "NERDTree.NoTreeError: No tree exists for the current buffer" 216 | endif 217 | 218 | return self.equals(b:NERDTreeRoot) 219 | endfunction 220 | 221 | "FUNCTION: TreeFileNode.makeRoot() {{{1 222 | "Make this node the root of the tree 223 | function! s:TreeFileNode.makeRoot() 224 | if self.path.isDirectory 225 | let b:NERDTreeRoot = self 226 | else 227 | call self.cacheParent() 228 | let b:NERDTreeRoot = self.parent 229 | endif 230 | 231 | call b:NERDTreeRoot.open() 232 | 233 | "change dir to the dir of the new root if instructed to 234 | if g:NERDTreeChDirMode ==# 2 235 | exec "cd " . b:NERDTreeRoot.path.str({'format': 'Edit'}) 236 | endif 237 | 238 | silent doautocmd User NERDTreeNewRoot 239 | endfunction 240 | 241 | "FUNCTION: TreeFileNode.New(path) {{{1 242 | "Returns a new TreeNode object with the given path and parent 243 | " 244 | "Args: 245 | "path: a path object representing the full filesystem path to the file/dir that the node represents 246 | function! s:TreeFileNode.New(path) 247 | if a:path.isDirectory 248 | return g:NERDTreeDirNode.New(a:path) 249 | else 250 | let newTreeNode = copy(self) 251 | let newTreeNode.path = a:path 252 | let newTreeNode.parent = {} 253 | return newTreeNode 254 | endif 255 | endfunction 256 | 257 | "FUNCTION: TreeFileNode.open() {{{1 258 | function! s:TreeFileNode.open(...) 259 | let opts = a:0 ? a:1 : {} 260 | let opener = g:NERDTreeOpener.New(self.path, opts) 261 | call opener.open(self) 262 | endfunction 263 | 264 | "FUNCTION: TreeFileNode.openSplit() {{{1 265 | "Open this node in a new window 266 | function! s:TreeFileNode.openSplit() 267 | call nerdtree#deprecated('TreeFileNode.openSplit', 'is deprecated, use .open() instead.') 268 | call self.open({'where': 'h'}) 269 | endfunction 270 | 271 | "FUNCTION: TreeFileNode.openVSplit() {{{1 272 | "Open this node in a new vertical window 273 | function! s:TreeFileNode.openVSplit() 274 | call nerdtree#deprecated('TreeFileNode.openVSplit', 'is deprecated, use .open() instead.') 275 | call self.open({'where': 'v'}) 276 | endfunction 277 | 278 | "FUNCTION: TreeFileNode.openInNewTab(options) {{{1 279 | function! s:TreeFileNode.openInNewTab(options) 280 | echomsg 'TreeFileNode.openInNewTab is deprecated' 281 | call self.open(extend({'where': 't'}, a:options)) 282 | endfunction 283 | 284 | "FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{1 285 | "Places the cursor on the line number this node is rendered on 286 | " 287 | "Args: 288 | "isJump: 1 if this cursor movement should be counted as a jump by vim 289 | "recurseUpward: try to put the cursor on the parent if the this node isnt 290 | "visible 291 | function! s:TreeFileNode.putCursorHere(isJump, recurseUpward) 292 | let ln = b:NERDTree.ui.getLineNum(self) 293 | if ln != -1 294 | if a:isJump 295 | mark ' 296 | endif 297 | call cursor(ln, col(".")) 298 | else 299 | if a:recurseUpward 300 | let node = self 301 | while node != {} && b:NERDTree.ui.getLineNum(node) ==# -1 302 | let node = node.parent 303 | call node.open() 304 | endwhile 305 | call b:NERDTree.render() 306 | call node.putCursorHere(a:isJump, 0) 307 | endif 308 | endif 309 | endfunction 310 | 311 | "FUNCTION: TreeFileNode.refresh() {{{1 312 | function! s:TreeFileNode.refresh() 313 | call self.path.refresh() 314 | endfunction 315 | 316 | "FUNCTION: TreeFileNode.refreshFlags() {{{1 317 | function! s:TreeFileNode.refreshFlags() 318 | call self.path.refreshFlags() 319 | endfunction 320 | 321 | "FUNCTION: TreeFileNode.rename() {{{1 322 | "Calls the rename method for this nodes path obj 323 | function! s:TreeFileNode.rename(newName) 324 | let newName = substitute(a:newName, '\(\\\|\/\)$', '', '') 325 | call self.path.rename(newName) 326 | call self.parent.removeChild(self) 327 | 328 | let parentPath = self.path.getParent() 329 | let newParent = b:NERDTreeRoot.findNode(parentPath) 330 | 331 | if newParent != {} 332 | call newParent.createChild(self.path, 1) 333 | call newParent.refresh() 334 | endif 335 | endfunction 336 | 337 | "FUNCTION: TreeFileNode.renderToString {{{1 338 | "returns a string representation for this tree to be rendered in the view 339 | function! s:TreeFileNode.renderToString() 340 | return self._renderToString(0, 0, [], self.getChildCount() ==# 1) 341 | endfunction 342 | 343 | "Args: 344 | "depth: the current depth in the tree for this call 345 | "drawText: 1 if we should actually draw the line for this node (if 0 then the 346 | "child nodes are rendered only) 347 | "vertMap: a binary array that indicates whether a vertical bar should be draw 348 | "for each depth in the tree 349 | "isLastChild:true if this curNode is the last child of its parent 350 | function! s:TreeFileNode._renderToString(depth, drawText, vertMap, isLastChild) 351 | let output = "" 352 | if a:drawText ==# 1 353 | 354 | let treeParts = '' 355 | 356 | "get all the leading spaces and vertical tree parts for this line 357 | if a:depth > 1 358 | for j in a:vertMap[0:-2] 359 | if g:NERDTreeDirArrows 360 | let treeParts = treeParts . ' ' 361 | else 362 | if j ==# 1 363 | let treeParts = treeParts . '| ' 364 | else 365 | let treeParts = treeParts . ' ' 366 | endif 367 | endif 368 | endfor 369 | endif 370 | 371 | "get the last vertical tree part for this line which will be different 372 | "if this node is the last child of its parent 373 | if !g:NERDTreeDirArrows 374 | if a:isLastChild 375 | let treeParts = treeParts . '`' 376 | else 377 | let treeParts = treeParts . '|' 378 | endif 379 | endif 380 | 381 | "smack the appropriate dir/file symbol on the line before the file/dir 382 | "name itself 383 | if self.path.isDirectory 384 | if self.isOpen 385 | if g:NERDTreeDirArrows 386 | let treeParts = treeParts . g:NERDTreeDirArrowCollapsible . ' ' 387 | else 388 | let treeParts = treeParts . '~' 389 | endif 390 | else 391 | if g:NERDTreeDirArrows 392 | let treeParts = treeParts . g:NERDTreeDirArrowExpandable . ' ' 393 | else 394 | let treeParts = treeParts . '+' 395 | endif 396 | endif 397 | else 398 | if g:NERDTreeDirArrows 399 | let treeParts = treeParts . ' ' 400 | else 401 | let treeParts = treeParts . '-' 402 | endif 403 | endif 404 | let line = treeParts . self.displayString() 405 | 406 | let output = output . line . "\n" 407 | endif 408 | 409 | "if the node is an open dir, draw its children 410 | if self.path.isDirectory ==# 1 && self.isOpen ==# 1 411 | 412 | let childNodesToDraw = self.getVisibleChildren() 413 | if len(childNodesToDraw) > 0 414 | 415 | "draw all the nodes children except the last 416 | let lastIndx = len(childNodesToDraw)-1 417 | if lastIndx > 0 418 | for i in childNodesToDraw[0:lastIndx-1] 419 | let output = output . i._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 1), 0) 420 | endfor 421 | endif 422 | 423 | "draw the last child, indicating that it IS the last 424 | let output = output . childNodesToDraw[lastIndx]._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 0), 1) 425 | endif 426 | endif 427 | 428 | return output 429 | endfunction 430 | 431 | " vim: set sw=4 sts=4 et fdm=marker: 432 | -------------------------------------------------------------------------------- /lib/nerdtree/ui.vim: -------------------------------------------------------------------------------- 1 | "CLASS: UI 2 | "============================================================ 3 | let s:UI = {} 4 | let g:NERDTreeUI = s:UI 5 | 6 | "FUNCTION: s:UI.centerView() {{{2 7 | "centers the nerd tree window around the cursor (provided the nerd tree 8 | "options permit) 9 | function! s:UI.centerView() 10 | if g:NERDTreeAutoCenter 11 | let current_line = winline() 12 | let lines_to_top = current_line 13 | let lines_to_bottom = winheight(g:NERDTree.GetWinNum()) - current_line 14 | if lines_to_top < g:NERDTreeAutoCenterThreshold || lines_to_bottom < g:NERDTreeAutoCenterThreshold 15 | normal! zz 16 | endif 17 | endif 18 | endfunction 19 | 20 | "FUNCTION: s:UI._dumpHelp {{{1 21 | "prints out the quick help 22 | function! s:UI._dumpHelp() 23 | let old_h = @h 24 | if b:treeShowHelp ==# 1 25 | let @h= "\" NERD tree (" . nerdtree#version() . ") quickhelp~\n" 26 | let @h=@h."\" ============================\n" 27 | let @h=@h."\" File node mappings~\n" 28 | let @h=@h."\" ". (g:NERDTreeMouseMode ==# 3 ? "single" : "double") ."-click,\n" 29 | let @h=@h."\" ,\n" 30 | if b:NERDTreeType ==# "primary" 31 | let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in prev window\n" 32 | else 33 | let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in current window\n" 34 | endif 35 | if b:NERDTreeType ==# "primary" 36 | let @h=@h."\" ". g:NERDTreeMapPreview .": preview\n" 37 | endif 38 | let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" 39 | let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" 40 | let @h=@h."\" middle-click,\n" 41 | let @h=@h."\" ". g:NERDTreeMapOpenSplit .": open split\n" 42 | let @h=@h."\" ". g:NERDTreeMapPreviewSplit .": preview split\n" 43 | let @h=@h."\" ". g:NERDTreeMapOpenVSplit .": open vsplit\n" 44 | let @h=@h."\" ". g:NERDTreeMapPreviewVSplit .": preview vsplit\n" 45 | 46 | let @h=@h."\"\n\" ----------------------------\n" 47 | let @h=@h."\" Directory node mappings~\n" 48 | let @h=@h."\" ". (g:NERDTreeMouseMode ==# 1 ? "double" : "single") ."-click,\n" 49 | let @h=@h."\" ". g:NERDTreeMapActivateNode .": open & close node\n" 50 | let @h=@h."\" ". g:NERDTreeMapOpenRecursively .": recursively open node\n" 51 | let @h=@h."\" ". g:NERDTreeMapCloseDir .": close parent of node\n" 52 | let @h=@h."\" ". g:NERDTreeMapCloseChildren .": close all child nodes of\n" 53 | let @h=@h."\" current node recursively\n" 54 | let @h=@h."\" middle-click,\n" 55 | let @h=@h."\" ". g:NERDTreeMapOpenExpl.": explore selected dir\n" 56 | 57 | let @h=@h."\"\n\" ----------------------------\n" 58 | let @h=@h."\" Bookmark table mappings~\n" 59 | let @h=@h."\" double-click,\n" 60 | let @h=@h."\" ". g:NERDTreeMapActivateNode .": open bookmark\n" 61 | let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" 62 | let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" 63 | let @h=@h."\" ". g:NERDTreeMapDeleteBookmark .": delete bookmark\n" 64 | 65 | let @h=@h."\"\n\" ----------------------------\n" 66 | let @h=@h."\" Tree navigation mappings~\n" 67 | let @h=@h."\" ". g:NERDTreeMapJumpRoot .": go to root\n" 68 | let @h=@h."\" ". g:NERDTreeMapJumpParent .": go to parent\n" 69 | let @h=@h."\" ". g:NERDTreeMapJumpFirstChild .": go to first child\n" 70 | let @h=@h."\" ". g:NERDTreeMapJumpLastChild .": go to last child\n" 71 | let @h=@h."\" ". g:NERDTreeMapJumpNextSibling .": go to next sibling\n" 72 | let @h=@h."\" ". g:NERDTreeMapJumpPrevSibling .": go to prev sibling\n" 73 | 74 | let @h=@h."\"\n\" ----------------------------\n" 75 | let @h=@h."\" Filesystem mappings~\n" 76 | let @h=@h."\" ". g:NERDTreeMapChangeRoot .": change tree root to the\n" 77 | let @h=@h."\" selected dir\n" 78 | let @h=@h."\" ". g:NERDTreeMapUpdir .": move tree root up a dir\n" 79 | let @h=@h."\" ". g:NERDTreeMapUpdirKeepOpen .": move tree root up a dir\n" 80 | let @h=@h."\" but leave old root open\n" 81 | let @h=@h."\" ". g:NERDTreeMapRefresh .": refresh cursor dir\n" 82 | let @h=@h."\" ". g:NERDTreeMapRefreshRoot .": refresh current root\n" 83 | let @h=@h."\" ". g:NERDTreeMapMenu .": Show menu\n" 84 | let @h=@h."\" ". g:NERDTreeMapChdir .":change the CWD to the\n" 85 | let @h=@h."\" selected dir\n" 86 | let @h=@h."\" ". g:NERDTreeMapCWD .":change tree root to CWD\n" 87 | 88 | let @h=@h."\"\n\" ----------------------------\n" 89 | let @h=@h."\" Tree filtering mappings~\n" 90 | let @h=@h."\" ". g:NERDTreeMapToggleHidden .": hidden files (" . (b:NERDTreeShowHidden ? "on" : "off") . ")\n" 91 | let @h=@h."\" ". g:NERDTreeMapToggleFilters .": file filters (" . (b:NERDTreeIgnoreEnabled ? "on" : "off") . ")\n" 92 | let @h=@h."\" ". g:NERDTreeMapToggleFiles .": files (" . (b:NERDTreeShowFiles ? "on" : "off") . ")\n" 93 | let @h=@h."\" ". g:NERDTreeMapToggleBookmarks .": bookmarks (" . (b:NERDTreeShowBookmarks ? "on" : "off") . ")\n" 94 | 95 | "add quickhelp entries for each custom key map 96 | let @h=@h."\"\n\" ----------------------------\n" 97 | let @h=@h."\" Custom mappings~\n" 98 | for i in g:NERDTreeKeyMap.All() 99 | if !empty(i.quickhelpText) 100 | let @h=@h."\" ". i.key .": ". i.quickhelpText ."\n" 101 | endif 102 | endfor 103 | 104 | let @h=@h."\"\n\" ----------------------------\n" 105 | let @h=@h."\" Other mappings~\n" 106 | let @h=@h."\" ". g:NERDTreeMapQuit .": Close the NERDTree window\n" 107 | let @h=@h."\" ". g:NERDTreeMapToggleZoom .": Zoom (maximize-minimize)\n" 108 | let @h=@h."\" the NERDTree window\n" 109 | let @h=@h."\" ". g:NERDTreeMapHelp .": toggle help\n" 110 | let @h=@h."\"\n\" ----------------------------\n" 111 | let @h=@h."\" Bookmark commands~\n" 112 | let @h=@h."\" :Bookmark []\n" 113 | let @h=@h."\" :BookmarkToRoot \n" 114 | let @h=@h."\" :RevealBookmark \n" 115 | let @h=@h."\" :OpenBookmark \n" 116 | let @h=@h."\" :ClearBookmarks []\n" 117 | let @h=@h."\" :ClearAllBookmarks\n" 118 | silent! put h 119 | elseif g:NERDTreeMinimalUI == 0 120 | let @h="\" Press ". g:NERDTreeMapHelp ." for help\n" 121 | silent! put h 122 | endif 123 | 124 | let @h = old_h 125 | endfunction 126 | 127 | 128 | "FUNCTION: s:UI.new(nerdtree) {{{1 129 | function! s:UI.New(nerdtree) 130 | let newObj = copy(self) 131 | let newObj.nerdtree = a:nerdtree 132 | return newObj 133 | endfunction 134 | 135 | "FUNCTION: s:UI.getPath(ln) {{{1 136 | "Gets the full path to the node that is rendered on the given line number 137 | " 138 | "Args: 139 | "ln: the line number to get the path for 140 | " 141 | "Return: 142 | "A path if a node was selected, {} if nothing is selected. 143 | "If the 'up a dir' line was selected then the path to the parent of the 144 | "current root is returned 145 | function! s:UI.getPath(ln) 146 | let line = getline(a:ln) 147 | 148 | let rootLine = self.getRootLineNum() 149 | 150 | "check to see if we have the root node 151 | if a:ln == rootLine 152 | return b:NERDTreeRoot.path 153 | endif 154 | 155 | if !g:NERDTreeDirArrows 156 | " in case called from outside the tree 157 | if line !~# '^ *[|`'.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.' ]' || line =~# '^$' 158 | return {} 159 | endif 160 | endif 161 | 162 | if line ==# s:UI.UpDirLine() 163 | return b:NERDTreeRoot.path.getParent() 164 | endif 165 | 166 | let indent = self._indentLevelFor(line) 167 | 168 | "remove the tree parts and the leading space 169 | let curFile = self._stripMarkup(line, 0) 170 | 171 | let wasdir = 0 172 | if curFile =~# '/$' 173 | let wasdir = 1 174 | let curFile = substitute(curFile, '/\?$', '/', "") 175 | endif 176 | 177 | let dir = "" 178 | let lnum = a:ln 179 | while lnum > 0 180 | let lnum = lnum - 1 181 | let curLine = getline(lnum) 182 | let curLineStripped = self._stripMarkup(curLine, 1) 183 | 184 | "have we reached the top of the tree? 185 | if lnum == rootLine 186 | let dir = b:NERDTreeRoot.path.str({'format': 'UI'}) . dir 187 | break 188 | endif 189 | if curLineStripped =~# '/$' 190 | let lpindent = self._indentLevelFor(curLine) 191 | if lpindent < indent 192 | let indent = indent - 1 193 | 194 | let dir = substitute (curLineStripped,'^\\', "", "") . dir 195 | continue 196 | endif 197 | endif 198 | endwhile 199 | let curFile = b:NERDTreeRoot.path.drive . dir . curFile 200 | let toReturn = g:NERDTreePath.New(curFile) 201 | return toReturn 202 | endfunction 203 | 204 | "FUNCTION: s:UI.getLineNum(file_node){{{1 205 | "returns the line number this node is rendered on, or -1 if it isnt rendered 206 | function! s:UI.getLineNum(file_node) 207 | "if the node is the root then return the root line no. 208 | if a:file_node.isRoot() 209 | return b:NERDTree.ui.getRootLineNum() 210 | endif 211 | 212 | let totalLines = line("$") 213 | 214 | "the path components we have matched so far 215 | let pathcomponents = [substitute(b:NERDTreeRoot.path.str({'format': 'UI'}), '/ *$', '', '')] 216 | "the index of the component we are searching for 217 | let curPathComponent = 1 218 | 219 | let fullpath = a:file_node.path.str({'format': 'UI'}) 220 | 221 | let lnum = b:NERDTree.ui.getRootLineNum() 222 | while lnum > 0 223 | let lnum = lnum + 1 224 | "have we reached the bottom of the tree? 225 | if lnum ==# totalLines+1 226 | return -1 227 | endif 228 | 229 | let curLine = getline(lnum) 230 | 231 | let indent = self._indentLevelFor(curLine) 232 | if indent ==# curPathComponent 233 | let curLine = self._stripMarkup(curLine, 1) 234 | 235 | let curPath = join(pathcomponents, '/') . '/' . curLine 236 | if stridx(fullpath, curPath, 0) ==# 0 237 | if fullpath ==# curPath || strpart(fullpath, len(curPath)-1,1) ==# '/' 238 | let curLine = substitute(curLine, '/ *$', '', '') 239 | call add(pathcomponents, curLine) 240 | let curPathComponent = curPathComponent + 1 241 | 242 | if fullpath ==# curPath 243 | return lnum 244 | endif 245 | endif 246 | endif 247 | endif 248 | endwhile 249 | return -1 250 | endfunction 251 | 252 | "FUNCTION: s:UI.getRootLineNum(){{{1 253 | "gets the line number of the root node 254 | function! s:UI.getRootLineNum() 255 | let rootLine = 1 256 | while getline(rootLine) !~# '^\(/\|<\)' 257 | let rootLine = rootLine + 1 258 | endwhile 259 | return rootLine 260 | endfunction 261 | 262 | "FUNCTION: s:UI._indentLevelFor(line) {{{1 263 | function! s:UI._indentLevelFor(line) 264 | let level = match(a:line, '[^ \-+~'.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'`|]') / s:UI.IndentWid() 265 | " check if line includes arrows 266 | if match(a:line, '['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.']') > -1 267 | " decrement level as arrow uses 3 ascii chars 268 | let level = level - 1 269 | endif 270 | return level 271 | endfunction 272 | 273 | "FUNCTION: s:UI.IndentWid() {{{1 274 | function! s:UI.IndentWid() 275 | return 2 276 | endfunction 277 | 278 | "FUNCTION: s:UI.MarkupReg() {{{1 279 | function! s:UI.MarkupReg() 280 | if g:NERDTreeDirArrows 281 | return '^\(['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'] \| \+['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'] \| \+\)' 282 | endif 283 | 284 | return '^[ `|]*[\-+~]' 285 | endfunction 286 | 287 | "FUNCTION: s:UI._renderBookmarks {{{1 288 | function! s:UI._renderBookmarks() 289 | 290 | if g:NERDTreeMinimalUI == 0 291 | call setline(line(".")+1, ">----------Bookmarks----------") 292 | call cursor(line(".")+1, col(".")) 293 | endif 294 | 295 | for i in g:NERDTreeBookmark.Bookmarks() 296 | call setline(line(".")+1, i.str()) 297 | call cursor(line(".")+1, col(".")) 298 | endfor 299 | 300 | call setline(line(".")+1, '') 301 | call cursor(line(".")+1, col(".")) 302 | endfunction 303 | 304 | "FUNCTION: s:UI.restoreScreenState() {{{1 305 | " 306 | "Sets the screen state back to what it was when nerdtree#saveScreenState was last 307 | "called. 308 | " 309 | "Assumes the cursor is in the NERDTree window 310 | function! s:UI.restoreScreenState() 311 | if !has_key(self, '_screenState') 312 | return 313 | endif 314 | exec("silent vertical resize " . self._screenState['oldWindowSize']) 315 | 316 | let old_scrolloff=&scrolloff 317 | let &scrolloff=0 318 | call cursor(self._screenState['oldTopLine'], 0) 319 | normal! zt 320 | call setpos(".", self._screenState['oldPos']) 321 | let &scrolloff=old_scrolloff 322 | endfunction 323 | 324 | "FUNCTION: s:UI.saveScreenState() {{{1 325 | "Saves the current cursor position in the current buffer and the window 326 | "scroll position 327 | function! s:UI.saveScreenState() 328 | let win = winnr() 329 | call g:NERDTree.CursorToTreeWin() 330 | let self._screenState = {} 331 | let self._screenState['oldPos'] = getpos(".") 332 | let self._screenState['oldTopLine'] = line("w0") 333 | let self._screenState['oldWindowSize']= winwidth("") 334 | call nerdtree#exec(win . "wincmd w") 335 | endfunction 336 | 337 | "FUNCTION: s:UI._stripMarkup(line, removeLeadingSpaces){{{1 338 | "returns the given line with all the tree parts stripped off 339 | " 340 | "Args: 341 | "line: the subject line 342 | "removeLeadingSpaces: 1 if leading spaces are to be removed (leading spaces = 343 | "any spaces before the actual text of the node) 344 | function! s:UI._stripMarkup(line, removeLeadingSpaces) 345 | let line = a:line 346 | "remove the tree parts and the leading space 347 | let line = substitute (line, g:NERDTreeUI.MarkupReg(),"","") 348 | 349 | "strip off any read only flag 350 | let line = substitute (line, ' \[RO\]', "","") 351 | 352 | "strip off any bookmark flags 353 | let line = substitute (line, ' {[^}]*}', "","") 354 | 355 | "strip off any executable flags 356 | let line = substitute (line, '*\ze\($\| \)', "","") 357 | 358 | "strip off any generic flags 359 | let line = substitute (line, '\[[^]]*\]', "","") 360 | 361 | let wasdir = 0 362 | if line =~# '/$' 363 | let wasdir = 1 364 | endif 365 | let line = substitute (line,' -> .*',"","") " remove link to 366 | if wasdir ==# 1 367 | let line = substitute (line, '/\?$', '/', "") 368 | endif 369 | 370 | if a:removeLeadingSpaces 371 | let line = substitute (line, '^ *', '', '') 372 | endif 373 | 374 | return line 375 | endfunction 376 | 377 | "FUNCTION: s:UI.render() {{{1 378 | function! s:UI.render() 379 | setlocal modifiable 380 | 381 | "remember the top line of the buffer and the current line so we can 382 | "restore the view exactly how it was 383 | let curLine = line(".") 384 | let curCol = col(".") 385 | let topLine = line("w0") 386 | 387 | "delete all lines in the buffer (being careful not to clobber a register) 388 | silent 1,$delete _ 389 | 390 | call self._dumpHelp() 391 | 392 | "delete the blank line before the help and add one after it 393 | if g:NERDTreeMinimalUI == 0 394 | call setline(line(".")+1, "") 395 | call cursor(line(".")+1, col(".")) 396 | endif 397 | 398 | if b:NERDTreeShowBookmarks 399 | call self._renderBookmarks() 400 | endif 401 | 402 | "add the 'up a dir' line 403 | if !g:NERDTreeMinimalUI 404 | call setline(line(".")+1, s:UI.UpDirLine()) 405 | call cursor(line(".")+1, col(".")) 406 | endif 407 | 408 | "draw the header line 409 | let header = b:NERDTreeRoot.path.str({'format': 'UI', 'truncateTo': winwidth(0)}) 410 | call setline(line(".")+1, header) 411 | call cursor(line(".")+1, col(".")) 412 | 413 | "draw the tree 414 | let old_o = @o 415 | let @o = b:NERDTreeRoot.renderToString() 416 | silent put o 417 | let @o = old_o 418 | 419 | "delete the blank line at the top of the buffer 420 | silent 1,1delete _ 421 | 422 | "restore the view 423 | let old_scrolloff=&scrolloff 424 | let &scrolloff=0 425 | call cursor(topLine, 1) 426 | normal! zt 427 | call cursor(curLine, curCol) 428 | let &scrolloff = old_scrolloff 429 | 430 | setlocal nomodifiable 431 | endfunction 432 | 433 | 434 | "FUNCTION: UI.renderViewSavingPosition {{{1 435 | "Renders the tree and ensures the cursor stays on the current node or the 436 | "current nodes parent if it is no longer available upon re-rendering 437 | function! s:UI.renderViewSavingPosition() 438 | let currentNode = g:NERDTreeFileNode.GetSelected() 439 | 440 | "go up the tree till we find a node that will be visible or till we run 441 | "out of nodes 442 | while currentNode != {} && !currentNode.isVisible() && !currentNode.isRoot() 443 | let currentNode = currentNode.parent 444 | endwhile 445 | 446 | call b:NERDTree.render() 447 | 448 | if currentNode != {} 449 | call currentNode.putCursorHere(0, 0) 450 | endif 451 | endfunction 452 | 453 | " FUNCTION: s:UI.toggleIgnoreFilter() {{{1 454 | " toggles the use of the NERDTreeIgnore option 455 | function! s:UI.toggleIgnoreFilter() 456 | let b:NERDTreeIgnoreEnabled = !b:NERDTreeIgnoreEnabled 457 | call b:NERDTree.ui.renderViewSavingPosition() 458 | call b:NERDTree.ui.centerView() 459 | endfunction 460 | 461 | " FUNCTION: s:UI.toggleShowBookmarks() {{{1 462 | " toggles the display of bookmarks 463 | function! s:UI.toggleShowBookmarks() 464 | let b:NERDTreeShowBookmarks = !b:NERDTreeShowBookmarks 465 | if b:NERDTreeShowBookmarks 466 | call b:NERDTree.render() 467 | call g:NERDTree.CursorToBookmarkTable() 468 | else 469 | call b:NERDTree.ui.renderViewSavingPosition() 470 | endif 471 | call b:NERDTree.ui.centerView() 472 | endfunction 473 | 474 | " FUNCTION: s:UI.toggleShowFiles() {{{1 475 | " toggles the display of hidden files 476 | function! s:UI.toggleShowFiles() 477 | let b:NERDTreeShowFiles = !b:NERDTreeShowFiles 478 | call b:NERDTree.ui.renderViewSavingPosition() 479 | call b:NERDTree.ui.centerView() 480 | endfunction 481 | 482 | " FUNCTION: s:UI.toggleShowHidden() {{{1 483 | " toggles the display of hidden files 484 | function! s:UI.toggleShowHidden() 485 | let b:NERDTreeShowHidden = !b:NERDTreeShowHidden 486 | call b:NERDTree.ui.renderViewSavingPosition() 487 | call self.centerView() 488 | endfunction 489 | 490 | " FUNCTION: s:UI.toggleZoom() {{{1 491 | " zoom (maximize/minimize) the NERDTree window 492 | function! s:UI.toggleZoom() 493 | if exists("b:NERDTreeZoomed") && b:NERDTreeZoomed 494 | let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize 495 | exec "silent vertical resize ". size 496 | let b:NERDTreeZoomed = 0 497 | else 498 | exec "vertical resize" 499 | let b:NERDTreeZoomed = 1 500 | endif 501 | endfunction 502 | 503 | "FUNCTION: s:UI.UpDirLine() {{{1 504 | function! s:UI.UpDirLine() 505 | return '.. (up a dir)' 506 | endfunction 507 | -------------------------------------------------------------------------------- /nerdtree_plugin/exec_menuitem.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================ 2 | " File: exec_menuitem.vim 3 | " Description: plugin for NERD Tree that provides an execute file menu item 4 | " Maintainer: Martin Grenfell 5 | " License: This program is free software. It comes without any warranty, 6 | " to the extent permitted by applicable law. You can redistribute 7 | " it and/or modify it under the terms of the Do What The Fuck You 8 | " Want To Public License, Version 2, as published by Sam Hocevar. 9 | " See http://sam.zoy.org/wtfpl/COPYING for more details. 10 | " 11 | " ============================================================================ 12 | if exists("g:loaded_nerdtree_exec_menuitem") 13 | finish 14 | endif 15 | let g:loaded_nerdtree_exec_menuitem = 1 16 | 17 | call NERDTreeAddMenuItem({ 18 | \ 'text': '(!)Execute file', 19 | \ 'shortcut': '!', 20 | \ 'callback': 'NERDTreeExecFile', 21 | \ 'isActiveCallback': 'NERDTreeExecFileActive' }) 22 | 23 | function! NERDTreeExecFileActive() 24 | let node = g:NERDTreeFileNode.GetSelected() 25 | return !node.path.isDirectory && node.path.isExecutable 26 | endfunction 27 | 28 | function! NERDTreeExecFile() 29 | let treenode = g:NERDTreeFileNode.GetSelected() 30 | echo "==========================================================\n" 31 | echo "Complete the command to execute (add arguments etc):\n" 32 | let cmd = treenode.path.str({'escape': 1}) 33 | let cmd = input(':!', cmd . ' ') 34 | 35 | if cmd != '' 36 | exec ':!' . cmd 37 | else 38 | echo "Aborted" 39 | endif 40 | endfunction 41 | -------------------------------------------------------------------------------- /nerdtree_plugin/fs_menu.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================ 2 | " File: fs_menu.vim 3 | " Description: plugin for the NERD Tree that provides a file system menu 4 | " Maintainer: Martin Grenfell 5 | " License: This program is free software. It comes without any warranty, 6 | " to the extent permitted by applicable law. You can redistribute 7 | " it and/or modify it under the terms of the Do What The Fuck You 8 | " Want To Public License, Version 2, as published by Sam Hocevar. 9 | " See http://sam.zoy.org/wtfpl/COPYING for more details. 10 | " 11 | " ============================================================================ 12 | if exists("g:loaded_nerdtree_fs_menu") 13 | finish 14 | endif 15 | let g:loaded_nerdtree_fs_menu = 1 16 | 17 | "Automatically delete the buffer after deleting or renaming a file 18 | if !exists("g:NERDTreeAutoDeleteBuffer") 19 | let g:NERDTreeAutoDeleteBuffer = 0 20 | endif 21 | 22 | call NERDTreeAddMenuItem({'text': '(a)dd a childnode', 'shortcut': 'a', 'callback': 'NERDTreeAddNode'}) 23 | call NERDTreeAddMenuItem({'text': '(m)ove the current node', 'shortcut': 'm', 'callback': 'NERDTreeMoveNode'}) 24 | call NERDTreeAddMenuItem({'text': '(d)elete the current node', 'shortcut': 'd', 'callback': 'NERDTreeDeleteNode'}) 25 | 26 | if has("gui_mac") || has("gui_macvim") || has("mac") 27 | call NERDTreeAddMenuItem({'text': '(r)eveal in Finder the current node', 'shortcut': 'r', 'callback': 'NERDTreeRevealInFinder'}) 28 | call NERDTreeAddMenuItem({'text': '(o)pen the current node with system editor', 'shortcut': 'o', 'callback': 'NERDTreeExecuteFile'}) 29 | call NERDTreeAddMenuItem({'text': '(q)uicklook the current node', 'shortcut': 'q', 'callback': 'NERDTreeQuickLook'}) 30 | endif 31 | 32 | if g:NERDTreePath.CopyingSupported() 33 | call NERDTreeAddMenuItem({'text': '(c)opy the current node', 'shortcut': 'c', 'callback': 'NERDTreeCopyNode'}) 34 | endif 35 | 36 | if has("unix") || has("osx") 37 | call NERDTreeAddMenuItem({'text': '(l)ist the current node', 'shortcut': 'l', 'callback': 'NERDTreeListNode'}) 38 | else 39 | call NERDTreeAddMenuItem({'text': '(l)ist the current node', 'shortcut': 'l', 'callback': 'NERDTreeListNodeWin32'}) 40 | endif 41 | 42 | "FUNCTION: s:promptToDelBuffer(bufnum, msg){{{1 43 | "prints out the given msg and, if the user responds by pushing 'y' then the 44 | "buffer with the given bufnum is deleted 45 | " 46 | "Args: 47 | "bufnum: the buffer that may be deleted 48 | "msg: a message that will be echoed to the user asking them if they wish to 49 | " del the buffer 50 | function! s:promptToDelBuffer(bufnum, msg) 51 | echo a:msg 52 | if g:NERDTreeAutoDeleteBuffer || nr2char(getchar()) ==# 'y' 53 | " 1. ensure that all windows which display the just deleted filename 54 | " now display an empty buffer (so a layout is preserved). 55 | " Is not it better to close single tabs with this file only ? 56 | let s:originalTabNumber = tabpagenr() 57 | let s:originalWindowNumber = winnr() 58 | exec "tabdo windo if winbufnr(0) == " . a:bufnum . " | exec ':enew! ' | endif" 59 | exec "tabnext " . s:originalTabNumber 60 | exec s:originalWindowNumber . "wincmd w" 61 | " 3. We don't need a previous buffer anymore 62 | exec "bwipeout! " . a:bufnum 63 | endif 64 | endfunction 65 | 66 | "FUNCTION: s:promptToRenameBuffer(bufnum, msg){{{1 67 | "prints out the given msg and, if the user responds by pushing 'y' then the 68 | "buffer with the given bufnum is replaced with a new one 69 | " 70 | "Args: 71 | "bufnum: the buffer that may be deleted 72 | "msg: a message that will be echoed to the user asking them if they wish to 73 | " del the buffer 74 | function! s:promptToRenameBuffer(bufnum, msg, newFileName) 75 | echo a:msg 76 | if g:NERDTreeAutoDeleteBuffer || nr2char(getchar()) ==# 'y' 77 | let quotedFileName = "'" . a:newFileName . "'" 78 | " 1. ensure that a new buffer is loaded 79 | exec "badd " . quotedFileName 80 | " 2. ensure that all windows which display the just deleted filename 81 | " display a buffer for a new filename. 82 | let s:originalTabNumber = tabpagenr() 83 | let s:originalWindowNumber = winnr() 84 | let editStr = g:NERDTreePath.New(a:newFileName).str({'format': 'Edit'}) 85 | exec "tabdo windo if winbufnr(0) == " . a:bufnum . " | exec ':e! " . editStr . "' | endif" 86 | exec "tabnext " . s:originalTabNumber 87 | exec s:originalWindowNumber . "wincmd w" 88 | " 3. We don't need a previous buffer anymore 89 | exec "bwipeout! " . a:bufnum 90 | endif 91 | endfunction 92 | "FUNCTION: NERDTreeAddNode(){{{1 93 | function! NERDTreeAddNode() 94 | let curDirNode = g:NERDTreeDirNode.GetSelected() 95 | 96 | let newNodeName = input("Add a childnode\n". 97 | \ "==========================================================\n". 98 | \ "Enter the dir/file name to be created. Dirs end with a '/'\n" . 99 | \ "", curDirNode.path.str() . g:NERDTreePath.Slash(), "file") 100 | 101 | if newNodeName ==# '' 102 | call nerdtree#echo("Node Creation Aborted.") 103 | return 104 | endif 105 | 106 | try 107 | let newPath = g:NERDTreePath.Create(newNodeName) 108 | let parentNode = b:NERDTreeRoot.findNode(newPath.getParent()) 109 | 110 | let newTreeNode = g:NERDTreeFileNode.New(newPath) 111 | if empty(parentNode) 112 | call b:NERDTreeRoot.refresh() 113 | call b:NERDTree.render() 114 | elseif parentNode.isOpen || !empty(parentNode.children) 115 | call parentNode.addChild(newTreeNode, 1) 116 | call NERDTreeRender() 117 | call newTreeNode.putCursorHere(1, 0) 118 | endif 119 | catch /^NERDTree/ 120 | call nerdtree#echoWarning("Node Not Created.") 121 | endtry 122 | endfunction 123 | 124 | "FUNCTION: NERDTreeMoveNode(){{{1 125 | function! NERDTreeMoveNode() 126 | let curNode = g:NERDTreeFileNode.GetSelected() 127 | let newNodePath = input("Rename the current node\n" . 128 | \ "==========================================================\n" . 129 | \ "Enter the new path for the node: \n" . 130 | \ "", curNode.path.str(), "file") 131 | 132 | if newNodePath ==# '' 133 | call nerdtree#echo("Node Renaming Aborted.") 134 | return 135 | endif 136 | 137 | try 138 | let bufnum = bufnr("^".curNode.path.str()."$") 139 | 140 | call curNode.rename(newNodePath) 141 | call NERDTreeRender() 142 | 143 | "if the node is open in a buffer, ask the user if they want to 144 | "close that buffer 145 | if bufnum != -1 146 | let prompt = "\nNode renamed.\n\nThe old file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? " (hidden)" : "") .". Replace this buffer with a new file? (yN)" 147 | call s:promptToRenameBuffer(bufnum, prompt, newNodePath) 148 | endif 149 | 150 | call curNode.putCursorHere(1, 0) 151 | 152 | redraw 153 | catch /^NERDTree/ 154 | call nerdtree#echoWarning("Node Not Renamed.") 155 | endtry 156 | endfunction 157 | 158 | " FUNCTION: NERDTreeDeleteNode() {{{1 159 | function! NERDTreeDeleteNode() 160 | let currentNode = g:NERDTreeFileNode.GetSelected() 161 | let confirmed = 0 162 | 163 | if currentNode.path.isDirectory 164 | let choice =input("Delete the current node\n" . 165 | \ "==========================================================\n" . 166 | \ "STOP! To delete this entire directory, type 'yes'\n" . 167 | \ "" . currentNode.path.str() . ": ") 168 | let confirmed = choice ==# 'yes' 169 | else 170 | echo "Delete the current node\n" . 171 | \ "==========================================================\n". 172 | \ "Are you sure you wish to delete the node:\n" . 173 | \ "" . currentNode.path.str() . " (yN):" 174 | let choice = nr2char(getchar()) 175 | let confirmed = choice ==# 'y' 176 | endif 177 | 178 | 179 | if confirmed 180 | try 181 | call currentNode.delete() 182 | call NERDTreeRender() 183 | 184 | "if the node is open in a buffer, ask the user if they want to 185 | "close that buffer 186 | let bufnum = bufnr("^".currentNode.path.str()."$") 187 | if buflisted(bufnum) 188 | let prompt = "\nNode deleted.\n\nThe file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? " (hidden)" : "") .". Delete this buffer? (yN)" 189 | call s:promptToDelBuffer(bufnum, prompt) 190 | endif 191 | 192 | redraw 193 | catch /^NERDTree/ 194 | call nerdtree#echoWarning("Could not remove node") 195 | endtry 196 | else 197 | call nerdtree#echo("delete aborted") 198 | endif 199 | 200 | endfunction 201 | 202 | " FUNCTION: NERDTreeListNode() {{{1 203 | function! NERDTreeListNode() 204 | let treenode = g:NERDTreeFileNode.GetSelected() 205 | if treenode != {} 206 | let metadata = split(system('ls -ld ' . shellescape(treenode.path.str())), '\n') 207 | call nerdtree#echo(metadata[0]) 208 | else 209 | call nerdtree#echo("No information avaialable") 210 | endif 211 | endfunction 212 | 213 | " FUNCTION: NERDTreeListNodeWin32() {{{1 214 | function! NERDTreeListNodeWin32() 215 | let treenode = g:NERDTreeFileNode.GetSelected() 216 | if treenode != {} 217 | let metadata = split(system('DIR /Q ' . shellescape(treenode.path.str()) . ' | FINDSTR "^[012][0-9]/[0-3][0-9]/[12][0-9][0-9][0-9]"'), '\n') 218 | call nerdtree#echo(metadata[0]) 219 | else 220 | call nerdtree#echo("No information avaialable") 221 | endif 222 | 223 | endfunction 224 | 225 | " FUNCTION: NERDTreeCopyNode() {{{1 226 | function! NERDTreeCopyNode() 227 | let currentNode = g:NERDTreeFileNode.GetSelected() 228 | let newNodePath = input("Copy the current node\n" . 229 | \ "==========================================================\n" . 230 | \ "Enter the new path to copy the node to: \n" . 231 | \ "", currentNode.path.str(), "file") 232 | 233 | if newNodePath != "" 234 | "strip trailing slash 235 | let newNodePath = substitute(newNodePath, '\/$', '', '') 236 | 237 | let confirmed = 1 238 | if currentNode.path.copyingWillOverwrite(newNodePath) 239 | call nerdtree#echo("Warning: copying may overwrite files! Continue? (yN)") 240 | let choice = nr2char(getchar()) 241 | let confirmed = choice ==# 'y' 242 | endif 243 | 244 | if confirmed 245 | try 246 | let newNode = currentNode.copy(newNodePath) 247 | if empty(newNode) 248 | call b:NERDTreeRoot.refresh() 249 | call b:NERDTree.render() 250 | else 251 | call NERDTreeRender() 252 | call newNode.putCursorHere(0, 0) 253 | endif 254 | catch /^NERDTree/ 255 | call nerdtree#echoWarning("Could not copy node") 256 | endtry 257 | endif 258 | else 259 | call nerdtree#echo("Copy aborted.") 260 | endif 261 | redraw 262 | endfunction 263 | 264 | " FUNCTION: NERDTreeQuickLook() {{{1 265 | function! NERDTreeQuickLook() 266 | let treenode = g:NERDTreeFileNode.GetSelected() 267 | if treenode != {} 268 | call system("qlmanage -p 2>/dev/null '" . treenode.path.str() . "'") 269 | endif 270 | endfunction 271 | 272 | " FUNCTION: NERDTreeRevealInFinder() {{{1 273 | function! NERDTreeRevealInFinder() 274 | let treenode = g:NERDTreeFileNode.GetSelected() 275 | if treenode != {} 276 | call system("open -R '" . treenode.path.str() . "'") 277 | endif 278 | endfunction 279 | 280 | " FUNCTION: NERDTreeExecuteFile() {{{1 281 | function! NERDTreeExecuteFile() 282 | let treenode = g:NERDTreeFileNode.GetSelected() 283 | if treenode != {} 284 | call system("open '" . treenode.path.str() . "'") 285 | endif 286 | endfunction 287 | " vim: set sw=4 sts=4 et fdm=marker: 288 | -------------------------------------------------------------------------------- /plugin/NERD_tree.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================ 2 | " File: NERD_tree.vim 3 | " Maintainer: Martin Grenfell 4 | " License: This program is free software. It comes without any warranty, 5 | " to the extent permitted by applicable law. You can redistribute 6 | " it and/or modify it under the terms of the Do What The Fuck You 7 | " Want To Public License, Version 2, as published by Sam Hocevar. 8 | " See http://sam.zoy.org/wtfpl/COPYING for more details. 9 | " 10 | " ============================================================================ 11 | " 12 | " SECTION: Script init stuff {{{1 13 | "============================================================ 14 | if exists("loaded_nerd_tree") 15 | finish 16 | endif 17 | if v:version < 700 18 | echoerr "NERDTree: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!" 19 | finish 20 | endif 21 | let loaded_nerd_tree = 1 22 | 23 | "for line continuation - i.e dont want C in &cpo 24 | let s:old_cpo = &cpo 25 | set cpo&vim 26 | 27 | "Function: s:initVariable() function {{{2 28 | "This function is used to initialise a given variable to a given value. The 29 | "variable is only initialised if it does not exist prior 30 | " 31 | "Args: 32 | "var: the name of the var to be initialised 33 | "value: the value to initialise var to 34 | " 35 | "Returns: 36 | "1 if the var is set, 0 otherwise 37 | function! s:initVariable(var, value) 38 | if !exists(a:var) 39 | exec 'let ' . a:var . ' = ' . "'" . substitute(a:value, "'", "''", "g") . "'" 40 | return 1 41 | endif 42 | return 0 43 | endfunction 44 | 45 | "SECTION: Init variable calls and other random constants {{{2 46 | call s:initVariable("g:NERDTreeAutoCenter", 1) 47 | call s:initVariable("g:NERDTreeAutoCenterThreshold", 3) 48 | call s:initVariable("g:NERDTreeCaseSensitiveSort", 0) 49 | call s:initVariable("g:NERDTreeSortHiddenFirst", 1) 50 | call s:initVariable("g:NERDTreeChDirMode", 0) 51 | call s:initVariable("g:NERDTreeMinimalUI", 0) 52 | if !exists("g:NERDTreeIgnore") 53 | let g:NERDTreeIgnore = ['\~$'] 54 | endif 55 | call s:initVariable("g:NERDTreeBookmarksFile", expand('$HOME') . '/.NERDTreeBookmarks') 56 | call s:initVariable("g:NERDTreeBookmarksSort", 1) 57 | call s:initVariable("g:NERDTreeHighlightCursorline", 1) 58 | call s:initVariable("g:NERDTreeHijackNetrw", 1) 59 | call s:initVariable("g:NERDTreeMouseMode", 1) 60 | call s:initVariable("g:NERDTreeNotificationThreshold", 100) 61 | call s:initVariable("g:NERDTreeQuitOnOpen", 0) 62 | call s:initVariable("g:NERDTreeRespectWildIgnore", 0) 63 | call s:initVariable("g:NERDTreeShowBookmarks", 0) 64 | call s:initVariable("g:NERDTreeShowFiles", 1) 65 | call s:initVariable("g:NERDTreeShowHidden", 0) 66 | call s:initVariable("g:NERDTreeShowLineNumbers", 0) 67 | call s:initVariable("g:NERDTreeSortDirs", 1) 68 | call s:initVariable("g:NERDTreeDirArrows", !nerdtree#runningWindows()) 69 | call s:initVariable("g:NERDTreeDirArrowExpandable", "▸") 70 | call s:initVariable("g:NERDTreeDirArrowCollapsible", "▾") 71 | call s:initVariable("g:NERDTreeCascadeOpenSingleChildDir", 1) 72 | 73 | if !exists("g:NERDTreeSortOrder") 74 | let g:NERDTreeSortOrder = ['\/$', '*', '\.swp$', '\.bak$', '\~$'] 75 | else 76 | "if there isnt a * in the sort sequence then add one 77 | if count(g:NERDTreeSortOrder, '*') < 1 78 | call add(g:NERDTreeSortOrder, '*') 79 | endif 80 | endif 81 | 82 | if !exists('g:NERDTreeStatusline') 83 | 84 | "the exists() crap here is a hack to stop vim spazzing out when 85 | "loading a session that was created with an open nerd tree. It spazzes 86 | "because it doesnt store b:NERDTreeRoot (its a b: var, and its a hash) 87 | let g:NERDTreeStatusline = "%{exists('b:NERDTreeRoot')?b:NERDTreeRoot.path.str():''}" 88 | 89 | endif 90 | call s:initVariable("g:NERDTreeWinPos", "left") 91 | call s:initVariable("g:NERDTreeWinSize", 31) 92 | 93 | "init the shell commands that will be used to copy nodes, and remove dir trees 94 | " 95 | "Note: the space after the command is important 96 | if nerdtree#runningWindows() 97 | call s:initVariable("g:NERDTreeRemoveDirCmd", 'rmdir /s /q ') 98 | else 99 | call s:initVariable("g:NERDTreeRemoveDirCmd", 'rm -rf ') 100 | call s:initVariable("g:NERDTreeCopyCmd", 'cp -r ') 101 | endif 102 | 103 | 104 | "SECTION: Init variable calls for key mappings {{{2 105 | call s:initVariable("g:NERDTreeMapActivateNode", "o") 106 | call s:initVariable("g:NERDTreeMapChangeRoot", "C") 107 | call s:initVariable("g:NERDTreeMapChdir", "cd") 108 | call s:initVariable("g:NERDTreeMapCloseChildren", "X") 109 | call s:initVariable("g:NERDTreeMapCloseDir", "x") 110 | call s:initVariable("g:NERDTreeMapDeleteBookmark", "D") 111 | call s:initVariable("g:NERDTreeMapMenu", "m") 112 | call s:initVariable("g:NERDTreeMapHelp", "?") 113 | call s:initVariable("g:NERDTreeMapJumpFirstChild", "K") 114 | call s:initVariable("g:NERDTreeMapJumpLastChild", "J") 115 | call s:initVariable("g:NERDTreeMapJumpNextSibling", "") 116 | call s:initVariable("g:NERDTreeMapJumpParent", "p") 117 | call s:initVariable("g:NERDTreeMapJumpPrevSibling", "") 118 | call s:initVariable("g:NERDTreeMapJumpRoot", "P") 119 | call s:initVariable("g:NERDTreeMapOpenExpl", "e") 120 | call s:initVariable("g:NERDTreeMapOpenInTab", "t") 121 | call s:initVariable("g:NERDTreeMapOpenInTabSilent", "T") 122 | call s:initVariable("g:NERDTreeMapOpenRecursively", "O") 123 | call s:initVariable("g:NERDTreeMapOpenSplit", "i") 124 | call s:initVariable("g:NERDTreeMapOpenVSplit", "s") 125 | call s:initVariable("g:NERDTreeMapPreview", "g" . NERDTreeMapActivateNode) 126 | call s:initVariable("g:NERDTreeMapPreviewSplit", "g" . NERDTreeMapOpenSplit) 127 | call s:initVariable("g:NERDTreeMapPreviewVSplit", "g" . NERDTreeMapOpenVSplit) 128 | call s:initVariable("g:NERDTreeMapQuit", "q") 129 | call s:initVariable("g:NERDTreeMapRefresh", "r") 130 | call s:initVariable("g:NERDTreeMapRefreshRoot", "R") 131 | call s:initVariable("g:NERDTreeMapToggleBookmarks", "B") 132 | call s:initVariable("g:NERDTreeMapToggleFiles", "F") 133 | call s:initVariable("g:NERDTreeMapToggleFilters", "f") 134 | call s:initVariable("g:NERDTreeMapToggleHidden", "I") 135 | call s:initVariable("g:NERDTreeMapToggleZoom", "A") 136 | call s:initVariable("g:NERDTreeMapUpdir", "u") 137 | call s:initVariable("g:NERDTreeMapUpdirKeepOpen", "U") 138 | call s:initVariable("g:NERDTreeMapCWD", "CD") 139 | 140 | "SECTION: Load class files{{{2 141 | call nerdtree#loadClassFiles() 142 | 143 | " SECTION: Commands {{{1 144 | "============================================================ 145 | call nerdtree#ui_glue#setupCommands() 146 | 147 | " SECTION: Auto commands {{{1 148 | "============================================================ 149 | augroup NERDTree 150 | "Save the cursor position whenever we close the nerd tree 151 | exec "autocmd BufLeave ". g:NERDTreeCreator.BufNamePrefix() ."* if g:NERDTree.IsOpen() | call b:NERDTree.ui.saveScreenState() | endif" 152 | 153 | "disallow insert mode in the NERDTree 154 | exec "autocmd BufEnter ". g:NERDTreeCreator.BufNamePrefix() ."* stopinsert" 155 | augroup END 156 | 157 | if g:NERDTreeHijackNetrw 158 | augroup NERDTreeHijackNetrw 159 | autocmd VimEnter * silent! autocmd! FileExplorer 160 | au BufEnter,VimEnter * call nerdtree#checkForBrowse(expand("")) 161 | augroup END 162 | endif 163 | 164 | " SECTION: Public API {{{1 165 | "============================================================ 166 | function! NERDTreeAddMenuItem(options) 167 | call g:NERDTreeMenuItem.Create(a:options) 168 | endfunction 169 | 170 | function! NERDTreeAddMenuSeparator(...) 171 | let opts = a:0 ? a:1 : {} 172 | call g:NERDTreeMenuItem.CreateSeparator(opts) 173 | endfunction 174 | 175 | function! NERDTreeAddSubmenu(options) 176 | return g:NERDTreeMenuItem.Create(a:options) 177 | endfunction 178 | 179 | function! NERDTreeAddKeyMap(options) 180 | call g:NERDTreeKeyMap.Create(a:options) 181 | endfunction 182 | 183 | function! NERDTreeRender() 184 | call nerdtree#renderView() 185 | endfunction 186 | 187 | function! NERDTreeFocus() 188 | if g:NERDTree.IsOpen() 189 | call g:NERDTree.CursorToTreeWin() 190 | else 191 | call g:NERDTreeCreator.TogglePrimary("") 192 | endif 193 | endfunction 194 | 195 | function! NERDTreeCWD() 196 | call NERDTreeFocus() 197 | call nerdtree#ui_glue#chRootCwd() 198 | endfunction 199 | 200 | function! NERDTreeAddPathFilter(callback) 201 | call g:NERDTree.AddPathFilter(a:callback) 202 | endfunction 203 | 204 | " SECTION: Post Source Actions {{{1 205 | call nerdtree#postSourceActions() 206 | 207 | "reset &cpo back to users setting 208 | let &cpo = s:old_cpo 209 | 210 | " vim: set sw=4 sts=4 et fdm=marker: 211 | -------------------------------------------------------------------------------- /syntax/nerdtree.vim: -------------------------------------------------------------------------------- 1 | let s:tree_up_dir_line = '.. (up a dir)' 2 | syn match NERDTreeIgnore #\~# 3 | syn match NERDTreeIgnore #\[RO\]# 4 | 5 | "highlighting for the .. (up dir) line at the top of the tree 6 | execute "syn match NERDTreeUp #\\V". s:tree_up_dir_line ."#" 7 | 8 | "quickhelp syntax elements 9 | syn match NERDTreeHelpKey #" \{1,2\}[^ ]*:#ms=s+2,me=e-1 10 | syn match NERDTreeHelpKey #" \{1,2\}[^ ]*,#ms=s+2,me=e-1 11 | syn match NERDTreeHelpTitle #" .*\~#ms=s+2,me=e-1 12 | syn match NERDTreeToggleOn #(on)#ms=s+1,he=e-1 13 | syn match NERDTreeToggleOff #(off)#ms=e-3,me=e-1 14 | syn match NERDTreeHelpCommand #" :.\{-}\>#hs=s+3 15 | syn match NERDTreeHelp #^".*# contains=NERDTreeHelpKey,NERDTreeHelpTitle,NERDTreeIgnore,NERDTreeToggleOff,NERDTreeToggleOn,NERDTreeHelpCommand 16 | 17 | "highlighting for sym links 18 | syn match NERDTreeLinkTarget #->.*# containedin=NERDTreeDir,NERDTreeFile 19 | syn match NERDTreeLinkFile #.* ->#me=e-3 containedin=NERDTreeFile 20 | syn match NERDTreeLinkDir #.*/ ->#me=e-3 containedin=NERDTreeDir 21 | 22 | "highlighing for directory nodes and file nodes 23 | syn match NERDTreeDirSlash #/# containedin=NERDTreeDir 24 | 25 | if g:NERDTreeDirArrows 26 | exec 'syn match NERDTreeClosable #'.escape(g:NERDTreeDirArrowCollapsible, '~').'# containedin=NERDTreeDir,NERDTreeFile' 27 | exec 'syn match NERDTreeOpenable #'.escape(g:NERDTreeDirArrowExpandable, '~').'# containedin=NERDTreeDir,NERDTreeFile' 28 | 29 | let s:dirArrows = escape(g:NERDTreeDirArrowCollapsible, '~').escape(g:NERDTreeDirArrowExpandable, '~') 30 | exec 'syn match NERDTreeDir #[^'.s:dirArrows.' ].*/#' 31 | syn match NERDTreeExecFile #^ .*\*\($\| \)# contains=NERDTreeRO,NERDTreeBookmark 32 | exec 'syn match NERDTreeFile #^[^"\.'.s:dirArrows.'] *[^'.s:dirArrows.']*# contains=NERDTreeLink,NERDTreeRO,NERDTreeBookmark,NERDTreeExecFile' 33 | 34 | "highlighting for readonly files 35 | syn match NERDTreeRO # *\zs.*\ze \[RO\]# contains=NERDTreeIgnore,NERDTreeBookmark,NERDTreeFile 36 | 37 | syn match NERDTreeFlags #^ *\zs\[.\]# containedin=NERDTreeFile,NERDTreeExecFile 38 | syn match NERDTreeFlags #\[.\]# containedin=NERDTreeDir 39 | else 40 | "highlighting for the ~/+ symbols for the directory nodes 41 | syn match NERDTreeClosable #\~\<# 42 | syn match NERDTreeClosable #\~\.# 43 | syn match NERDTreeOpenable #+\<# 44 | syn match NERDTreeOpenable #+\.#he=e-1 45 | 46 | "highlighting for the tree structural parts 47 | syn match NERDTreePart #|# 48 | syn match NERDTreePart #`# 49 | syn match NERDTreePartFile #[|`]-#hs=s+1 contains=NERDTreePart 50 | 51 | syn match NERDTreeDir #[^-| `].*/# contains=NERDTreeLink,NERDTreeOpenable,NERDTreeClosable 52 | syn match NERDTreeExecFile #[|` ].*\*\($\| \)# contains=NERDTreeLink,NERDTreePart,NERDTreePartFile,NERDTreeBookmark 53 | syn match NERDTreeFile #|-.*# contains=NERDTreeLink,NERDTreePart,NERDTreePartFile,NERDTreeBookmark,NERDTreeExecFile 54 | syn match NERDTreeFile #`-.*# contains=NERDTreeLink,NERDTreePart,NERDTreePartFile,NERDTreeBookmark,NERDTreeExecFile 55 | 56 | "highlighting for readonly files 57 | syn match NERDTreeRO #|-.*\[RO\]#he=e-5 contains=NERDTreeIgnore,NERDTreeBookmark,NERDTreePart,NERDTreePartFile 58 | 59 | syn match NERDTreeFlags #-\[.\]# containedin=NERDTreeFile,NERDTreePartFile 60 | syn match NERDTreeFlags #[+~]\zs\[.\]# containedin=NERDTreeDir 61 | endif 62 | 63 | syn match NERDTreeCWD #^[# 70 | syn match NERDTreeBookmarksHeader #^>-\+Bookmarks-\+$# contains=NERDTreeBookmarksLeader 71 | syn match NERDTreeBookmarkName #^>.\{-} #he=e-1 contains=NERDTreeBookmarksLeader 72 | syn match NERDTreeBookmark #^>.*$# contains=NERDTreeBookmarksLeader,NERDTreeBookmarkName,NERDTreeBookmarksHeader 73 | 74 | hi def link NERDTreePart Special 75 | hi def link NERDTreePartFile Type 76 | hi def link NERDTreeExecFile Title 77 | hi def link NERDTreeDirSlash Identifier 78 | 79 | hi def link NERDTreeBookmarksHeader statement 80 | hi def link NERDTreeBookmarksLeader ignore 81 | hi def link NERDTreeBookmarkName Identifier 82 | hi def link NERDTreeBookmark normal 83 | 84 | hi def link NERDTreeHelp String 85 | hi def link NERDTreeHelpKey Identifier 86 | hi def link NERDTreeHelpCommand Identifier 87 | hi def link NERDTreeHelpTitle Macro 88 | hi def link NERDTreeToggleOn Question 89 | hi def link NERDTreeToggleOff WarningMsg 90 | 91 | hi def link NERDTreeLinkTarget Type 92 | hi def link NERDTreeLinkFile Macro 93 | hi def link NERDTreeLinkDir Macro 94 | 95 | hi def link NERDTreeDir Directory 96 | hi def link NERDTreeUp Directory 97 | hi def link NERDTreeFile Normal 98 | hi def link NERDTreeCWD Statement 99 | hi def link NERDTreeOpenable Title 100 | hi def link NERDTreeClosable Title 101 | hi def link NERDTreeIgnore ignore 102 | hi def link NERDTreeRO WarningMsg 103 | hi def link NERDTreeBookmark Statement 104 | hi def link NERDTreeFlags Number 105 | 106 | hi def link NERDTreeCurrentNode Search 107 | --------------------------------------------------------------------------------