nerdtree

A tree explorer plugin for vim.
Index Commits Files Refs
nerdtree_plugin/fs_menu.vim (18931B)
   1 " ============================================================================
   2 " File:        fs_menu.vim
   3 " Description: plugin for the NERD Tree that provides a file system menu
   4 " Maintainer:  Martin Grenfell <martin.grenfell at gmail dot com>
   5 " License:     This program is free software. It comes without any warranty,
   6 "              to the extent permitted by applicable law. You can redistribute
   7 "              it and/or modify it under the terms of the Do What The Fuck You
   8 "              Want To Public License, Version 2, as published by Sam Hocevar.
   9 "              See http://sam.zoy.org/wtfpl/COPYING for more details.
  10 "
  11 " ============================================================================
  12 if exists('g:loaded_nerdtree_fs_menu')
  13     finish
  14 endif
  15 let g:loaded_nerdtree_fs_menu = 1
  16 
  17 "Automatically delete the buffer after deleting or renaming a file
  18 if !exists('g:NERDTreeAutoDeleteBuffer')
  19     let g:NERDTreeAutoDeleteBuffer = 0
  20 endif
  21 
  22 call NERDTreeAddMenuItem({'text': '(a)dd a childnode', 'shortcut': 'a', 'callback': 'NERDTreeAddNode'})
  23 call NERDTreeAddMenuItem({'text': '(m)ove the current node', 'shortcut': 'm', 'callback': 'NERDTreeMoveNode'})
  24 call NERDTreeAddMenuItem({'text': '(d)elete the current node', 'shortcut': 'd', 'callback': 'NERDTreeDeleteNode'})
  25 
  26 if has('gui_mac') || has('gui_macvim') || has('mac')
  27     call NERDTreeAddMenuItem({'text': '(r)eveal in Finder the current node', 'shortcut': 'r', 'callback': 'NERDTreeRevealInFinder'})
  28     call NERDTreeAddMenuItem({'text': '(o)pen the current node with system editor', 'shortcut': 'o', 'callback': 'NERDTreeExecuteFile'})
  29     call NERDTreeAddMenuItem({'text': '(q)uicklook the current node', 'shortcut': 'q', 'callback': 'NERDTreeQuickLook'})
  30 endif
  31 
  32 if executable('xdg-open')
  33     call NERDTreeAddMenuItem({'text': '(r)eveal the current node in file manager', 'shortcut': 'r', 'callback': 'NERDTreeRevealFileLinux'})
  34     call NERDTreeAddMenuItem({'text': '(o)pen the current node with system editor', 'shortcut': 'o', 'callback': 'NERDTreeExecuteFileLinux'})
  35 endif
  36 
  37 if nerdtree#runningWindows()
  38     call NERDTreeAddMenuItem({'text': '(o)pen the current node with system editor', 'shortcut': 'o', 'callback': 'NERDTreeExecuteFileWindows'})
  39 endif
  40 
  41 if g:NERDTreePath.CopyingSupported()
  42     call NERDTreeAddMenuItem({'text': '(c)opy the current node', 'shortcut': 'c', 'callback': 'NERDTreeCopyNode'})
  43 endif
  44 call NERDTreeAddMenuItem({'text': (has('clipboard')?'copy (p)ath to clipboard':'print (p)ath to screen'), 'shortcut': 'p', 'callback': 'NERDTreeCopyPath'})
  45 
  46 if has('unix') || has('osx')
  47     call NERDTreeAddMenuItem({'text': '(l)ist the current node', 'shortcut': 'l', 'callback': 'NERDTreeListNode'})
  48     call NERDTreeAddMenuItem({'text': '(C)hange node permissions', 'shortcut':'C', 'callback': 'NERDTreeChangePermissions'})
  49 else
  50     call NERDTreeAddMenuItem({'text': '(l)ist the current node', 'shortcut': 'l', 'callback': 'NERDTreeListNodeWin32'})
  51 endif
  52 
  53 if exists('*system')
  54     call NERDTreeAddMenuItem({'text': 'Run (s)ystem command in this directory', 'shortcut':'s', 'callback': 'NERDTreeSystemCommand'})
  55 endif
  56 
  57 "FUNCTION: s:inputPrompt(action){{{1
  58 "returns the string that should be prompted to the user for the given action
  59 "
  60 "Args:
  61 "action: the action that is being performed, e.g. 'delete'
  62 function! s:inputPrompt(action)
  63     if a:action ==# 'add'
  64         let title = 'Add a childnode'
  65         let info = "Enter the dir/file name to be created. Dirs end with a '/'"
  66         let minimal = 'Add node:'
  67 
  68     elseif a:action ==# 'copy'
  69         let title = 'Copy the current node'
  70         let info = 'Enter the new path to copy the node to:'
  71         let minimal = 'Copy to:'
  72 
  73     elseif a:action ==# 'delete'
  74         let title = 'Delete the current node'
  75         let info = 'Are you sure you wish to delete the node:'
  76         let minimal = 'Delete?'
  77 
  78     elseif a:action ==# 'deleteNonEmpty'
  79         let title = 'Delete the current node'
  80         let info =  "STOP! Directory is not empty! To delete, type 'yes'"
  81         let minimal = 'Delete directory?'
  82 
  83     elseif a:action ==# 'move'
  84         let title = 'Rename the current node'
  85         let info = 'Enter the new path for the node:'
  86         let minimal = 'Move to:'
  87     endif
  88 
  89     if g:NERDTreeMenuController.isMinimal()
  90         redraw! " Clear the menu
  91         return minimal . ' '
  92     else
  93         let divider = '=========================================================='
  94         return title . "\n" . divider . "\n" . info . "\n"
  95     end
  96 endfunction
  97 
  98 "FUNCTION: s:promptToDelBuffer(bufnum, msg){{{1
  99 "prints out the given msg and, if the user responds by pushing 'y' then the
 100 "buffer with the given bufnum is deleted
 101 "
 102 "Args:
 103 "bufnum: the buffer that may be deleted
 104 "msg: a message that will be echoed to the user asking them if they wish to
 105 "     del the buffer
 106 function! s:promptToDelBuffer(bufnum, msg)
 107     echo a:msg
 108     if g:NERDTreeAutoDeleteBuffer || nr2char(getchar()) ==# 'y'
 109         " 1. ensure that all windows which display the just deleted filename
 110         " now display an empty buffer (so a layout is preserved).
 111         " Is not it better to close single tabs with this file only ?
 112         let s:originalTabNumber = tabpagenr()
 113         let s:originalWindowNumber = winnr()
 114         " Go to the next buffer in buffer list if at least one extra buffer is listed
 115         " Otherwise open a new empty buffer
 116         if v:version >= 800
 117             let l:listedBufferCount = len(getbufinfo({'buflisted':1}))
 118         elseif v:version >= 702
 119             let l:listedBufferCount = len(filter(range(1, bufnr('$')), 'buflisted(v:val)'))
 120         else
 121             " Ignore buffer count in this case to make sure we keep the old
 122             " behavior
 123             let l:listedBufferCount = 0
 124         endif
 125         if l:listedBufferCount > 1
 126             call nerdtree#exec('tabdo windo if winbufnr(0) ==# ' . a:bufnum . " | exec ':bnext! ' | endif", 1)
 127         else
 128             call nerdtree#exec('tabdo windo if winbufnr(0) ==# ' . a:bufnum . " | exec ':enew! ' | endif", 1)
 129         endif
 130         call nerdtree#exec('tabnext ' . s:originalTabNumber, 1)
 131         call nerdtree#exec(s:originalWindowNumber . 'wincmd w', 1)
 132         " 3. We don't need a previous buffer anymore
 133         call nerdtree#exec('bwipeout! ' . a:bufnum, 0)
 134     endif
 135 endfunction
 136 
 137 "FUNCTION: s:renameBuffer(bufNum, newNodeName, isDirectory){{{1
 138 "The buffer with the given bufNum is replaced with a new one
 139 "
 140 "Args:
 141 "bufNum: the buffer that may be deleted
 142 "newNodeName: the name given to the renamed node
 143 "isDirectory: determines how to do the create the new filenames
 144 function! s:renameBuffer(bufNum, newNodeName, isDirectory)
 145     if a:isDirectory
 146         let quotedFileName = fnameescape(a:newNodeName . '/' . fnamemodify(bufname(a:bufNum),':t'))
 147         let editStr = g:NERDTreePath.New(a:newNodeName . '/' . fnamemodify(bufname(a:bufNum),':t')).str({'format': 'Edit'})
 148     else
 149         let quotedFileName = fnameescape(a:newNodeName)
 150         let editStr = g:NERDTreePath.New(a:newNodeName).str({'format': 'Edit'})
 151     endif
 152     " 1. ensure that a new buffer is loaded
 153     call nerdtree#exec('badd ' . quotedFileName, 0)
 154     " 2. ensure that all windows which display the just deleted filename
 155     " display a buffer for a new filename.
 156     let s:originalTabNumber = tabpagenr()
 157     let s:originalWindowNumber = winnr()
 158     call nerdtree#exec('tabdo windo if winbufnr(0) ==# ' . a:bufNum . " | exec ':e! " . editStr . "' | endif", 0)
 159     call nerdtree#exec('tabnext ' . s:originalTabNumber, 1)
 160     call nerdtree#exec(s:originalWindowNumber . 'wincmd w', 1)
 161     " 3. We don't need a previous buffer anymore
 162     try
 163         call nerdtree#exec('confirm bwipeout ' . a:bufNum, 0)
 164     catch
 165         " This happens when answering Cancel if confirmation is needed. Do nothing.
 166     endtry
 167 endfunction
 168 
 169 "FUNCTION: NERDTreeAddNode(){{{1
 170 function! NERDTreeAddNode()
 171     let curDirNode = g:NERDTreeDirNode.GetSelected()
 172     let prompt = s:inputPrompt('add')
 173     let newNodeName = substitute(input(prompt, curDirNode.path.str() . nerdtree#slash(), 'file'), '\(^\s*\|\s*$\)', '', 'g')
 174 
 175     if newNodeName ==# ''
 176         call nerdtree#echo('Node Creation Aborted.')
 177         return
 178     endif
 179 
 180     try
 181         let newPath = g:NERDTreePath.Create(newNodeName)
 182         let parentNode = b:NERDTree.root.findNode(newPath.getParent())
 183 
 184         let newTreeNode = g:NERDTreeFileNode.New(newPath, b:NERDTree)
 185         " Emptying g:NERDTreeOldSortOrder forces the sort to
 186         " recalculate the cached sortKey so nodes sort correctly.
 187         let g:NERDTreeOldSortOrder = []
 188         if empty(parentNode)
 189             call b:NERDTree.root.refresh()
 190             call b:NERDTree.render()
 191         elseif parentNode.isOpen || !empty(parentNode.children)
 192             call parentNode.addChild(newTreeNode, 1)
 193             call NERDTreeRender()
 194             call newTreeNode.putCursorHere(1, 0)
 195         endif
 196 
 197         redraw!
 198     catch /^NERDTree/
 199         call nerdtree#echoWarning('Node Not Created.')
 200     endtry
 201 endfunction
 202 
 203 "FUNCTION: NERDTreeMoveNode(){{{1
 204 function! NERDTreeMoveNode()
 205     let curNode = g:NERDTreeFileNode.GetSelected()
 206     let prompt = s:inputPrompt('move')
 207     let newNodePath = input(prompt, curNode.path.str(), 'file')
 208     while filereadable(newNodePath)
 209         call nerdtree#echoWarning('This destination already exists. Try again.')
 210         let newNodePath = substitute(input(prompt, curNode.path.str(), 'file'), '\(^\s*\|\s*$\)', '', 'g')
 211     endwhile
 212 
 213 
 214     if newNodePath ==# ''
 215         call nerdtree#echo('Node Renaming Aborted.')
 216         return
 217     endif
 218 
 219     try
 220         if curNode.path.isDirectory
 221             let l:curPath = escape(curNode.path.str(),'\') . (nerdtree#runningWindows()?'\\':'/') . '.*'
 222             let l:openBuffers = filter(range(1,bufnr('$')),'bufexists(v:val) && fnamemodify(bufname(v:val),":p") =~# "'.escape(l:curPath,'\').'"')
 223         else
 224             let l:openBuffers = filter(range(1,bufnr('$')),'bufexists(v:val) && fnamemodify(bufname(v:val),":p") ==# curNode.path.str()')
 225         endif
 226 
 227         call curNode.rename(newNodePath)
 228         " Emptying g:NERDTreeOldSortOrder forces the sort to
 229         " recalculate the cached sortKey so nodes sort correctly.
 230         let g:NERDTreeOldSortOrder = []
 231         call b:NERDTree.root.refresh()
 232         call NERDTreeRender()
 233 
 234         " If the file node is open, or files under the directory node are
 235         " open, ask the user if they want to replace the file(s) with the
 236         " renamed files.
 237         if !empty(l:openBuffers)
 238             if curNode.path.isDirectory
 239                 echo "\nDirectory renamed.\n\nFiles with the old directory name are open in buffers " . join(l:openBuffers, ', ') . '. Replace these buffers with the new files? (yN)'
 240             else
 241                 echo "\nFile renamed.\n\nThe old file is open in buffer " . l:openBuffers[0] . '. Replace this buffer with the new file? (yN)'
 242             endif
 243             if g:NERDTreeAutoDeleteBuffer || nr2char(getchar()) ==# 'y'
 244                 for bufNum in l:openBuffers
 245                     call s:renameBuffer(bufNum, newNodePath, curNode.path.isDirectory)
 246                 endfor
 247             endif
 248         endif
 249 
 250         call curNode.putCursorHere(1, 0)
 251 
 252         redraw!
 253     catch /^NERDTree/
 254         call nerdtree#echoWarning('Node Not Renamed.')
 255     endtry
 256 endfunction
 257 
 258 " FUNCTION: NERDTreeDeleteNode() {{{1
 259 function! NERDTreeDeleteNode()
 260     let currentNode = g:NERDTreeFileNode.GetSelected()
 261     let confirmed = 0
 262 
 263     if currentNode.path.isDirectory && ((currentNode.isOpen && currentNode.getChildCount() > 0) ||
 264                                       \ (len(currentNode._glob('*', 1)) > 0))
 265         let prompt = s:inputPrompt('deleteNonEmpty') . currentNode.path.str() . ': '
 266         let choice = input(prompt)
 267         let confirmed = choice ==# 'yes'
 268     else
 269         let prompt = s:inputPrompt('delete') . currentNode.path.str() . ' (yN): '
 270         echo prompt
 271         let choice = nr2char(getchar())
 272         let confirmed = choice ==# 'y'
 273     endif
 274 
 275     if confirmed
 276         try
 277             call currentNode.delete()
 278             call NERDTreeRender()
 279 
 280             "if the node is open in a buffer, ask the user if they want to
 281             "close that buffer
 282             let bufnum = bufnr('^'.currentNode.path.str().'$')
 283             if buflisted(bufnum)
 284                 let prompt = "\nNode deleted.\n\nThe file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? ' (hidden)' : '') .'. Delete this buffer? (yN)'
 285                 call s:promptToDelBuffer(bufnum, prompt)
 286             endif
 287 
 288             redraw!
 289         catch /^NERDTree/
 290             call nerdtree#echoWarning('Could not remove node')
 291         endtry
 292     else
 293         call nerdtree#echo('delete aborted')
 294     endif
 295 endfunction
 296 
 297 " FUNCTION: NERDTreeListNode() {{{1
 298 function! NERDTreeListNode()
 299     let treenode = g:NERDTreeFileNode.GetSelected()
 300     if !empty(treenode)
 301         let s:uname = system('uname')
 302         let stat_cmd = 'stat -c "%s" '
 303 
 304         if s:uname =~? 'Darwin'
 305             let stat_cmd = 'stat -f "%z" '
 306         endif
 307 
 308         let cmd = 'size=$(' . stat_cmd . shellescape(treenode.path.str()) . ') && ' .
 309         \         'size_with_commas=$(echo $size | sed -e :a -e "s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta") && ' .
 310         \         'ls -ld ' . shellescape(treenode.path.str()) . ' | sed -e "s/ $size / $size_with_commas /"'
 311 
 312         let metadata = split(system(cmd),'\n')
 313         call nerdtree#echo(metadata[0])
 314     else
 315         call nerdtree#echo('No information available')
 316     endif
 317 endfunction
 318 
 319 " FUNCTION: NERDTreeListNodeWin32() {{{1
 320 function! NERDTreeListNodeWin32()
 321     let l:node = g:NERDTreeFileNode.GetSelected()
 322 
 323     if !empty(l:node)
 324         let l:path = l:node.path.str()
 325         call nerdtree#echo(printf('%s:%s  MOD:%s  BYTES:%d  PERMISSIONS:%s',
 326                     \ toupper(getftype(l:path)),
 327                     \ fnamemodify(l:path, ':t'),
 328                     \ strftime('%c', getftime(l:path)),
 329                     \ getfsize(l:path),
 330                     \ getfperm(l:path)))
 331         return
 332     endif
 333 
 334     call nerdtree#echo('node not recognized')
 335 endfunction
 336 
 337 " FUNCTION: NERDTreeChangePermissions() {{{1
 338 function! NERDTreeChangePermissions()
 339     let l:node = g:NERDTreeFileNode.GetSelected()
 340     let l:prompt = "change node permissions: "
 341     let l:newNodePerm = input(l:prompt)
 342 
 343     if !empty(l:node)
 344         let l:path = l:node.path.str()
 345         let l:cmd = 'chmod ' .. newNodePerm .. ' ' .. path
 346         let l:error = split(system(l:cmd), '\n')
 347 
 348         if !empty(l:error)
 349             call nerdtree#echo(l:error[0])
 350         endif
 351 
 352         call b:NERDTree.root.refresh()
 353         call b:NERDTree.render()
 354         return
 355     endif
 356 
 357     call nerdtree#echo('node not recognized')
 358 endfunction
 359 
 360 " FUNCTION: NERDTreeCopyNode() {{{1
 361 function! NERDTreeCopyNode()
 362     let currentNode = g:NERDTreeFileNode.GetSelected()
 363     let prompt = s:inputPrompt('copy')
 364     let newNodePath = substitute(input(prompt, currentNode.path.str(), 'file'), '\(^\s*\|\s*$\)', '', 'g')
 365 
 366     if newNodePath !=# ''
 367         "strip trailing slash
 368         let newNodePath = substitute(newNodePath, '\/$', '', '')
 369 
 370         let confirmed = 1
 371         if currentNode.path.copyingWillOverwrite(newNodePath)
 372             call nerdtree#echo('Warning: copying may overwrite files! Continue? (yN)')
 373             let choice = nr2char(getchar())
 374             let confirmed = choice ==# 'y'
 375         endif
 376 
 377         if confirmed
 378             try
 379                 let newNode = currentNode.copy(newNodePath)
 380                 " Emptying g:NERDTreeOldSortOrder forces the sort to
 381                 " recalculate the cached sortKey so nodes sort correctly.
 382                 let g:NERDTreeOldSortOrder = []
 383                 if empty(newNode)
 384                     call b:NERDTree.root.refresh()
 385                     call b:NERDTree.render()
 386                 else
 387                     call NERDTreeRender()
 388                     call newNode.putCursorHere(0, 0)
 389                 endif
 390             catch /^NERDTree/
 391                 call nerdtree#echoWarning('Could not copy node')
 392             endtry
 393         endif
 394     else
 395         call nerdtree#echo('Copy aborted.')
 396     endif
 397     redraw!
 398 endfunction
 399 
 400 " FUNCTION: NERDTreeCopyPath() {{{1
 401 function! NERDTreeCopyPath()
 402     let l:nodePath = g:NERDTreeFileNode.GetSelected().path.str()
 403     if has('clipboard')
 404         if &clipboard ==# 'unnamedplus'
 405             let @+ = l:nodePath
 406         else
 407             let @* = l:nodePath
 408         endif
 409         call nerdtree#echo('The path [' . l:nodePath . '] was copied to your clipboard.')
 410     else
 411         call nerdtree#echo('The full path is: ' . l:nodePath)
 412     endif
 413 endfunction
 414 
 415 " FUNCTION: NERDTreeQuickLook() {{{1
 416 function! NERDTreeQuickLook()
 417     let l:node = g:NERDTreeFileNode.GetSelected()
 418 
 419     if empty(l:node)
 420         return
 421     endif
 422 
 423     call system('qlmanage -p 2>/dev/null ' . shellescape(l:node.path.str()))
 424 endfunction
 425 
 426 " FUNCTION: NERDTreeRevealInFinder() {{{1
 427 function! NERDTreeRevealInFinder()
 428     let l:node = g:NERDTreeFileNode.GetSelected()
 429 
 430     if empty(l:node)
 431         return
 432     endif
 433 
 434     call system('open -R ' . shellescape(l:node.path.str()))
 435 endfunction
 436 
 437 " FUNCTION: NERDTreeExecuteFile() {{{1
 438 function! NERDTreeExecuteFile()
 439     let l:node = g:NERDTreeFileNode.GetSelected()
 440 
 441     if empty(l:node)
 442         return
 443     endif
 444 
 445     call system('open ' . shellescape(l:node.path.str()))
 446 endfunction
 447 
 448 " FUNCTION: NERDTreeRevealFileLinux() {{{1
 449 function! NERDTreeRevealFileLinux()
 450     let l:node = g:NERDTreeFileNode.GetSelected()
 451 
 452     if empty(l:node)
 453         return
 454     endif
 455 
 456     " Handle the edge case of "/", which has no parent.
 457     if l:node.path.str() ==# '/'
 458         call system('xdg-open /')
 459         return
 460     endif
 461 
 462     if empty(l:node.parent)
 463         return
 464     endif
 465 
 466     call system('xdg-open ' . shellescape(l:node.parent.path.str()))
 467 endfunction
 468 
 469 " FUNCTION: NERDTreeExecuteFileLinux() {{{1
 470 function! NERDTreeExecuteFileLinux()
 471     let l:node = g:NERDTreeFileNode.GetSelected()
 472 
 473     if empty(l:node)
 474         return
 475     endif
 476 
 477     call system('xdg-open ' . shellescape(l:node.path.str()))
 478 endfunction
 479 
 480 " FUNCTION: NERDTreeExecuteFileWindows() {{{1
 481 function! NERDTreeExecuteFileWindows()
 482     let l:node = g:NERDTreeFileNode.GetSelected()
 483 
 484     if empty(l:node)
 485         return
 486     endif
 487 
 488     call system('cmd.exe /c start "" ' . shellescape(l:node.path.str()))
 489 endfunction
 490 
 491 " FUNCTION: NERDTreeSystemCommand() {{{1
 492 function! NERDTreeSystemCommand()
 493     let l:node = g:NERDTreeFileNode.GetSelected()
 494 
 495     if empty(l:node)
 496         return
 497     endif
 498 
 499     let l:cwd = getcwd()
 500     let l:directory = l:node.path.isDirectory ? l:node.path.str() : l:node.parent.path.str()
 501     execute 'cd '.l:directory
 502 
 503     let l:nl = nr2char(10)
 504     echo l:nl . system(input(l:directory . (nerdtree#runningWindows() ? '> ' : ' $ ')))
 505     execute 'cd '.l:cwd
 506 endfunction
 507 
 508 " vim: set sw=4 sts=4 et fdm=marker: