├── .gitignore ├── README.md ├── bin ├── cpu_ratio.sh ├── sourcebash ├── http_connection_info └── ubuntu_ntp.sh ├── .screenrc ├── do ├── .vimrc ├── sources.list.163 └── .vim ├── nerdtree_plugin ├── exec_menuitem.vim └── fs_menu.vim ├── syntax └── nerdtree.vim ├── doc └── NERD_tree.txt └── plugin └── NERD_tree.vim /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #ulric-unix-home 2 | -------------------------------------------------------------------------------- /bin/cpu_ratio.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | mpstat -P ALL 1 4 | -------------------------------------------------------------------------------- /bin/sourcebash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ~/.bashrc 4 | source ~/.bash_profile 5 | source ~/.profile 6 | -------------------------------------------------------------------------------- /bin/http_connection_info: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 4 | -------------------------------------------------------------------------------- /bin/ubuntu_ntp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | apt-get -y install ntp 4 | echo "server 10.180.2.231 5 | server 10.20.100.231" > /etc/ntp.conf 6 | /etc/init.d/ntp start 7 | hwclock -w 8 | -------------------------------------------------------------------------------- /.screenrc: -------------------------------------------------------------------------------- 1 | # display status line 2 | hardstatus alwayslastline 3 | hardstatus string '%{= kG}[ %{G}%H %{g}][%= %{= kw}%?%-Lw%?%{r}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}]' 4 | 5 | # fix screen not source .bash_profile 6 | shell -$SHELL 7 | screen bash 8 | vbell off 9 | -------------------------------------------------------------------------------- /do: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | set -e 4 | 5 | dir=`pwd` 6 | 7 | install_file() 8 | { 9 | src="${dir}/"$1 10 | des="$HOME/$1" 11 | if [ -f $des -o -d $des ];then 12 | if [ -f "${des}.bak" -o -d "${des}.bak" ];then 13 | rm -rf "${des}.bak" 14 | fi 15 | mv -f $des "${des}.bak" 16 | fi 17 | ln -s $src $des 18 | } 19 | 20 | install_file .screenrc 21 | install_file .vimrc 22 | install_file .vim 23 | 24 | -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | set nocp 2 | set ru 3 | set hls 4 | set is 5 | set nu 6 | syntax enable 7 | syntax on 8 | colorscheme desert 9 | set backspace=indent,eol,start 10 | set whichwrap=b,s,<,>,[,] 11 | set encoding=utf-8 12 | set langmenu=zh_CN.UTF-8 13 | set fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,euc-jp,euc-kr,latin1 14 | set ambiwidth=double 15 | filetype plugin indent on 16 | set sw=4 17 | set ts=4 18 | set et 19 | set smarttab 20 | set lbr 21 | set tw=120 22 | set fo+=mB 23 | set sm 24 | set cin 25 | set ai 26 | set history=20 27 | set selectmode= 28 | set keymodel= 29 | set selection=inclusive 30 | set wildmenu 31 | set guifont=Consolas:h12:cANSI 32 | set mousemodel=popup 33 | -------------------------------------------------------------------------------- /sources.list.163: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | cat > /etc/apt/sources.list < 5 | " Last Change: 22 July, 2009 6 | " License: This program is free software. It comes without any warranty, 7 | " to the extent permitted by applicable law. You can redistribute 8 | " it and/or modify it under the terms of the Do What The Fuck You 9 | " Want To Public License, Version 2, as published by Sam Hocevar. 10 | " See http://sam.zoy.org/wtfpl/COPYING for more details. 11 | " 12 | " ============================================================================ 13 | if exists("g:loaded_nerdtree_exec_menuitem") 14 | finish 15 | endif 16 | let g:loaded_nerdtree_exec_menuitem = 1 17 | 18 | call NERDTreeAddMenuItem({ 19 | \ 'text': '(!)Execute file', 20 | \ 'shortcut': '!', 21 | \ 'callback': 'NERDTreeExecFile', 22 | \ 'isActiveCallback': 'NERDTreeExecFileActive' }) 23 | 24 | function! NERDTreeExecFileActive() 25 | let node = g:NERDTreeFileNode.GetSelected() 26 | return !node.path.isDirectory && node.path.isExecutable 27 | endfunction 28 | 29 | function! NERDTreeExecFile() 30 | let treenode = g:NERDTreeFileNode.GetSelected() 31 | echo "==========================================================\n" 32 | echo "Complete the command to execute (add arguments etc):\n" 33 | let cmd = treenode.path.str({'escape': 1}) 34 | let cmd = input(':!', cmd . ' ') 35 | 36 | if cmd != '' 37 | exec ':!' . cmd 38 | else 39 | echo "Aborted" 40 | endif 41 | endfunction 42 | -------------------------------------------------------------------------------- /.vim/syntax/nerdtree.vim: -------------------------------------------------------------------------------- 1 | let s:tree_up_dir_line = '.. (up a dir)' 2 | "NERDTreeFlags are syntax items that should be invisible, but give clues as to 3 | "how things should be highlighted 4 | syn match NERDTreeFlag #\~# 5 | syn match NERDTreeFlag #\[RO\]# 6 | 7 | "highlighting for the .. (up dir) line at the top of the tree 8 | execute "syn match NERDTreeUp #\\V". s:tree_up_dir_line ."#" 9 | 10 | "highlighting for the ~/+ symbols for the directory nodes 11 | syn match NERDTreeClosable #\~\<# 12 | syn match NERDTreeClosable #\~\.# 13 | syn match NERDTreeOpenable #+\<# 14 | syn match NERDTreeOpenable #+\.#he=e-1 15 | 16 | "highlighting for the tree structural parts 17 | syn match NERDTreePart #|# 18 | syn match NERDTreePart #`# 19 | syn match NERDTreePartFile #[|`]-#hs=s+1 contains=NERDTreePart 20 | 21 | "quickhelp syntax elements 22 | syn match NERDTreeHelpKey #" \{1,2\}[^ ]*:#hs=s+2,he=e-1 23 | syn match NERDTreeHelpKey #" \{1,2\}[^ ]*,#hs=s+2,he=e-1 24 | syn match NERDTreeHelpTitle #" .*\~#hs=s+2,he=e-1 contains=NERDTreeFlag 25 | syn match NERDTreeToggleOn #".*(on)#hs=e-2,he=e-1 contains=NERDTreeHelpKey 26 | syn match NERDTreeToggleOff #".*(off)#hs=e-3,he=e-1 contains=NERDTreeHelpKey 27 | syn match NERDTreeHelpCommand #" :.\{-}\>#hs=s+3 28 | syn match NERDTreeHelp #^".*# contains=NERDTreeHelpKey,NERDTreeHelpTitle,NERDTreeFlag,NERDTreeToggleOff,NERDTreeToggleOn,NERDTreeHelpCommand 29 | 30 | "highlighting for readonly files 31 | syn match NERDTreeRO #.*\[RO\]#hs=s+2 contains=NERDTreeFlag,NERDTreeBookmark,NERDTreePart,NERDTreePartFile 32 | 33 | "highlighting for sym links 34 | syn match NERDTreeLink #[^-| `].* -> # contains=NERDTreeBookmark,NERDTreeOpenable,NERDTreeClosable,NERDTreeDirSlash 35 | 36 | "highlighing for directory nodes and file nodes 37 | syn match NERDTreeDirSlash #/# 38 | syn match NERDTreeDir #[^-| `].*/# contains=NERDTreeLink,NERDTreeDirSlash,NERDTreeOpenable,NERDTreeClosable 39 | syn match NERDTreeExecFile #[|` ].*\*\($\| \)# contains=NERDTreeLink,NERDTreePart,NERDTreeRO,NERDTreePartFile,NERDTreeBookmark 40 | syn match NERDTreeFile #|-.*# contains=NERDTreeLink,NERDTreePart,NERDTreeRO,NERDTreePartFile,NERDTreeBookmark,NERDTreeExecFile 41 | syn match NERDTreeFile #`-.*# contains=NERDTreeLink,NERDTreePart,NERDTreeRO,NERDTreePartFile,NERDTreeBookmark,NERDTreeExecFile 42 | syn match NERDTreeCWD #^[# 49 | syn match NERDTreeBookmarksHeader #^>-\+Bookmarks-\+$# contains=NERDTreeBookmarksLeader 50 | syn match NERDTreeBookmarkName #^>.\{-} #he=e-1 contains=NERDTreeBookmarksLeader 51 | syn match NERDTreeBookmark #^>.*$# contains=NERDTreeBookmarksLeader,NERDTreeBookmarkName,NERDTreeBookmarksHeader 52 | 53 | if exists("g:NERDChristmasTree") && g:NERDChristmasTree 54 | hi def link NERDTreePart Special 55 | hi def link NERDTreePartFile Type 56 | hi def link NERDTreeFile Normal 57 | hi def link NERDTreeExecFile Title 58 | hi def link NERDTreeDirSlash Identifier 59 | hi def link NERDTreeClosable Type 60 | else 61 | hi def link NERDTreePart Normal 62 | hi def link NERDTreePartFile Normal 63 | hi def link NERDTreeFile Normal 64 | hi def link NERDTreeClosable Title 65 | endif 66 | 67 | hi def link NERDTreeBookmarksHeader statement 68 | hi def link NERDTreeBookmarksLeader ignore 69 | hi def link NERDTreeBookmarkName Identifier 70 | hi def link NERDTreeBookmark normal 71 | 72 | hi def link NERDTreeHelp String 73 | hi def link NERDTreeHelpKey Identifier 74 | hi def link NERDTreeHelpCommand Identifier 75 | hi def link NERDTreeHelpTitle Macro 76 | hi def link NERDTreeToggleOn Question 77 | hi def link NERDTreeToggleOff WarningMsg 78 | 79 | hi def link NERDTreeDir Directory 80 | hi def link NERDTreeUp Directory 81 | hi def link NERDTreeCWD Statement 82 | hi def link NERDTreeLink Macro 83 | hi def link NERDTreeOpenable Title 84 | hi def link NERDTreeFlag ignore 85 | hi def link NERDTreeRO WarningMsg 86 | hi def link NERDTreeBookmark Statement 87 | 88 | hi def link NERDTreeCurrentNode Search 89 | -------------------------------------------------------------------------------- /.vim/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 | " Last Change: 17 July, 2009 6 | " License: This program is free software. It comes without any warranty, 7 | " to the extent permitted by applicable law. You can redistribute 8 | " it and/or modify it under the terms of the Do What The Fuck You 9 | " Want To Public License, Version 2, as published by Sam Hocevar. 10 | " See http://sam.zoy.org/wtfpl/COPYING for more details. 11 | " 12 | " ============================================================================ 13 | if exists("g:loaded_nerdtree_fs_menu") 14 | finish 15 | endif 16 | let g:loaded_nerdtree_fs_menu = 1 17 | 18 | call NERDTreeAddMenuItem({'text': '(a)dd a childnode', 'shortcut': 'a', 'callback': 'NERDTreeAddNode'}) 19 | call NERDTreeAddMenuItem({'text': '(m)ove the current node', 'shortcut': 'm', 'callback': 'NERDTreeMoveNode'}) 20 | call NERDTreeAddMenuItem({'text': '(d)elete the current node', 'shortcut': 'd', 'callback': 'NERDTreeDeleteNode'}) 21 | 22 | if has("gui_mac") || has("gui_macvim") 23 | call NERDTreeAddMenuItem({'text': '(r)eveal in Finder the current node', 'shortcut': 'r', 'callback': 'NERDTreeRevealInFinder'}) 24 | call NERDTreeAddMenuItem({'text': '(o)pen the current node with system editor', 'shortcut': 'o', 'callback': 'NERDTreeExecuteFile'}) 25 | call NERDTreeAddMenuItem({'text': '(q)uicklook the current node', 'shortcut': 'q', 'callback': 'NERDTreeQuickLook'}) 26 | endif 27 | 28 | if g:NERDTreePath.CopyingSupported() 29 | call NERDTreeAddMenuItem({'text': '(c)copy the current node', 'shortcut': 'c', 'callback': 'NERDTreeCopyNode'}) 30 | endif 31 | 32 | "FUNCTION: s:echo(msg){{{1 33 | function! s:echo(msg) 34 | redraw 35 | echomsg "NERDTree: " . a:msg 36 | endfunction 37 | 38 | "FUNCTION: s:echoWarning(msg){{{1 39 | function! s:echoWarning(msg) 40 | echohl warningmsg 41 | call s:echo(a:msg) 42 | echohl normal 43 | endfunction 44 | 45 | "FUNCTION: s:promptToDelBuffer(bufnum, msg){{{1 46 | "prints out the given msg and, if the user responds by pushing 'y' then the 47 | "buffer with the given bufnum is deleted 48 | " 49 | "Args: 50 | "bufnum: the buffer that may be deleted 51 | "msg: a message that will be echoed to the user asking them if they wish to 52 | " del the buffer 53 | function! s:promptToDelBuffer(bufnum, msg) 54 | echo a:msg 55 | if nr2char(getchar()) ==# 'y' 56 | exec "silent bdelete! " . a:bufnum 57 | endif 58 | endfunction 59 | 60 | "FUNCTION: NERDTreeAddNode(){{{1 61 | function! NERDTreeAddNode() 62 | let curDirNode = g:NERDTreeDirNode.GetSelected() 63 | 64 | let newNodeName = input("Add a childnode\n". 65 | \ "==========================================================\n". 66 | \ "Enter the dir/file name to be created. Dirs end with a '/'\n" . 67 | \ "", curDirNode.path.str() . g:NERDTreePath.Slash(), "file") 68 | 69 | if newNodeName ==# '' 70 | call s:echo("Node Creation Aborted.") 71 | return 72 | endif 73 | 74 | try 75 | let newPath = g:NERDTreePath.Create(newNodeName) 76 | let parentNode = b:NERDTreeRoot.findNode(newPath.getParent()) 77 | 78 | let newTreeNode = g:NERDTreeFileNode.New(newPath) 79 | if parentNode.isOpen || !empty(parentNode.children) 80 | call parentNode.addChild(newTreeNode, 1) 81 | call NERDTreeRender() 82 | call newTreeNode.putCursorHere(1, 0) 83 | endif 84 | catch /^NERDTree/ 85 | call s:echoWarning("Node Not Created.") 86 | endtry 87 | endfunction 88 | 89 | "FUNCTION: NERDTreeMoveNode(){{{1 90 | function! NERDTreeMoveNode() 91 | let curNode = g:NERDTreeFileNode.GetSelected() 92 | let newNodePath = input("Rename the current node\n" . 93 | \ "==========================================================\n" . 94 | \ "Enter the new path for the node: \n" . 95 | \ "", curNode.path.str(), "file") 96 | 97 | if newNodePath ==# '' 98 | call s:echo("Node Renaming Aborted.") 99 | return 100 | endif 101 | 102 | try 103 | let bufnum = bufnr(curNode.path.str()) 104 | 105 | call curNode.rename(newNodePath) 106 | call NERDTreeRender() 107 | 108 | "if the node is open in a buffer, ask the user if they want to 109 | "close that buffer 110 | if bufnum != -1 111 | let prompt = "\nNode renamed.\n\nThe old file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? " (hidden)" : "") .". Delete this buffer? (yN)" 112 | call s:promptToDelBuffer(bufnum, prompt) 113 | endif 114 | 115 | call curNode.putCursorHere(1, 0) 116 | 117 | redraw 118 | catch /^NERDTree/ 119 | call s:echoWarning("Node Not Renamed.") 120 | endtry 121 | endfunction 122 | 123 | " FUNCTION: NERDTreeDeleteNode() {{{1 124 | function! NERDTreeDeleteNode() 125 | let currentNode = g:NERDTreeFileNode.GetSelected() 126 | let confirmed = 0 127 | 128 | if currentNode.path.isDirectory 129 | let choice =input("Delete the current node\n" . 130 | \ "==========================================================\n" . 131 | \ "STOP! To delete this entire directory, type 'yes'\n" . 132 | \ "" . currentNode.path.str() . ": ") 133 | let confirmed = choice ==# 'yes' 134 | else 135 | echo "Delete the current node\n" . 136 | \ "==========================================================\n". 137 | \ "Are you sure you wish to delete the node:\n" . 138 | \ "" . currentNode.path.str() . " (yN):" 139 | let choice = nr2char(getchar()) 140 | let confirmed = choice ==# 'y' 141 | endif 142 | 143 | 144 | if confirmed 145 | try 146 | call currentNode.delete() 147 | call NERDTreeRender() 148 | 149 | "if the node is open in a buffer, ask the user if they want to 150 | "close that buffer 151 | let bufnum = bufnr(currentNode.path.str()) 152 | if buflisted(bufnum) 153 | let prompt = "\nNode deleted.\n\nThe file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? " (hidden)" : "") .". Delete this buffer? (yN)" 154 | call s:promptToDelBuffer(bufnum, prompt) 155 | endif 156 | 157 | redraw 158 | catch /^NERDTree/ 159 | call s:echoWarning("Could not remove node") 160 | endtry 161 | else 162 | call s:echo("delete aborted") 163 | endif 164 | 165 | endfunction 166 | 167 | " FUNCTION: NERDTreeCopyNode() {{{1 168 | function! NERDTreeCopyNode() 169 | let currentNode = g:NERDTreeFileNode.GetSelected() 170 | let newNodePath = input("Copy the current node\n" . 171 | \ "==========================================================\n" . 172 | \ "Enter the new path to copy the node to: \n" . 173 | \ "", currentNode.path.str(), "file") 174 | 175 | if newNodePath != "" 176 | "strip trailing slash 177 | let newNodePath = substitute(newNodePath, '\/$', '', '') 178 | 179 | let confirmed = 1 180 | if currentNode.path.copyingWillOverwrite(newNodePath) 181 | call s:echo("Warning: copying may overwrite files! Continue? (yN)") 182 | let choice = nr2char(getchar()) 183 | let confirmed = choice ==# 'y' 184 | endif 185 | 186 | if confirmed 187 | try 188 | let newNode = currentNode.copy(newNodePath) 189 | if !empty(newNode) 190 | call NERDTreeRender() 191 | call newNode.putCursorHere(0, 0) 192 | endif 193 | catch /^NERDTree/ 194 | call s:echoWarning("Could not copy node") 195 | endtry 196 | endif 197 | else 198 | call s:echo("Copy aborted.") 199 | endif 200 | redraw 201 | endfunction 202 | 203 | function! NERDTreeQuickLook() 204 | let treenode = g:NERDTreeFileNode.GetSelected() 205 | if treenode != {} 206 | call system("qlmanage -p 2>/dev/null '" . treenode.path.str() . "'") 207 | endif 208 | endfunction 209 | 210 | function! NERDTreeRevealInFinder() 211 | let treenode = g:NERDTreeFileNode.GetSelected() 212 | if treenode != {} 213 | let x = system("open -R '" . treenode.path.str() . "'") 214 | endif 215 | endfunction 216 | 217 | function! NERDTreeExecuteFile() 218 | let treenode = g:NERDTreeFileNode.GetSelected() 219 | if treenode != {} 220 | let x = system("open '" . treenode.path.str() . "'") 221 | endif 222 | endfunction 223 | 224 | " vim: set sw=4 sts=4 et fdm=marker: 225 | -------------------------------------------------------------------------------- /.vim/doc/NERD_tree.txt: -------------------------------------------------------------------------------- 1 | *NERD_tree.txt* A tree explorer plugin that owns your momma! 2 | 3 | 4 | 5 | omg its ... ~ 6 | 7 | ________ ________ _ ____________ ____ __________ ____________~ 8 | /_ __/ / / / ____/ / | / / ____/ __ \/ __ \ /_ __/ __ \/ ____/ ____/~ 9 | / / / /_/ / __/ / |/ / __/ / /_/ / / / / / / / /_/ / __/ / __/ ~ 10 | / / / __ / /___ / /| / /___/ _, _/ /_/ / / / / _, _/ /___/ /___ ~ 11 | /_/ /_/ /_/_____/ /_/ |_/_____/_/ |_/_____/ /_/ /_/ |_/_____/_____/ ~ 12 | 13 | 14 | Reference Manual~ 15 | 16 | 17 | 18 | 19 | ============================================================================== 20 | CONTENTS *NERDTree-contents* 21 | 22 | 1.Intro...................................|NERDTree| 23 | 2.Functionality provided..................|NERDTreeFunctionality| 24 | 2.1.Global commands...................|NERDTreeGlobalCommands| 25 | 2.2.Bookmarks.........................|NERDTreeBookmarks| 26 | 2.2.1.The bookmark table..........|NERDTreeBookmarkTable| 27 | 2.2.2.Bookmark commands...........|NERDTreeBookmarkCommands| 28 | 2.2.3.Invalid bookmarks...........|NERDTreeInvalidBookmarks| 29 | 2.3.NERD tree mappings................|NERDTreeMappings| 30 | 2.4.The NERD tree menu................|NERDTreeMenu| 31 | 3.Options.................................|NERDTreeOptions| 32 | 3.1.Option summary....................|NERDTreeOptionSummary| 33 | 3.2.Option details....................|NERDTreeOptionDetails| 34 | 4.The NERD tree API.......................|NERDTreeAPI| 35 | 4.1.Key map API.......................|NERDTreeKeymapAPI| 36 | 4.2.Menu API..........................|NERDTreeMenuAPI| 37 | 5.About...................................|NERDTreeAbout| 38 | 6.Changelog...............................|NERDTreeChangelog| 39 | 7.Credits.................................|NERDTreeCredits| 40 | 8.License.................................|NERDTreeLicense| 41 | 42 | ============================================================================== 43 | 1. Intro *NERDTree* 44 | 45 | What is this "NERD tree"?? 46 | 47 | The NERD tree allows you to explore your filesystem and to open files and 48 | directories. It presents the filesystem to you in the form of a tree which you 49 | manipulate with the keyboard and/or mouse. It also allows you to perform 50 | simple filesystem operations. 51 | 52 | The following features and functionality are provided by the NERD tree: 53 | * Files and directories are displayed in a hierarchical tree structure 54 | * Different highlighting is provided for the following types of nodes: 55 | * files 56 | * directories 57 | * sym-links 58 | * windows .lnk files 59 | * read-only files 60 | * executable files 61 | * Many (customisable) mappings are provided to manipulate the tree: 62 | * Mappings to open/close/explore directory nodes 63 | * Mappings to open files in new/existing windows/tabs 64 | * Mappings to change the current root of the tree 65 | * Mappings to navigate around the tree 66 | * ... 67 | * Directories and files can be bookmarked. 68 | * Most NERD tree navigation can also be done with the mouse 69 | * Filtering of tree content (can be toggled at runtime) 70 | * custom file filters to prevent e.g. vim backup files being displayed 71 | * optional displaying of hidden files (. files) 72 | * files can be "turned off" so that only directories are displayed 73 | * The position and size of the NERD tree window can be customised 74 | * The order in which the nodes in the tree are listed can be customised. 75 | * A model of your filesystem is created/maintained as you explore it. This 76 | has several advantages: 77 | * All filesystem information is cached and is only re-read on demand 78 | * If you revisit a part of the tree that you left earlier in your 79 | session, the directory nodes will be opened/closed as you left them 80 | * The script remembers the cursor position and window position in the NERD 81 | tree so you can toggle it off (or just close the tree window) and then 82 | reopen it (with NERDTreeToggle) the NERD tree window will appear exactly 83 | as you left it 84 | * You can have a separate NERD tree for each tab, share trees across tabs, 85 | or a mix of both. 86 | * By default the script overrides the default file browser (netw), so if 87 | you :edit a directory a (slighly modified) NERD tree will appear in the 88 | current window 89 | * A programmable menu system is provided (simulates right clicking on a 90 | node) 91 | * one default menu plugin is provided to perform basic filesytem 92 | operations (create/delete/move/copy files/directories) 93 | * There's an API for adding your own keymappings 94 | 95 | 96 | ============================================================================== 97 | 2. Functionality provided *NERDTreeFunctionality* 98 | 99 | ------------------------------------------------------------------------------ 100 | 2.1. Global Commands *NERDTreeGlobalCommands* 101 | 102 | :NERDTree [ | ] *:NERDTree* 103 | Opens a fresh NERD tree. The root of the tree depends on the argument 104 | given. There are 3 cases: If no argument is given, the current directory 105 | will be used. If a directory is given, that will be used. If a bookmark 106 | name is given, the corresponding directory will be used. For example: > 107 | :NERDTree /home/marty/vim7/src 108 | :NERDTree foo (foo is the name of a bookmark) 109 | < 110 | :NERDTreeFromBookmark *:NERDTreeFromBookmark* 111 | Opens a fresh NERD tree with the root initialized to the dir for 112 | . This only reason to use this command over :NERDTree is for 113 | the completion (which is for bookmarks rather than directories). 114 | 115 | :NERDTreeToggle [ | ] *:NERDTreeToggle* 116 | If a NERD tree already exists for this tab, it is reopened and rendered 117 | again. If no NERD tree exists for this tab then this command acts the 118 | same as the |:NERDTree| command. 119 | 120 | :NERDTreeMirror *:NERDTreeMirror* 121 | Shares an existing NERD tree, from another tab, in the current tab. 122 | Changes made to one tree are reflected in both as they are actually the 123 | same buffer. 124 | 125 | If only one other NERD tree exists, that tree is automatically mirrored. If 126 | more than one exists, the script will ask which tree to mirror. 127 | 128 | :NERDTreeClose *:NERDTreeClose* 129 | Close the NERD tree in this tab. 130 | 131 | :NERDTreeFind *:NERDTreeFind* 132 | Find the current file in the tree. 133 | 134 | If not tree exists and the current file is under vim's CWD, then init a 135 | tree at the CWD and reveal the file. Otherwise init a tree in the current 136 | file's directory. 137 | 138 | In any case, the current file is revealed and the cursor is placed on it. 139 | 140 | ------------------------------------------------------------------------------ 141 | 2.2. Bookmarks *NERDTreeBookmarks* 142 | 143 | Bookmarks in the NERD tree are a way to tag files or directories of interest. 144 | For example, you could use bookmarks to tag all of your project directories. 145 | 146 | ------------------------------------------------------------------------------ 147 | 2.2.1. The Bookmark Table *NERDTreeBookmarkTable* 148 | 149 | If the bookmark table is active (see |NERDTree-B| and 150 | |'NERDTreeShowBookmarks'|), it will be rendered above the tree. You can double 151 | click bookmarks or use the |NERDTree-o| mapping to activate them. See also, 152 | |NERDTree-t| and |NERDTree-T| 153 | 154 | ------------------------------------------------------------------------------ 155 | 2.2.2. Bookmark commands *NERDTreeBookmarkCommands* 156 | 157 | Note that the following commands are only available in the NERD tree buffer. 158 | 159 | :Bookmark 160 | Bookmark the current node as . If there is already a 161 | bookmark, it is overwritten. must not contain spaces. 162 | If is not provided, it defaults to the file or directory name. 163 | For directories, a trailing slash is present. 164 | 165 | :BookmarkToRoot 166 | Make the directory corresponding to the new root. If a treenode 167 | corresponding to is already cached somewhere in the tree then 168 | the current tree will be used, otherwise a fresh tree will be opened. 169 | Note that if points to a file then its parent will be used 170 | instead. 171 | 172 | :RevealBookmark 173 | If the node is cached under the current root then it will be revealed 174 | (i.e. directory nodes above it will be opened) and the cursor will be 175 | placed on it. 176 | 177 | :OpenBookmark 178 | must point to a file. The file is opened as though |NERDTree-o| 179 | was applied. If the node is cached under the current root then it will be 180 | revealed and the cursor will be placed on it. 181 | 182 | :ClearBookmarks [] 183 | Remove all the given bookmarks. If no bookmarks are given then remove all 184 | bookmarks on the current node. 185 | 186 | :ClearAllBookmarks 187 | Remove all bookmarks. 188 | 189 | :ReadBookmarks 190 | Re-read the bookmarks in the |'NERDTreeBookmarksFile'|. 191 | 192 | See also |:NERDTree| and |:NERDTreeFromBookmark|. 193 | 194 | ------------------------------------------------------------------------------ 195 | 2.2.3. Invalid Bookmarks *NERDTreeInvalidBookmarks* 196 | 197 | If invalid bookmarks are detected, the script will issue an error message and 198 | the invalid bookmarks will become unavailable for use. 199 | 200 | These bookmarks will still be stored in the bookmarks file (see 201 | |'NERDTreeBookmarksFile'|), down the bottom. There will always be a blank line 202 | after the valid bookmarks but before the invalid ones. 203 | 204 | Each line in the bookmarks file represents one bookmark. The proper format is: 205 | 206 | 207 | After you have corrected any invalid bookmarks, either restart vim, or go 208 | :ReadBookmarks from the NERD tree window. 209 | 210 | ------------------------------------------------------------------------------ 211 | 2.3. NERD tree Mappings *NERDTreeMappings* 212 | 213 | Default Description~ help-tag~ 214 | Key~ 215 | 216 | o.......Open files, directories and bookmarks....................|NERDTree-o| 217 | go......Open selected file, but leave cursor in the NERDTree.....|NERDTree-go| 218 | t.......Open selected node/bookmark in a new tab.................|NERDTree-t| 219 | T.......Same as 't' but keep the focus on the current tab........|NERDTree-T| 220 | i.......Open selected file in a split window.....................|NERDTree-i| 221 | gi......Same as i, but leave the cursor on the NERDTree..........|NERDTree-gi| 222 | s.......Open selected file in a new vsplit.......................|NERDTree-s| 223 | gs......Same as s, but leave the cursor on the NERDTree..........|NERDTree-gs| 224 | O.......Recursively open the selected directory..................|NERDTree-O| 225 | x.......Close the current nodes parent...........................|NERDTree-x| 226 | X.......Recursively close all children of the current node.......|NERDTree-X| 227 | e.......Edit the current dif.....................................|NERDTree-e| 228 | 229 | ...............same as |NERDTree-o|. 230 | double-click.......same as the |NERDTree-o| map. 231 | middle-click.......same as |NERDTree-i| for files, same as 232 | |NERDTree-e| for dirs. 233 | 234 | D.......Delete the current bookmark .............................|NERDTree-D| 235 | 236 | P.......Jump to the root node....................................|NERDTree-P| 237 | p.......Jump to current nodes parent.............................|NERDTree-p| 238 | K.......Jump up inside directories at the current tree depth.....|NERDTree-K| 239 | J.......Jump down inside directories at the current tree depth...|NERDTree-J| 240 | ...Jump down to the next sibling of the current directory...|NERDTree-C-J| 241 | ...Jump up to the previous sibling of the current directory.|NERDTree-C-K| 242 | 243 | C.......Change the tree root to the selected dir.................|NERDTree-C| 244 | u.......Move the tree root up one directory......................|NERDTree-u| 245 | U.......Same as 'u' except the old root node is left open........|NERDTree-U| 246 | r.......Recursively refresh the current directory................|NERDTree-r| 247 | R.......Recursively refresh the current root.....................|NERDTree-R| 248 | m.......Display the NERD tree menu...............................|NERDTree-m| 249 | cd......Change the CWD to the dir of the selected node...........|NERDTree-cd| 250 | 251 | I.......Toggle whether hidden files displayed....................|NERDTree-I| 252 | f.......Toggle whether the file filters are used.................|NERDTree-f| 253 | F.......Toggle whether files are displayed.......................|NERDTree-F| 254 | B.......Toggle whether the bookmark table is displayed...........|NERDTree-B| 255 | 256 | q.......Close the NERDTree window................................|NERDTree-q| 257 | A.......Zoom (maximize/minimize) the NERDTree window.............|NERDTree-A| 258 | ?.......Toggle the display of the quick help.....................|NERDTree-?| 259 | 260 | ------------------------------------------------------------------------------ 261 | *NERDTree-o* 262 | Default key: o 263 | Map option: NERDTreeMapActivateNode 264 | Applies to: files and directories. 265 | 266 | If a file node is selected, it is opened in the previous window. 267 | 268 | If a directory is selected it is opened or closed depending on its current 269 | state. 270 | 271 | If a bookmark that links to a directory is selected then that directory 272 | becomes the new root. 273 | 274 | If a bookmark that links to a file is selected then that file is opened in the 275 | previous window. 276 | 277 | ------------------------------------------------------------------------------ 278 | *NERDTree-go* 279 | Default key: go 280 | Map option: None 281 | Applies to: files. 282 | 283 | If a file node is selected, it is opened in the previous window, but the 284 | cursor does not move. 285 | 286 | The key combo for this mapping is always "g" + NERDTreeMapActivateNode (see 287 | |NERDTree-o|). 288 | 289 | ------------------------------------------------------------------------------ 290 | *NERDTree-t* 291 | Default key: t 292 | Map option: NERDTreeMapOpenInTab 293 | Applies to: files and directories. 294 | 295 | Opens the selected file in a new tab. If a directory is selected, a fresh 296 | NERD Tree for that directory is opened in a new tab. 297 | 298 | If a bookmark which points to a directory is selected, open a NERD tree for 299 | that directory in a new tab. If the bookmark points to a file, open that file 300 | in a new tab. 301 | 302 | ------------------------------------------------------------------------------ 303 | *NERDTree-T* 304 | Default key: T 305 | Map option: NERDTreeMapOpenInTabSilent 306 | Applies to: files and directories. 307 | 308 | The same as |NERDTree-t| except that the focus is kept in the current tab. 309 | 310 | ------------------------------------------------------------------------------ 311 | *NERDTree-i* 312 | Default key: i 313 | Map option: NERDTreeMapOpenSplit 314 | Applies to: files. 315 | 316 | Opens the selected file in a new split window and puts the cursor in the new 317 | window. 318 | 319 | ------------------------------------------------------------------------------ 320 | *NERDTree-gi* 321 | Default key: gi 322 | Map option: None 323 | Applies to: files. 324 | 325 | The same as |NERDTree-i| except that the cursor is not moved. 326 | 327 | The key combo for this mapping is always "g" + NERDTreeMapOpenSplit (see 328 | |NERDTree-i|). 329 | 330 | ------------------------------------------------------------------------------ 331 | *NERDTree-s* 332 | Default key: s 333 | Map option: NERDTreeMapOpenVSplit 334 | Applies to: files. 335 | 336 | Opens the selected file in a new vertically split window and puts the cursor in 337 | the new window. 338 | 339 | ------------------------------------------------------------------------------ 340 | *NERDTree-gs* 341 | Default key: gs 342 | Map option: None 343 | Applies to: files. 344 | 345 | The same as |NERDTree-s| except that the cursor is not moved. 346 | 347 | The key combo for this mapping is always "g" + NERDTreeMapOpenVSplit (see 348 | |NERDTree-s|). 349 | 350 | ------------------------------------------------------------------------------ 351 | *NERDTree-O* 352 | Default key: O 353 | Map option: NERDTreeMapOpenRecursively 354 | Applies to: directories. 355 | 356 | Recursively opens the selelected directory. 357 | 358 | All files and directories are cached, but if a directory would not be 359 | displayed due to file filters (see |'NERDTreeIgnore'| |NERDTree-f|) or the 360 | hidden file filter (see |'NERDTreeShowHidden'|) then its contents are not 361 | cached. This is handy, especially if you have .svn directories. 362 | 363 | ------------------------------------------------------------------------------ 364 | *NERDTree-x* 365 | Default key: x 366 | Map option: NERDTreeMapCloseDir 367 | Applies to: files and directories. 368 | 369 | Closes the parent of the selected node. 370 | 371 | ------------------------------------------------------------------------------ 372 | *NERDTree-X* 373 | Default key: X 374 | Map option: NERDTreeMapCloseChildren 375 | Applies to: directories. 376 | 377 | Recursively closes all children of the selected directory. 378 | 379 | Tip: To quickly "reset" the tree, use |NERDTree-P| with this mapping. 380 | 381 | ------------------------------------------------------------------------------ 382 | *NERDTree-e* 383 | Default key: e 384 | Map option: NERDTreeMapOpenExpl 385 | Applies to: files and directories. 386 | 387 | |:edit|s the selected directory, or the selected file's directory. This could 388 | result in a NERD tree or a netrw being opened, depending on 389 | |'NERDTreeHijackNetrw'|. 390 | 391 | ------------------------------------------------------------------------------ 392 | *NERDTree-D* 393 | Default key: D 394 | Map option: NERDTreeMapDeleteBookmark 395 | Applies to: lines in the bookmarks table 396 | 397 | Deletes the currently selected bookmark. 398 | 399 | ------------------------------------------------------------------------------ 400 | *NERDTree-P* 401 | Default key: P 402 | Map option: NERDTreeMapJumpRoot 403 | Applies to: no restrictions. 404 | 405 | Jump to the tree root. 406 | 407 | ------------------------------------------------------------------------------ 408 | *NERDTree-p* 409 | Default key: p 410 | Map option: NERDTreeMapJumpParent 411 | Applies to: files and directories. 412 | 413 | Jump to the parent node of the selected node. 414 | 415 | ------------------------------------------------------------------------------ 416 | *NERDTree-K* 417 | Default key: K 418 | Map option: NERDTreeMapJumpFirstChild 419 | Applies to: files and directories. 420 | 421 | Jump to the first child of the current nodes parent. 422 | 423 | If the cursor is already on the first node then do the following: 424 | * loop back thru the siblings of the current nodes parent until we find an 425 | open dir with children 426 | * go to the first child of that node 427 | 428 | ------------------------------------------------------------------------------ 429 | *NERDTree-J* 430 | Default key: J 431 | Map option: NERDTreeMapJumpLastChild 432 | Applies to: files and directories. 433 | 434 | Jump to the last child of the current nodes parent. 435 | 436 | If the cursor is already on the last node then do the following: 437 | * loop forward thru the siblings of the current nodes parent until we find 438 | an open dir with children 439 | * go to the last child of that node 440 | 441 | ------------------------------------------------------------------------------ 442 | *NERDTree-C-J* 443 | Default key: 444 | Map option: NERDTreeMapJumpNextSibling 445 | Applies to: files and directories. 446 | 447 | Jump to the next sibling of the selected node. 448 | 449 | ------------------------------------------------------------------------------ 450 | *NERDTree-C-K* 451 | Default key: 452 | Map option: NERDTreeMapJumpPrevSibling 453 | Applies to: files and directories. 454 | 455 | Jump to the previous sibling of the selected node. 456 | 457 | ------------------------------------------------------------------------------ 458 | *NERDTree-C* 459 | Default key: C 460 | Map option: NERDTreeMapChdir 461 | Applies to: directories. 462 | 463 | Make the selected directory node the new tree root. If a file is selected, its 464 | parent is used. 465 | 466 | ------------------------------------------------------------------------------ 467 | *NERDTree-u* 468 | Default key: u 469 | Map option: NERDTreeMapUpdir 470 | Applies to: no restrictions. 471 | 472 | Move the tree root up a dir (like doing a "cd .."). 473 | 474 | ------------------------------------------------------------------------------ 475 | *NERDTree-U* 476 | Default key: U 477 | Map option: NERDTreeMapUpdirKeepOpen 478 | Applies to: no restrictions. 479 | 480 | Like |NERDTree-u| except that the old tree root is kept open. 481 | 482 | ------------------------------------------------------------------------------ 483 | *NERDTree-r* 484 | Default key: r 485 | Map option: NERDTreeMapRefresh 486 | Applies to: files and directories. 487 | 488 | If a dir is selected, recursively refresh that dir, i.e. scan the filesystem 489 | for changes and represent them in the tree. 490 | 491 | If a file node is selected then the above is done on it's parent. 492 | 493 | ------------------------------------------------------------------------------ 494 | *NERDTree-R* 495 | Default key: R 496 | Map option: NERDTreeMapRefreshRoot 497 | Applies to: no restrictions. 498 | 499 | Recursively refresh the tree root. 500 | 501 | ------------------------------------------------------------------------------ 502 | *NERDTree-m* 503 | Default key: m 504 | Map option: NERDTreeMapMenu 505 | Applies to: files and directories. 506 | 507 | Display the NERD tree menu. See |NERDTreeMenu| for details. 508 | 509 | ------------------------------------------------------------------------------ 510 | *NERDTree-cd* 511 | Default key: cd 512 | Map option: NERDTreeMapChdir 513 | Applies to: files and directories. 514 | 515 | Change vims current working directory to that of the selected node. 516 | 517 | ------------------------------------------------------------------------------ 518 | *NERDTree-I* 519 | Default key: I 520 | Map option: NERDTreeMapToggleHidden 521 | Applies to: no restrictions. 522 | 523 | Toggles whether hidden files (i.e. "dot files") are displayed. 524 | 525 | ------------------------------------------------------------------------------ 526 | *NERDTree-f* 527 | Default key: f 528 | Map option: NERDTreeMapToggleFilters 529 | Applies to: no restrictions. 530 | 531 | Toggles whether file filters are used. See |'NERDTreeIgnore'| for details. 532 | 533 | ------------------------------------------------------------------------------ 534 | *NERDTree-F* 535 | Default key: F 536 | Map option: NERDTreeMapToggleFiles 537 | Applies to: no restrictions. 538 | 539 | Toggles whether file nodes are displayed. 540 | 541 | ------------------------------------------------------------------------------ 542 | *NERDTree-B* 543 | Default key: B 544 | Map option: NERDTreeMapToggleBookmarks 545 | Applies to: no restrictions. 546 | 547 | Toggles whether the bookmarks table is displayed. 548 | 549 | ------------------------------------------------------------------------------ 550 | *NERDTree-q* 551 | Default key: q 552 | Map option: NERDTreeMapQuit 553 | Applies to: no restrictions. 554 | 555 | Closes the NERDtree window. 556 | 557 | ------------------------------------------------------------------------------ 558 | *NERDTree-A* 559 | Default key: A 560 | Map option: NERDTreeMapToggleZoom 561 | Applies to: no restrictions. 562 | 563 | Maximize (zoom) and minimize the NERDtree window. 564 | 565 | ------------------------------------------------------------------------------ 566 | *NERDTree-?* 567 | Default key: ? 568 | Map option: NERDTreeMapHelp 569 | Applies to: no restrictions. 570 | 571 | Toggles whether the quickhelp is displayed. 572 | 573 | ------------------------------------------------------------------------------ 574 | 2.3. The NERD tree menu *NERDTreeMenu* 575 | 576 | The NERD tree has a menu that can be programmed via the an API (see 577 | |NERDTreeMenuAPI|). The idea is to simulate the "right click" menus that most 578 | file explorers have. 579 | 580 | The script comes with two default menu plugins: exec_menuitem.vim and 581 | fs_menu.vim. fs_menu.vim adds some basic filesystem operations to the menu for 582 | creating/deleting/moving/copying files and dirs. exec_menuitem.vim provides a 583 | menu item to execute executable files. 584 | 585 | Related tags: |NERDTree-m| |NERDTreeApi| 586 | 587 | ============================================================================== 588 | 3. Customisation *NERDTreeOptions* 589 | 590 | 591 | ------------------------------------------------------------------------------ 592 | 3.1. Customisation summary *NERDTreeOptionSummary* 593 | 594 | The script provides the following options that can customise the behaviour the 595 | NERD tree. These options should be set in your vimrc. 596 | 597 | |'loaded_nerd_tree'| Turns off the script. 598 | 599 | |'NERDChristmasTree'| Tells the NERD tree to make itself colourful 600 | and pretty. 601 | 602 | |'NERDTreeAutoCenter'| Controls whether the NERD tree window centers 603 | when the cursor moves within a specified 604 | distance to the top/bottom of the window. 605 | |'NERDTreeAutoCenterThreshold'| Controls the sensitivity of autocentering. 606 | 607 | |'NERDTreeCaseSensitiveSort'| Tells the NERD tree whether to be case 608 | sensitive or not when sorting nodes. 609 | 610 | |'NERDTreeChDirMode'| Tells the NERD tree if/when it should change 611 | vim's current working directory. 612 | 613 | |'NERDTreeHighlightCursorline'| Tell the NERD tree whether to highlight the 614 | current cursor line. 615 | 616 | |'NERDTreeHijackNetrw'| Tell the NERD tree whether to replace the netrw 617 | autocommands for exploring local directories. 618 | 619 | |'NERDTreeIgnore'| Tells the NERD tree which files to ignore. 620 | 621 | |'NERDTreeBookmarksFile'| Where the bookmarks are stored. 622 | 623 | |'NERDTreeMouseMode'| Tells the NERD tree how to handle mouse 624 | clicks. 625 | 626 | |'NERDTreeQuitOnOpen'| Closes the tree window after opening a file. 627 | 628 | |'NERDTreeShowBookmarks'| Tells the NERD tree whether to display the 629 | bookmarks table on startup. 630 | 631 | |'NERDTreeShowFiles'| Tells the NERD tree whether to display files 632 | in the tree on startup. 633 | 634 | |'NERDTreeShowHidden'| Tells the NERD tree whether to display hidden 635 | files on startup. 636 | 637 | |'NERDTreeShowLineNumbers'| Tells the NERD tree whether to display line 638 | numbers in the tree window. 639 | 640 | |'NERDTreeSortOrder'| Tell the NERD tree how to sort the nodes in 641 | the tree. 642 | 643 | |'NERDTreeStatusline'| Set a statusline for NERD tree windows. 644 | 645 | |'NERDTreeWinPos'| Tells the script where to put the NERD tree 646 | window. 647 | 648 | |'NERDTreeWinSize'| Sets the window size when the NERD tree is 649 | opened. 650 | 651 | |'NERDTreeMinimalUI'| Disables display of the 'Bookmarks' label and 652 | 'Press ? for help' text. 653 | 654 | |'NERDTreeDirArrows'| Tells the NERD tree to use arrows instead of 655 | + ~ chars when displaying directories. 656 | 657 | ------------------------------------------------------------------------------ 658 | 3.2. Customisation details *NERDTreeOptionDetails* 659 | 660 | To enable any of the below options you should put the given line in your 661 | ~/.vimrc 662 | 663 | *'loaded_nerd_tree'* 664 | If this plugin is making you feel homicidal, it may be a good idea to turn it 665 | off with this line in your vimrc: > 666 | let loaded_nerd_tree=1 667 | < 668 | ------------------------------------------------------------------------------ 669 | *'NERDChristmasTree'* 670 | Values: 0 or 1. 671 | Default: 1. 672 | 673 | If this option is set to 1 then some extra syntax highlighting elements are 674 | added to the nerd tree to make it more colourful. 675 | 676 | Set it to 0 for a more vanilla looking tree. 677 | 678 | ------------------------------------------------------------------------------ 679 | *'NERDTreeAutoCenter'* 680 | Values: 0 or 1. 681 | Default: 1 682 | 683 | If set to 1, the NERD tree window will center around the cursor if it moves to 684 | within |'NERDTreeAutoCenterThreshold'| lines of the top/bottom of the window. 685 | 686 | This is ONLY done in response to tree navigation mappings, 687 | i.e. |NERDTree-J| |NERDTree-K| |NERDTree-C-J| |NERDTree-C-K| |NERDTree-p| 688 | |NERDTree-P| 689 | 690 | The centering is done with a |zz| operation. 691 | 692 | ------------------------------------------------------------------------------ 693 | *'NERDTreeAutoCenterThreshold'* 694 | Values: Any natural number. 695 | Default: 3 696 | 697 | This option controls the "sensitivity" of the NERD tree auto centering. See 698 | |'NERDTreeAutoCenter'| for details. 699 | 700 | ------------------------------------------------------------------------------ 701 | *'NERDTreeCaseSensitiveSort'* 702 | Values: 0 or 1. 703 | Default: 0. 704 | 705 | By default the NERD tree does not sort nodes case sensitively, i.e. nodes 706 | could appear like this: > 707 | bar.c 708 | Baz.c 709 | blarg.c 710 | boner.c 711 | Foo.c 712 | < 713 | But, if you set this option to 1 then the case of the nodes will be taken into 714 | account. The above nodes would then be sorted like this: > 715 | Baz.c 716 | Foo.c 717 | bar.c 718 | blarg.c 719 | boner.c 720 | < 721 | ------------------------------------------------------------------------------ 722 | *'NERDTreeChDirMode'* 723 | 724 | Values: 0, 1 or 2. 725 | Default: 0. 726 | 727 | Use this option to tell the script when (if at all) to change the current 728 | working directory (CWD) for vim. 729 | 730 | If it is set to 0 then the CWD is never changed by the NERD tree. 731 | 732 | If set to 1 then the CWD is changed when the NERD tree is first loaded to the 733 | directory it is initialized in. For example, if you start the NERD tree with > 734 | :NERDTree /home/marty/foobar 735 | < 736 | then the CWD will be changed to /home/marty/foobar and will not be changed 737 | again unless you init another NERD tree with a similar command. 738 | 739 | If the option is set to 2 then it behaves the same as if set to 1 except that 740 | the CWD is changed whenever the tree root is changed. For example, if the CWD 741 | is /home/marty/foobar and you make the node for /home/marty/foobar/baz the new 742 | root then the CWD will become /home/marty/foobar/baz. 743 | 744 | ------------------------------------------------------------------------------ 745 | *'NERDTreeHighlightCursorline'* 746 | Values: 0 or 1. 747 | Default: 1. 748 | 749 | If set to 1, the current cursor line in the NERD tree buffer will be 750 | highlighted. This is done using the |'cursorline'| option. 751 | 752 | ------------------------------------------------------------------------------ 753 | *'NERDTreeHijackNetrw'* 754 | Values: 0 or 1. 755 | Default: 1. 756 | 757 | If set to 1, doing a > 758 | :edit 759 | < 760 | will open up a "secondary" NERD tree instead of a netrw in the target window. 761 | 762 | Secondary NERD trees behaves slighly different from a regular trees in the 763 | following respects: 764 | 1. 'o' will open the selected file in the same window as the tree, 765 | replacing it. 766 | 2. you can have as many secondary tree as you want in the same tab. 767 | 768 | ------------------------------------------------------------------------------ 769 | *'NERDTreeIgnore'* 770 | Values: a list of regular expressions. 771 | Default: ['\~$']. 772 | 773 | This option is used to specify which files the NERD tree should ignore. It 774 | must be a list of regular expressions. When the NERD tree is rendered, any 775 | files/dirs that match any of the regex's in 'NERDTreeIgnore' wont be 776 | displayed. 777 | 778 | For example if you put the following line in your vimrc: > 779 | let NERDTreeIgnore=['\.vim$', '\~$'] 780 | < 781 | then all files ending in .vim or ~ will be ignored. 782 | 783 | Note: to tell the NERD tree not to ignore any files you must use the following 784 | line: > 785 | let NERDTreeIgnore=[] 786 | < 787 | 788 | The file filters can be turned on and off dynamically with the |NERDTree-f| 789 | mapping. 790 | 791 | ------------------------------------------------------------------------------ 792 | *'NERDTreeBookmarksFile'* 793 | Values: a path 794 | Default: $HOME/.NERDTreeBookmarks 795 | 796 | This is where bookmarks are saved. See |NERDTreeBookmarkCommands|. 797 | 798 | ------------------------------------------------------------------------------ 799 | *'NERDTreeMouseMode'* 800 | Values: 1, 2 or 3. 801 | Default: 1. 802 | 803 | If set to 1 then a double click on a node is required to open it. 804 | If set to 2 then a single click will open directory nodes, while a double 805 | click will still be required for file nodes. 806 | If set to 3 then a single click will open any node. 807 | 808 | Note: a double click anywhere on a line that a tree node is on will 809 | activate it, but all single-click activations must be done on name of the node 810 | itself. For example, if you have the following node: > 811 | | | |-application.rb 812 | < 813 | then (to single click activate it) you must click somewhere in 814 | 'application.rb'. 815 | 816 | ------------------------------------------------------------------------------ 817 | *'NERDTreeQuitOnOpen'* 818 | 819 | Values: 0 or 1. 820 | Default: 0 821 | 822 | If set to 1, the NERD tree window will close after opening a file with the 823 | |NERDTree-o|, |NERDTree-i|, |NERDTree-t| and |NERDTree-T| mappings. 824 | 825 | ------------------------------------------------------------------------------ 826 | *'NERDTreeShowBookmarks'* 827 | Values: 0 or 1. 828 | Default: 0. 829 | 830 | If this option is set to 1 then the bookmarks table will be displayed. 831 | 832 | This option can be toggled dynamically, per tree, with the |NERDTree-B| 833 | mapping. 834 | 835 | ------------------------------------------------------------------------------ 836 | *'NERDTreeShowFiles'* 837 | Values: 0 or 1. 838 | Default: 1. 839 | 840 | If this option is set to 1 then files are displayed in the NERD tree. If it is 841 | set to 0 then only directories are displayed. 842 | 843 | This option can be toggled dynamically, per tree, with the |NERDTree-F| 844 | mapping and is useful for drastically shrinking the tree when you are 845 | navigating to a different part of the tree. 846 | 847 | ------------------------------------------------------------------------------ 848 | *'NERDTreeShowHidden'* 849 | Values: 0 or 1. 850 | Default: 0. 851 | 852 | This option tells vim whether to display hidden files by default. This option 853 | can be dynamically toggled, per tree, with the |NERDTree-I| mapping. Use one 854 | of the follow lines to set this option: > 855 | let NERDTreeShowHidden=0 856 | let NERDTreeShowHidden=1 857 | < 858 | 859 | ------------------------------------------------------------------------------ 860 | *'NERDTreeShowLineNumbers'* 861 | Values: 0 or 1. 862 | Default: 0. 863 | 864 | This option tells vim whether to display line numbers for the NERD tree 865 | window. Use one of the follow lines to set this option: > 866 | let NERDTreeShowLineNumbers=0 867 | let NERDTreeShowLineNumbers=1 868 | < 869 | 870 | ------------------------------------------------------------------------------ 871 | *'NERDTreeSortOrder'* 872 | Values: a list of regular expressions. 873 | Default: ['\/$', '*', '\.swp$', '\.bak$', '\~$'] 874 | 875 | This option is set to a list of regular expressions which are used to 876 | specify the order of nodes under their parent. 877 | 878 | For example, if the option is set to: > 879 | ['\.vim$', '\.c$', '\.h$', '*', 'foobar'] 880 | < 881 | then all .vim files will be placed at the top, followed by all .c files then 882 | all .h files. All files containing the string 'foobar' will be placed at the 883 | end. The star is a special flag: it tells the script that every node that 884 | doesnt match any of the other regexps should be placed here. 885 | 886 | If no star is present in 'NERDTreeSortOrder' then one is automatically 887 | appended to the array. 888 | 889 | The regex '\/$' should be used to match directory nodes. 890 | 891 | After this sorting is done, the files in each group are sorted alphabetically. 892 | 893 | Other examples: > 894 | (1) ['*', '\/$'] 895 | (2) [] 896 | (3) ['\/$', '\.rb$', '\.php$', '*', '\.swp$', '\.bak$', '\~$'] 897 | < 898 | 1. Directories will appear last, everything else will appear above. 899 | 2. Everything will simply appear in alphabetical order. 900 | 3. Dirs will appear first, then ruby and php. Swap files, bak files and vim 901 | backup files will appear last with everything else preceding them. 902 | 903 | ------------------------------------------------------------------------------ 904 | *'NERDTreeStatusline'* 905 | Values: Any valid statusline setting. 906 | Default: %{b:NERDTreeRoot.path.strForOS(0)} 907 | 908 | Tells the script what to use as the |'statusline'| setting for NERD tree 909 | windows. 910 | 911 | Note that the statusline is set using |:let-&| not |:set| so escaping spaces 912 | isn't necessary. 913 | 914 | Setting this option to -1 will will deactivate it so that your global 915 | statusline setting is used instead. 916 | 917 | ------------------------------------------------------------------------------ 918 | *'NERDTreeWinPos'* 919 | Values: "left" or "right" 920 | Default: "left". 921 | 922 | This option is used to determine where NERD tree window is placed on the 923 | screen. 924 | 925 | This option makes it possible to use two different explorer plugins 926 | simultaneously. For example, you could have the taglist plugin on the left of 927 | the window and the NERD tree on the right. 928 | 929 | ------------------------------------------------------------------------------ 930 | *'NERDTreeWinSize'* 931 | Values: a positive integer. 932 | Default: 31. 933 | 934 | This option is used to change the size of the NERD tree when it is loaded. 935 | 936 | ------------------------------------------------------------------------------ 937 | *'NERDTreeMinimalUI'* 938 | Values: 0 or 1 939 | Default: 0 940 | 941 | This options disables the 'Bookmarks' label 'Press ? for help' text. Use one 942 | of the following lines to set this option: > 943 | let NERDTreeMinimalUI=0 944 | let NERDTreeMinimalUI=1 945 | < 946 | 947 | ------------------------------------------------------------------------------ 948 | *'NERDTreeDirArrows'* 949 | Values: 0 or 1 950 | Default: 0. 951 | 952 | This option is used to change the default look of directory nodes displayed in 953 | the tree. When set to 0 it shows old-school bars (|), + and ~ chars. If set to 954 | 1 it shows right and down arrows. Use one of the follow lines to set this 955 | option: > 956 | let NERDTreeDirArrows=0 957 | let NERDTreeDirArrows=1 958 | < 959 | 960 | ============================================================================== 961 | 4. The NERD tree API *NERDTreeAPI* 962 | 963 | The NERD tree script allows you to add custom key mappings and menu items via 964 | a set of API calls. Any scripts that use this API should be placed in 965 | ~/.vim/nerdtree_plugin/ (*nix) or ~/vimfiles/nerdtree_plugin (windows). 966 | 967 | The script exposes some prototype objects that can be used to manipulate the 968 | tree and/or get information from it: > 969 | g:NERDTreePath 970 | g:NERDTreeDirNode 971 | g:NERDTreeFileNode 972 | g:NERDTreeBookmark 973 | < 974 | See the code/comments in NERD_tree.vim to find how to use these objects. The 975 | following code conventions are used: 976 | * class members start with a capital letter 977 | * instance members start with a lower case letter 978 | * private members start with an underscore 979 | 980 | See this blog post for more details: 981 | http://got-ravings.blogspot.com/2008/09/vim-pr0n-prototype-based-objects.html 982 | 983 | ------------------------------------------------------------------------------ 984 | 4.1. Key map API *NERDTreeKeymapAPI* 985 | 986 | NERDTreeAddKeyMap({options}) *NERDTreeAddKeyMap()* 987 | Adds a new keymapping for all NERD tree buffers. 988 | {options} must be a dictionary, and must contain the following keys: 989 | "key" - the trigger key for the new mapping 990 | "callback" - the function the new mapping will be bound to 991 | "quickhelpText" - the text that will appear in the quickhelp (see 992 | |NERDTree-?|) 993 | 994 | Example: > 995 | call NERDTreeAddKeyMap({ 996 | \ 'key': 'b', 997 | \ 'callback': 'NERDTreeEchoCurrentNode', 998 | \ 'quickhelpText': 'echo full path of current node' }) 999 | 1000 | function! NERDTreeEchoCurrentNode() 1001 | let n = g:NERDTreeFileNode.GetSelected() 1002 | if n != {} 1003 | echomsg 'Current node: ' . n.path.str() 1004 | endif 1005 | endfunction 1006 | < 1007 | This code should sit in a file like ~/.vim/nerdtree_plugin/mymapping.vim. 1008 | It adds a (rather useless) mapping on 'b' which echos the full path to the 1009 | current node. 1010 | 1011 | ------------------------------------------------------------------------------ 1012 | 4.2. Menu API *NERDTreeMenuAPI* 1013 | 1014 | NERDTreeAddSubmenu({options}) *NERDTreeAddSubmenu()* 1015 | Creates and returns a new submenu. 1016 | 1017 | {options} must be a dictionary and must contain the following keys: 1018 | "text" - the text of the submenu that the user will see 1019 | "shortcut" - a shortcut key for the submenu (need not be unique) 1020 | 1021 | The following keys are optional: 1022 | "isActiveCallback" - a function that will be called to determine whether 1023 | this submenu item will be displayed or not. The callback function must return 1024 | 0 or 1. 1025 | "parent" - the parent submenu of the new submenu (returned from a previous 1026 | invocation of NERDTreeAddSubmenu()). If this key is left out then the new 1027 | submenu will sit under the top level menu. 1028 | 1029 | See below for an example. 1030 | 1031 | NERDTreeAddMenuItem({options}) *NERDTreeAddMenuItem()* 1032 | Adds a new menu item to the NERD tree menu (see |NERDTreeMenu|). 1033 | 1034 | {options} must be a dictionary and must contain the 1035 | following keys: 1036 | "text" - the text of the menu item which the user will see 1037 | "shortcut" - a shortcut key for the menu item (need not be unique) 1038 | "callback" - the function that will be called when the user activates the 1039 | menu item. 1040 | 1041 | The following keys are optional: 1042 | "isActiveCallback" - a function that will be called to determine whether 1043 | this menu item will be displayed or not. The callback function must return 1044 | 0 or 1. 1045 | "parent" - if the menu item belongs under a submenu then this key must be 1046 | specified. This value for this key will be the object that 1047 | was returned when the submenu was created with |NERDTreeAddSubmenu()|. 1048 | 1049 | See below for an example. 1050 | 1051 | NERDTreeAddMenuSeparator([{options}]) *NERDTreeAddMenuSeparator()* 1052 | Adds a menu separator (a row of dashes). 1053 | 1054 | {options} is an optional dictionary that may contain the following keys: 1055 | "isActiveCallback" - see description in |NERDTreeAddMenuItem()|. 1056 | 1057 | Below is an example of the menu API in action. > 1058 | call NERDTreeAddMenuSeparator() 1059 | 1060 | call NERDTreeAddMenuItem({ 1061 | \ 'text': 'a (t)op level menu item', 1062 | \ 'shortcut': 't', 1063 | \ 'callback': 'SomeFunction' }) 1064 | 1065 | let submenu = NERDTreeAddSubmenu({ 1066 | \ 'text': 'a (s)ub menu', 1067 | \ 'shortcut': 's' }) 1068 | 1069 | call NERDTreeAddMenuItem({ 1070 | \ 'text': '(n)ested item 1', 1071 | \ 'shortcut': 'n', 1072 | \ 'callback': 'SomeFunction', 1073 | \ 'parent': submenu }) 1074 | 1075 | call NERDTreeAddMenuItem({ 1076 | \ 'text': '(n)ested item 2', 1077 | \ 'shortcut': 'n', 1078 | \ 'callback': 'SomeFunction', 1079 | \ 'parent': submenu }) 1080 | < 1081 | This will create the following menu: > 1082 | -------------------- 1083 | a (t)op level menu item 1084 | a (s)ub menu 1085 | < 1086 | Where selecting "a (s)ub menu" will lead to a second menu: > 1087 | (n)ested item 1 1088 | (n)ested item 2 1089 | < 1090 | When any of the 3 concrete menu items are selected the function "SomeFunction" 1091 | will be called. 1092 | 1093 | ------------------------------------------------------------------------------ 1094 | NERDTreeRender() *NERDTreeRender()* 1095 | Re-renders the NERD tree buffer. Useful if you change the state of the 1096 | tree and you want to it to be reflected in the UI. 1097 | 1098 | ============================================================================== 1099 | 5. About *NERDTreeAbout* 1100 | 1101 | The author of the NERD tree is a terrible terrible monster called Martyzilla 1102 | who gobbles up small children with milk and sugar for breakfast. 1103 | 1104 | He can be reached at martin.grenfell at gmail dot com. He would love to hear 1105 | from you, so feel free to send him suggestions and/or comments about this 1106 | plugin. Don't be shy --- the worst he can do is slaughter you and stuff you in 1107 | the fridge for later ;) 1108 | 1109 | The latest stable versions can be found at 1110 | http://www.vim.org/scripts/script.php?script_id=1658 1111 | 1112 | The latest dev versions are on github 1113 | http://github.com/scrooloose/nerdtree 1114 | 1115 | 1116 | ============================================================================== 1117 | 6. Changelog *NERDTreeChangelog* 1118 | 1119 | 4.2.0 1120 | - Add NERDTreeDirArrows option to make the UI use pretty arrow chars 1121 | instead of the old +~| chars to define the tree structure (sickill) 1122 | - shift the syntax highlighting out into its own syntax file (gnap) 1123 | - add some mac specific options to the filesystem menu - for macvim 1124 | only (andersonfreitas) 1125 | - Add NERDTreeMinimalUI option to remove some non functional parts of the 1126 | nerdtree ui (camthompson) 1127 | - tweak the behaviour of :NERDTreeFind - see :help :NERDTreeFind for the 1128 | new behaviour (benjamingeiger) 1129 | - if no name is given to :Bookmark, make it default to the name of the 1130 | target file/dir (minyoung) 1131 | - use 'file' completion when doing copying, create, and move 1132 | operations (EvanDotPro) 1133 | - lots of misc bug fixes (paddyoloughlin, sdewald, camthompson, Vitaly 1134 | Bogdanov, AndrewRadev, mathias, scottstvnsn, kml, wycats, me RAWR!) 1135 | 1136 | 4.1.0 1137 | features: 1138 | - NERDTreeFind to reveal the node for the current buffer in the tree, 1139 | see |NERDTreeFind|. This effectively merges the FindInNERDTree plugin (by 1140 | Doug McInnes) into the script. 1141 | - make NERDTreeQuitOnOpen apply to the t/T keymaps too. Thanks to Stefan 1142 | Ritter and Rémi Prévost. 1143 | - truncate the root node if wider than the tree window. Thanks to Victor 1144 | Gonzalez. 1145 | 1146 | bugfixes: 1147 | - really fix window state restoring 1148 | - fix some win32 path escaping issues. Thanks to Stephan Baumeister, Ricky, 1149 | jfilip1024, and Chris Chambers 1150 | 1151 | 4.0.0 1152 | - add a new programmable menu system (see :help NERDTreeMenu). 1153 | - add new APIs to add menus/menu-items to the menu system as well as 1154 | custom key mappings to the NERD tree buffer (see :help NERDTreeAPI). 1155 | - removed the old API functions 1156 | - added a mapping to maximize/restore the size of nerd tree window, thanks 1157 | to Guillaume Duranceau for the patch. See :help NERDTree-A for details. 1158 | 1159 | - fix a bug where secondary nerd trees (netrw hijacked trees) and 1160 | NERDTreeQuitOnOpen didnt play nicely, thanks to Curtis Harvey. 1161 | - fix a bug where the script ignored directories whose name ended in a dot, 1162 | thanks to Aggelos Orfanakos for the patch. 1163 | - fix a bug when using the x mapping on the tree root, thanks to Bryan 1164 | Venteicher for the patch. 1165 | - fix a bug where the cursor position/window size of the nerd tree buffer 1166 | wasnt being stored on closing the window, thanks to Richard Hart. 1167 | - fix a bug where NERDTreeMirror would mirror the wrong tree 1168 | 1169 | 3.1.1 1170 | - fix a bug where a non-listed no-name buffer was getting created every 1171 | time the tree windows was created, thanks to Derek Wyatt and owen1 1172 | - make behave the same as the 'o' mapping 1173 | - some helptag fixes in the doc, thanks strull 1174 | - fix a bug when using :set nohidden and opening a file where the previous 1175 | buf was modified. Thanks iElectric 1176 | - other minor fixes 1177 | 1178 | 3.1.0 1179 | New features: 1180 | - add mappings to open files in a vsplit, see :help NERDTree-s and :help 1181 | NERDTree-gs 1182 | - make the statusline for the nerd tree window default to something 1183 | hopefully more useful. See :help 'NERDTreeStatusline' 1184 | Bugfixes: 1185 | - make the hijack netrw functionality work when vim is started with "vim 1186 | " (thanks to Alf Mikula for the patch). 1187 | - fix a bug where the CWD wasnt being changed for some operations even when 1188 | NERDTreeChDirMode==2 (thanks to Lucas S. Buchala) 1189 | - add -bar to all the nerd tree :commands so they can chain with other 1190 | :commands (thanks to tpope) 1191 | - fix bugs when ignorecase was set (thanks to nach) 1192 | - fix a bug with the relative path code (thanks to nach) 1193 | - fix a bug where doing a :cd would cause :NERDTreeToggle to fail (thanks nach) 1194 | 1195 | 1196 | 3.0.1 1197 | Bugfixes: 1198 | - fix bugs with :NERDTreeToggle and :NERDTreeMirror when 'hidden 1199 | was not set 1200 | - fix a bug where :NERDTree would fail if was relative and 1201 | didnt start with a ./ or ../ Thanks to James Kanze. 1202 | - make the q mapping work with secondary (:e style) trees, 1203 | thanks to jamessan 1204 | - fix a bunch of small bugs with secondary trees 1205 | 1206 | More insane refactoring. 1207 | 1208 | 3.0.0 1209 | - hijack netrw so that doing an :edit will put a NERD tree in 1210 | the window rather than a netrw browser. See :help 'NERDTreeHijackNetrw' 1211 | - allow sharing of trees across tabs, see :help :NERDTreeMirror 1212 | - remove "top" and "bottom" as valid settings for NERDTreeWinPos 1213 | - change the '' mapping to 'i' 1214 | - change the 'H' mapping to 'I' 1215 | - lots of refactoring 1216 | 1217 | ============================================================================== 1218 | 7. Credits *NERDTreeCredits* 1219 | 1220 | Thanks to the following people for testing, bug reports, ideas etc. Without 1221 | you I probably would have got bored of the hacking the NERD tree and 1222 | just downloaded pr0n instead. 1223 | 1224 | Tim Carey-Smith (halorgium) 1225 | Vigil 1226 | Nick Brettell 1227 | Thomas Scott Urban 1228 | Terrance Cohen 1229 | Yegappan Lakshmanan 1230 | Jason Mills 1231 | Michael Geddes (frogonwheels) 1232 | Yu Jun 1233 | Michael Madsen 1234 | AOYAMA Shotaro 1235 | Zhang Weiwu 1236 | Niels Aan de Brugh 1237 | Olivier Yiptong 1238 | Zhang Shuhan 1239 | Cory Echols 1240 | Piotr Czachur 1241 | Yuan Jiang 1242 | Matan Nassau 1243 | Maxim Kim 1244 | Charlton Wang 1245 | Matt Wozniski (godlygeek) 1246 | knekk 1247 | Sean Chou 1248 | Ryan Penn 1249 | Simon Peter Nicholls 1250 | Michael Foobar 1251 | Tomasz Chomiuk 1252 | Denis Pokataev 1253 | Tim Pope (tpope) 1254 | James Kanze 1255 | James Vega (jamessan) 1256 | Frederic Chanal (nach) 1257 | Alf Mikula 1258 | Lucas S. Buchala 1259 | Curtis Harvey 1260 | Guillaume Duranceau 1261 | Richard Hart (hates) 1262 | Doug McInnes 1263 | Stefan Ritter 1264 | Rémi Prévost 1265 | Victor Gonzalez 1266 | Stephan Baumeister 1267 | Ricky 1268 | jfilip1024 1269 | Chris Chambers 1270 | Vitaly Bogdanov 1271 | Patrick O'Loughlin (paddyoloughlin) 1272 | Cam Thompson (camthompson) 1273 | Marcin Kulik (sickill) 1274 | Steve DeWald (sdewald) 1275 | Ivan Necas (iNecas) 1276 | George Ang (gnap) 1277 | Evan Coury (EvanDotPro) 1278 | Andrew Radev (AndrewRadev) 1279 | Matt Gauger (mathias) 1280 | Scott Stevenson (scottstvnsn) 1281 | Anderson Freitas (andersonfreitas) 1282 | Kamil K. Lemański (kml) 1283 | Yehuda Katz (wycats) 1284 | Min-Young Wu (minyoung) 1285 | Benjamin Geiger (benjamingeiger) 1286 | 1287 | ============================================================================== 1288 | 8. License *NERDTreeLicense* 1289 | 1290 | The NERD tree is released under the wtfpl. 1291 | See http://sam.zoy.org/wtfpl/COPYING. 1292 | -------------------------------------------------------------------------------- /.vim/plugin/NERD_tree.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================ 2 | " File: NERD_tree.vim 3 | " Description: vim global plugin that provides a nice tree explorer 4 | " Maintainer: Martin Grenfell 5 | " Last Change: 28 December, 2011 6 | " License: This program is free software. It comes without any warranty, 7 | " to the extent permitted by applicable law. You can redistribute 8 | " it and/or modify it under the terms of the Do What The Fuck You 9 | " Want To Public License, Version 2, as published by Sam Hocevar. 10 | " See http://sam.zoy.org/wtfpl/COPYING for more details. 11 | " 12 | " ============================================================================ 13 | let s:NERD_tree_version = '4.2.0' 14 | 15 | " SECTION: Script init stuff {{{1 16 | "============================================================ 17 | if exists("loaded_nerd_tree") 18 | finish 19 | endif 20 | if v:version < 700 21 | echoerr "NERDTree: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!" 22 | finish 23 | endif 24 | let loaded_nerd_tree = 1 25 | 26 | "for line continuation - i.e dont want C in &cpo 27 | let s:old_cpo = &cpo 28 | set cpo&vim 29 | 30 | let s:running_windows = has("win16") || has("win32") || has("win64") 31 | 32 | "Function: s:initVariable() function {{{2 33 | "This function is used to initialise a given variable to a given value. The 34 | "variable is only initialised if it does not exist prior 35 | " 36 | "Args: 37 | "var: the name of the var to be initialised 38 | "value: the value to initialise var to 39 | " 40 | "Returns: 41 | "1 if the var is set, 0 otherwise 42 | function! s:initVariable(var, value) 43 | if !exists(a:var) 44 | exec 'let ' . a:var . ' = ' . "'" . substitute(a:value, "'", "''", "g") . "'" 45 | return 1 46 | endif 47 | return 0 48 | endfunction 49 | 50 | "SECTION: Init variable calls and other random constants {{{2 51 | call s:initVariable("g:NERDChristmasTree", 1) 52 | call s:initVariable("g:NERDTreeAutoCenter", 1) 53 | call s:initVariable("g:NERDTreeAutoCenterThreshold", 3) 54 | call s:initVariable("g:NERDTreeCaseSensitiveSort", 0) 55 | call s:initVariable("g:NERDTreeChDirMode", 0) 56 | call s:initVariable("g:NERDTreeMinimalUI", 0) 57 | if !exists("g:NERDTreeIgnore") 58 | let g:NERDTreeIgnore = ['\~$'] 59 | endif 60 | call s:initVariable("g:NERDTreeBookmarksFile", expand('$HOME') . '/.NERDTreeBookmarks') 61 | call s:initVariable("g:NERDTreeHighlightCursorline", 1) 62 | call s:initVariable("g:NERDTreeHijackNetrw", 1) 63 | call s:initVariable("g:NERDTreeMouseMode", 1) 64 | call s:initVariable("g:NERDTreeNotificationThreshold", 100) 65 | call s:initVariable("g:NERDTreeQuitOnOpen", 0) 66 | call s:initVariable("g:NERDTreeShowBookmarks", 0) 67 | call s:initVariable("g:NERDTreeShowFiles", 1) 68 | call s:initVariable("g:NERDTreeShowHidden", 0) 69 | call s:initVariable("g:NERDTreeShowLineNumbers", 0) 70 | call s:initVariable("g:NERDTreeSortDirs", 1) 71 | call s:initVariable("g:NERDTreeDirArrows", !s:running_windows) 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 | "we need to use this number many times for sorting... so we calculate it only 83 | "once here 84 | let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*') 85 | 86 | if !exists('g:NERDTreeStatusline') 87 | 88 | "the exists() crap here is a hack to stop vim spazzing out when 89 | "loading a session that was created with an open nerd tree. It spazzes 90 | "because it doesnt store b:NERDTreeRoot (its a b: var, and its a hash) 91 | let g:NERDTreeStatusline = "%{exists('b:NERDTreeRoot')?b:NERDTreeRoot.path.str():''}" 92 | 93 | endif 94 | call s:initVariable("g:NERDTreeWinPos", "left") 95 | call s:initVariable("g:NERDTreeWinSize", 31) 96 | 97 | "init the shell commands that will be used to copy nodes, and remove dir trees 98 | " 99 | "Note: the space after the command is important 100 | if s:running_windows 101 | call s:initVariable("g:NERDTreeRemoveDirCmd", 'rmdir /s /q ') 102 | else 103 | call s:initVariable("g:NERDTreeRemoveDirCmd", 'rm -rf ') 104 | call s:initVariable("g:NERDTreeCopyCmd", 'cp -r ') 105 | endif 106 | 107 | 108 | "SECTION: Init variable calls for key mappings {{{2 109 | call s:initVariable("g:NERDTreeMapActivateNode", "o") 110 | call s:initVariable("g:NERDTreeMapChangeRoot", "C") 111 | call s:initVariable("g:NERDTreeMapChdir", "cd") 112 | call s:initVariable("g:NERDTreeMapCloseChildren", "X") 113 | call s:initVariable("g:NERDTreeMapCloseDir", "x") 114 | call s:initVariable("g:NERDTreeMapDeleteBookmark", "D") 115 | call s:initVariable("g:NERDTreeMapMenu", "m") 116 | call s:initVariable("g:NERDTreeMapHelp", "?") 117 | call s:initVariable("g:NERDTreeMapJumpFirstChild", "K") 118 | call s:initVariable("g:NERDTreeMapJumpLastChild", "J") 119 | call s:initVariable("g:NERDTreeMapJumpNextSibling", "") 120 | call s:initVariable("g:NERDTreeMapJumpParent", "p") 121 | call s:initVariable("g:NERDTreeMapJumpPrevSibling", "") 122 | call s:initVariable("g:NERDTreeMapJumpRoot", "P") 123 | call s:initVariable("g:NERDTreeMapOpenExpl", "e") 124 | call s:initVariable("g:NERDTreeMapOpenInTab", "t") 125 | call s:initVariable("g:NERDTreeMapOpenInTabSilent", "T") 126 | call s:initVariable("g:NERDTreeMapOpenRecursively", "O") 127 | call s:initVariable("g:NERDTreeMapOpenSplit", "i") 128 | call s:initVariable("g:NERDTreeMapOpenVSplit", "s") 129 | call s:initVariable("g:NERDTreeMapPreview", "g" . NERDTreeMapActivateNode) 130 | call s:initVariable("g:NERDTreeMapPreviewSplit", "g" . NERDTreeMapOpenSplit) 131 | call s:initVariable("g:NERDTreeMapPreviewVSplit", "g" . NERDTreeMapOpenVSplit) 132 | call s:initVariable("g:NERDTreeMapQuit", "q") 133 | call s:initVariable("g:NERDTreeMapRefresh", "r") 134 | call s:initVariable("g:NERDTreeMapRefreshRoot", "R") 135 | call s:initVariable("g:NERDTreeMapToggleBookmarks", "B") 136 | call s:initVariable("g:NERDTreeMapToggleFiles", "F") 137 | call s:initVariable("g:NERDTreeMapToggleFilters", "f") 138 | call s:initVariable("g:NERDTreeMapToggleHidden", "I") 139 | call s:initVariable("g:NERDTreeMapToggleZoom", "A") 140 | call s:initVariable("g:NERDTreeMapUpdir", "u") 141 | call s:initVariable("g:NERDTreeMapUpdirKeepOpen", "U") 142 | 143 | "SECTION: Script level variable declaration{{{2 144 | if s:running_windows 145 | let s:escape_chars = " `\|\"#%&,?()\*^<>" 146 | else 147 | let s:escape_chars = " \\`\|\"#%&,?()\*^<>[]" 148 | endif 149 | let s:NERDTreeBufName = 'NERD_tree_' 150 | 151 | let s:tree_wid = 2 152 | let s:tree_markup_reg = '^[ `|]*[\-+~▾▸ ]\+' 153 | let s:tree_up_dir_line = '.. (up a dir)' 154 | 155 | "the number to add to the nerd tree buffer name to make the buf name unique 156 | let s:next_buffer_number = 1 157 | 158 | " SECTION: Commands {{{1 159 | "============================================================ 160 | "init the command that users start the nerd tree with 161 | command! -n=? -complete=dir -bar NERDTree :call s:initNerdTree('') 162 | command! -n=? -complete=dir -bar NERDTreeToggle :call s:toggle('') 163 | command! -n=0 -bar NERDTreeClose :call s:closeTreeIfOpen() 164 | command! -n=1 -complete=customlist,s:completeBookmarks -bar NERDTreeFromBookmark call s:initNerdTree('') 165 | command! -n=0 -bar NERDTreeMirror call s:initNerdTreeMirror() 166 | command! -n=0 -bar NERDTreeFind call s:findAndRevealPath() 167 | " SECTION: Auto commands {{{1 168 | "============================================================ 169 | augroup NERDTree 170 | "Save the cursor position whenever we close the nerd tree 171 | exec "autocmd BufWinLeave ". s:NERDTreeBufName ."* call saveScreenState()" 172 | 173 | "disallow insert mode in the NERDTree 174 | exec "autocmd BufEnter ". s:NERDTreeBufName ."* stopinsert" 175 | 176 | "cache bookmarks when vim loads 177 | autocmd VimEnter * call s:Bookmark.CacheBookmarks(0) 178 | 179 | "load all nerdtree plugins after vim starts 180 | autocmd VimEnter * runtime! nerdtree_plugin/**/*.vim 181 | augroup END 182 | 183 | if g:NERDTreeHijackNetrw 184 | augroup NERDTreeHijackNetrw 185 | autocmd VimEnter * silent! autocmd! FileExplorer 186 | au BufEnter,VimEnter * call s:checkForBrowse(expand("")) 187 | augroup END 188 | endif 189 | 190 | "SECTION: Classes {{{1 191 | "============================================================ 192 | "CLASS: Bookmark {{{2 193 | "============================================================ 194 | let s:Bookmark = {} 195 | " FUNCTION: Bookmark.activate() {{{3 196 | function! s:Bookmark.activate() 197 | if self.path.isDirectory 198 | call self.toRoot() 199 | else 200 | if self.validate() 201 | let n = s:TreeFileNode.New(self.path) 202 | call n.open() 203 | call s:closeTreeIfQuitOnOpen() 204 | endif 205 | endif 206 | endfunction 207 | " FUNCTION: Bookmark.AddBookmark(name, path) {{{3 208 | " Class method to add a new bookmark to the list, if a previous bookmark exists 209 | " with the same name, just update the path for that bookmark 210 | function! s:Bookmark.AddBookmark(name, path) 211 | for i in s:Bookmark.Bookmarks() 212 | if i.name ==# a:name 213 | let i.path = a:path 214 | return 215 | endif 216 | endfor 217 | call add(s:Bookmark.Bookmarks(), s:Bookmark.New(a:name, a:path)) 218 | call s:Bookmark.Sort() 219 | endfunction 220 | " Function: Bookmark.Bookmarks() {{{3 221 | " Class method to get all bookmarks. Lazily initializes the bookmarks global 222 | " variable 223 | function! s:Bookmark.Bookmarks() 224 | if !exists("g:NERDTreeBookmarks") 225 | let g:NERDTreeBookmarks = [] 226 | endif 227 | return g:NERDTreeBookmarks 228 | endfunction 229 | " Function: Bookmark.BookmarkExistsFor(name) {{{3 230 | " class method that returns 1 if a bookmark with the given name is found, 0 231 | " otherwise 232 | function! s:Bookmark.BookmarkExistsFor(name) 233 | try 234 | call s:Bookmark.BookmarkFor(a:name) 235 | return 1 236 | catch /^NERDTree.BookmarkNotFoundError/ 237 | return 0 238 | endtry 239 | endfunction 240 | " Function: Bookmark.BookmarkFor(name) {{{3 241 | " Class method to get the bookmark that has the given name. {} is return if no 242 | " bookmark is found 243 | function! s:Bookmark.BookmarkFor(name) 244 | for i in s:Bookmark.Bookmarks() 245 | if i.name ==# a:name 246 | return i 247 | endif 248 | endfor 249 | throw "NERDTree.BookmarkNotFoundError: no bookmark found for name: \"". a:name .'"' 250 | endfunction 251 | " Function: Bookmark.BookmarkNames() {{{3 252 | " Class method to return an array of all bookmark names 253 | function! s:Bookmark.BookmarkNames() 254 | let names = [] 255 | for i in s:Bookmark.Bookmarks() 256 | call add(names, i.name) 257 | endfor 258 | return names 259 | endfunction 260 | " FUNCTION: Bookmark.CacheBookmarks(silent) {{{3 261 | " Class method to read all bookmarks from the bookmarks file intialize 262 | " bookmark objects for each one. 263 | " 264 | " Args: 265 | " silent - dont echo an error msg if invalid bookmarks are found 266 | function! s:Bookmark.CacheBookmarks(silent) 267 | if filereadable(g:NERDTreeBookmarksFile) 268 | let g:NERDTreeBookmarks = [] 269 | let g:NERDTreeInvalidBookmarks = [] 270 | let bookmarkStrings = readfile(g:NERDTreeBookmarksFile) 271 | let invalidBookmarksFound = 0 272 | for i in bookmarkStrings 273 | 274 | "ignore blank lines 275 | if i != '' 276 | 277 | let name = substitute(i, '^\(.\{-}\) .*$', '\1', '') 278 | let path = substitute(i, '^.\{-} \(.*\)$', '\1', '') 279 | 280 | try 281 | let bookmark = s:Bookmark.New(name, s:Path.New(path)) 282 | call add(g:NERDTreeBookmarks, bookmark) 283 | catch /^NERDTree.InvalidArgumentsError/ 284 | call add(g:NERDTreeInvalidBookmarks, i) 285 | let invalidBookmarksFound += 1 286 | endtry 287 | endif 288 | endfor 289 | if invalidBookmarksFound 290 | call s:Bookmark.Write() 291 | if !a:silent 292 | call s:echo(invalidBookmarksFound . " invalid bookmarks were read. See :help NERDTreeInvalidBookmarks for info.") 293 | endif 294 | endif 295 | call s:Bookmark.Sort() 296 | endif 297 | endfunction 298 | " FUNCTION: Bookmark.compareTo(otherbookmark) {{{3 299 | " Compare these two bookmarks for sorting purposes 300 | function! s:Bookmark.compareTo(otherbookmark) 301 | return a:otherbookmark.name < self.name 302 | endfunction 303 | " FUNCTION: Bookmark.ClearAll() {{{3 304 | " Class method to delete all bookmarks. 305 | function! s:Bookmark.ClearAll() 306 | for i in s:Bookmark.Bookmarks() 307 | call i.delete() 308 | endfor 309 | call s:Bookmark.Write() 310 | endfunction 311 | " FUNCTION: Bookmark.delete() {{{3 312 | " Delete this bookmark. If the node for this bookmark is under the current 313 | " root, then recache bookmarks for its Path object 314 | function! s:Bookmark.delete() 315 | let node = {} 316 | try 317 | let node = self.getNode(1) 318 | catch /^NERDTree.BookmarkedNodeNotFoundError/ 319 | endtry 320 | call remove(s:Bookmark.Bookmarks(), index(s:Bookmark.Bookmarks(), self)) 321 | if !empty(node) 322 | call node.path.cacheDisplayString() 323 | endif 324 | call s:Bookmark.Write() 325 | endfunction 326 | " FUNCTION: Bookmark.getNode(searchFromAbsoluteRoot) {{{3 327 | " Gets the treenode for this bookmark 328 | " 329 | " Args: 330 | " searchFromAbsoluteRoot: specifies whether we should search from the current 331 | " tree root, or the highest cached node 332 | function! s:Bookmark.getNode(searchFromAbsoluteRoot) 333 | let searchRoot = a:searchFromAbsoluteRoot ? s:TreeDirNode.AbsoluteTreeRoot() : b:NERDTreeRoot 334 | let targetNode = searchRoot.findNode(self.path) 335 | if empty(targetNode) 336 | throw "NERDTree.BookmarkedNodeNotFoundError: no node was found for bookmark: " . self.name 337 | endif 338 | return targetNode 339 | endfunction 340 | " FUNCTION: Bookmark.GetNodeForName(name, searchFromAbsoluteRoot) {{{3 341 | " Class method that finds the bookmark with the given name and returns the 342 | " treenode for it. 343 | function! s:Bookmark.GetNodeForName(name, searchFromAbsoluteRoot) 344 | let bookmark = s:Bookmark.BookmarkFor(a:name) 345 | return bookmark.getNode(a:searchFromAbsoluteRoot) 346 | endfunction 347 | " FUNCTION: Bookmark.GetSelected() {{{3 348 | " returns the Bookmark the cursor is over, or {} 349 | function! s:Bookmark.GetSelected() 350 | let line = getline(".") 351 | let name = substitute(line, '^>\(.\{-}\) .\+$', '\1', '') 352 | if name != line 353 | try 354 | return s:Bookmark.BookmarkFor(name) 355 | catch /^NERDTree.BookmarkNotFoundError/ 356 | return {} 357 | endtry 358 | endif 359 | return {} 360 | endfunction 361 | 362 | " Function: Bookmark.InvalidBookmarks() {{{3 363 | " Class method to get all invalid bookmark strings read from the bookmarks 364 | " file 365 | function! s:Bookmark.InvalidBookmarks() 366 | if !exists("g:NERDTreeInvalidBookmarks") 367 | let g:NERDTreeInvalidBookmarks = [] 368 | endif 369 | return g:NERDTreeInvalidBookmarks 370 | endfunction 371 | " FUNCTION: Bookmark.mustExist() {{{3 372 | function! s:Bookmark.mustExist() 373 | if !self.path.exists() 374 | call s:Bookmark.CacheBookmarks(1) 375 | throw "NERDTree.BookmarkPointsToInvalidLocationError: the bookmark \"". 376 | \ self.name ."\" points to a non existing location: \"". self.path.str() 377 | endif 378 | endfunction 379 | " FUNCTION: Bookmark.New(name, path) {{{3 380 | " Create a new bookmark object with the given name and path object 381 | function! s:Bookmark.New(name, path) 382 | if a:name =~# ' ' 383 | throw "NERDTree.IllegalBookmarkNameError: illegal name:" . a:name 384 | endif 385 | 386 | let newBookmark = copy(self) 387 | let newBookmark.name = a:name 388 | let newBookmark.path = a:path 389 | return newBookmark 390 | endfunction 391 | " FUNCTION: Bookmark.openInNewTab(options) {{{3 392 | " Create a new bookmark object with the given name and path object 393 | function! s:Bookmark.openInNewTab(options) 394 | let currentTab = tabpagenr() 395 | if self.path.isDirectory 396 | tabnew 397 | call s:initNerdTree(self.name) 398 | else 399 | exec "tabedit " . self.path.str({'format': 'Edit'}) 400 | endif 401 | 402 | if has_key(a:options, 'stayInCurrentTab') 403 | exec "tabnext " . currentTab 404 | endif 405 | endfunction 406 | " Function: Bookmark.setPath(path) {{{3 407 | " makes this bookmark point to the given path 408 | function! s:Bookmark.setPath(path) 409 | let self.path = a:path 410 | endfunction 411 | " Function: Bookmark.Sort() {{{3 412 | " Class method that sorts all bookmarks 413 | function! s:Bookmark.Sort() 414 | let CompareFunc = function("s:compareBookmarks") 415 | call sort(s:Bookmark.Bookmarks(), CompareFunc) 416 | endfunction 417 | " Function: Bookmark.str() {{{3 418 | " Get the string that should be rendered in the view for this bookmark 419 | function! s:Bookmark.str() 420 | let pathStrMaxLen = winwidth(s:getTreeWinNum()) - 4 - len(self.name) 421 | if &nu 422 | let pathStrMaxLen = pathStrMaxLen - &numberwidth 423 | endif 424 | 425 | let pathStr = self.path.str({'format': 'UI'}) 426 | if len(pathStr) > pathStrMaxLen 427 | let pathStr = '<' . strpart(pathStr, len(pathStr) - pathStrMaxLen) 428 | endif 429 | return '>' . self.name . ' ' . pathStr 430 | endfunction 431 | " FUNCTION: Bookmark.toRoot() {{{3 432 | " Make the node for this bookmark the new tree root 433 | function! s:Bookmark.toRoot() 434 | if self.validate() 435 | try 436 | let targetNode = self.getNode(1) 437 | catch /^NERDTree.BookmarkedNodeNotFoundError/ 438 | let targetNode = s:TreeFileNode.New(s:Bookmark.BookmarkFor(self.name).path) 439 | endtry 440 | call targetNode.makeRoot() 441 | call s:renderView() 442 | call targetNode.putCursorHere(0, 0) 443 | endif 444 | endfunction 445 | " FUNCTION: Bookmark.ToRoot(name) {{{3 446 | " Make the node for this bookmark the new tree root 447 | function! s:Bookmark.ToRoot(name) 448 | let bookmark = s:Bookmark.BookmarkFor(a:name) 449 | call bookmark.toRoot() 450 | endfunction 451 | 452 | 453 | "FUNCTION: Bookmark.validate() {{{3 454 | function! s:Bookmark.validate() 455 | if self.path.exists() 456 | return 1 457 | else 458 | call s:Bookmark.CacheBookmarks(1) 459 | call s:renderView() 460 | call s:echo(self.name . "now points to an invalid location. See :help NERDTreeInvalidBookmarks for info.") 461 | return 0 462 | endif 463 | endfunction 464 | 465 | " Function: Bookmark.Write() {{{3 466 | " Class method to write all bookmarks to the bookmarks file 467 | function! s:Bookmark.Write() 468 | let bookmarkStrings = [] 469 | for i in s:Bookmark.Bookmarks() 470 | call add(bookmarkStrings, i.name . ' ' . i.path.str()) 471 | endfor 472 | 473 | "add a blank line before the invalid ones 474 | call add(bookmarkStrings, "") 475 | 476 | for j in s:Bookmark.InvalidBookmarks() 477 | call add(bookmarkStrings, j) 478 | endfor 479 | call writefile(bookmarkStrings, g:NERDTreeBookmarksFile) 480 | endfunction 481 | "CLASS: KeyMap {{{2 482 | "============================================================ 483 | let s:KeyMap = {} 484 | "FUNCTION: KeyMap.All() {{{3 485 | function! s:KeyMap.All() 486 | if !exists("s:keyMaps") 487 | let s:keyMaps = [] 488 | endif 489 | return s:keyMaps 490 | endfunction 491 | 492 | "FUNCTION: KeyMap.BindAll() {{{3 493 | function! s:KeyMap.BindAll() 494 | for i in s:KeyMap.All() 495 | call i.bind() 496 | endfor 497 | endfunction 498 | 499 | "FUNCTION: KeyMap.bind() {{{3 500 | function! s:KeyMap.bind() 501 | exec "nnoremap ". self.key ." :call ". self.callback ."()" 502 | endfunction 503 | 504 | "FUNCTION: KeyMap.Create(options) {{{3 505 | function! s:KeyMap.Create(options) 506 | let newKeyMap = copy(self) 507 | let newKeyMap.key = a:options['key'] 508 | let newKeyMap.quickhelpText = a:options['quickhelpText'] 509 | let newKeyMap.callback = a:options['callback'] 510 | call add(s:KeyMap.All(), newKeyMap) 511 | endfunction 512 | "CLASS: MenuController {{{2 513 | "============================================================ 514 | let s:MenuController = {} 515 | "FUNCTION: MenuController.New(menuItems) {{{3 516 | "create a new menu controller that operates on the given menu items 517 | function! s:MenuController.New(menuItems) 518 | let newMenuController = copy(self) 519 | if a:menuItems[0].isSeparator() 520 | let newMenuController.menuItems = a:menuItems[1:-1] 521 | else 522 | let newMenuController.menuItems = a:menuItems 523 | endif 524 | return newMenuController 525 | endfunction 526 | 527 | "FUNCTION: MenuController.showMenu() {{{3 528 | "start the main loop of the menu and get the user to choose/execute a menu 529 | "item 530 | function! s:MenuController.showMenu() 531 | call self._saveOptions() 532 | 533 | try 534 | let self.selection = 0 535 | 536 | let done = 0 537 | while !done 538 | redraw! 539 | call self._echoPrompt() 540 | let key = nr2char(getchar()) 541 | let done = self._handleKeypress(key) 542 | endwhile 543 | finally 544 | call self._restoreOptions() 545 | endtry 546 | 547 | if self.selection != -1 548 | let m = self._current() 549 | call m.execute() 550 | endif 551 | endfunction 552 | 553 | "FUNCTION: MenuController._echoPrompt() {{{3 554 | function! s:MenuController._echoPrompt() 555 | echo "NERDTree Menu. Use j/k/enter and the shortcuts indicated" 556 | echo "==========================================================" 557 | 558 | for i in range(0, len(self.menuItems)-1) 559 | if self.selection == i 560 | echo "> " . self.menuItems[i].text 561 | else 562 | echo " " . self.menuItems[i].text 563 | endif 564 | endfor 565 | endfunction 566 | 567 | "FUNCTION: MenuController._current(key) {{{3 568 | "get the MenuItem that is currently selected 569 | function! s:MenuController._current() 570 | return self.menuItems[self.selection] 571 | endfunction 572 | 573 | "FUNCTION: MenuController._handleKeypress(key) {{{3 574 | "change the selection (if appropriate) and return 1 if the user has made 575 | "their choice, 0 otherwise 576 | function! s:MenuController._handleKeypress(key) 577 | if a:key == 'j' 578 | call self._cursorDown() 579 | elseif a:key == 'k' 580 | call self._cursorUp() 581 | elseif a:key == nr2char(27) "escape 582 | let self.selection = -1 583 | return 1 584 | elseif a:key == "\r" || a:key == "\n" "enter and ctrl-j 585 | return 1 586 | else 587 | let index = self._nextIndexFor(a:key) 588 | if index != -1 589 | let self.selection = index 590 | if len(self._allIndexesFor(a:key)) == 1 591 | return 1 592 | endif 593 | endif 594 | endif 595 | 596 | return 0 597 | endfunction 598 | 599 | "FUNCTION: MenuController._allIndexesFor(shortcut) {{{3 600 | "get indexes to all menu items with the given shortcut 601 | function! s:MenuController._allIndexesFor(shortcut) 602 | let toReturn = [] 603 | 604 | for i in range(0, len(self.menuItems)-1) 605 | if self.menuItems[i].shortcut == a:shortcut 606 | call add(toReturn, i) 607 | endif 608 | endfor 609 | 610 | return toReturn 611 | endfunction 612 | 613 | "FUNCTION: MenuController._nextIndexFor(shortcut) {{{3 614 | "get the index to the next menu item with the given shortcut, starts from the 615 | "current cursor location and wraps around to the top again if need be 616 | function! s:MenuController._nextIndexFor(shortcut) 617 | for i in range(self.selection+1, len(self.menuItems)-1) 618 | if self.menuItems[i].shortcut == a:shortcut 619 | return i 620 | endif 621 | endfor 622 | 623 | for i in range(0, self.selection) 624 | if self.menuItems[i].shortcut == a:shortcut 625 | return i 626 | endif 627 | endfor 628 | 629 | return -1 630 | endfunction 631 | 632 | "FUNCTION: MenuController._setCmdheight() {{{3 633 | "sets &cmdheight to whatever is needed to display the menu 634 | function! s:MenuController._setCmdheight() 635 | let &cmdheight = len(self.menuItems) + 3 636 | endfunction 637 | 638 | "FUNCTION: MenuController._saveOptions() {{{3 639 | "set any vim options that are required to make the menu work (saving their old 640 | "values) 641 | function! s:MenuController._saveOptions() 642 | let self._oldLazyredraw = &lazyredraw 643 | let self._oldCmdheight = &cmdheight 644 | set nolazyredraw 645 | call self._setCmdheight() 646 | endfunction 647 | 648 | "FUNCTION: MenuController._restoreOptions() {{{3 649 | "restore the options we saved in _saveOptions() 650 | function! s:MenuController._restoreOptions() 651 | let &cmdheight = self._oldCmdheight 652 | let &lazyredraw = self._oldLazyredraw 653 | endfunction 654 | 655 | "FUNCTION: MenuController._cursorDown() {{{3 656 | "move the cursor to the next menu item, skipping separators 657 | function! s:MenuController._cursorDown() 658 | let done = 0 659 | while !done 660 | if self.selection < len(self.menuItems)-1 661 | let self.selection += 1 662 | else 663 | let self.selection = 0 664 | endif 665 | 666 | if !self._current().isSeparator() 667 | let done = 1 668 | endif 669 | endwhile 670 | endfunction 671 | 672 | "FUNCTION: MenuController._cursorUp() {{{3 673 | "move the cursor to the previous menu item, skipping separators 674 | function! s:MenuController._cursorUp() 675 | let done = 0 676 | while !done 677 | if self.selection > 0 678 | let self.selection -= 1 679 | else 680 | let self.selection = len(self.menuItems)-1 681 | endif 682 | 683 | if !self._current().isSeparator() 684 | let done = 1 685 | endif 686 | endwhile 687 | endfunction 688 | 689 | "CLASS: MenuItem {{{2 690 | "============================================================ 691 | let s:MenuItem = {} 692 | "FUNCTION: MenuItem.All() {{{3 693 | "get all top level menu items 694 | function! s:MenuItem.All() 695 | if !exists("s:menuItems") 696 | let s:menuItems = [] 697 | endif 698 | return s:menuItems 699 | endfunction 700 | 701 | "FUNCTION: MenuItem.AllEnabled() {{{3 702 | "get all top level menu items that are currently enabled 703 | function! s:MenuItem.AllEnabled() 704 | let toReturn = [] 705 | for i in s:MenuItem.All() 706 | if i.enabled() 707 | call add(toReturn, i) 708 | endif 709 | endfor 710 | return toReturn 711 | endfunction 712 | 713 | "FUNCTION: MenuItem.Create(options) {{{3 714 | "make a new menu item and add it to the global list 715 | function! s:MenuItem.Create(options) 716 | let newMenuItem = copy(self) 717 | 718 | let newMenuItem.text = a:options['text'] 719 | let newMenuItem.shortcut = a:options['shortcut'] 720 | let newMenuItem.children = [] 721 | 722 | let newMenuItem.isActiveCallback = -1 723 | if has_key(a:options, 'isActiveCallback') 724 | let newMenuItem.isActiveCallback = a:options['isActiveCallback'] 725 | endif 726 | 727 | let newMenuItem.callback = -1 728 | if has_key(a:options, 'callback') 729 | let newMenuItem.callback = a:options['callback'] 730 | endif 731 | 732 | if has_key(a:options, 'parent') 733 | call add(a:options['parent'].children, newMenuItem) 734 | else 735 | call add(s:MenuItem.All(), newMenuItem) 736 | endif 737 | 738 | return newMenuItem 739 | endfunction 740 | 741 | "FUNCTION: MenuItem.CreateSeparator(options) {{{3 742 | "make a new separator menu item and add it to the global list 743 | function! s:MenuItem.CreateSeparator(options) 744 | let standard_options = { 'text': '--------------------', 745 | \ 'shortcut': -1, 746 | \ 'callback': -1 } 747 | let options = extend(a:options, standard_options, "force") 748 | 749 | return s:MenuItem.Create(options) 750 | endfunction 751 | 752 | "FUNCTION: MenuItem.CreateSubmenu(options) {{{3 753 | "make a new submenu and add it to global list 754 | function! s:MenuItem.CreateSubmenu(options) 755 | let standard_options = { 'callback': -1 } 756 | let options = extend(a:options, standard_options, "force") 757 | 758 | return s:MenuItem.Create(options) 759 | endfunction 760 | 761 | "FUNCTION: MenuItem.enabled() {{{3 762 | "return 1 if this menu item should be displayed 763 | " 764 | "delegates off to the isActiveCallback, and defaults to 1 if no callback was 765 | "specified 766 | function! s:MenuItem.enabled() 767 | if self.isActiveCallback != -1 768 | return {self.isActiveCallback}() 769 | endif 770 | return 1 771 | endfunction 772 | 773 | "FUNCTION: MenuItem.execute() {{{3 774 | "perform the action behind this menu item, if this menuitem has children then 775 | "display a new menu for them, otherwise deletegate off to the menuitem's 776 | "callback 777 | function! s:MenuItem.execute() 778 | if len(self.children) 779 | let mc = s:MenuController.New(self.children) 780 | call mc.showMenu() 781 | else 782 | if self.callback != -1 783 | call {self.callback}() 784 | endif 785 | endif 786 | endfunction 787 | 788 | "FUNCTION: MenuItem.isSeparator() {{{3 789 | "return 1 if this menuitem is a separator 790 | function! s:MenuItem.isSeparator() 791 | return self.callback == -1 && self.children == [] 792 | endfunction 793 | 794 | "FUNCTION: MenuItem.isSubmenu() {{{3 795 | "return 1 if this menuitem is a submenu 796 | function! s:MenuItem.isSubmenu() 797 | return self.callback == -1 && !empty(self.children) 798 | endfunction 799 | 800 | "CLASS: TreeFileNode {{{2 801 | "This class is the parent of the TreeDirNode class and constitures the 802 | "'Component' part of the composite design pattern between the treenode 803 | "classes. 804 | "============================================================ 805 | let s:TreeFileNode = {} 806 | "FUNCTION: TreeFileNode.activate(forceKeepWinOpen) {{{3 807 | function! s:TreeFileNode.activate(forceKeepWinOpen) 808 | call self.open() 809 | if !a:forceKeepWinOpen 810 | call s:closeTreeIfQuitOnOpen() 811 | end 812 | endfunction 813 | "FUNCTION: TreeFileNode.bookmark(name) {{{3 814 | "bookmark this node with a:name 815 | function! s:TreeFileNode.bookmark(name) 816 | 817 | "if a bookmark exists with the same name and the node is cached then save 818 | "it so we can update its display string 819 | let oldMarkedNode = {} 820 | try 821 | let oldMarkedNode = s:Bookmark.GetNodeForName(a:name, 1) 822 | catch /^NERDTree.BookmarkNotFoundError/ 823 | catch /^NERDTree.BookmarkedNodeNotFoundError/ 824 | endtry 825 | 826 | call s:Bookmark.AddBookmark(a:name, self.path) 827 | call self.path.cacheDisplayString() 828 | call s:Bookmark.Write() 829 | 830 | if !empty(oldMarkedNode) 831 | call oldMarkedNode.path.cacheDisplayString() 832 | endif 833 | endfunction 834 | "FUNCTION: TreeFileNode.cacheParent() {{{3 835 | "initializes self.parent if it isnt already 836 | function! s:TreeFileNode.cacheParent() 837 | if empty(self.parent) 838 | let parentPath = self.path.getParent() 839 | if parentPath.equals(self.path) 840 | throw "NERDTree.CannotCacheParentError: already at root" 841 | endif 842 | let self.parent = s:TreeFileNode.New(parentPath) 843 | endif 844 | endfunction 845 | "FUNCTION: TreeFileNode.compareNodes {{{3 846 | "This is supposed to be a class level method but i cant figure out how to 847 | "get func refs to work from a dict.. 848 | " 849 | "A class level method that compares two nodes 850 | " 851 | "Args: 852 | "n1, n2: the 2 nodes to compare 853 | function! s:compareNodes(n1, n2) 854 | return a:n1.path.compareTo(a:n2.path) 855 | endfunction 856 | 857 | "FUNCTION: TreeFileNode.clearBoomarks() {{{3 858 | function! s:TreeFileNode.clearBoomarks() 859 | for i in s:Bookmark.Bookmarks() 860 | if i.path.equals(self.path) 861 | call i.delete() 862 | end 863 | endfor 864 | call self.path.cacheDisplayString() 865 | endfunction 866 | "FUNCTION: TreeFileNode.copy(dest) {{{3 867 | function! s:TreeFileNode.copy(dest) 868 | call self.path.copy(a:dest) 869 | let newPath = s:Path.New(a:dest) 870 | let parent = b:NERDTreeRoot.findNode(newPath.getParent()) 871 | if !empty(parent) 872 | call parent.refresh() 873 | return parent.findNode(newPath) 874 | else 875 | return {} 876 | endif 877 | endfunction 878 | 879 | "FUNCTION: TreeFileNode.delete {{{3 880 | "Removes this node from the tree and calls the Delete method for its path obj 881 | function! s:TreeFileNode.delete() 882 | call self.path.delete() 883 | call self.parent.removeChild(self) 884 | endfunction 885 | 886 | "FUNCTION: TreeFileNode.displayString() {{{3 887 | " 888 | "Returns a string that specifies how the node should be represented as a 889 | "string 890 | " 891 | "Return: 892 | "a string that can be used in the view to represent this node 893 | function! s:TreeFileNode.displayString() 894 | return self.path.displayString() 895 | endfunction 896 | 897 | "FUNCTION: TreeFileNode.equals(treenode) {{{3 898 | " 899 | "Compares this treenode to the input treenode and returns 1 if they are the 900 | "same node. 901 | " 902 | "Use this method instead of == because sometimes when the treenodes contain 903 | "many children, vim seg faults when doing == 904 | " 905 | "Args: 906 | "treenode: the other treenode to compare to 907 | function! s:TreeFileNode.equals(treenode) 908 | return self.path.str() ==# a:treenode.path.str() 909 | endfunction 910 | 911 | "FUNCTION: TreeFileNode.findNode(path) {{{3 912 | "Returns self if this node.path.Equals the given path. 913 | "Returns {} if not equal. 914 | " 915 | "Args: 916 | "path: the path object to compare against 917 | function! s:TreeFileNode.findNode(path) 918 | if a:path.equals(self.path) 919 | return self 920 | endif 921 | return {} 922 | endfunction 923 | "FUNCTION: TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) {{{3 924 | " 925 | "Finds the next sibling for this node in the indicated direction. This sibling 926 | "must be a directory and may/may not have children as specified. 927 | " 928 | "Args: 929 | "direction: 0 if you want to find the previous sibling, 1 for the next sibling 930 | " 931 | "Return: 932 | "a treenode object or {} if no appropriate sibling could be found 933 | function! s:TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) 934 | "if we have no parent then we can have no siblings 935 | if self.parent != {} 936 | let nextSibling = self.findSibling(a:direction) 937 | 938 | while nextSibling != {} 939 | if nextSibling.path.isDirectory && nextSibling.hasVisibleChildren() && nextSibling.isOpen 940 | return nextSibling 941 | endif 942 | let nextSibling = nextSibling.findSibling(a:direction) 943 | endwhile 944 | endif 945 | 946 | return {} 947 | endfunction 948 | "FUNCTION: TreeFileNode.findSibling(direction) {{{3 949 | " 950 | "Finds the next sibling for this node in the indicated direction 951 | " 952 | "Args: 953 | "direction: 0 if you want to find the previous sibling, 1 for the next sibling 954 | " 955 | "Return: 956 | "a treenode object or {} if no sibling could be found 957 | function! s:TreeFileNode.findSibling(direction) 958 | "if we have no parent then we can have no siblings 959 | if self.parent != {} 960 | 961 | "get the index of this node in its parents children 962 | let siblingIndx = self.parent.getChildIndex(self.path) 963 | 964 | if siblingIndx != -1 965 | "move a long to the next potential sibling node 966 | let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1 967 | 968 | "keep moving along to the next sibling till we find one that is valid 969 | let numSiblings = self.parent.getChildCount() 970 | while siblingIndx >= 0 && siblingIndx < numSiblings 971 | 972 | "if the next node is not an ignored node (i.e. wont show up in the 973 | "view) then return it 974 | if self.parent.children[siblingIndx].path.ignore() ==# 0 975 | return self.parent.children[siblingIndx] 976 | endif 977 | 978 | "go to next node 979 | let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1 980 | endwhile 981 | endif 982 | endif 983 | 984 | return {} 985 | endfunction 986 | 987 | "FUNCTION: TreeFileNode.getLineNum(){{{3 988 | "returns the line number this node is rendered on, or -1 if it isnt rendered 989 | function! s:TreeFileNode.getLineNum() 990 | "if the node is the root then return the root line no. 991 | if self.isRoot() 992 | return s:TreeFileNode.GetRootLineNum() 993 | endif 994 | 995 | let totalLines = line("$") 996 | 997 | "the path components we have matched so far 998 | let pathcomponents = [substitute(b:NERDTreeRoot.path.str({'format': 'UI'}), '/ *$', '', '')] 999 | "the index of the component we are searching for 1000 | let curPathComponent = 1 1001 | 1002 | let fullpath = self.path.str({'format': 'UI'}) 1003 | 1004 | 1005 | let lnum = s:TreeFileNode.GetRootLineNum() 1006 | while lnum > 0 1007 | let lnum = lnum + 1 1008 | "have we reached the bottom of the tree? 1009 | if lnum ==# totalLines+1 1010 | return -1 1011 | endif 1012 | 1013 | let curLine = getline(lnum) 1014 | 1015 | let indent = s:indentLevelFor(curLine) 1016 | if indent ==# curPathComponent 1017 | let curLine = s:stripMarkupFromLine(curLine, 1) 1018 | 1019 | let curPath = join(pathcomponents, '/') . '/' . curLine 1020 | if stridx(fullpath, curPath, 0) ==# 0 1021 | if fullpath ==# curPath || strpart(fullpath, len(curPath)-1,1) ==# '/' 1022 | let curLine = substitute(curLine, '/ *$', '', '') 1023 | call add(pathcomponents, curLine) 1024 | let curPathComponent = curPathComponent + 1 1025 | 1026 | if fullpath ==# curPath 1027 | return lnum 1028 | endif 1029 | endif 1030 | endif 1031 | endif 1032 | endwhile 1033 | return -1 1034 | endfunction 1035 | 1036 | "FUNCTION: TreeFileNode.GetRootForTab(){{{3 1037 | "get the root node for this tab 1038 | function! s:TreeFileNode.GetRootForTab() 1039 | if s:treeExistsForTab() 1040 | return getbufvar(t:NERDTreeBufName, 'NERDTreeRoot') 1041 | end 1042 | return {} 1043 | endfunction 1044 | "FUNCTION: TreeFileNode.GetRootLineNum(){{{3 1045 | "gets the line number of the root node 1046 | function! s:TreeFileNode.GetRootLineNum() 1047 | let rootLine = 1 1048 | while getline(rootLine) !~# '^\(/\|<\)' 1049 | let rootLine = rootLine + 1 1050 | endwhile 1051 | return rootLine 1052 | endfunction 1053 | 1054 | "FUNCTION: TreeFileNode.GetSelected() {{{3 1055 | "gets the treenode that the cursor is currently over 1056 | function! s:TreeFileNode.GetSelected() 1057 | try 1058 | let path = s:getPath(line(".")) 1059 | if path ==# {} 1060 | return {} 1061 | endif 1062 | return b:NERDTreeRoot.findNode(path) 1063 | catch /NERDTree/ 1064 | return {} 1065 | endtry 1066 | endfunction 1067 | "FUNCTION: TreeFileNode.isVisible() {{{3 1068 | "returns 1 if this node should be visible according to the tree filters and 1069 | "hidden file filters (and their on/off status) 1070 | function! s:TreeFileNode.isVisible() 1071 | return !self.path.ignore() 1072 | endfunction 1073 | "FUNCTION: TreeFileNode.isRoot() {{{3 1074 | "returns 1 if this node is b:NERDTreeRoot 1075 | function! s:TreeFileNode.isRoot() 1076 | if !s:treeExistsForBuf() 1077 | throw "NERDTree.NoTreeError: No tree exists for the current buffer" 1078 | endif 1079 | 1080 | return self.equals(b:NERDTreeRoot) 1081 | endfunction 1082 | 1083 | "FUNCTION: TreeFileNode.makeRoot() {{{3 1084 | "Make this node the root of the tree 1085 | function! s:TreeFileNode.makeRoot() 1086 | if self.path.isDirectory 1087 | let b:NERDTreeRoot = self 1088 | else 1089 | call self.cacheParent() 1090 | let b:NERDTreeRoot = self.parent 1091 | endif 1092 | 1093 | call b:NERDTreeRoot.open() 1094 | 1095 | "change dir to the dir of the new root if instructed to 1096 | if g:NERDTreeChDirMode ==# 2 1097 | exec "cd " . b:NERDTreeRoot.path.str({'format': 'Edit'}) 1098 | endif 1099 | endfunction 1100 | "FUNCTION: TreeFileNode.New(path) {{{3 1101 | "Returns a new TreeNode object with the given path and parent 1102 | " 1103 | "Args: 1104 | "path: a path object representing the full filesystem path to the file/dir that the node represents 1105 | function! s:TreeFileNode.New(path) 1106 | if a:path.isDirectory 1107 | return s:TreeDirNode.New(a:path) 1108 | else 1109 | let newTreeNode = copy(self) 1110 | let newTreeNode.path = a:path 1111 | let newTreeNode.parent = {} 1112 | return newTreeNode 1113 | endif 1114 | endfunction 1115 | 1116 | "FUNCTION: TreeFileNode.open() {{{3 1117 | "Open the file represented by the given node in the current window, splitting 1118 | "the window if needed 1119 | " 1120 | "ARGS: 1121 | "treenode: file node to open 1122 | function! s:TreeFileNode.open() 1123 | if b:NERDTreeType ==# "secondary" 1124 | exec 'edit ' . self.path.str({'format': 'Edit'}) 1125 | return 1126 | endif 1127 | 1128 | "if the file is already open in this tab then just stick the cursor in it 1129 | let winnr = bufwinnr('^' . self.path.str() . '$') 1130 | if winnr != -1 1131 | call s:exec(winnr . "wincmd w") 1132 | 1133 | else 1134 | if !s:isWindowUsable(winnr("#")) && s:firstUsableWindow() ==# -1 1135 | call self.openSplit() 1136 | else 1137 | try 1138 | if !s:isWindowUsable(winnr("#")) 1139 | call s:exec(s:firstUsableWindow() . "wincmd w") 1140 | else 1141 | call s:exec('wincmd p') 1142 | endif 1143 | exec ("edit " . self.path.str({'format': 'Edit'})) 1144 | catch /^Vim\%((\a\+)\)\=:E37/ 1145 | call s:putCursorInTreeWin() 1146 | throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self.path.str() ." is already open and modified." 1147 | catch /^Vim\%((\a\+)\)\=:/ 1148 | echo v:exception 1149 | endtry 1150 | endif 1151 | endif 1152 | endfunction 1153 | "FUNCTION: TreeFileNode.openSplit() {{{3 1154 | "Open this node in a new window 1155 | function! s:TreeFileNode.openSplit() 1156 | 1157 | if b:NERDTreeType ==# "secondary" 1158 | exec "split " . self.path.str({'format': 'Edit'}) 1159 | return 1160 | endif 1161 | 1162 | " Save the user's settings for splitbelow and splitright 1163 | let savesplitbelow=&splitbelow 1164 | let savesplitright=&splitright 1165 | 1166 | " 'there' will be set to a command to move from the split window 1167 | " back to the explorer window 1168 | " 1169 | " 'back' will be set to a command to move from the explorer window 1170 | " back to the newly split window 1171 | " 1172 | " 'right' and 'below' will be set to the settings needed for 1173 | " splitbelow and splitright IF the explorer is the only window. 1174 | " 1175 | let there= g:NERDTreeWinPos ==# "left" ? "wincmd h" : "wincmd l" 1176 | let back = g:NERDTreeWinPos ==# "left" ? "wincmd l" : "wincmd h" 1177 | let right= g:NERDTreeWinPos ==# "left" 1178 | let below=0 1179 | 1180 | " Attempt to go to adjacent window 1181 | call s:exec(back) 1182 | 1183 | let onlyOneWin = (winnr("$") ==# 1) 1184 | 1185 | " If no adjacent window, set splitright and splitbelow appropriately 1186 | if onlyOneWin 1187 | let &splitright=right 1188 | let &splitbelow=below 1189 | else 1190 | " found adjacent window - invert split direction 1191 | let &splitright=!right 1192 | let &splitbelow=!below 1193 | endif 1194 | 1195 | let splitMode = onlyOneWin ? "vertical" : "" 1196 | 1197 | " Open the new window 1198 | try 1199 | exec(splitMode." sp " . self.path.str({'format': 'Edit'})) 1200 | catch /^Vim\%((\a\+)\)\=:E37/ 1201 | call s:putCursorInTreeWin() 1202 | throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self.path.str() ." is already open and modified." 1203 | catch /^Vim\%((\a\+)\)\=:/ 1204 | "do nothing 1205 | endtry 1206 | 1207 | "resize the tree window if no other window was open before 1208 | if onlyOneWin 1209 | let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize 1210 | call s:exec(there) 1211 | exec("silent ". splitMode ." resize ". size) 1212 | call s:exec('wincmd p') 1213 | endif 1214 | 1215 | " Restore splitmode settings 1216 | let &splitbelow=savesplitbelow 1217 | let &splitright=savesplitright 1218 | endfunction 1219 | "FUNCTION: TreeFileNode.openVSplit() {{{3 1220 | "Open this node in a new vertical window 1221 | function! s:TreeFileNode.openVSplit() 1222 | if b:NERDTreeType ==# "secondary" 1223 | exec "vnew " . self.path.str({'format': 'Edit'}) 1224 | return 1225 | endif 1226 | 1227 | let winwidth = winwidth(".") 1228 | if winnr("$")==#1 1229 | let winwidth = g:NERDTreeWinSize 1230 | endif 1231 | 1232 | call s:exec("wincmd p") 1233 | exec "vnew " . self.path.str({'format': 'Edit'}) 1234 | 1235 | "resize the nerd tree back to the original size 1236 | call s:putCursorInTreeWin() 1237 | exec("silent vertical resize ". winwidth) 1238 | call s:exec('wincmd p') 1239 | endfunction 1240 | "FUNCTION: TreeFileNode.openInNewTab(options) {{{3 1241 | function! s:TreeFileNode.openInNewTab(options) 1242 | let currentTab = tabpagenr() 1243 | 1244 | if !has_key(a:options, 'keepTreeOpen') 1245 | call s:closeTreeIfQuitOnOpen() 1246 | endif 1247 | 1248 | exec "tabedit " . self.path.str({'format': 'Edit'}) 1249 | 1250 | if has_key(a:options, 'stayInCurrentTab') && a:options['stayInCurrentTab'] 1251 | exec "tabnext " . currentTab 1252 | endif 1253 | 1254 | endfunction 1255 | "FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{3 1256 | "Places the cursor on the line number this node is rendered on 1257 | " 1258 | "Args: 1259 | "isJump: 1 if this cursor movement should be counted as a jump by vim 1260 | "recurseUpward: try to put the cursor on the parent if the this node isnt 1261 | "visible 1262 | function! s:TreeFileNode.putCursorHere(isJump, recurseUpward) 1263 | let ln = self.getLineNum() 1264 | if ln != -1 1265 | if a:isJump 1266 | mark ' 1267 | endif 1268 | call cursor(ln, col(".")) 1269 | else 1270 | if a:recurseUpward 1271 | let node = self 1272 | while node != {} && node.getLineNum() ==# -1 1273 | let node = node.parent 1274 | call node.open() 1275 | endwhile 1276 | call s:renderView() 1277 | call node.putCursorHere(a:isJump, 0) 1278 | endif 1279 | endif 1280 | endfunction 1281 | 1282 | "FUNCTION: TreeFileNode.refresh() {{{3 1283 | function! s:TreeFileNode.refresh() 1284 | call self.path.refresh() 1285 | endfunction 1286 | "FUNCTION: TreeFileNode.rename() {{{3 1287 | "Calls the rename method for this nodes path obj 1288 | function! s:TreeFileNode.rename(newName) 1289 | let newName = substitute(a:newName, '\(\\\|\/\)$', '', '') 1290 | call self.path.rename(newName) 1291 | call self.parent.removeChild(self) 1292 | 1293 | let parentPath = self.path.getParent() 1294 | let newParent = b:NERDTreeRoot.findNode(parentPath) 1295 | 1296 | if newParent != {} 1297 | call newParent.createChild(self.path, 1) 1298 | call newParent.refresh() 1299 | endif 1300 | endfunction 1301 | "FUNCTION: TreeFileNode.renderToString {{{3 1302 | "returns a string representation for this tree to be rendered in the view 1303 | function! s:TreeFileNode.renderToString() 1304 | return self._renderToString(0, 0, [], self.getChildCount() ==# 1) 1305 | endfunction 1306 | 1307 | 1308 | "Args: 1309 | "depth: the current depth in the tree for this call 1310 | "drawText: 1 if we should actually draw the line for this node (if 0 then the 1311 | "child nodes are rendered only) 1312 | "vertMap: a binary array that indicates whether a vertical bar should be draw 1313 | "for each depth in the tree 1314 | "isLastChild:true if this curNode is the last child of its parent 1315 | function! s:TreeFileNode._renderToString(depth, drawText, vertMap, isLastChild) 1316 | let output = "" 1317 | if a:drawText ==# 1 1318 | 1319 | let treeParts = '' 1320 | 1321 | "get all the leading spaces and vertical tree parts for this line 1322 | if a:depth > 1 1323 | for j in a:vertMap[0:-2] 1324 | if g:NERDTreeDirArrows 1325 | let treeParts = treeParts . ' ' 1326 | else 1327 | if j ==# 1 1328 | let treeParts = treeParts . '| ' 1329 | else 1330 | let treeParts = treeParts . ' ' 1331 | endif 1332 | endif 1333 | endfor 1334 | endif 1335 | 1336 | "get the last vertical tree part for this line which will be different 1337 | "if this node is the last child of its parent 1338 | if !g:NERDTreeDirArrows 1339 | if a:isLastChild 1340 | let treeParts = treeParts . '`' 1341 | else 1342 | let treeParts = treeParts . '|' 1343 | endif 1344 | endif 1345 | 1346 | "smack the appropriate dir/file symbol on the line before the file/dir 1347 | "name itself 1348 | if self.path.isDirectory 1349 | if self.isOpen 1350 | if g:NERDTreeDirArrows 1351 | let treeParts = treeParts . '▾ ' 1352 | else 1353 | let treeParts = treeParts . '~' 1354 | endif 1355 | else 1356 | if g:NERDTreeDirArrows 1357 | let treeParts = treeParts . '▸ ' 1358 | else 1359 | let treeParts = treeParts . '+' 1360 | endif 1361 | endif 1362 | else 1363 | if g:NERDTreeDirArrows 1364 | let treeParts = treeParts . ' ' 1365 | else 1366 | let treeParts = treeParts . '-' 1367 | endif 1368 | endif 1369 | let line = treeParts . self.displayString() 1370 | 1371 | let output = output . line . "\n" 1372 | endif 1373 | 1374 | "if the node is an open dir, draw its children 1375 | if self.path.isDirectory ==# 1 && self.isOpen ==# 1 1376 | 1377 | let childNodesToDraw = self.getVisibleChildren() 1378 | if len(childNodesToDraw) > 0 1379 | 1380 | "draw all the nodes children except the last 1381 | let lastIndx = len(childNodesToDraw)-1 1382 | if lastIndx > 0 1383 | for i in childNodesToDraw[0:lastIndx-1] 1384 | let output = output . i._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 1), 0) 1385 | endfor 1386 | endif 1387 | 1388 | "draw the last child, indicating that it IS the last 1389 | let output = output . childNodesToDraw[lastIndx]._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 0), 1) 1390 | endif 1391 | endif 1392 | 1393 | return output 1394 | endfunction 1395 | "CLASS: TreeDirNode {{{2 1396 | "This class is a child of the TreeFileNode class and constitutes the 1397 | "'Composite' part of the composite design pattern between the treenode 1398 | "classes. 1399 | "============================================================ 1400 | let s:TreeDirNode = copy(s:TreeFileNode) 1401 | "FUNCTION: TreeDirNode.AbsoluteTreeRoot(){{{3 1402 | "class method that returns the highest cached ancestor of the current root 1403 | function! s:TreeDirNode.AbsoluteTreeRoot() 1404 | let currentNode = b:NERDTreeRoot 1405 | while currentNode.parent != {} 1406 | let currentNode = currentNode.parent 1407 | endwhile 1408 | return currentNode 1409 | endfunction 1410 | "FUNCTION: TreeDirNode.activate(forceKeepWinOpen) {{{3 1411 | unlet s:TreeDirNode.activate 1412 | function! s:TreeDirNode.activate(forceKeepWinOpen) 1413 | call self.toggleOpen() 1414 | call s:renderView() 1415 | call self.putCursorHere(0, 0) 1416 | endfunction 1417 | "FUNCTION: TreeDirNode.addChild(treenode, inOrder) {{{3 1418 | "Adds the given treenode to the list of children for this node 1419 | " 1420 | "Args: 1421 | "-treenode: the node to add 1422 | "-inOrder: 1 if the new node should be inserted in sorted order 1423 | function! s:TreeDirNode.addChild(treenode, inOrder) 1424 | call add(self.children, a:treenode) 1425 | let a:treenode.parent = self 1426 | 1427 | if a:inOrder 1428 | call self.sortChildren() 1429 | endif 1430 | endfunction 1431 | 1432 | "FUNCTION: TreeDirNode.close() {{{3 1433 | "Closes this directory 1434 | function! s:TreeDirNode.close() 1435 | let self.isOpen = 0 1436 | endfunction 1437 | 1438 | "FUNCTION: TreeDirNode.closeChildren() {{{3 1439 | "Closes all the child dir nodes of this node 1440 | function! s:TreeDirNode.closeChildren() 1441 | for i in self.children 1442 | if i.path.isDirectory 1443 | call i.close() 1444 | call i.closeChildren() 1445 | endif 1446 | endfor 1447 | endfunction 1448 | 1449 | "FUNCTION: TreeDirNode.createChild(path, inOrder) {{{3 1450 | "Instantiates a new child node for this node with the given path. The new 1451 | "nodes parent is set to this node. 1452 | " 1453 | "Args: 1454 | "path: a Path object that this node will represent/contain 1455 | "inOrder: 1 if the new node should be inserted in sorted order 1456 | " 1457 | "Returns: 1458 | "the newly created node 1459 | function! s:TreeDirNode.createChild(path, inOrder) 1460 | let newTreeNode = s:TreeFileNode.New(a:path) 1461 | call self.addChild(newTreeNode, a:inOrder) 1462 | return newTreeNode 1463 | endfunction 1464 | 1465 | "FUNCTION: TreeDirNode.findNode(path) {{{3 1466 | "Will find one of the children (recursively) that has the given path 1467 | " 1468 | "Args: 1469 | "path: a path object 1470 | unlet s:TreeDirNode.findNode 1471 | function! s:TreeDirNode.findNode(path) 1472 | if a:path.equals(self.path) 1473 | return self 1474 | endif 1475 | if stridx(a:path.str(), self.path.str(), 0) ==# -1 1476 | return {} 1477 | endif 1478 | 1479 | if self.path.isDirectory 1480 | for i in self.children 1481 | let retVal = i.findNode(a:path) 1482 | if retVal != {} 1483 | return retVal 1484 | endif 1485 | endfor 1486 | endif 1487 | return {} 1488 | endfunction 1489 | "FUNCTION: TreeDirNode.getChildCount() {{{3 1490 | "Returns the number of children this node has 1491 | function! s:TreeDirNode.getChildCount() 1492 | return len(self.children) 1493 | endfunction 1494 | 1495 | "FUNCTION: TreeDirNode.getChild(path) {{{3 1496 | "Returns child node of this node that has the given path or {} if no such node 1497 | "exists. 1498 | " 1499 | "This function doesnt not recurse into child dir nodes 1500 | " 1501 | "Args: 1502 | "path: a path object 1503 | function! s:TreeDirNode.getChild(path) 1504 | if stridx(a:path.str(), self.path.str(), 0) ==# -1 1505 | return {} 1506 | endif 1507 | 1508 | let index = self.getChildIndex(a:path) 1509 | if index ==# -1 1510 | return {} 1511 | else 1512 | return self.children[index] 1513 | endif 1514 | 1515 | endfunction 1516 | 1517 | "FUNCTION: TreeDirNode.getChildByIndex(indx, visible) {{{3 1518 | "returns the child at the given index 1519 | "Args: 1520 | "indx: the index to get the child from 1521 | "visible: 1 if only the visible children array should be used, 0 if all the 1522 | "children should be searched. 1523 | function! s:TreeDirNode.getChildByIndex(indx, visible) 1524 | let array_to_search = a:visible? self.getVisibleChildren() : self.children 1525 | if a:indx > len(array_to_search) 1526 | throw "NERDTree.InvalidArgumentsError: Index is out of bounds." 1527 | endif 1528 | return array_to_search[a:indx] 1529 | endfunction 1530 | 1531 | "FUNCTION: TreeDirNode.getChildIndex(path) {{{3 1532 | "Returns the index of the child node of this node that has the given path or 1533 | "-1 if no such node exists. 1534 | " 1535 | "This function doesnt not recurse into child dir nodes 1536 | " 1537 | "Args: 1538 | "path: a path object 1539 | function! s:TreeDirNode.getChildIndex(path) 1540 | if stridx(a:path.str(), self.path.str(), 0) ==# -1 1541 | return -1 1542 | endif 1543 | 1544 | "do a binary search for the child 1545 | let a = 0 1546 | let z = self.getChildCount() 1547 | while a < z 1548 | let mid = (a+z)/2 1549 | let diff = a:path.compareTo(self.children[mid].path) 1550 | 1551 | if diff ==# -1 1552 | let z = mid 1553 | elseif diff ==# 1 1554 | let a = mid+1 1555 | else 1556 | return mid 1557 | endif 1558 | endwhile 1559 | return -1 1560 | endfunction 1561 | 1562 | "FUNCTION: TreeDirNode.GetSelected() {{{3 1563 | "Returns the current node if it is a dir node, or else returns the current 1564 | "nodes parent 1565 | unlet s:TreeDirNode.GetSelected 1566 | function! s:TreeDirNode.GetSelected() 1567 | let currentDir = s:TreeFileNode.GetSelected() 1568 | if currentDir != {} && !currentDir.isRoot() 1569 | if currentDir.path.isDirectory ==# 0 1570 | let currentDir = currentDir.parent 1571 | endif 1572 | endif 1573 | return currentDir 1574 | endfunction 1575 | "FUNCTION: TreeDirNode.getVisibleChildCount() {{{3 1576 | "Returns the number of visible children this node has 1577 | function! s:TreeDirNode.getVisibleChildCount() 1578 | return len(self.getVisibleChildren()) 1579 | endfunction 1580 | 1581 | "FUNCTION: TreeDirNode.getVisibleChildren() {{{3 1582 | "Returns a list of children to display for this node, in the correct order 1583 | " 1584 | "Return: 1585 | "an array of treenodes 1586 | function! s:TreeDirNode.getVisibleChildren() 1587 | let toReturn = [] 1588 | for i in self.children 1589 | if i.path.ignore() ==# 0 1590 | call add(toReturn, i) 1591 | endif 1592 | endfor 1593 | return toReturn 1594 | endfunction 1595 | 1596 | "FUNCTION: TreeDirNode.hasVisibleChildren() {{{3 1597 | "returns 1 if this node has any childre, 0 otherwise.. 1598 | function! s:TreeDirNode.hasVisibleChildren() 1599 | return self.getVisibleChildCount() != 0 1600 | endfunction 1601 | 1602 | "FUNCTION: TreeDirNode._initChildren() {{{3 1603 | "Removes all childen from this node and re-reads them 1604 | " 1605 | "Args: 1606 | "silent: 1 if the function should not echo any "please wait" messages for 1607 | "large directories 1608 | " 1609 | "Return: the number of child nodes read 1610 | function! s:TreeDirNode._initChildren(silent) 1611 | "remove all the current child nodes 1612 | let self.children = [] 1613 | 1614 | "get an array of all the files in the nodes dir 1615 | let dir = self.path 1616 | let globDir = dir.str({'format': 'Glob'}) 1617 | let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*') 1618 | let files = split(filesStr, "\n") 1619 | 1620 | if !a:silent && len(files) > g:NERDTreeNotificationThreshold 1621 | call s:echo("Please wait, caching a large dir ...") 1622 | endif 1623 | 1624 | let invalidFilesFound = 0 1625 | for i in files 1626 | 1627 | "filter out the .. and . directories 1628 | "Note: we must match .. AND ../ cos sometimes the globpath returns 1629 | "../ for path with strange chars (eg $) 1630 | if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' 1631 | 1632 | "put the next file in a new node and attach it 1633 | try 1634 | let path = s:Path.New(i) 1635 | call self.createChild(path, 0) 1636 | catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/ 1637 | let invalidFilesFound += 1 1638 | endtry 1639 | endif 1640 | endfor 1641 | 1642 | call self.sortChildren() 1643 | 1644 | if !a:silent && len(files) > g:NERDTreeNotificationThreshold 1645 | call s:echo("Please wait, caching a large dir ... DONE (". self.getChildCount() ." nodes cached).") 1646 | endif 1647 | 1648 | if invalidFilesFound 1649 | call s:echoWarning(invalidFilesFound . " file(s) could not be loaded into the NERD tree") 1650 | endif 1651 | return self.getChildCount() 1652 | endfunction 1653 | "FUNCTION: TreeDirNode.New(path) {{{3 1654 | "Returns a new TreeNode object with the given path and parent 1655 | " 1656 | "Args: 1657 | "path: a path object representing the full filesystem path to the file/dir that the node represents 1658 | unlet s:TreeDirNode.New 1659 | function! s:TreeDirNode.New(path) 1660 | if a:path.isDirectory != 1 1661 | throw "NERDTree.InvalidArgumentsError: A TreeDirNode object must be instantiated with a directory Path object." 1662 | endif 1663 | 1664 | let newTreeNode = copy(self) 1665 | let newTreeNode.path = a:path 1666 | 1667 | let newTreeNode.isOpen = 0 1668 | let newTreeNode.children = [] 1669 | 1670 | let newTreeNode.parent = {} 1671 | 1672 | return newTreeNode 1673 | endfunction 1674 | "FUNCTION: TreeDirNode.open() {{{3 1675 | "Reads in all this nodes children 1676 | " 1677 | "Return: the number of child nodes read 1678 | unlet s:TreeDirNode.open 1679 | function! s:TreeDirNode.open() 1680 | let self.isOpen = 1 1681 | if self.children ==# [] 1682 | return self._initChildren(0) 1683 | else 1684 | return 0 1685 | endif 1686 | endfunction 1687 | 1688 | " FUNCTION: TreeDirNode.openExplorer() {{{3 1689 | " opens an explorer window for this node in the previous window (could be a 1690 | " nerd tree or a netrw) 1691 | function! s:TreeDirNode.openExplorer() 1692 | let oldwin = winnr() 1693 | call s:exec('wincmd p') 1694 | if oldwin ==# winnr() || (&modified && s:bufInWindows(winbufnr(winnr())) < 2) 1695 | call s:exec('wincmd p') 1696 | call self.openSplit() 1697 | else 1698 | exec ("silent edit " . self.path.str({'format': 'Edit'})) 1699 | endif 1700 | endfunction 1701 | "FUNCTION: TreeDirNode.openInNewTab(options) {{{3 1702 | unlet s:TreeDirNode.openInNewTab 1703 | function! s:TreeDirNode.openInNewTab(options) 1704 | let currentTab = tabpagenr() 1705 | 1706 | if !has_key(a:options, 'keepTreeOpen') || !a:options['keepTreeOpen'] 1707 | call s:closeTreeIfQuitOnOpen() 1708 | endif 1709 | 1710 | tabnew 1711 | call s:initNerdTree(self.path.str()) 1712 | 1713 | if has_key(a:options, 'stayInCurrentTab') && a:options['stayInCurrentTab'] 1714 | exec "tabnext " . currentTab 1715 | endif 1716 | endfunction 1717 | "FUNCTION: TreeDirNode.openRecursively() {{{3 1718 | "Opens this treenode and all of its children whose paths arent 'ignored' 1719 | "because of the file filters. 1720 | " 1721 | "This method is actually a wrapper for the OpenRecursively2 method which does 1722 | "the work. 1723 | function! s:TreeDirNode.openRecursively() 1724 | call self._openRecursively2(1) 1725 | endfunction 1726 | 1727 | "FUNCTION: TreeDirNode._openRecursively2() {{{3 1728 | "Opens this all children of this treenode recursively if either: 1729 | " *they arent filtered by file filters 1730 | " *a:forceOpen is 1 1731 | " 1732 | "Args: 1733 | "forceOpen: 1 if this node should be opened regardless of file filters 1734 | function! s:TreeDirNode._openRecursively2(forceOpen) 1735 | if self.path.ignore() ==# 0 || a:forceOpen 1736 | let self.isOpen = 1 1737 | if self.children ==# [] 1738 | call self._initChildren(1) 1739 | endif 1740 | 1741 | for i in self.children 1742 | if i.path.isDirectory ==# 1 1743 | call i._openRecursively2(0) 1744 | endif 1745 | endfor 1746 | endif 1747 | endfunction 1748 | 1749 | "FUNCTION: TreeDirNode.refresh() {{{3 1750 | unlet s:TreeDirNode.refresh 1751 | function! s:TreeDirNode.refresh() 1752 | call self.path.refresh() 1753 | 1754 | "if this node was ever opened, refresh its children 1755 | if self.isOpen || !empty(self.children) 1756 | "go thru all the files/dirs under this node 1757 | let newChildNodes = [] 1758 | let invalidFilesFound = 0 1759 | let dir = self.path 1760 | let globDir = dir.str({'format': 'Glob'}) 1761 | let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*') 1762 | let files = split(filesStr, "\n") 1763 | for i in files 1764 | "filter out the .. and . directories 1765 | "Note: we must match .. AND ../ cos sometimes the globpath returns 1766 | "../ for path with strange chars (eg $) 1767 | if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' 1768 | 1769 | try 1770 | "create a new path and see if it exists in this nodes children 1771 | let path = s:Path.New(i) 1772 | let newNode = self.getChild(path) 1773 | if newNode != {} 1774 | call newNode.refresh() 1775 | call add(newChildNodes, newNode) 1776 | 1777 | "the node doesnt exist so create it 1778 | else 1779 | let newNode = s:TreeFileNode.New(path) 1780 | let newNode.parent = self 1781 | call add(newChildNodes, newNode) 1782 | endif 1783 | 1784 | 1785 | catch /^NERDTree.InvalidArgumentsError/ 1786 | let invalidFilesFound = 1 1787 | endtry 1788 | endif 1789 | endfor 1790 | 1791 | "swap this nodes children out for the children we just read/refreshed 1792 | let self.children = newChildNodes 1793 | call self.sortChildren() 1794 | 1795 | if invalidFilesFound 1796 | call s:echoWarning("some files could not be loaded into the NERD tree") 1797 | endif 1798 | endif 1799 | endfunction 1800 | 1801 | "FUNCTION: TreeDirNode.reveal(path) {{{3 1802 | "reveal the given path, i.e. cache and open all treenodes needed to display it 1803 | "in the UI 1804 | function! s:TreeDirNode.reveal(path) 1805 | if !a:path.isUnder(self.path) 1806 | throw "NERDTree.InvalidArgumentsError: " . a:path.str() . " should be under " . self.path.str() 1807 | endif 1808 | 1809 | call self.open() 1810 | 1811 | if self.path.equals(a:path.getParent()) 1812 | let n = self.findNode(a:path) 1813 | call s:renderView() 1814 | call n.putCursorHere(1,0) 1815 | return 1816 | endif 1817 | 1818 | let p = a:path 1819 | while !p.getParent().equals(self.path) 1820 | let p = p.getParent() 1821 | endwhile 1822 | 1823 | let n = self.findNode(p) 1824 | call n.reveal(a:path) 1825 | endfunction 1826 | "FUNCTION: TreeDirNode.removeChild(treenode) {{{3 1827 | " 1828 | "Removes the given treenode from this nodes set of children 1829 | " 1830 | "Args: 1831 | "treenode: the node to remove 1832 | " 1833 | "Throws a NERDTree.ChildNotFoundError if the given treenode is not found 1834 | function! s:TreeDirNode.removeChild(treenode) 1835 | for i in range(0, self.getChildCount()-1) 1836 | if self.children[i].equals(a:treenode) 1837 | call remove(self.children, i) 1838 | return 1839 | endif 1840 | endfor 1841 | 1842 | throw "NERDTree.ChildNotFoundError: child node was not found" 1843 | endfunction 1844 | 1845 | "FUNCTION: TreeDirNode.sortChildren() {{{3 1846 | " 1847 | "Sorts the children of this node according to alphabetical order and the 1848 | "directory priority. 1849 | " 1850 | function! s:TreeDirNode.sortChildren() 1851 | let CompareFunc = function("s:compareNodes") 1852 | call sort(self.children, CompareFunc) 1853 | endfunction 1854 | 1855 | "FUNCTION: TreeDirNode.toggleOpen() {{{3 1856 | "Opens this directory if it is closed and vice versa 1857 | function! s:TreeDirNode.toggleOpen() 1858 | if self.isOpen ==# 1 1859 | call self.close() 1860 | else 1861 | call self.open() 1862 | endif 1863 | endfunction 1864 | 1865 | "FUNCTION: TreeDirNode.transplantChild(newNode) {{{3 1866 | "Replaces the child of this with the given node (where the child node's full 1867 | "path matches a:newNode's fullpath). The search for the matching node is 1868 | "non-recursive 1869 | " 1870 | "Arg: 1871 | "newNode: the node to graft into the tree 1872 | function! s:TreeDirNode.transplantChild(newNode) 1873 | for i in range(0, self.getChildCount()-1) 1874 | if self.children[i].equals(a:newNode) 1875 | let self.children[i] = a:newNode 1876 | let a:newNode.parent = self 1877 | break 1878 | endif 1879 | endfor 1880 | endfunction 1881 | "============================================================ 1882 | "CLASS: Path {{{2 1883 | "============================================================ 1884 | let s:Path = {} 1885 | "FUNCTION: Path.AbsolutePathFor(str) {{{3 1886 | function! s:Path.AbsolutePathFor(str) 1887 | let prependCWD = 0 1888 | if s:running_windows 1889 | let prependCWD = a:str !~# '^.:\(\\\|\/\)' 1890 | else 1891 | let prependCWD = a:str !~# '^/' 1892 | endif 1893 | 1894 | let toReturn = a:str 1895 | if prependCWD 1896 | let toReturn = getcwd() . s:Path.Slash() . a:str 1897 | endif 1898 | 1899 | return toReturn 1900 | endfunction 1901 | "FUNCTION: Path.bookmarkNames() {{{3 1902 | function! s:Path.bookmarkNames() 1903 | if !exists("self._bookmarkNames") 1904 | call self.cacheDisplayString() 1905 | endif 1906 | return self._bookmarkNames 1907 | endfunction 1908 | "FUNCTION: Path.cacheDisplayString() {{{3 1909 | function! s:Path.cacheDisplayString() 1910 | let self.cachedDisplayString = self.getLastPathComponent(1) 1911 | 1912 | if self.isExecutable 1913 | let self.cachedDisplayString = self.cachedDisplayString . '*' 1914 | endif 1915 | 1916 | let self._bookmarkNames = [] 1917 | for i in s:Bookmark.Bookmarks() 1918 | if i.path.equals(self) 1919 | call add(self._bookmarkNames, i.name) 1920 | endif 1921 | endfor 1922 | if !empty(self._bookmarkNames) 1923 | let self.cachedDisplayString .= ' {' . join(self._bookmarkNames) . '}' 1924 | endif 1925 | 1926 | if self.isSymLink 1927 | let self.cachedDisplayString .= ' -> ' . self.symLinkDest 1928 | endif 1929 | 1930 | if self.isReadOnly 1931 | let self.cachedDisplayString .= ' [RO]' 1932 | endif 1933 | endfunction 1934 | "FUNCTION: Path.changeToDir() {{{3 1935 | function! s:Path.changeToDir() 1936 | let dir = self.str({'format': 'Cd'}) 1937 | if self.isDirectory ==# 0 1938 | let dir = self.getParent().str({'format': 'Cd'}) 1939 | endif 1940 | 1941 | try 1942 | execute "cd " . dir 1943 | call s:echo("CWD is now: " . getcwd()) 1944 | catch 1945 | throw "NERDTree.PathChangeError: cannot change CWD to " . dir 1946 | endtry 1947 | endfunction 1948 | 1949 | "FUNCTION: Path.compareTo() {{{3 1950 | " 1951 | "Compares this Path to the given path and returns 0 if they are equal, -1 if 1952 | "this Path is "less than" the given path, or 1 if it is "greater". 1953 | " 1954 | "Args: 1955 | "path: the path object to compare this to 1956 | " 1957 | "Return: 1958 | "1, -1 or 0 1959 | function! s:Path.compareTo(path) 1960 | let thisPath = self.getLastPathComponent(1) 1961 | let thatPath = a:path.getLastPathComponent(1) 1962 | 1963 | "if the paths are the same then clearly we return 0 1964 | if thisPath ==# thatPath 1965 | return 0 1966 | endif 1967 | 1968 | let thisSS = self.getSortOrderIndex() 1969 | let thatSS = a:path.getSortOrderIndex() 1970 | 1971 | "compare the sort sequences, if they are different then the return 1972 | "value is easy 1973 | if thisSS < thatSS 1974 | return -1 1975 | elseif thisSS > thatSS 1976 | return 1 1977 | else 1978 | "if the sort sequences are the same then compare the paths 1979 | "alphabetically 1980 | let pathCompare = g:NERDTreeCaseSensitiveSort ? thisPath <# thatPath : thisPath limit 2392 | let toReturn = "<" . strpart(toReturn, len(toReturn) - limit + 1) 2393 | endif 2394 | endif 2395 | 2396 | return toReturn 2397 | endfunction 2398 | 2399 | "FUNCTION: Path._strForUI() {{{3 2400 | function! s:Path._strForUI() 2401 | let toReturn = '/' . join(self.pathSegments, '/') 2402 | if self.isDirectory && toReturn != '/' 2403 | let toReturn = toReturn . '/' 2404 | endif 2405 | return toReturn 2406 | endfunction 2407 | 2408 | "FUNCTION: Path._strForCd() {{{3 2409 | " 2410 | " returns a string that can be used with :cd 2411 | function! s:Path._strForCd() 2412 | return escape(self.str(), s:escape_chars) 2413 | endfunction 2414 | "FUNCTION: Path._strForEdit() {{{3 2415 | " 2416 | "Return: the string for this path that is suitable to be used with the :edit 2417 | "command 2418 | function! s:Path._strForEdit() 2419 | let p = self.str({'format': 'UI'}) 2420 | let cwd = getcwd() 2421 | 2422 | if s:running_windows 2423 | let p = tolower(self.str()) 2424 | let cwd = tolower(getcwd()) 2425 | endif 2426 | 2427 | let p = escape(p, s:escape_chars) 2428 | 2429 | let cwd = cwd . s:Path.Slash() 2430 | 2431 | "return a relative path if we can 2432 | if stridx(p, cwd) ==# 0 2433 | let p = strpart(p, strlen(cwd)) 2434 | endif 2435 | 2436 | if p ==# '' 2437 | let p = '.' 2438 | endif 2439 | 2440 | return p 2441 | 2442 | endfunction 2443 | "FUNCTION: Path._strForGlob() {{{3 2444 | function! s:Path._strForGlob() 2445 | let lead = s:Path.Slash() 2446 | 2447 | "if we are running windows then slap a drive letter on the front 2448 | if s:running_windows 2449 | let lead = self.drive . '\' 2450 | endif 2451 | 2452 | let toReturn = lead . join(self.pathSegments, s:Path.Slash()) 2453 | 2454 | if !s:running_windows 2455 | let toReturn = escape(toReturn, s:escape_chars) 2456 | endif 2457 | return toReturn 2458 | endfunction 2459 | "FUNCTION: Path._str() {{{3 2460 | " 2461 | "Gets the string path for this path object that is appropriate for the OS. 2462 | "EG, in windows c:\foo\bar 2463 | " in *nix /foo/bar 2464 | function! s:Path._str() 2465 | let lead = s:Path.Slash() 2466 | 2467 | "if we are running windows then slap a drive letter on the front 2468 | if s:running_windows 2469 | let lead = self.drive . '\' 2470 | endif 2471 | 2472 | return lead . join(self.pathSegments, s:Path.Slash()) 2473 | endfunction 2474 | 2475 | "FUNCTION: Path.strTrunk() {{{3 2476 | "Gets the path without the last segment on the end. 2477 | function! s:Path.strTrunk() 2478 | return self.drive . '/' . join(self.pathSegments[0:-2], '/') 2479 | endfunction 2480 | 2481 | "FUNCTION: Path.WinToUnixPath(pathstr){{{3 2482 | "Takes in a windows path and returns the unix equiv 2483 | " 2484 | "A class level method 2485 | " 2486 | "Args: 2487 | "pathstr: the windows path to convert 2488 | function! s:Path.WinToUnixPath(pathstr) 2489 | if !s:running_windows 2490 | return a:pathstr 2491 | endif 2492 | 2493 | let toReturn = a:pathstr 2494 | 2495 | "remove the x:\ of the front 2496 | let toReturn = substitute(toReturn, '^.*:\(\\\|/\)\?', '/', "") 2497 | 2498 | "convert all \ chars to / 2499 | let toReturn = substitute(toReturn, '\', '/', "g") 2500 | 2501 | return toReturn 2502 | endfunction 2503 | 2504 | " SECTION: General Functions {{{1 2505 | "============================================================ 2506 | "FUNCTION: s:bufInWindows(bnum){{{2 2507 | "[[STOLEN FROM VTREEEXPLORER.VIM]] 2508 | "Determine the number of windows open to this buffer number. 2509 | "Care of Yegappan Lakshman. Thanks! 2510 | " 2511 | "Args: 2512 | "bnum: the subject buffers buffer number 2513 | function! s:bufInWindows(bnum) 2514 | let cnt = 0 2515 | let winnum = 1 2516 | while 1 2517 | let bufnum = winbufnr(winnum) 2518 | if bufnum < 0 2519 | break 2520 | endif 2521 | if bufnum ==# a:bnum 2522 | let cnt = cnt + 1 2523 | endif 2524 | let winnum = winnum + 1 2525 | endwhile 2526 | 2527 | return cnt 2528 | endfunction " >>> 2529 | "FUNCTION: s:checkForBrowse(dir) {{{2 2530 | "inits a secondary nerd tree in the current buffer if appropriate 2531 | function! s:checkForBrowse(dir) 2532 | if a:dir != '' && isdirectory(a:dir) 2533 | call s:initNerdTreeInPlace(a:dir) 2534 | endif 2535 | endfunction 2536 | "FUNCTION: s:compareBookmarks(first, second) {{{2 2537 | "Compares two bookmarks 2538 | function! s:compareBookmarks(first, second) 2539 | return a:first.compareTo(a:second) 2540 | endfunction 2541 | 2542 | " FUNCTION: s:completeBookmarks(A,L,P) {{{2 2543 | " completion function for the bookmark commands 2544 | function! s:completeBookmarks(A,L,P) 2545 | return filter(s:Bookmark.BookmarkNames(), 'v:val =~# "^' . a:A . '"') 2546 | endfunction 2547 | " FUNCTION: s:exec(cmd) {{{2 2548 | " same as :exec cmd but eventignore=all is set for the duration 2549 | function! s:exec(cmd) 2550 | let old_ei = &ei 2551 | set ei=all 2552 | exec a:cmd 2553 | let &ei = old_ei 2554 | endfunction 2555 | " FUNCTION: s:findAndRevealPath() {{{2 2556 | function! s:findAndRevealPath() 2557 | try 2558 | let p = s:Path.New(expand("%:p")) 2559 | catch /^NERDTree.InvalidArgumentsError/ 2560 | call s:echo("no file for the current buffer") 2561 | return 2562 | endtry 2563 | 2564 | if !s:treeExistsForTab() 2565 | try 2566 | let cwd = s:Path.New(getcwd()) 2567 | catch /^NERDTree.InvalidArgumentsError/ 2568 | call s:echo("current directory does not exist.") 2569 | let cwd = p.getParent() 2570 | endtry 2571 | 2572 | if p.isUnder(cwd) 2573 | call s:initNerdTree(cwd.str()) 2574 | else 2575 | call s:initNerdTree(p.getParent().str()) 2576 | endif 2577 | else 2578 | if !p.isUnder(s:TreeFileNode.GetRootForTab().path) 2579 | call s:initNerdTree(p.getParent().str()) 2580 | else 2581 | if !s:isTreeOpen() 2582 | call s:toggle("") 2583 | endif 2584 | endif 2585 | endif 2586 | call s:putCursorInTreeWin() 2587 | call b:NERDTreeRoot.reveal(p) 2588 | endfunction 2589 | "FUNCTION: s:initNerdTree(name) {{{2 2590 | "Initialise the nerd tree for this tab. The tree will start in either the 2591 | "given directory, or the directory associated with the given bookmark 2592 | " 2593 | "Args: 2594 | "name: the name of a bookmark or a directory 2595 | function! s:initNerdTree(name) 2596 | let path = {} 2597 | if s:Bookmark.BookmarkExistsFor(a:name) 2598 | let path = s:Bookmark.BookmarkFor(a:name).path 2599 | else 2600 | let dir = a:name ==# '' ? getcwd() : a:name 2601 | 2602 | "hack to get an absolute path if a relative path is given 2603 | if dir =~# '^\.' 2604 | let dir = getcwd() . s:Path.Slash() . dir 2605 | endif 2606 | let dir = resolve(dir) 2607 | 2608 | try 2609 | let path = s:Path.New(dir) 2610 | catch /^NERDTree.InvalidArgumentsError/ 2611 | call s:echo("No bookmark or directory found for: " . a:name) 2612 | return 2613 | endtry 2614 | endif 2615 | if !path.isDirectory 2616 | let path = path.getParent() 2617 | endif 2618 | 2619 | "if instructed to, then change the vim CWD to the dir the NERDTree is 2620 | "inited in 2621 | if g:NERDTreeChDirMode != 0 2622 | call path.changeToDir() 2623 | endif 2624 | 2625 | if s:treeExistsForTab() 2626 | if s:isTreeOpen() 2627 | call s:closeTree() 2628 | endif 2629 | unlet t:NERDTreeBufName 2630 | endif 2631 | 2632 | let newRoot = s:TreeDirNode.New(path) 2633 | call newRoot.open() 2634 | 2635 | call s:createTreeWin() 2636 | let b:treeShowHelp = 0 2637 | let b:NERDTreeIgnoreEnabled = 1 2638 | let b:NERDTreeShowFiles = g:NERDTreeShowFiles 2639 | let b:NERDTreeShowHidden = g:NERDTreeShowHidden 2640 | let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks 2641 | let b:NERDTreeRoot = newRoot 2642 | 2643 | let b:NERDTreeType = "primary" 2644 | 2645 | call s:renderView() 2646 | call b:NERDTreeRoot.putCursorHere(0, 0) 2647 | endfunction 2648 | 2649 | "FUNCTION: s:initNerdTreeInPlace(dir) {{{2 2650 | function! s:initNerdTreeInPlace(dir) 2651 | try 2652 | let path = s:Path.New(a:dir) 2653 | catch /^NERDTree.InvalidArgumentsError/ 2654 | call s:echo("Invalid directory name:" . a:name) 2655 | return 2656 | endtry 2657 | 2658 | "we want the directory buffer to disappear when we do the :edit below 2659 | setlocal bufhidden=wipe 2660 | 2661 | let previousBuf = expand("#") 2662 | 2663 | "we need a unique name for each secondary tree buffer to ensure they are 2664 | "all independent 2665 | exec "silent edit " . s:nextBufferName() 2666 | 2667 | let b:NERDTreePreviousBuf = bufnr(previousBuf) 2668 | 2669 | let b:NERDTreeRoot = s:TreeDirNode.New(path) 2670 | call b:NERDTreeRoot.open() 2671 | 2672 | call s:setCommonBufOptions() 2673 | let b:NERDTreeType = "secondary" 2674 | 2675 | call s:renderView() 2676 | endfunction 2677 | " FUNCTION: s:initNerdTreeMirror() {{{2 2678 | function! s:initNerdTreeMirror() 2679 | 2680 | "get the names off all the nerd tree buffers 2681 | let treeBufNames = [] 2682 | for i in range(1, tabpagenr("$")) 2683 | let nextName = s:tabpagevar(i, 'NERDTreeBufName') 2684 | if nextName != -1 && (!exists("t:NERDTreeBufName") || nextName != t:NERDTreeBufName) 2685 | call add(treeBufNames, nextName) 2686 | endif 2687 | endfor 2688 | let treeBufNames = s:unique(treeBufNames) 2689 | 2690 | "map the option names (that the user will be prompted with) to the nerd 2691 | "tree buffer names 2692 | let options = {} 2693 | let i = 0 2694 | while i < len(treeBufNames) 2695 | let bufName = treeBufNames[i] 2696 | let treeRoot = getbufvar(bufName, "NERDTreeRoot") 2697 | let options[i+1 . '. ' . treeRoot.path.str() . ' (buf name: ' . bufName . ')'] = bufName 2698 | let i = i + 1 2699 | endwhile 2700 | 2701 | "work out which tree to mirror, if there is more than 1 then ask the user 2702 | let bufferName = '' 2703 | if len(keys(options)) > 1 2704 | let choices = ["Choose a tree to mirror"] 2705 | let choices = extend(choices, sort(keys(options))) 2706 | let choice = inputlist(choices) 2707 | if choice < 1 || choice > len(options) || choice ==# '' 2708 | return 2709 | endif 2710 | 2711 | let bufferName = options[sort(keys(options))[choice-1]] 2712 | elseif len(keys(options)) ==# 1 2713 | let bufferName = values(options)[0] 2714 | else 2715 | call s:echo("No trees to mirror") 2716 | return 2717 | endif 2718 | 2719 | if s:treeExistsForTab() && s:isTreeOpen() 2720 | call s:closeTree() 2721 | endif 2722 | 2723 | let t:NERDTreeBufName = bufferName 2724 | call s:createTreeWin() 2725 | exec 'buffer ' . bufferName 2726 | if !&hidden 2727 | call s:renderView() 2728 | endif 2729 | endfunction 2730 | " FUNCTION: s:nextBufferName() {{{2 2731 | " returns the buffer name for the next nerd tree 2732 | function! s:nextBufferName() 2733 | let name = s:NERDTreeBufName . s:next_buffer_number 2734 | let s:next_buffer_number += 1 2735 | return name 2736 | endfunction 2737 | " FUNCTION: s:tabpagevar(tabnr, var) {{{2 2738 | function! s:tabpagevar(tabnr, var) 2739 | let currentTab = tabpagenr() 2740 | let old_ei = &ei 2741 | set ei=all 2742 | 2743 | exec "tabnext " . a:tabnr 2744 | let v = -1 2745 | if exists('t:' . a:var) 2746 | exec 'let v = t:' . a:var 2747 | endif 2748 | exec "tabnext " . currentTab 2749 | 2750 | let &ei = old_ei 2751 | 2752 | return v 2753 | endfunction 2754 | " Function: s:treeExistsForBuffer() {{{2 2755 | " Returns 1 if a nerd tree root exists in the current buffer 2756 | function! s:treeExistsForBuf() 2757 | return exists("b:NERDTreeRoot") 2758 | endfunction 2759 | " Function: s:treeExistsForTab() {{{2 2760 | " Returns 1 if a nerd tree root exists in the current tab 2761 | function! s:treeExistsForTab() 2762 | return exists("t:NERDTreeBufName") 2763 | endfunction 2764 | " Function: s:unique(list) {{{2 2765 | " returns a:list without duplicates 2766 | function! s:unique(list) 2767 | let uniqlist = [] 2768 | for elem in a:list 2769 | if index(uniqlist, elem) ==# -1 2770 | let uniqlist += [elem] 2771 | endif 2772 | endfor 2773 | return uniqlist 2774 | endfunction 2775 | " SECTION: Public API {{{1 2776 | "============================================================ 2777 | let g:NERDTreePath = s:Path 2778 | let g:NERDTreeDirNode = s:TreeDirNode 2779 | let g:NERDTreeFileNode = s:TreeFileNode 2780 | let g:NERDTreeBookmark = s:Bookmark 2781 | 2782 | function! NERDTreeAddMenuItem(options) 2783 | call s:MenuItem.Create(a:options) 2784 | endfunction 2785 | 2786 | function! NERDTreeAddMenuSeparator(...) 2787 | let opts = a:0 ? a:1 : {} 2788 | call s:MenuItem.CreateSeparator(opts) 2789 | endfunction 2790 | 2791 | function! NERDTreeAddSubmenu(options) 2792 | return s:MenuItem.Create(a:options) 2793 | endfunction 2794 | 2795 | function! NERDTreeAddKeyMap(options) 2796 | call s:KeyMap.Create(a:options) 2797 | endfunction 2798 | 2799 | function! NERDTreeRender() 2800 | call s:renderView() 2801 | endfunction 2802 | 2803 | " SECTION: View Functions {{{1 2804 | "============================================================ 2805 | "FUNCTION: s:centerView() {{{2 2806 | "centers the nerd tree window around the cursor (provided the nerd tree 2807 | "options permit) 2808 | function! s:centerView() 2809 | if g:NERDTreeAutoCenter 2810 | let current_line = winline() 2811 | let lines_to_top = current_line 2812 | let lines_to_bottom = winheight(s:getTreeWinNum()) - current_line 2813 | if lines_to_top < g:NERDTreeAutoCenterThreshold || lines_to_bottom < g:NERDTreeAutoCenterThreshold 2814 | normal! zz 2815 | endif 2816 | endif 2817 | endfunction 2818 | "FUNCTION: s:closeTree() {{{2 2819 | "Closes the primary NERD tree window for this tab 2820 | function! s:closeTree() 2821 | if !s:isTreeOpen() 2822 | throw "NERDTree.NoTreeFoundError: no NERDTree is open" 2823 | endif 2824 | 2825 | if winnr("$") != 1 2826 | if winnr() == s:getTreeWinNum() 2827 | wincmd p 2828 | let bufnr = bufnr("") 2829 | wincmd p 2830 | else 2831 | let bufnr = bufnr("") 2832 | endif 2833 | 2834 | call s:exec(s:getTreeWinNum() . " wincmd w") 2835 | close 2836 | call s:exec(bufwinnr(bufnr) . " wincmd w") 2837 | else 2838 | close 2839 | endif 2840 | endfunction 2841 | 2842 | "FUNCTION: s:closeTreeIfOpen() {{{2 2843 | "Closes the NERD tree window if it is open 2844 | function! s:closeTreeIfOpen() 2845 | if s:isTreeOpen() 2846 | call s:closeTree() 2847 | endif 2848 | endfunction 2849 | "FUNCTION: s:closeTreeIfQuitOnOpen() {{{2 2850 | "Closes the NERD tree window if the close on open option is set 2851 | function! s:closeTreeIfQuitOnOpen() 2852 | if g:NERDTreeQuitOnOpen && s:isTreeOpen() 2853 | call s:closeTree() 2854 | endif 2855 | endfunction 2856 | "FUNCTION: s:createTreeWin() {{{2 2857 | "Inits the NERD tree window. ie. opens it, sizes it, sets all the local 2858 | "options etc 2859 | function! s:createTreeWin() 2860 | "create the nerd tree window 2861 | let splitLocation = g:NERDTreeWinPos ==# "left" ? "topleft " : "botright " 2862 | let splitSize = g:NERDTreeWinSize 2863 | 2864 | if !exists('t:NERDTreeBufName') 2865 | let t:NERDTreeBufName = s:nextBufferName() 2866 | silent! exec splitLocation . 'vertical ' . splitSize . ' new' 2867 | silent! exec "edit " . t:NERDTreeBufName 2868 | else 2869 | silent! exec splitLocation . 'vertical ' . splitSize . ' split' 2870 | silent! exec "buffer " . t:NERDTreeBufName 2871 | endif 2872 | 2873 | setlocal winfixwidth 2874 | call s:setCommonBufOptions() 2875 | endfunction 2876 | 2877 | "FUNCTION: s:dumpHelp {{{2 2878 | "prints out the quick help 2879 | function! s:dumpHelp() 2880 | let old_h = @h 2881 | if b:treeShowHelp ==# 1 2882 | let @h= "\" NERD tree (" . s:NERD_tree_version . ") quickhelp~\n" 2883 | let @h=@h."\" ============================\n" 2884 | let @h=@h."\" File node mappings~\n" 2885 | let @h=@h."\" ". (g:NERDTreeMouseMode ==# 3 ? "single" : "double") ."-click,\n" 2886 | let @h=@h."\" ,\n" 2887 | if b:NERDTreeType ==# "primary" 2888 | let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in prev window\n" 2889 | else 2890 | let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in current window\n" 2891 | endif 2892 | if b:NERDTreeType ==# "primary" 2893 | let @h=@h."\" ". g:NERDTreeMapPreview .": preview\n" 2894 | endif 2895 | let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" 2896 | let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" 2897 | let @h=@h."\" middle-click,\n" 2898 | let @h=@h."\" ". g:NERDTreeMapOpenSplit .": open split\n" 2899 | let @h=@h."\" ". g:NERDTreeMapPreviewSplit .": preview split\n" 2900 | let @h=@h."\" ". g:NERDTreeMapOpenVSplit .": open vsplit\n" 2901 | let @h=@h."\" ". g:NERDTreeMapPreviewVSplit .": preview vsplit\n" 2902 | 2903 | let @h=@h."\"\n\" ----------------------------\n" 2904 | let @h=@h."\" Directory node mappings~\n" 2905 | let @h=@h."\" ". (g:NERDTreeMouseMode ==# 1 ? "double" : "single") ."-click,\n" 2906 | let @h=@h."\" ". g:NERDTreeMapActivateNode .": open & close node\n" 2907 | let @h=@h."\" ". g:NERDTreeMapOpenRecursively .": recursively open node\n" 2908 | let @h=@h."\" ". g:NERDTreeMapCloseDir .": close parent of node\n" 2909 | let @h=@h."\" ". g:NERDTreeMapCloseChildren .": close all child nodes of\n" 2910 | let @h=@h."\" current node recursively\n" 2911 | let @h=@h."\" middle-click,\n" 2912 | let @h=@h."\" ". g:NERDTreeMapOpenExpl.": explore selected dir\n" 2913 | 2914 | let @h=@h."\"\n\" ----------------------------\n" 2915 | let @h=@h."\" Bookmark table mappings~\n" 2916 | let @h=@h."\" double-click,\n" 2917 | let @h=@h."\" ". g:NERDTreeMapActivateNode .": open bookmark\n" 2918 | let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" 2919 | let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" 2920 | let @h=@h."\" ". g:NERDTreeMapDeleteBookmark .": delete bookmark\n" 2921 | 2922 | let @h=@h."\"\n\" ----------------------------\n" 2923 | let @h=@h."\" Tree navigation mappings~\n" 2924 | let @h=@h."\" ". g:NERDTreeMapJumpRoot .": go to root\n" 2925 | let @h=@h."\" ". g:NERDTreeMapJumpParent .": go to parent\n" 2926 | let @h=@h."\" ". g:NERDTreeMapJumpFirstChild .": go to first child\n" 2927 | let @h=@h."\" ". g:NERDTreeMapJumpLastChild .": go to last child\n" 2928 | let @h=@h."\" ". g:NERDTreeMapJumpNextSibling .": go to next sibling\n" 2929 | let @h=@h."\" ". g:NERDTreeMapJumpPrevSibling .": go to prev sibling\n" 2930 | 2931 | let @h=@h."\"\n\" ----------------------------\n" 2932 | let @h=@h."\" Filesystem mappings~\n" 2933 | let @h=@h."\" ". g:NERDTreeMapChangeRoot .": change tree root to the\n" 2934 | let @h=@h."\" selected dir\n" 2935 | let @h=@h."\" ". g:NERDTreeMapUpdir .": move tree root up a dir\n" 2936 | let @h=@h."\" ". g:NERDTreeMapUpdirKeepOpen .": move tree root up a dir\n" 2937 | let @h=@h."\" but leave old root open\n" 2938 | let @h=@h."\" ". g:NERDTreeMapRefresh .": refresh cursor dir\n" 2939 | let @h=@h."\" ". g:NERDTreeMapRefreshRoot .": refresh current root\n" 2940 | let @h=@h."\" ". g:NERDTreeMapMenu .": Show menu\n" 2941 | let @h=@h."\" ". g:NERDTreeMapChdir .":change the CWD to the\n" 2942 | let @h=@h."\" selected dir\n" 2943 | 2944 | let @h=@h."\"\n\" ----------------------------\n" 2945 | let @h=@h."\" Tree filtering mappings~\n" 2946 | let @h=@h."\" ". g:NERDTreeMapToggleHidden .": hidden files (" . (b:NERDTreeShowHidden ? "on" : "off") . ")\n" 2947 | let @h=@h."\" ". g:NERDTreeMapToggleFilters .": file filters (" . (b:NERDTreeIgnoreEnabled ? "on" : "off") . ")\n" 2948 | let @h=@h."\" ". g:NERDTreeMapToggleFiles .": files (" . (b:NERDTreeShowFiles ? "on" : "off") . ")\n" 2949 | let @h=@h."\" ". g:NERDTreeMapToggleBookmarks .": bookmarks (" . (b:NERDTreeShowBookmarks ? "on" : "off") . ")\n" 2950 | 2951 | "add quickhelp entries for each custom key map 2952 | if len(s:KeyMap.All()) 2953 | let @h=@h."\"\n\" ----------------------------\n" 2954 | let @h=@h."\" Custom mappings~\n" 2955 | for i in s:KeyMap.All() 2956 | let @h=@h."\" ". i.key .": ". i.quickhelpText ."\n" 2957 | endfor 2958 | endif 2959 | 2960 | let @h=@h."\"\n\" ----------------------------\n" 2961 | let @h=@h."\" Other mappings~\n" 2962 | let @h=@h."\" ". g:NERDTreeMapQuit .": Close the NERDTree window\n" 2963 | let @h=@h."\" ". g:NERDTreeMapToggleZoom .": Zoom (maximize-minimize)\n" 2964 | let @h=@h."\" the NERDTree window\n" 2965 | let @h=@h."\" ". g:NERDTreeMapHelp .": toggle help\n" 2966 | let @h=@h."\"\n\" ----------------------------\n" 2967 | let @h=@h."\" Bookmark commands~\n" 2968 | let @h=@h."\" :Bookmark \n" 2969 | let @h=@h."\" :BookmarkToRoot \n" 2970 | let @h=@h."\" :RevealBookmark \n" 2971 | let @h=@h."\" :OpenBookmark \n" 2972 | let @h=@h."\" :ClearBookmarks []\n" 2973 | let @h=@h."\" :ClearAllBookmarks\n" 2974 | silent! put h 2975 | elseif g:NERDTreeMinimalUI == 0 2976 | let @h="\" Press ". g:NERDTreeMapHelp ." for help\n" 2977 | silent! put h 2978 | endif 2979 | 2980 | let @h = old_h 2981 | endfunction 2982 | "FUNCTION: s:echo {{{2 2983 | "A wrapper for :echo. Appends 'NERDTree:' on the front of all messages 2984 | " 2985 | "Args: 2986 | "msg: the message to echo 2987 | function! s:echo(msg) 2988 | redraw 2989 | echomsg "NERDTree: " . a:msg 2990 | endfunction 2991 | "FUNCTION: s:echoWarning {{{2 2992 | "Wrapper for s:echo, sets the message type to warningmsg for this message 2993 | "Args: 2994 | "msg: the message to echo 2995 | function! s:echoWarning(msg) 2996 | echohl warningmsg 2997 | call s:echo(a:msg) 2998 | echohl normal 2999 | endfunction 3000 | "FUNCTION: s:echoError {{{2 3001 | "Wrapper for s:echo, sets the message type to errormsg for this message 3002 | "Args: 3003 | "msg: the message to echo 3004 | function! s:echoError(msg) 3005 | echohl errormsg 3006 | call s:echo(a:msg) 3007 | echohl normal 3008 | endfunction 3009 | "FUNCTION: s:firstUsableWindow(){{{2 3010 | "find the window number of the first normal window 3011 | function! s:firstUsableWindow() 3012 | let i = 1 3013 | while i <= winnr("$") 3014 | let bnum = winbufnr(i) 3015 | if bnum != -1 && getbufvar(bnum, '&buftype') ==# '' 3016 | \ && !getwinvar(i, '&previewwindow') 3017 | \ && (!getbufvar(bnum, '&modified') || &hidden) 3018 | return i 3019 | endif 3020 | 3021 | let i += 1 3022 | endwhile 3023 | return -1 3024 | endfunction 3025 | "FUNCTION: s:getPath(ln) {{{2 3026 | "Gets the full path to the node that is rendered on the given line number 3027 | " 3028 | "Args: 3029 | "ln: the line number to get the path for 3030 | " 3031 | "Return: 3032 | "A path if a node was selected, {} if nothing is selected. 3033 | "If the 'up a dir' line was selected then the path to the parent of the 3034 | "current root is returned 3035 | function! s:getPath(ln) 3036 | let line = getline(a:ln) 3037 | 3038 | let rootLine = s:TreeFileNode.GetRootLineNum() 3039 | 3040 | "check to see if we have the root node 3041 | if a:ln == rootLine 3042 | return b:NERDTreeRoot.path 3043 | endif 3044 | 3045 | if !g:NERDTreeDirArrows 3046 | " in case called from outside the tree 3047 | if line !~# '^ *[|`▸▾ ]' || line =~# '^$' 3048 | return {} 3049 | endif 3050 | endif 3051 | 3052 | if line ==# s:tree_up_dir_line 3053 | return b:NERDTreeRoot.path.getParent() 3054 | endif 3055 | 3056 | let indent = s:indentLevelFor(line) 3057 | 3058 | "remove the tree parts and the leading space 3059 | let curFile = s:stripMarkupFromLine(line, 0) 3060 | 3061 | let wasdir = 0 3062 | if curFile =~# '/$' 3063 | let wasdir = 1 3064 | let curFile = substitute(curFile, '/\?$', '/', "") 3065 | endif 3066 | 3067 | let dir = "" 3068 | let lnum = a:ln 3069 | while lnum > 0 3070 | let lnum = lnum - 1 3071 | let curLine = getline(lnum) 3072 | let curLineStripped = s:stripMarkupFromLine(curLine, 1) 3073 | 3074 | "have we reached the top of the tree? 3075 | if lnum == rootLine 3076 | let dir = b:NERDTreeRoot.path.str({'format': 'UI'}) . dir 3077 | break 3078 | endif 3079 | if curLineStripped =~# '/$' 3080 | let lpindent = s:indentLevelFor(curLine) 3081 | if lpindent < indent 3082 | let indent = indent - 1 3083 | 3084 | let dir = substitute (curLineStripped,'^\\', "", "") . dir 3085 | continue 3086 | endif 3087 | endif 3088 | endwhile 3089 | let curFile = b:NERDTreeRoot.path.drive . dir . curFile 3090 | let toReturn = s:Path.New(curFile) 3091 | return toReturn 3092 | endfunction 3093 | 3094 | "FUNCTION: s:getTreeWinNum() {{{2 3095 | "gets the nerd tree window number for this tab 3096 | function! s:getTreeWinNum() 3097 | if exists("t:NERDTreeBufName") 3098 | return bufwinnr(t:NERDTreeBufName) 3099 | else 3100 | return -1 3101 | endif 3102 | endfunction 3103 | "FUNCTION: s:indentLevelFor(line) {{{2 3104 | function! s:indentLevelFor(line) 3105 | let level = match(a:line, '[^ \-+~▸▾`|]') / s:tree_wid 3106 | " check if line includes arrows 3107 | if match(a:line, '[▸▾]') > -1 3108 | " decrement level as arrow uses 3 ascii chars 3109 | let level = level - 1 3110 | endif 3111 | return level 3112 | endfunction 3113 | "FUNCTION: s:isTreeOpen() {{{2 3114 | function! s:isTreeOpen() 3115 | return s:getTreeWinNum() != -1 3116 | endfunction 3117 | "FUNCTION: s:isWindowUsable(winnumber) {{{2 3118 | "Returns 0 if opening a file from the tree in the given window requires it to 3119 | "be split, 1 otherwise 3120 | " 3121 | "Args: 3122 | "winnumber: the number of the window in question 3123 | function! s:isWindowUsable(winnumber) 3124 | "gotta split if theres only one window (i.e. the NERD tree) 3125 | if winnr("$") ==# 1 3126 | return 0 3127 | endif 3128 | 3129 | let oldwinnr = winnr() 3130 | call s:exec(a:winnumber . "wincmd p") 3131 | let specialWindow = getbufvar("%", '&buftype') != '' || getwinvar('%', '&previewwindow') 3132 | let modified = &modified 3133 | call s:exec(oldwinnr . "wincmd p") 3134 | 3135 | "if its a special window e.g. quickfix or another explorer plugin then we 3136 | "have to split 3137 | if specialWindow 3138 | return 0 3139 | endif 3140 | 3141 | if &hidden 3142 | return 1 3143 | endif 3144 | 3145 | return !modified || s:bufInWindows(winbufnr(a:winnumber)) >= 2 3146 | endfunction 3147 | 3148 | " FUNCTION: s:jumpToChild(direction) {{{2 3149 | " Args: 3150 | " direction: 0 if going to first child, 1 if going to last 3151 | function! s:jumpToChild(direction) 3152 | let currentNode = s:TreeFileNode.GetSelected() 3153 | if currentNode ==# {} || currentNode.isRoot() 3154 | call s:echo("cannot jump to " . (a:direction ? "last" : "first") . " child") 3155 | return 3156 | end 3157 | let dirNode = currentNode.parent 3158 | let childNodes = dirNode.getVisibleChildren() 3159 | 3160 | let targetNode = childNodes[0] 3161 | if a:direction 3162 | let targetNode = childNodes[len(childNodes) - 1] 3163 | endif 3164 | 3165 | if targetNode.equals(currentNode) 3166 | let siblingDir = currentNode.parent.findOpenDirSiblingWithVisibleChildren(a:direction) 3167 | if siblingDir != {} 3168 | let indx = a:direction ? siblingDir.getVisibleChildCount()-1 : 0 3169 | let targetNode = siblingDir.getChildByIndex(indx, 1) 3170 | endif 3171 | endif 3172 | 3173 | call targetNode.putCursorHere(1, 0) 3174 | 3175 | call s:centerView() 3176 | endfunction 3177 | 3178 | 3179 | "FUNCTION: s:promptToDelBuffer(bufnum, msg){{{2 3180 | "prints out the given msg and, if the user responds by pushing 'y' then the 3181 | "buffer with the given bufnum is deleted 3182 | " 3183 | "Args: 3184 | "bufnum: the buffer that may be deleted 3185 | "msg: a message that will be echoed to the user asking them if they wish to 3186 | " del the buffer 3187 | function! s:promptToDelBuffer(bufnum, msg) 3188 | echo a:msg 3189 | if nr2char(getchar()) ==# 'y' 3190 | exec "silent bdelete! " . a:bufnum 3191 | endif 3192 | endfunction 3193 | 3194 | "FUNCTION: s:putCursorOnBookmarkTable(){{{2 3195 | "Places the cursor at the top of the bookmarks table 3196 | function! s:putCursorOnBookmarkTable() 3197 | if !b:NERDTreeShowBookmarks 3198 | throw "NERDTree.IllegalOperationError: cant find bookmark table, bookmarks arent active" 3199 | endif 3200 | 3201 | if g:NERDTreeMinimalUI 3202 | return cursor(1, 2) 3203 | endif 3204 | 3205 | let rootNodeLine = s:TreeFileNode.GetRootLineNum() 3206 | 3207 | let line = 1 3208 | while getline(line) !~# '^>-\+Bookmarks-\+$' 3209 | let line = line + 1 3210 | if line >= rootNodeLine 3211 | throw "NERDTree.BookmarkTableNotFoundError: didnt find the bookmarks table" 3212 | endif 3213 | endwhile 3214 | call cursor(line, 2) 3215 | endfunction 3216 | 3217 | "FUNCTION: s:putCursorInTreeWin(){{{2 3218 | "Places the cursor in the nerd tree window 3219 | function! s:putCursorInTreeWin() 3220 | if !s:isTreeOpen() 3221 | throw "NERDTree.InvalidOperationError: cant put cursor in NERD tree window, no window exists" 3222 | endif 3223 | 3224 | call s:exec(s:getTreeWinNum() . "wincmd w") 3225 | endfunction 3226 | 3227 | "FUNCTION: s:renderBookmarks {{{2 3228 | function! s:renderBookmarks() 3229 | 3230 | if g:NERDTreeMinimalUI == 0 3231 | call setline(line(".")+1, ">----------Bookmarks----------") 3232 | call cursor(line(".")+1, col(".")) 3233 | endif 3234 | 3235 | for i in s:Bookmark.Bookmarks() 3236 | call setline(line(".")+1, i.str()) 3237 | call cursor(line(".")+1, col(".")) 3238 | endfor 3239 | 3240 | call setline(line(".")+1, '') 3241 | call cursor(line(".")+1, col(".")) 3242 | endfunction 3243 | "FUNCTION: s:renderView {{{2 3244 | "The entry function for rendering the tree 3245 | function! s:renderView() 3246 | setlocal modifiable 3247 | 3248 | "remember the top line of the buffer and the current line so we can 3249 | "restore the view exactly how it was 3250 | let curLine = line(".") 3251 | let curCol = col(".") 3252 | let topLine = line("w0") 3253 | 3254 | "delete all lines in the buffer (being careful not to clobber a register) 3255 | silent 1,$delete _ 3256 | 3257 | call s:dumpHelp() 3258 | 3259 | "delete the blank line before the help and add one after it 3260 | if g:NERDTreeMinimalUI == 0 3261 | call setline(line(".")+1, "") 3262 | call cursor(line(".")+1, col(".")) 3263 | endif 3264 | 3265 | if b:NERDTreeShowBookmarks 3266 | call s:renderBookmarks() 3267 | endif 3268 | 3269 | "add the 'up a dir' line 3270 | if !g:NERDTreeMinimalUI 3271 | call setline(line(".")+1, s:tree_up_dir_line) 3272 | call cursor(line(".")+1, col(".")) 3273 | endif 3274 | 3275 | "draw the header line 3276 | let header = b:NERDTreeRoot.path.str({'format': 'UI', 'truncateTo': winwidth(0)}) 3277 | call setline(line(".")+1, header) 3278 | call cursor(line(".")+1, col(".")) 3279 | 3280 | "draw the tree 3281 | let old_o = @o 3282 | let @o = b:NERDTreeRoot.renderToString() 3283 | silent put o 3284 | let @o = old_o 3285 | 3286 | "delete the blank line at the top of the buffer 3287 | silent 1,1delete _ 3288 | 3289 | "restore the view 3290 | let old_scrolloff=&scrolloff 3291 | let &scrolloff=0 3292 | call cursor(topLine, 1) 3293 | normal! zt 3294 | call cursor(curLine, curCol) 3295 | let &scrolloff = old_scrolloff 3296 | 3297 | setlocal nomodifiable 3298 | endfunction 3299 | 3300 | "FUNCTION: s:renderViewSavingPosition {{{2 3301 | "Renders the tree and ensures the cursor stays on the current node or the 3302 | "current nodes parent if it is no longer available upon re-rendering 3303 | function! s:renderViewSavingPosition() 3304 | let currentNode = s:TreeFileNode.GetSelected() 3305 | 3306 | "go up the tree till we find a node that will be visible or till we run 3307 | "out of nodes 3308 | while currentNode != {} && !currentNode.isVisible() && !currentNode.isRoot() 3309 | let currentNode = currentNode.parent 3310 | endwhile 3311 | 3312 | call s:renderView() 3313 | 3314 | if currentNode != {} 3315 | call currentNode.putCursorHere(0, 0) 3316 | endif 3317 | endfunction 3318 | "FUNCTION: s:restoreScreenState() {{{2 3319 | " 3320 | "Sets the screen state back to what it was when s:saveScreenState was last 3321 | "called. 3322 | " 3323 | "Assumes the cursor is in the NERDTree window 3324 | function! s:restoreScreenState() 3325 | if !exists("b:NERDTreeOldTopLine") || !exists("b:NERDTreeOldPos") || !exists("b:NERDTreeOldWindowSize") 3326 | return 3327 | endif 3328 | exec("silent vertical resize ".b:NERDTreeOldWindowSize) 3329 | 3330 | let old_scrolloff=&scrolloff 3331 | let &scrolloff=0 3332 | call cursor(b:NERDTreeOldTopLine, 0) 3333 | normal! zt 3334 | call setpos(".", b:NERDTreeOldPos) 3335 | let &scrolloff=old_scrolloff 3336 | endfunction 3337 | 3338 | "FUNCTION: s:saveScreenState() {{{2 3339 | "Saves the current cursor position in the current buffer and the window 3340 | "scroll position 3341 | function! s:saveScreenState() 3342 | let win = winnr() 3343 | try 3344 | call s:putCursorInTreeWin() 3345 | let b:NERDTreeOldPos = getpos(".") 3346 | let b:NERDTreeOldTopLine = line("w0") 3347 | let b:NERDTreeOldWindowSize = winwidth("") 3348 | call s:exec(win . "wincmd w") 3349 | catch /^NERDTree.InvalidOperationError/ 3350 | endtry 3351 | endfunction 3352 | 3353 | "FUNCTION: s:setCommonBufOptions() {{{2 3354 | function! s:setCommonBufOptions() 3355 | "throwaway buffer options 3356 | setlocal noswapfile 3357 | setlocal buftype=nofile 3358 | setlocal bufhidden=hide 3359 | setlocal nowrap 3360 | setlocal foldcolumn=0 3361 | setlocal nobuflisted 3362 | setlocal nospell 3363 | if g:NERDTreeShowLineNumbers 3364 | setlocal nu 3365 | else 3366 | setlocal nonu 3367 | if v:version >= 703 3368 | setlocal nornu 3369 | endif 3370 | endif 3371 | 3372 | iabc 3373 | 3374 | if g:NERDTreeHighlightCursorline 3375 | setlocal cursorline 3376 | endif 3377 | 3378 | call s:setupStatusline() 3379 | 3380 | 3381 | let b:treeShowHelp = 0 3382 | let b:NERDTreeIgnoreEnabled = 1 3383 | let b:NERDTreeShowFiles = g:NERDTreeShowFiles 3384 | let b:NERDTreeShowHidden = g:NERDTreeShowHidden 3385 | let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks 3386 | setfiletype nerdtree 3387 | call s:bindMappings() 3388 | endfunction 3389 | 3390 | "FUNCTION: s:setupStatusline() {{{2 3391 | function! s:setupStatusline() 3392 | if g:NERDTreeStatusline != -1 3393 | let &l:statusline = g:NERDTreeStatusline 3394 | endif 3395 | endfunction 3396 | "FUNCTION: s:stripMarkupFromLine(line, removeLeadingSpaces){{{2 3397 | "returns the given line with all the tree parts stripped off 3398 | " 3399 | "Args: 3400 | "line: the subject line 3401 | "removeLeadingSpaces: 1 if leading spaces are to be removed (leading spaces = 3402 | "any spaces before the actual text of the node) 3403 | function! s:stripMarkupFromLine(line, removeLeadingSpaces) 3404 | let line = a:line 3405 | "remove the tree parts and the leading space 3406 | let line = substitute (line, s:tree_markup_reg,"","") 3407 | 3408 | "strip off any read only flag 3409 | let line = substitute (line, ' \[RO\]', "","") 3410 | 3411 | "strip off any bookmark flags 3412 | let line = substitute (line, ' {[^}]*}', "","") 3413 | 3414 | "strip off any executable flags 3415 | let line = substitute (line, '*\ze\($\| \)', "","") 3416 | 3417 | let wasdir = 0 3418 | if line =~# '/$' 3419 | let wasdir = 1 3420 | endif 3421 | let line = substitute (line,' -> .*',"","") " remove link to 3422 | if wasdir ==# 1 3423 | let line = substitute (line, '/\?$', '/', "") 3424 | endif 3425 | 3426 | if a:removeLeadingSpaces 3427 | let line = substitute (line, '^ *', '', '') 3428 | endif 3429 | 3430 | return line 3431 | endfunction 3432 | 3433 | "FUNCTION: s:toggle(dir) {{{2 3434 | "Toggles the NERD tree. I.e the NERD tree is open, it is closed, if it is 3435 | "closed it is restored or initialized (if it doesnt exist) 3436 | " 3437 | "Args: 3438 | "dir: the full path for the root node (is only used if the NERD tree is being 3439 | "initialized. 3440 | function! s:toggle(dir) 3441 | if s:treeExistsForTab() 3442 | if !s:isTreeOpen() 3443 | call s:createTreeWin() 3444 | if !&hidden 3445 | call s:renderView() 3446 | endif 3447 | call s:restoreScreenState() 3448 | else 3449 | call s:closeTree() 3450 | endif 3451 | else 3452 | call s:initNerdTree(a:dir) 3453 | endif 3454 | endfunction 3455 | "SECTION: Interface bindings {{{1 3456 | "============================================================ 3457 | "FUNCTION: s:activateNode(forceKeepWindowOpen) {{{2 3458 | "If the current node is a file, open it in the previous window (or a new one 3459 | "if the previous is modified). If it is a directory then it is opened. 3460 | " 3461 | "args: 3462 | "forceKeepWindowOpen - dont close the window even if NERDTreeQuitOnOpen is set 3463 | function! s:activateNode(forceKeepWindowOpen) 3464 | if getline(".") ==# s:tree_up_dir_line 3465 | return s:upDir(0) 3466 | endif 3467 | 3468 | let treenode = s:TreeFileNode.GetSelected() 3469 | if treenode != {} 3470 | call treenode.activate(a:forceKeepWindowOpen) 3471 | else 3472 | let bookmark = s:Bookmark.GetSelected() 3473 | if !empty(bookmark) 3474 | call bookmark.activate() 3475 | endif 3476 | endif 3477 | endfunction 3478 | 3479 | "FUNCTION: s:bindMappings() {{{2 3480 | function! s:bindMappings() 3481 | " set up mappings and commands for this buffer 3482 | nnoremap :call handleMiddleMouse() 3483 | nnoremap :call checkForActivate() 3484 | nnoremap <2-leftmouse> :call activateNode(0) 3485 | 3486 | exec "nnoremap ". g:NERDTreeMapActivateNode . " :call activateNode(0)" 3487 | exec "nnoremap ". g:NERDTreeMapOpenSplit ." :call openEntrySplit(0,0)" 3488 | exec "nnoremap :call activateNode(0)" 3489 | 3490 | exec "nnoremap ". g:NERDTreeMapPreview ." :call previewNode(0)" 3491 | exec "nnoremap ". g:NERDTreeMapPreviewSplit ." :call previewNode(1)" 3492 | 3493 | exec "nnoremap ". g:NERDTreeMapOpenVSplit ." :call openEntrySplit(1,0)" 3494 | exec "nnoremap ". g:NERDTreeMapPreviewVSplit ." :call previewNode(2)" 3495 | 3496 | exec "nnoremap ". g:NERDTreeMapOpenRecursively ." :call openNodeRecursively()" 3497 | 3498 | exec "nnoremap ". g:NERDTreeMapUpdirKeepOpen ." :call upDir(1)" 3499 | exec "nnoremap ". g:NERDTreeMapUpdir ." :call upDir(0)" 3500 | exec "nnoremap ". g:NERDTreeMapChangeRoot ." :call chRoot()" 3501 | 3502 | exec "nnoremap ". g:NERDTreeMapChdir ." :call chCwd()" 3503 | 3504 | exec "nnoremap ". g:NERDTreeMapQuit ." :call closeTreeWindow()" 3505 | 3506 | exec "nnoremap ". g:NERDTreeMapRefreshRoot ." :call refreshRoot()" 3507 | exec "nnoremap ". g:NERDTreeMapRefresh ." :call refreshCurrent()" 3508 | 3509 | exec "nnoremap ". g:NERDTreeMapHelp ." :call displayHelp()" 3510 | exec "nnoremap ". g:NERDTreeMapToggleZoom ." :call toggleZoom()" 3511 | exec "nnoremap ". g:NERDTreeMapToggleHidden ." :call toggleShowHidden()" 3512 | exec "nnoremap ". g:NERDTreeMapToggleFilters ." :call toggleIgnoreFilter()" 3513 | exec "nnoremap ". g:NERDTreeMapToggleFiles ." :call toggleShowFiles()" 3514 | exec "nnoremap ". g:NERDTreeMapToggleBookmarks ." :call toggleShowBookmarks()" 3515 | 3516 | exec "nnoremap ". g:NERDTreeMapCloseDir ." :call closeCurrentDir()" 3517 | exec "nnoremap ". g:NERDTreeMapCloseChildren ." :call closeChildren()" 3518 | 3519 | exec "nnoremap ". g:NERDTreeMapMenu ." :call showMenu()" 3520 | 3521 | exec "nnoremap ". g:NERDTreeMapJumpParent ." :call jumpToParent()" 3522 | exec "nnoremap ". g:NERDTreeMapJumpNextSibling ." :call jumpToSibling(1)" 3523 | exec "nnoremap ". g:NERDTreeMapJumpPrevSibling ." :call jumpToSibling(0)" 3524 | exec "nnoremap ". g:NERDTreeMapJumpFirstChild ." :call jumpToFirstChild()" 3525 | exec "nnoremap ". g:NERDTreeMapJumpLastChild ." :call jumpToLastChild()" 3526 | exec "nnoremap ". g:NERDTreeMapJumpRoot ." :call jumpToRoot()" 3527 | 3528 | exec "nnoremap ". g:NERDTreeMapOpenInTab ." :call openInNewTab(0)" 3529 | exec "nnoremap ". g:NERDTreeMapOpenInTabSilent ." :call openInNewTab(1)" 3530 | 3531 | exec "nnoremap ". g:NERDTreeMapOpenExpl ." :call openExplorer()" 3532 | 3533 | exec "nnoremap ". g:NERDTreeMapDeleteBookmark ." :call deleteBookmark()" 3534 | 3535 | "bind all the user custom maps 3536 | call s:KeyMap.BindAll() 3537 | 3538 | command! -buffer -nargs=? Bookmark :call bookmarkNode('') 3539 | command! -buffer -complete=customlist,s:completeBookmarks -nargs=1 RevealBookmark :call revealBookmark('') 3540 | command! -buffer -complete=customlist,s:completeBookmarks -nargs=1 OpenBookmark :call openBookmark('') 3541 | command! -buffer -complete=customlist,s:completeBookmarks -nargs=* ClearBookmarks call clearBookmarks('') 3542 | command! -buffer -complete=customlist,s:completeBookmarks -nargs=+ BookmarkToRoot call s:Bookmark.ToRoot('') 3543 | command! -buffer -nargs=0 ClearAllBookmarks call s:Bookmark.ClearAll() call renderView() 3544 | command! -buffer -nargs=0 ReadBookmarks call s:Bookmark.CacheBookmarks(0) call renderView() 3545 | command! -buffer -nargs=0 WriteBookmarks call s:Bookmark.Write() 3546 | endfunction 3547 | 3548 | " FUNCTION: s:bookmarkNode(name) {{{2 3549 | " Associate the current node with the given name 3550 | function! s:bookmarkNode(...) 3551 | let currentNode = s:TreeFileNode.GetSelected() 3552 | if currentNode != {} 3553 | let name = a:1 3554 | if empty(name) 3555 | let name = currentNode.path.getLastPathComponent(0) 3556 | endif 3557 | try 3558 | call currentNode.bookmark(name) 3559 | call s:renderView() 3560 | catch /^NERDTree.IllegalBookmarkNameError/ 3561 | call s:echo("bookmark names must not contain spaces") 3562 | endtry 3563 | else 3564 | call s:echo("select a node first") 3565 | endif 3566 | endfunction 3567 | "FUNCTION: s:checkForActivate() {{{2 3568 | "Checks if the click should open the current node, if so then activate() is 3569 | "called (directories are automatically opened if the symbol beside them is 3570 | "clicked) 3571 | function! s:checkForActivate() 3572 | let currentNode = s:TreeFileNode.GetSelected() 3573 | if currentNode != {} 3574 | let startToCur = strpart(getline(line(".")), 0, col(".")) 3575 | 3576 | if currentNode.path.isDirectory 3577 | if startToCur =~# s:tree_markup_reg . '$' && startToCur =~# '[+~▾▸]$' 3578 | call s:activateNode(0) 3579 | return 3580 | endif 3581 | endif 3582 | 3583 | if (g:NERDTreeMouseMode ==# 2 && currentNode.path.isDirectory) || g:NERDTreeMouseMode ==# 3 3584 | let char = strpart(startToCur, strlen(startToCur)-1, 1) 3585 | if char !~# s:tree_markup_reg 3586 | call s:activateNode(0) 3587 | return 3588 | endif 3589 | endif 3590 | endif 3591 | endfunction 3592 | 3593 | " FUNCTION: s:chCwd() {{{2 3594 | function! s:chCwd() 3595 | let treenode = s:TreeFileNode.GetSelected() 3596 | if treenode ==# {} 3597 | call s:echo("Select a node first") 3598 | return 3599 | endif 3600 | 3601 | try 3602 | call treenode.path.changeToDir() 3603 | catch /^NERDTree.PathChangeError/ 3604 | call s:echoWarning("could not change cwd") 3605 | endtry 3606 | endfunction 3607 | 3608 | " FUNCTION: s:chRoot() {{{2 3609 | " changes the current root to the selected one 3610 | function! s:chRoot() 3611 | let treenode = s:TreeFileNode.GetSelected() 3612 | if treenode ==# {} 3613 | call s:echo("Select a node first") 3614 | return 3615 | endif 3616 | 3617 | call treenode.makeRoot() 3618 | call s:renderView() 3619 | call b:NERDTreeRoot.putCursorHere(0, 0) 3620 | endfunction 3621 | 3622 | " FUNCTION: s:clearBookmarks(bookmarks) {{{2 3623 | function! s:clearBookmarks(bookmarks) 3624 | if a:bookmarks ==# '' 3625 | let currentNode = s:TreeFileNode.GetSelected() 3626 | if currentNode != {} 3627 | call currentNode.clearBoomarks() 3628 | endif 3629 | else 3630 | for name in split(a:bookmarks, ' ') 3631 | let bookmark = s:Bookmark.BookmarkFor(name) 3632 | call bookmark.delete() 3633 | endfor 3634 | endif 3635 | call s:renderView() 3636 | endfunction 3637 | " FUNCTION: s:closeChildren() {{{2 3638 | " closes all childnodes of the current node 3639 | function! s:closeChildren() 3640 | let currentNode = s:TreeDirNode.GetSelected() 3641 | if currentNode ==# {} 3642 | call s:echo("Select a node first") 3643 | return 3644 | endif 3645 | 3646 | call currentNode.closeChildren() 3647 | call s:renderView() 3648 | call currentNode.putCursorHere(0, 0) 3649 | endfunction 3650 | " FUNCTION: s:closeCurrentDir() {{{2 3651 | " closes the parent dir of the current node 3652 | function! s:closeCurrentDir() 3653 | let treenode = s:TreeFileNode.GetSelected() 3654 | if treenode ==# {} 3655 | call s:echo("Select a node first") 3656 | return 3657 | endif 3658 | 3659 | let parent = treenode.parent 3660 | if parent ==# {} || parent.isRoot() 3661 | call s:echo("cannot close tree root") 3662 | else 3663 | call treenode.parent.close() 3664 | call s:renderView() 3665 | call treenode.parent.putCursorHere(0, 0) 3666 | endif 3667 | endfunction 3668 | " FUNCTION: s:closeTreeWindow() {{{2 3669 | " close the tree window 3670 | function! s:closeTreeWindow() 3671 | if b:NERDTreeType ==# "secondary" && b:NERDTreePreviousBuf != -1 3672 | exec "buffer " . b:NERDTreePreviousBuf 3673 | else 3674 | if winnr("$") > 1 3675 | call s:closeTree() 3676 | else 3677 | call s:echo("Cannot close last window") 3678 | endif 3679 | endif 3680 | endfunction 3681 | " FUNCTION: s:deleteBookmark() {{{2 3682 | " if the cursor is on a bookmark, prompt to delete 3683 | function! s:deleteBookmark() 3684 | let bookmark = s:Bookmark.GetSelected() 3685 | if bookmark ==# {} 3686 | call s:echo("Put the cursor on a bookmark") 3687 | return 3688 | endif 3689 | 3690 | echo "Are you sure you wish to delete the bookmark:\n\"" . bookmark.name . "\" (yN):" 3691 | 3692 | if nr2char(getchar()) ==# 'y' 3693 | try 3694 | call bookmark.delete() 3695 | call s:renderView() 3696 | redraw 3697 | catch /^NERDTree/ 3698 | call s:echoWarning("Could not remove bookmark") 3699 | endtry 3700 | else 3701 | call s:echo("delete aborted" ) 3702 | endif 3703 | 3704 | endfunction 3705 | 3706 | " FUNCTION: s:displayHelp() {{{2 3707 | " toggles the help display 3708 | function! s:displayHelp() 3709 | let b:treeShowHelp = b:treeShowHelp ? 0 : 1 3710 | call s:renderView() 3711 | call s:centerView() 3712 | endfunction 3713 | 3714 | " FUNCTION: s:handleMiddleMouse() {{{2 3715 | function! s:handleMiddleMouse() 3716 | let curNode = s:TreeFileNode.GetSelected() 3717 | if curNode ==# {} 3718 | call s:echo("Put the cursor on a node first" ) 3719 | return 3720 | endif 3721 | 3722 | if curNode.path.isDirectory 3723 | call s:openExplorer() 3724 | else 3725 | call s:openEntrySplit(0,0) 3726 | endif 3727 | endfunction 3728 | 3729 | 3730 | " FUNCTION: s:jumpToFirstChild() {{{2 3731 | " wrapper for the jump to child method 3732 | function! s:jumpToFirstChild() 3733 | call s:jumpToChild(0) 3734 | endfunction 3735 | 3736 | " FUNCTION: s:jumpToLastChild() {{{2 3737 | " wrapper for the jump to child method 3738 | function! s:jumpToLastChild() 3739 | call s:jumpToChild(1) 3740 | endfunction 3741 | 3742 | " FUNCTION: s:jumpToParent() {{{2 3743 | " moves the cursor to the parent of the current node 3744 | function! s:jumpToParent() 3745 | let currentNode = s:TreeFileNode.GetSelected() 3746 | if !empty(currentNode) 3747 | if !empty(currentNode.parent) 3748 | call currentNode.parent.putCursorHere(1, 0) 3749 | call s:centerView() 3750 | else 3751 | call s:echo("cannot jump to parent") 3752 | endif 3753 | else 3754 | call s:echo("put the cursor on a node first") 3755 | endif 3756 | endfunction 3757 | 3758 | " FUNCTION: s:jumpToRoot() {{{2 3759 | " moves the cursor to the root node 3760 | function! s:jumpToRoot() 3761 | call b:NERDTreeRoot.putCursorHere(1, 0) 3762 | call s:centerView() 3763 | endfunction 3764 | 3765 | " FUNCTION: s:jumpToSibling() {{{2 3766 | " moves the cursor to the sibling of the current node in the given direction 3767 | " 3768 | " Args: 3769 | " forward: 1 if the cursor should move to the next sibling, 0 if it should 3770 | " move back to the previous sibling 3771 | function! s:jumpToSibling(forward) 3772 | let currentNode = s:TreeFileNode.GetSelected() 3773 | if !empty(currentNode) 3774 | let sibling = currentNode.findSibling(a:forward) 3775 | 3776 | if !empty(sibling) 3777 | call sibling.putCursorHere(1, 0) 3778 | call s:centerView() 3779 | endif 3780 | else 3781 | call s:echo("put the cursor on a node first") 3782 | endif 3783 | endfunction 3784 | 3785 | " FUNCTION: s:openBookmark(name) {{{2 3786 | " put the cursor on the given bookmark and, if its a file, open it 3787 | function! s:openBookmark(name) 3788 | try 3789 | let targetNode = s:Bookmark.GetNodeForName(a:name, 0) 3790 | call targetNode.putCursorHere(0, 1) 3791 | redraw! 3792 | catch /^NERDTree.BookmarkedNodeNotFoundError/ 3793 | call s:echo("note - target node is not cached") 3794 | let bookmark = s:Bookmark.BookmarkFor(a:name) 3795 | let targetNode = s:TreeFileNode.New(bookmark.path) 3796 | endtry 3797 | if targetNode.path.isDirectory 3798 | call targetNode.openExplorer() 3799 | else 3800 | call targetNode.open() 3801 | endif 3802 | endfunction 3803 | " FUNCTION: s:openEntrySplit(vertical, forceKeepWindowOpen) {{{2 3804 | "Opens the currently selected file from the explorer in a 3805 | "new window 3806 | " 3807 | "args: 3808 | "forceKeepWindowOpen - dont close the window even if NERDTreeQuitOnOpen is set 3809 | function! s:openEntrySplit(vertical, forceKeepWindowOpen) 3810 | let treenode = s:TreeFileNode.GetSelected() 3811 | if treenode != {} 3812 | if a:vertical 3813 | call treenode.openVSplit() 3814 | else 3815 | call treenode.openSplit() 3816 | endif 3817 | if !a:forceKeepWindowOpen 3818 | call s:closeTreeIfQuitOnOpen() 3819 | endif 3820 | else 3821 | call s:echo("select a node first") 3822 | endif 3823 | endfunction 3824 | 3825 | " FUNCTION: s:openExplorer() {{{2 3826 | function! s:openExplorer() 3827 | let treenode = s:TreeDirNode.GetSelected() 3828 | if treenode != {} 3829 | call treenode.openExplorer() 3830 | else 3831 | call s:echo("select a node first") 3832 | endif 3833 | endfunction 3834 | 3835 | " FUNCTION: s:openInNewTab(stayCurrentTab) {{{2 3836 | " Opens the selected node or bookmark in a new tab 3837 | " Args: 3838 | " stayCurrentTab: if 1 then vim will stay in the current tab, if 0 then vim 3839 | " will go to the tab where the new file is opened 3840 | function! s:openInNewTab(stayCurrentTab) 3841 | let target = s:TreeFileNode.GetSelected() 3842 | if target == {} 3843 | let target = s:Bookmark.GetSelected() 3844 | endif 3845 | 3846 | if target != {} 3847 | call target.openInNewTab({'stayInCurrentTab': a:stayCurrentTab}) 3848 | endif 3849 | endfunction 3850 | 3851 | " FUNCTION: s:openNodeRecursively() {{{2 3852 | function! s:openNodeRecursively() 3853 | let treenode = s:TreeFileNode.GetSelected() 3854 | if treenode ==# {} || treenode.path.isDirectory ==# 0 3855 | call s:echo("Select a directory node first" ) 3856 | else 3857 | call s:echo("Recursively opening node. Please wait...") 3858 | call treenode.openRecursively() 3859 | call s:renderView() 3860 | redraw 3861 | call s:echo("Recursively opening node. Please wait... DONE") 3862 | endif 3863 | 3864 | endfunction 3865 | 3866 | "FUNCTION: s:previewNode() {{{2 3867 | "Args: 3868 | " openNewWin: if 0, use the previous window, if 1 open in new split, if 2 3869 | " open in a vsplit 3870 | function! s:previewNode(openNewWin) 3871 | let currentBuf = bufnr("") 3872 | if a:openNewWin > 0 3873 | call s:openEntrySplit(a:openNewWin ==# 2,1) 3874 | else 3875 | call s:activateNode(1) 3876 | end 3877 | call s:exec(bufwinnr(currentBuf) . "wincmd w") 3878 | endfunction 3879 | 3880 | " FUNCTION: s:revealBookmark(name) {{{2 3881 | " put the cursor on the node associate with the given name 3882 | function! s:revealBookmark(name) 3883 | try 3884 | let targetNode = s:Bookmark.GetNodeForName(a:name, 0) 3885 | call targetNode.putCursorHere(0, 1) 3886 | catch /^NERDTree.BookmarkNotFoundError/ 3887 | call s:echo("Bookmark isnt cached under the current root") 3888 | endtry 3889 | endfunction 3890 | " FUNCTION: s:refreshRoot() {{{2 3891 | " Reloads the current root. All nodes below this will be lost and the root dir 3892 | " will be reloaded. 3893 | function! s:refreshRoot() 3894 | call s:echo("Refreshing the root node. This could take a while...") 3895 | call b:NERDTreeRoot.refresh() 3896 | call s:renderView() 3897 | redraw 3898 | call s:echo("Refreshing the root node. This could take a while... DONE") 3899 | endfunction 3900 | 3901 | " FUNCTION: s:refreshCurrent() {{{2 3902 | " refreshes the root for the current node 3903 | function! s:refreshCurrent() 3904 | let treenode = s:TreeDirNode.GetSelected() 3905 | if treenode ==# {} 3906 | call s:echo("Refresh failed. Select a node first") 3907 | return 3908 | endif 3909 | 3910 | call s:echo("Refreshing node. This could take a while...") 3911 | call treenode.refresh() 3912 | call s:renderView() 3913 | redraw 3914 | call s:echo("Refreshing node. This could take a while... DONE") 3915 | endfunction 3916 | " FUNCTION: s:showMenu() {{{2 3917 | function! s:showMenu() 3918 | let curNode = s:TreeFileNode.GetSelected() 3919 | if curNode ==# {} 3920 | call s:echo("Put the cursor on a node first" ) 3921 | return 3922 | endif 3923 | 3924 | let mc = s:MenuController.New(s:MenuItem.AllEnabled()) 3925 | call mc.showMenu() 3926 | endfunction 3927 | 3928 | " FUNCTION: s:toggleIgnoreFilter() {{{2 3929 | " toggles the use of the NERDTreeIgnore option 3930 | function! s:toggleIgnoreFilter() 3931 | let b:NERDTreeIgnoreEnabled = !b:NERDTreeIgnoreEnabled 3932 | call s:renderViewSavingPosition() 3933 | call s:centerView() 3934 | endfunction 3935 | 3936 | " FUNCTION: s:toggleShowBookmarks() {{{2 3937 | " toggles the display of bookmarks 3938 | function! s:toggleShowBookmarks() 3939 | let b:NERDTreeShowBookmarks = !b:NERDTreeShowBookmarks 3940 | if b:NERDTreeShowBookmarks 3941 | call s:renderView() 3942 | call s:putCursorOnBookmarkTable() 3943 | else 3944 | call s:renderViewSavingPosition() 3945 | endif 3946 | call s:centerView() 3947 | endfunction 3948 | " FUNCTION: s:toggleShowFiles() {{{2 3949 | " toggles the display of hidden files 3950 | function! s:toggleShowFiles() 3951 | let b:NERDTreeShowFiles = !b:NERDTreeShowFiles 3952 | call s:renderViewSavingPosition() 3953 | call s:centerView() 3954 | endfunction 3955 | 3956 | " FUNCTION: s:toggleShowHidden() {{{2 3957 | " toggles the display of hidden files 3958 | function! s:toggleShowHidden() 3959 | let b:NERDTreeShowHidden = !b:NERDTreeShowHidden 3960 | call s:renderViewSavingPosition() 3961 | call s:centerView() 3962 | endfunction 3963 | 3964 | " FUNCTION: s:toggleZoom() {{2 3965 | " zoom (maximize/minimize) the NERDTree window 3966 | function! s:toggleZoom() 3967 | if exists("b:NERDTreeZoomed") && b:NERDTreeZoomed 3968 | let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize 3969 | exec "silent vertical resize ". size 3970 | let b:NERDTreeZoomed = 0 3971 | else 3972 | exec "vertical resize" 3973 | let b:NERDTreeZoomed = 1 3974 | endif 3975 | endfunction 3976 | 3977 | "FUNCTION: s:upDir(keepState) {{{2 3978 | "moves the tree up a level 3979 | " 3980 | "Args: 3981 | "keepState: 1 if the current root should be left open when the tree is 3982 | "re-rendered 3983 | function! s:upDir(keepState) 3984 | let cwd = b:NERDTreeRoot.path.str({'format': 'UI'}) 3985 | if cwd ==# "/" || cwd =~# '^[^/]..$' 3986 | call s:echo("already at top dir") 3987 | else 3988 | if !a:keepState 3989 | call b:NERDTreeRoot.close() 3990 | endif 3991 | 3992 | let oldRoot = b:NERDTreeRoot 3993 | 3994 | if empty(b:NERDTreeRoot.parent) 3995 | let path = b:NERDTreeRoot.path.getParent() 3996 | let newRoot = s:TreeDirNode.New(path) 3997 | call newRoot.open() 3998 | call newRoot.transplantChild(b:NERDTreeRoot) 3999 | let b:NERDTreeRoot = newRoot 4000 | else 4001 | let b:NERDTreeRoot = b:NERDTreeRoot.parent 4002 | endif 4003 | 4004 | if g:NERDTreeChDirMode ==# 2 4005 | call b:NERDTreeRoot.path.changeToDir() 4006 | endif 4007 | 4008 | call s:renderView() 4009 | call oldRoot.putCursorHere(0, 0) 4010 | endif 4011 | endfunction 4012 | 4013 | 4014 | "reset &cpo back to users setting 4015 | let &cpo = s:old_cpo 4016 | 4017 | " vim: set sw=4 sts=4 et fdm=marker: 4018 | --------------------------------------------------------------------------------