From 2bb858f3da96f9eece8ec1230e5815e25f42c5bd Mon Sep 17 00:00:00 2001 From: Philippe Serhal Date: Sun, 11 Jan 2015 13:17:08 -0800 Subject: [PATCH] Track vim plugins. --- vim/autoload/pathogen.vim | 347 ++ vim/bundle/ctrlp.vim/.gitignore | 6 + vim/bundle/ctrlp.vim/autoload/ctrlp.vim | 2289 +++++++++++++ .../ctrlp.vim/autoload/ctrlp/bookmarkdir.vim | 140 + .../ctrlp.vim/autoload/ctrlp/buffertag.vim | 264 ++ .../ctrlp.vim/autoload/ctrlp/changes.vim | 98 + vim/bundle/ctrlp.vim/autoload/ctrlp/dir.vim | 95 + vim/bundle/ctrlp.vim/autoload/ctrlp/line.vim | 72 + vim/bundle/ctrlp.vim/autoload/ctrlp/mixed.vim | 88 + .../ctrlp.vim/autoload/ctrlp/mrufiles.vim | 154 + .../ctrlp.vim/autoload/ctrlp/quickfix.vim | 59 + .../ctrlp.vim/autoload/ctrlp/rtscript.vim | 59 + vim/bundle/ctrlp.vim/autoload/ctrlp/tag.vim | 138 + vim/bundle/ctrlp.vim/autoload/ctrlp/undo.vim | 154 + vim/bundle/ctrlp.vim/autoload/ctrlp/utils.vim | 110 + vim/bundle/ctrlp.vim/doc/ctrlp.txt | 1451 ++++++++ vim/bundle/ctrlp.vim/plugin/ctrlp.vim | 68 + vim/bundle/ctrlp.vim/readme.md | 88 + vim/bundle/indentLine/.gitattributes | 22 + vim/bundle/indentLine/.gitignore | 171 + vim/bundle/indentLine/README.md | 58 + .../indentLine/after/plugin/indentLine.vim | 216 ++ vim/bundle/indentLine/doc/indentLine.txt | 166 + .../glyph/indentLine-dotted-guide.eps | 169 + vim/bundle/nerdtree/.gitignore | 3 + vim/bundle/nerdtree/README.markdown | 113 + vim/bundle/nerdtree/autoload/nerdtree.vim | 407 +++ .../nerdtree/autoload/nerdtree/ui_glue.vim | 644 ++++ vim/bundle/nerdtree/doc/NERD_tree.txt | 1379 ++++++++ vim/bundle/nerdtree/lib/nerdtree/bookmark.vim | 319 ++ vim/bundle/nerdtree/lib/nerdtree/creator.vim | 357 ++ vim/bundle/nerdtree/lib/nerdtree/event.vim | 13 + vim/bundle/nerdtree/lib/nerdtree/flag_set.vim | 56 + vim/bundle/nerdtree/lib/nerdtree/key_map.vim | 159 + .../nerdtree/lib/nerdtree/menu_controller.vim | 180 + .../nerdtree/lib/nerdtree/menu_item.vim | 114 + vim/bundle/nerdtree/lib/nerdtree/nerdtree.vim | 39 + vim/bundle/nerdtree/lib/nerdtree/notifier.vim | 35 + vim/bundle/nerdtree/lib/nerdtree/opener.vim | 336 ++ vim/bundle/nerdtree/lib/nerdtree/path.vim | 754 +++++ .../nerdtree/lib/nerdtree/tree_dir_node.vim | 543 +++ .../nerdtree/lib/nerdtree/tree_file_node.vim | 431 +++ vim/bundle/nerdtree/lib/nerdtree/ui.vim | 332 ++ .../nerdtree_plugin/exec_menuitem.vim | 41 + .../nerdtree/nerdtree_plugin/fs_menu.vim | 270 ++ vim/bundle/nerdtree/plugin/NERD_tree.vim | 205 ++ vim/bundle/nerdtree/syntax/nerdtree.vim | 105 + vim/bundle/vim-coffee-script/.gitignore | 4 + vim/bundle/vim-coffee-script/Copying.md | 15 + vim/bundle/vim-coffee-script/Makefile | 25 + vim/bundle/vim-coffee-script/News.md | 22 + vim/bundle/vim-coffee-script/Readme.md | 599 ++++ vim/bundle/vim-coffee-script/Thanks.md | 44 + vim/bundle/vim-coffee-script/Todo.md | 1 + .../vim-coffee-script/after/indent/html.vim | 33 + .../vim-coffee-script/after/syntax/haml.vim | 13 + .../vim-coffee-script/after/syntax/html.vim | 11 + .../vim-coffee-script/autoload/coffee.vim | 54 + .../vim-coffee-script/compiler/cake.vim | 15 + .../vim-coffee-script/compiler/coffee.vim | 82 + .../vim-coffee-script/doc/coffee-script.txt | 4 + .../vim-coffee-script/ftdetect/coffee.vim | 17 + .../vim-coffee-script/ftplugin/coffee.vim | 409 +++ .../vim-coffee-script/indent/coffee.vim | 428 +++ .../vim-coffee-script/syntax/coffee.vim | 221 ++ .../vim-coffee-script/test/test-interp.coffee | 3 + .../vim-coffee-script/test/test-ops.coffee | 90 + .../test/test-reserved.coffee | 27 + vim/bundle/vim-coffee-script/test/test.haml | 3 + vim/bundle/vim-coffee-script/test/test.html | 7 + vim/bundle/vim-commentary/.gitignore | 1 + .../vim-commentary/CONTRIBUTING.markdown | 1 + vim/bundle/vim-commentary/README.markdown | 51 + vim/bundle/vim-commentary/doc/commentary.txt | 35 + .../vim-commentary/plugin/commentary.vim | 100 + vim/bundle/vim-fugitive/.gitignore | 1 + vim/bundle/vim-fugitive/CONTRIBUTING.markdown | 18 + vim/bundle/vim-fugitive/README.markdown | 118 + vim/bundle/vim-fugitive/doc/fugitive.txt | 345 ++ vim/bundle/vim-fugitive/plugin/fugitive.vim | 2916 +++++++++++++++++ vim/bundle/vim-jade/README.markdown | 19 + vim/bundle/vim-jade/ftdetect/jade.vim | 2 + vim/bundle/vim-jade/ftplugin/jade.vim | 55 + vim/bundle/vim-jade/indent/jade.vim | 70 + vim/bundle/vim-jade/syntax/jade.vim | 99 + vim/bundle/vim-repeat/README.markdown | 53 + vim/bundle/vim-repeat/autoload/repeat.vim | 119 + vim/bundle/vim-stylus/changelog.md | 41 + vim/bundle/vim-stylus/ftdetect/stylus.vim | 3 + vim/bundle/vim-stylus/ftplugin/stylus.vim | 63 + vim/bundle/vim-stylus/indent/stylus.vim | 129 + vim/bundle/vim-stylus/readme.md | 19 + vim/bundle/vim-stylus/syntax/stylus.vim | 376 +++ vim/bundle/vim-stylus/test.styl | 80 + vim/bundle/vim-surround/.gitignore | 1 + vim/bundle/vim-surround/README.markdown | 97 + vim/bundle/vim-surround/doc/surround.txt | 205 ++ vim/bundle/vim-surround/plugin/surround.vim | 590 ++++ vim/colors/wombat.vim | 51 + 99 files changed, 21102 insertions(+) create mode 100644 vim/autoload/pathogen.vim create mode 100644 vim/bundle/ctrlp.vim/.gitignore create mode 100644 vim/bundle/ctrlp.vim/autoload/ctrlp.vim create mode 100644 vim/bundle/ctrlp.vim/autoload/ctrlp/bookmarkdir.vim create mode 100644 vim/bundle/ctrlp.vim/autoload/ctrlp/buffertag.vim create mode 100644 vim/bundle/ctrlp.vim/autoload/ctrlp/changes.vim create mode 100644 vim/bundle/ctrlp.vim/autoload/ctrlp/dir.vim create mode 100644 vim/bundle/ctrlp.vim/autoload/ctrlp/line.vim create mode 100644 vim/bundle/ctrlp.vim/autoload/ctrlp/mixed.vim create mode 100644 vim/bundle/ctrlp.vim/autoload/ctrlp/mrufiles.vim create mode 100644 vim/bundle/ctrlp.vim/autoload/ctrlp/quickfix.vim create mode 100644 vim/bundle/ctrlp.vim/autoload/ctrlp/rtscript.vim create mode 100644 vim/bundle/ctrlp.vim/autoload/ctrlp/tag.vim create mode 100644 vim/bundle/ctrlp.vim/autoload/ctrlp/undo.vim create mode 100644 vim/bundle/ctrlp.vim/autoload/ctrlp/utils.vim create mode 100644 vim/bundle/ctrlp.vim/doc/ctrlp.txt create mode 100644 vim/bundle/ctrlp.vim/plugin/ctrlp.vim create mode 100644 vim/bundle/ctrlp.vim/readme.md create mode 100644 vim/bundle/indentLine/.gitattributes create mode 100644 vim/bundle/indentLine/.gitignore create mode 100644 vim/bundle/indentLine/README.md create mode 100644 vim/bundle/indentLine/after/plugin/indentLine.vim create mode 100644 vim/bundle/indentLine/doc/indentLine.txt create mode 100644 vim/bundle/indentLine/glyph/indentLine-dotted-guide.eps create mode 100644 vim/bundle/nerdtree/.gitignore create mode 100644 vim/bundle/nerdtree/README.markdown create mode 100644 vim/bundle/nerdtree/autoload/nerdtree.vim create mode 100644 vim/bundle/nerdtree/autoload/nerdtree/ui_glue.vim create mode 100644 vim/bundle/nerdtree/doc/NERD_tree.txt create mode 100644 vim/bundle/nerdtree/lib/nerdtree/bookmark.vim create mode 100644 vim/bundle/nerdtree/lib/nerdtree/creator.vim create mode 100644 vim/bundle/nerdtree/lib/nerdtree/event.vim create mode 100644 vim/bundle/nerdtree/lib/nerdtree/flag_set.vim create mode 100644 vim/bundle/nerdtree/lib/nerdtree/key_map.vim create mode 100644 vim/bundle/nerdtree/lib/nerdtree/menu_controller.vim create mode 100644 vim/bundle/nerdtree/lib/nerdtree/menu_item.vim create mode 100644 vim/bundle/nerdtree/lib/nerdtree/nerdtree.vim create mode 100644 vim/bundle/nerdtree/lib/nerdtree/notifier.vim create mode 100644 vim/bundle/nerdtree/lib/nerdtree/opener.vim create mode 100644 vim/bundle/nerdtree/lib/nerdtree/path.vim create mode 100644 vim/bundle/nerdtree/lib/nerdtree/tree_dir_node.vim create mode 100644 vim/bundle/nerdtree/lib/nerdtree/tree_file_node.vim create mode 100644 vim/bundle/nerdtree/lib/nerdtree/ui.vim create mode 100644 vim/bundle/nerdtree/nerdtree_plugin/exec_menuitem.vim create mode 100644 vim/bundle/nerdtree/nerdtree_plugin/fs_menu.vim create mode 100644 vim/bundle/nerdtree/plugin/NERD_tree.vim create mode 100644 vim/bundle/nerdtree/syntax/nerdtree.vim create mode 100644 vim/bundle/vim-coffee-script/.gitignore create mode 100644 vim/bundle/vim-coffee-script/Copying.md create mode 100644 vim/bundle/vim-coffee-script/Makefile create mode 100644 vim/bundle/vim-coffee-script/News.md create mode 100644 vim/bundle/vim-coffee-script/Readme.md create mode 100644 vim/bundle/vim-coffee-script/Thanks.md create mode 100644 vim/bundle/vim-coffee-script/Todo.md create mode 100644 vim/bundle/vim-coffee-script/after/indent/html.vim create mode 100644 vim/bundle/vim-coffee-script/after/syntax/haml.vim create mode 100644 vim/bundle/vim-coffee-script/after/syntax/html.vim create mode 100644 vim/bundle/vim-coffee-script/autoload/coffee.vim create mode 100644 vim/bundle/vim-coffee-script/compiler/cake.vim create mode 100644 vim/bundle/vim-coffee-script/compiler/coffee.vim create mode 100644 vim/bundle/vim-coffee-script/doc/coffee-script.txt create mode 100644 vim/bundle/vim-coffee-script/ftdetect/coffee.vim create mode 100644 vim/bundle/vim-coffee-script/ftplugin/coffee.vim create mode 100644 vim/bundle/vim-coffee-script/indent/coffee.vim create mode 100644 vim/bundle/vim-coffee-script/syntax/coffee.vim create mode 100644 vim/bundle/vim-coffee-script/test/test-interp.coffee create mode 100644 vim/bundle/vim-coffee-script/test/test-ops.coffee create mode 100644 vim/bundle/vim-coffee-script/test/test-reserved.coffee create mode 100644 vim/bundle/vim-coffee-script/test/test.haml create mode 100644 vim/bundle/vim-coffee-script/test/test.html create mode 100644 vim/bundle/vim-commentary/.gitignore create mode 100644 vim/bundle/vim-commentary/CONTRIBUTING.markdown create mode 100644 vim/bundle/vim-commentary/README.markdown create mode 100644 vim/bundle/vim-commentary/doc/commentary.txt create mode 100644 vim/bundle/vim-commentary/plugin/commentary.vim create mode 100644 vim/bundle/vim-fugitive/.gitignore create mode 100644 vim/bundle/vim-fugitive/CONTRIBUTING.markdown create mode 100644 vim/bundle/vim-fugitive/README.markdown create mode 100644 vim/bundle/vim-fugitive/doc/fugitive.txt create mode 100644 vim/bundle/vim-fugitive/plugin/fugitive.vim create mode 100644 vim/bundle/vim-jade/README.markdown create mode 100644 vim/bundle/vim-jade/ftdetect/jade.vim create mode 100644 vim/bundle/vim-jade/ftplugin/jade.vim create mode 100644 vim/bundle/vim-jade/indent/jade.vim create mode 100644 vim/bundle/vim-jade/syntax/jade.vim create mode 100644 vim/bundle/vim-repeat/README.markdown create mode 100644 vim/bundle/vim-repeat/autoload/repeat.vim create mode 100644 vim/bundle/vim-stylus/changelog.md create mode 100644 vim/bundle/vim-stylus/ftdetect/stylus.vim create mode 100644 vim/bundle/vim-stylus/ftplugin/stylus.vim create mode 100644 vim/bundle/vim-stylus/indent/stylus.vim create mode 100644 vim/bundle/vim-stylus/readme.md create mode 100644 vim/bundle/vim-stylus/syntax/stylus.vim create mode 100644 vim/bundle/vim-stylus/test.styl create mode 100644 vim/bundle/vim-surround/.gitignore create mode 100644 vim/bundle/vim-surround/README.markdown create mode 100644 vim/bundle/vim-surround/doc/surround.txt create mode 100644 vim/bundle/vim-surround/plugin/surround.vim create mode 100644 vim/colors/wombat.vim diff --git a/vim/autoload/pathogen.vim b/vim/autoload/pathogen.vim new file mode 100644 index 0000000..a13ae08 --- /dev/null +++ b/vim/autoload/pathogen.vim @@ -0,0 +1,347 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.3 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a relative path to invoke +" pathogen#interpose() (defaults to "bundle/{}"), or an absolute path to invoke +" pathogen#surround(). Curly braces are expanded with pathogen#expand(): +" "bundle/{}" finds all subdirectories inside "bundle" inside all directories +" in the runtime path. +function! pathogen#infect(...) abort + for path in a:0 ? filter(reverse(copy(a:000)), 'type(v:val) == type("")') : ['bundle/{}'] + if path =~# '^\%({\=[$~\\/]\|{\=\w:[\\/]\).*[{}*]' + call pathogen#surround(path) + elseif path =~# '^\%([$~\\/]\|\w:[\\/]\)' + call s:warn('Change pathogen#infect('.string(path).') to pathogen#infect('.string(path.'/{}').')') + call pathogen#surround(path . '/{}') + elseif path =~# '[{}*]' + call pathogen#interpose(path) + else + call s:warn('Change pathogen#infect('.string(path).') to pathogen#infect('.string(path.'/{}').')') + call pathogen#interpose(path . '/{}') + endif + endfor + call pathogen#cycle_filetype() + if pathogen#is_disabled($MYVIMRC) + return 'finish' + endif + return '' +endfunction + +" Split a path into a list. +function! pathogen#split(path) abort + if type(a:path) == type([]) | return a:path | endif + if empty(a:path) | return [] | endif + let split = split(a:path,'\\\@]','\\&','') + endif +endfunction + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) abort "{{{1 + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction + +" Section: Deprecated + +function! s:warn(msg) abort + echohl WarningMsg + echomsg a:msg + echohl NONE +endfunction + +" Prepend all subdirectories of path to the rtp, and append all 'after' +" directories in those subdirectories. Deprecated. +function! pathogen#runtime_prepend_subdirectories(path) abort + call s:warn('Change pathogen#runtime_prepend_subdirectories('.string(a:path).') to pathogen#infect('.string(a:path.'/{}').')') + return pathogen#surround(a:path . pathogen#slash() . '{}') +endfunction + +function! pathogen#incubate(...) abort + let name = a:0 ? a:1 : 'bundle/{}' + call s:warn('Change pathogen#incubate('.(a:0 ? string(a:1) : '').') to pathogen#infect('.string(name).')') + return pathogen#interpose(name) +endfunction + +" Deprecated alias for pathogen#interpose(). +function! pathogen#runtime_append_all_bundles(...) abort + if a:0 + call s:warn('Change pathogen#runtime_append_all_bundles('.string(a:1).') to pathogen#infect('.string(a:1.'/{}').')') + else + call s:warn('Change pathogen#runtime_append_all_bundles() to pathogen#infect()') + endif + return pathogen#interpose(a:0 ? a:1 . '/{}' : 'bundle/{}') +endfunction + +if exists(':Vedit') + finish +endif + +let s:vopen_warning = 0 + +function! s:find(count,cmd,file,lcd) + let rtp = pathogen#join(1,pathogen#split(&runtimepath)) + let file = pathogen#runtime_findfile(a:file,a:count) + if file ==# '' + return "echoerr 'E345: Can''t find file \"".a:file."\" in runtimepath'" + endif + if !s:vopen_warning + let s:vopen_warning = 1 + let warning = '|echohl WarningMsg|echo "Install scriptease.vim to continue using :V'.a:cmd.'"|echohl NONE' + else + let warning = '' + endif + if a:lcd + let path = file[0:-strlen(a:file)-2] + execute 'lcd `=path`' + return a:cmd.' '.pathogen#fnameescape(a:file) . warning + else + return a:cmd.' '.pathogen#fnameescape(file) . warning + endif +endfunction + +function! s:Findcomplete(A,L,P) + let sep = pathogen#slash() + let cheats = { + \'a': 'autoload', + \'d': 'doc', + \'f': 'ftplugin', + \'i': 'indent', + \'p': 'plugin', + \'s': 'syntax'} + if a:A =~# '^\w[\\/]' && has_key(cheats,a:A[0]) + let request = cheats[a:A[0]].a:A[1:-1] + else + let request = a:A + endif + let pattern = substitute(request,'/\|\'.sep,'*'.sep,'g').'*' + let found = {} + for path in pathogen#split(&runtimepath) + let path = expand(path, ':p') + let matches = split(glob(path.sep.pattern),"\n") + call map(matches,'isdirectory(v:val) ? v:val.sep : v:val') + call map(matches,'expand(v:val, ":p")[strlen(path)+1:-1]') + for match in matches + let found[match] = 1 + endfor + endfor + return sort(keys(found)) +endfunction + +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Ve :execute s:find(,'edit',,0) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vedit :execute s:find(,'edit',,0) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vopen :execute s:find(,'edit',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vsplit :execute s:find(,'split',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vvsplit :execute s:find(,'vsplit',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vtabedit :execute s:find(,'tabedit',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vpedit :execute s:find(,'pedit',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vread :execute s:find(,'read',,1) + +" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=': diff --git a/vim/bundle/ctrlp.vim/.gitignore b/vim/bundle/ctrlp.vim/.gitignore new file mode 100644 index 0000000..06fcd83 --- /dev/null +++ b/vim/bundle/ctrlp.vim/.gitignore @@ -0,0 +1,6 @@ +*.markdown +*.zip +note.txt +tags +.hg* +tmp/* diff --git a/vim/bundle/ctrlp.vim/autoload/ctrlp.vim b/vim/bundle/ctrlp.vim/autoload/ctrlp.vim new file mode 100644 index 0000000..19ac146 --- /dev/null +++ b/vim/bundle/ctrlp.vim/autoload/ctrlp.vim @@ -0,0 +1,2289 @@ +" ============================================================================= +" File: autoload/ctrlp.vim +" Description: Fuzzy file, buffer, mru, tag, etc finder. +" Author: Kien Nguyen +" Version: 1.79 +" ============================================================================= + +" ** Static variables {{{1 +" s:ignore() {{{2 +fu! s:ignore() + let igdirs = [ + \ '\.git', + \ '\.hg', + \ '\.svn', + \ '_darcs', + \ '\.bzr', + \ '\.cdv', + \ '\~\.dep', + \ '\~\.dot', + \ '\~\.nib', + \ '\~\.plst', + \ '\.pc', + \ '_MTN', + \ 'blib', + \ 'CVS', + \ 'RCS', + \ 'SCCS', + \ '_sgbak', + \ 'autom4te\.cache', + \ 'cover_db', + \ '_build', + \ ] + let igfiles = [ + \ '\~$', + \ '#.+#$', + \ '[._].*\.swp$', + \ 'core\.\d+$', + \ '\.exe$', + \ '\.so$', + \ '\.bak$', + \ '\.png$', + \ '\.jpg$', + \ '\.gif$', + \ '\.zip$', + \ '\.rar$', + \ '\.tar\.gz$', + \ ] + retu { + \ 'dir': '\v[\/]('.join(igdirs, '|').')$', + \ 'file': '\v'.join(igfiles, '|'), + \ } +endf +" Script local vars {{{2 +let [s:pref, s:bpref, s:opts, s:new_opts, s:lc_opts] = + \ ['g:ctrlp_', 'b:ctrlp_', { + \ 'abbrev': ['s:abbrev', {}], + \ 'arg_map': ['s:argmap', 0], + \ 'buffer_func': ['s:buffunc', {}], + \ 'by_filename': ['s:byfname', 0], + \ 'custom_ignore': ['s:usrign', s:ignore()], + \ 'default_input': ['s:deftxt', 0], + \ 'dont_split': ['s:nosplit', 'netrw'], + \ 'dotfiles': ['s:showhidden', 0], + \ 'extensions': ['s:extensions', []], + \ 'follow_symlinks': ['s:folsym', 0], + \ 'highlight_match': ['s:mathi', [1, 'CtrlPMatch']], + \ 'jump_to_buffer': ['s:jmptobuf', 'Et'], + \ 'key_loop': ['s:keyloop', 0], + \ 'lazy_update': ['s:lazy', 0], + \ 'match_func': ['s:matcher', {}], + \ 'match_window': ['s:mw', ''], + \ 'match_window_bottom': ['s:mwbottom', 1], + \ 'match_window_reversed': ['s:mwreverse', 1], + \ 'max_depth': ['s:maxdepth', 40], + \ 'max_files': ['s:maxfiles', 10000], + \ 'max_height': ['s:mxheight', 10], + \ 'max_history': ['s:maxhst', exists('+hi') ? &hi : 20], + \ 'mruf_default_order': ['s:mrudef', 0], + \ 'open_func': ['s:openfunc', {}], + \ 'open_multi': ['s:opmul', '1v'], + \ 'open_new_file': ['s:newfop', 'v'], + \ 'prompt_mappings': ['s:urprtmaps', 0], + \ 'regexp_search': ['s:regexp', 0], + \ 'root_markers': ['s:rmarkers', []], + \ 'split_window': ['s:splitwin', 0], + \ 'status_func': ['s:status', {}], + \ 'tabpage_position': ['s:tabpage', 'ac'], + \ 'use_caching': ['s:caching', 1], + \ 'use_migemo': ['s:migemo', 0], + \ 'user_command': ['s:usrcmd', ''], + \ 'working_path_mode': ['s:pathmode', 'ra'], + \ }, { + \ 'open_multiple_files': 's:opmul', + \ 'regexp': 's:regexp', + \ 'reuse_window': 's:nosplit', + \ 'show_hidden': 's:showhidden', + \ 'switch_buffer': 's:jmptobuf', + \ }, { + \ 'root_markers': 's:rmarkers', + \ 'user_command': 's:usrcmd', + \ 'working_path_mode': 's:pathmode', + \ }] + +" Global options +let s:glbs = { 'magic': 1, 'to': 1, 'tm': 0, 'sb': 1, 'hls': 0, 'im': 0, + \ 'report': 9999, 'sc': 0, 'ss': 0, 'siso': 0, 'mfd': 200, 'ttimeout': 0, + \ 'gcr': 'a:blinkon0', 'ic': 1, 'lmap': '', 'mousef': 0, 'imd': 1 } + +" Keymaps +let [s:lcmap, s:prtmaps] = ['nn ', { + \ 'PrtBS()': ['', ''], + \ 'PrtDelete()': [''], + \ 'PrtDeleteWord()': [''], + \ 'PrtClear()': [''], + \ 'PrtSelectMove("j")': ['', ''], + \ 'PrtSelectMove("k")': ['', ''], + \ 'PrtSelectMove("t")': ['', ''], + \ 'PrtSelectMove("b")': ['', ''], + \ 'PrtSelectMove("u")': ['', ''], + \ 'PrtSelectMove("d")': ['', ''], + \ 'PrtHistory(-1)': [''], + \ 'PrtHistory(1)': [''], + \ 'AcceptSelection("e")': ['', '<2-LeftMouse>'], + \ 'AcceptSelection("h")': ['', '', ''], + \ 'AcceptSelection("t")': [''], + \ 'AcceptSelection("v")': ['', ''], + \ 'ToggleFocus()': [''], + \ 'ToggleRegex()': [''], + \ 'ToggleByFname()': [''], + \ 'ToggleType(1)': ['', ''], + \ 'ToggleType(-1)': ['', ''], + \ 'PrtExpandDir()': [''], + \ 'PrtInsert("c")': ['', ''], + \ 'PrtInsert()': [''], + \ 'PrtCurStart()': [''], + \ 'PrtCurEnd()': [''], + \ 'PrtCurLeft()': ['', '', ''], + \ 'PrtCurRight()': ['', ''], + \ 'PrtClearCache()': [''], + \ 'PrtDeleteEnt()': [''], + \ 'CreateNewFile()': [''], + \ 'MarkToOpen()': [''], + \ 'OpenMulti()': [''], + \ 'PrtExit()': ['', '', ''], + \ }] + +if !has('gui_running') + cal add(s:prtmaps['PrtBS()'], remove(s:prtmaps['PrtCurLeft()'], 0)) +en + +let s:compare_lim = 3000 + +let s:ficounts = {} + +let s:ccex = s:pref.'clear_cache_on_exit' + +" Regexp +let s:fpats = { + \ '^\(\\|\)\|\(\\|\)$': '\\|', + \ '^\\\(zs\|ze\|<\|>\)': '^\\\(zs\|ze\|<\|>\)', + \ '^\S\*$': '\*', + \ '^\S\\?$': '\\?', + \ } + +" Keypad +let s:kprange = { + \ 'Plus': '+', + \ 'Minus': '-', + \ 'Divide': '/', + \ 'Multiply': '*', + \ 'Point': '.', + \ } + +" Highlight groups +let s:hlgrps = { + \ 'NoEntries': 'Error', + \ 'Mode1': 'Character', + \ 'Mode2': 'LineNr', + \ 'Stats': 'Function', + \ 'Match': 'Identifier', + \ 'PrtBase': 'Comment', + \ 'PrtText': 'Normal', + \ 'PrtCursor': 'Constant', + \ } +" Get the options {{{2 +fu! s:opts(...) + unl! s:usrign s:usrcmd s:urprtmaps + for each in ['byfname', 'regexp', 'extensions'] | if exists('s:'.each) + let {each} = s:{each} + en | endfo + for [ke, va] in items(s:opts) + let {va[0]} = exists(s:pref.ke) ? {s:pref.ke} : va[1] + endfo + unl va + for [ke, va] in items(s:new_opts) + let {va} = {exists(s:pref.ke) ? s:pref.ke : va} + endfo + unl va + for [ke, va] in items(s:lc_opts) + if exists(s:bpref.ke) + unl {va} + let {va} = {s:bpref.ke} + en + endfo + " Match window options + cal s:match_window_opts() + " One-time values + if a:0 && a:1 != {} + unl va + for [ke, va] in items(a:1) + let opke = substitute(ke, '\(\w:\)\?ctrlp_', '', '') + if has_key(s:lc_opts, opke) + let sva = s:lc_opts[opke] + unl {sva} + let {sva} = va + en + endfo + en + for each in ['byfname', 'regexp'] | if exists(each) + let s:{each} = {each} + en | endfo + if !exists('g:ctrlp_newcache') | let g:ctrlp_newcache = 0 | en + let s:maxdepth = min([s:maxdepth, 100]) + let s:glob = s:showhidden ? '.*\|*' : '*' + let s:igntype = empty(s:usrign) ? -1 : type(s:usrign) + let s:lash = ctrlp#utils#lash() + if s:keyloop + let [s:lazy, s:glbs['imd']] = [0, 0] + en + if s:lazy + cal extend(s:glbs, { 'ut': ( s:lazy > 1 ? s:lazy : 250 ) }) + en + " Extensions + if !( exists('extensions') && extensions == s:extensions ) + for each in s:extensions + exe 'ru autoload/ctrlp/'.each.'.vim' + endfo + en + " Keymaps + if type(s:urprtmaps) == 4 + cal extend(s:prtmaps, s:urprtmaps) + en +endf + +fu! s:match_window_opts() + let s:mw_pos = + \ s:mw =~ 'top\|bottom' ? matchstr(s:mw, 'top\|bottom') : + \ exists('g:ctrlp_match_window_bottom') ? ( s:mwbottom ? 'bottom' : 'top' ) + \ : 'bottom' + let s:mw_order = + \ s:mw =~ 'order:[^,]\+' ? matchstr(s:mw, 'order:\zs[^,]\+') : + \ exists('g:ctrlp_match_window_reversed') ? ( s:mwreverse ? 'btt' : 'ttb' ) + \ : 'btt' + let s:mw_max = + \ s:mw =~ 'max:[^,]\+' ? str2nr(matchstr(s:mw, 'max:\zs\d\+')) : + \ exists('g:ctrlp_max_height') ? s:mxheight + \ : 10 + let s:mw_min = + \ s:mw =~ 'min:[^,]\+' ? str2nr(matchstr(s:mw, 'min:\zs\d\+')) : 1 + let [s:mw_max, s:mw_min] = [max([s:mw_max, 1]), max([s:mw_min, 1])] + let s:mw_min = min([s:mw_min, s:mw_max]) + let s:mw_res = + \ s:mw =~ 'results:[^,]\+' ? str2nr(matchstr(s:mw, 'results:\zs\d\+')) + \ : min([s:mw_max, &lines]) + let s:mw_res = max([s:mw_res, 1]) +endf +"}}}1 +" * Open & Close {{{1 +fu! s:Open() + cal s:log(1) + cal s:getenv() + cal s:execextvar('enter') + sil! exe 'keepa' ( s:mw_pos == 'top' ? 'to' : 'bo' ) '1new ControlP' + cal s:buffunc(1) + let [s:bufnr, s:winw] = [bufnr('%'), winwidth(0)] + let [s:focus, s:prompt] = [1, ['', '', '']] + abc + if !exists('s:hstry') + let hst = filereadable(s:gethistloc()[1]) ? s:gethistdata() : [''] + let s:hstry = empty(hst) || !s:maxhst ? [''] : hst + en + for [ke, va] in items(s:glbs) | if exists('+'.ke) + sil! exe 'let s:glb_'.ke.' = &'.ke.' | let &'.ke.' = '.string(va) + en | endfo + if s:opmul != '0' && has('signs') + sign define ctrlpmark text=+> texthl=Search + en + cal s:setupblank() +endf + +fu! s:Close() + cal s:buffunc(0) + if winnr('$') == 1 + bw! + el + try | bun! + cat | clo! | endt + cal s:unmarksigns() + en + for key in keys(s:glbs) | if exists('+'.key) + sil! exe 'let &'.key.' = s:glb_'.key + en | endfo + if exists('s:glb_acd') | let &acd = s:glb_acd | en + let g:ctrlp_lines = [] + if s:winres[1] >= &lines && s:winres[2] == winnr('$') + exe s:winres[0].s:winres[0] + en + unl! s:focus s:hisidx s:hstgot s:marked s:statypes s:cline s:init s:savestr + \ s:mrbs s:did_exp + cal ctrlp#recordhist() + cal s:execextvar('exit') + cal s:log(0) + let v:errmsg = s:ermsg + ec +endf +" * Clear caches {{{1 +fu! ctrlp#clr(...) + let [s:matches, g:ctrlp_new{ a:0 ? a:1 : 'cache' }] = [1, 1] +endf + +fu! ctrlp#clra() + let cadir = ctrlp#utils#cachedir() + if isdirectory(cadir) + let cafiles = split(s:glbpath(s:fnesc(cadir, 'g', ','), '**', 1), "\n") + let eval = '!isdirectory(v:val) && v:val !~ ''\v[\/]cache[.a-z]+$|\.log$''' + sil! cal map(s:ifilter(cafiles, eval), 'delete(v:val)') + en + cal ctrlp#clr() +endf + +fu! s:Reset(args) + let opts = has_key(a:args, 'opts') ? [a:args['opts']] : [] + cal call('s:opts', opts) + cal s:autocmds() + cal ctrlp#utils#opts() + cal s:execextvar('opts') +endf +" * Files {{{1 +fu! ctrlp#files() + let cafile = ctrlp#utils#cachefile() + if g:ctrlp_newcache || !filereadable(cafile) || s:nocache(cafile) + let [lscmd, s:initcwd, g:ctrlp_allfiles] = [s:lsCmd(), s:dyncwd, []] + " Get the list of files + if empty(lscmd) + if !ctrlp#igncwd(s:dyncwd) + cal s:GlobPath(s:fnesc(s:dyncwd, 'g', ','), 0) + en + el + sil! cal ctrlp#progress('Indexing...') + try | cal s:UserCmd(lscmd) + cat | retu [] | endt + en + " Remove base directory + cal ctrlp#rmbasedir(g:ctrlp_allfiles) + if len(g:ctrlp_allfiles) <= s:compare_lim + cal sort(g:ctrlp_allfiles, 'ctrlp#complen') + en + cal s:writecache(cafile) + let catime = getftime(cafile) + el + let catime = getftime(cafile) + if !( exists('s:initcwd') && s:initcwd == s:dyncwd ) + \ || get(s:ficounts, s:dyncwd, [0, catime])[1] != catime + let s:initcwd = s:dyncwd + let g:ctrlp_allfiles = ctrlp#utils#readfile(cafile) + en + en + cal extend(s:ficounts, { s:dyncwd : [len(g:ctrlp_allfiles), catime] }) + retu g:ctrlp_allfiles +endf + +fu! s:GlobPath(dirs, depth) + let entries = split(globpath(a:dirs, s:glob), "\n") + let [dnf, depth] = [ctrlp#dirnfile(entries), a:depth + 1] + cal extend(g:ctrlp_allfiles, dnf[1]) + if !empty(dnf[0]) && !s:maxf(len(g:ctrlp_allfiles)) && depth <= s:maxdepth + sil! cal ctrlp#progress(len(g:ctrlp_allfiles), 1) + cal s:GlobPath(join(map(dnf[0], 's:fnesc(v:val, "g", ",")'), ','), depth) + en +endf + +fu! s:UserCmd(lscmd) + let [path, lscmd] = [s:dyncwd, a:lscmd] + let do_ign = + \ type(s:usrcmd) == 4 && has_key(s:usrcmd, 'ignore') && s:usrcmd['ignore'] + if do_ign && ctrlp#igncwd(s:cwd) | retu | en + if exists('+ssl') && &ssl + let [ssl, &ssl, path] = [&ssl, 0, tr(path, '/', '\')] + en + if has('win32') || has('win64') + let lscmd = substitute(lscmd, '\v(^|\&\&\s*)\zscd (/d)@!', 'cd /d ', '') + en + let path = exists('*shellescape') ? shellescape(path) : path + let g:ctrlp_allfiles = split(system(printf(lscmd, path)), "\n") + if exists('+ssl') && exists('ssl') + let &ssl = ssl + cal map(g:ctrlp_allfiles, 'tr(v:val, "\\", "/")') + en + if exists('s:vcscmd') && s:vcscmd + cal map(g:ctrlp_allfiles, 'tr(v:val, "/", "\\")') + en + if do_ign + if !empty(s:usrign) + let g:ctrlp_allfiles = ctrlp#dirnfile(g:ctrlp_allfiles)[1] + en + if &wig != '' + cal filter(g:ctrlp_allfiles, 'glob(v:val) != ""') + en + en +endf + +fu! s:lsCmd() + let cmd = s:usrcmd + if type(cmd) == 1 + retu cmd + elsei type(cmd) == 3 && len(cmd) >= 2 && cmd[:1] != ['', ''] + if s:findroot(s:dyncwd, cmd[0], 0, 1) == [] + retu len(cmd) == 3 ? cmd[2] : '' + en + let s:vcscmd = s:lash == '\' + retu cmd[1] + elsei type(cmd) == 4 && ( has_key(cmd, 'types') || has_key(cmd, 'fallback') ) + let fndroot = [] + if has_key(cmd, 'types') && cmd['types'] != {} + let [markrs, cmdtypes] = [[], values(cmd['types'])] + for pair in cmdtypes + cal add(markrs, pair[0]) + endfo + let fndroot = s:findroot(s:dyncwd, markrs, 0, 1) + en + if fndroot == [] + retu has_key(cmd, 'fallback') ? cmd['fallback'] : '' + en + for pair in cmdtypes + if pair[0] == fndroot[0] | brea | en + endfo + let s:vcscmd = s:lash == '\' + retu pair[1] + en +endf +" - Buffers {{{1 +fu! ctrlp#buffers(...) + let ids = sort(filter(range(1, bufnr('$')), 'empty(getbufvar(v:val, "&bt"))' + \ .' && getbufvar(v:val, "&bl")'), 's:compmreb') + if a:0 && a:1 == 'id' + retu ids + el + let bufs = [[], []] + for id in ids + let bname = bufname(id) + let ebname = bname == '' + let fname = fnamemodify(ebname ? '['.id.'*No Name]' : bname, ':.') + cal add(bufs[ebname], fname) + endfo + retu bufs[0] + bufs[1] + en +endf +" * MatchedItems() {{{1 +fu! s:MatchIt(items, pat, limit, exc) + let [lines, id] = [[], 0] + let pat = + \ s:byfname() ? map(split(a:pat, '^[^;]\+\\\@= 0 + cal add(lines, item) + en | cat | brea | endt + if a:limit > 0 && len(lines) >= a:limit | brea | en + endfo + let s:mdata = [s:dyncwd, s:itemtype, s:regexp, s:sublist(a:items, id, -1)] + retu lines +endf + +fu! s:MatchedItems(items, pat, limit) + let exc = exists('s:crfilerel') ? s:crfilerel : '' + let items = s:narrowable() ? s:matched + s:mdata[3] : a:items + if s:matcher != {} + let argms = + \ has_key(s:matcher, 'arg_type') && s:matcher['arg_type'] == 'dict' ? [{ + \ 'items': items, + \ 'str': a:pat, + \ 'limit': a:limit, + \ 'mmode': s:mmode(), + \ 'ispath': s:ispath, + \ 'crfile': exc, + \ 'regex': s:regexp, + \ }] : [items, a:pat, a:limit, s:mmode(), s:ispath, exc, s:regexp] + let lines = call(s:matcher['match'], argms, s:matcher) + el + let lines = s:MatchIt(items, a:pat, a:limit, exc) + en + let s:matches = len(lines) + unl! s:did_exp + retu lines +endf + +fu! s:SplitPattern(str) + let str = a:str + if s:migemo && s:regexp && len(str) > 0 && executable('cmigemo') + let str = s:migemo(str) + en + let s:savestr = str + if s:regexp + let pat = s:regexfilter(str) + el + let lst = split(str, '\zs') + if exists('+ssl') && !&ssl + cal map(lst, 'escape(v:val, ''\'')') + en + for each in ['^', '$', '.'] + cal map(lst, 'escape(v:val, each)') + endfo + en + if exists('lst') + let pat = '' + if !empty(lst) + if s:byfname() && index(lst, ';') > 0 + let fbar = index(lst, ';') + let lst_1 = s:sublist(lst, 0, fbar - 1) + let lst_2 = len(lst) - 1 > fbar ? s:sublist(lst, fbar + 1, -1) : [''] + let pat = s:buildpat(lst_1).';'.s:buildpat(lst_2) + el + let pat = s:buildpat(lst) + en + en + en + retu escape(pat, '~') +endf +" * BuildPrompt() {{{1 +fu! s:Render(lines, pat) + let [&ma, lines, s:res_count] = [1, a:lines, len(a:lines)] + let height = min([max([s:mw_min, s:res_count]), s:winmaxh]) + let pat = s:byfname() ? split(a:pat, '^[^;]\+\\\@' ).( s:byfname() ? 'd' : '>' ).'> ' + let str = escape(s:getinput(), '\') + let lazy = str == '' || exists('s:force') || !has('autocmd') ? 0 : s:lazy + if a:upd && !lazy && ( s:matches || s:regexp || exists('s:did_exp') + \ || str =~ '\(\\\(<\|>\)\|[*|]\)\|\(\\\:\([^:]\|\\:\)*$\)' ) + sil! cal s:Update(str) + en + sil! cal ctrlp#statusline() + " Toggling + let [hiactive, hicursor, base] = s:focus + \ ? ['CtrlPPrtText', 'CtrlPPrtCursor', base] + \ : ['CtrlPPrtBase', 'CtrlPPrtBase', tr(base, '>', '-')] + let hibase = 'CtrlPPrtBase' + " Build it + redr + let prt = copy(s:prompt) + cal map(prt, 'escape(v:val, ''"\'')') + exe 'echoh' hibase '| echon "'.base.'" + \ | echoh' hiactive '| echon "'.prt[0].'" + \ | echoh' hicursor '| echon "'.prt[1].'" + \ | echoh' hiactive '| echon "'.prt[2].'" | echoh None' + " Append the cursor at the end + if empty(prt[1]) && s:focus + exe 'echoh' hibase '| echon "_" | echoh None' + en +endf +" - SetDefTxt() {{{1 +fu! s:SetDefTxt() + if s:deftxt == '0' || ( s:deftxt == 1 && !s:ispath ) | retu | en + let txt = s:deftxt + if !type(txt) + let path = s:crfpath.s:lash(s:crfpath) + let txt = txt && !stridx(path, s:dyncwd) ? ctrlp#rmbasedir([path])[0] : '' + en + let s:prompt[0] = txt +endf +" ** Prt Actions {{{1 +" Editing {{{2 +fu! s:PrtClear() + if !s:focus | retu | en + unl! s:hstgot + let [s:prompt, s:matches] = [['', '', ''], 1] + cal s:BuildPrompt(1) +endf + +fu! s:PrtAdd(char) + unl! s:hstgot + let s:act_add = 1 + let s:prompt[0] .= a:char + cal s:BuildPrompt(1) + unl s:act_add +endf + +fu! s:PrtBS() + if !s:focus | retu | en + unl! s:hstgot + let [s:prompt[0], s:matches] = [substitute(s:prompt[0], '.$', '', ''), 1] + cal s:BuildPrompt(1) +endf + +fu! s:PrtDelete() + if !s:focus | retu | en + unl! s:hstgot + let [prt, s:matches] = [s:prompt, 1] + let prt[1] = matchstr(prt[2], '^.') + let prt[2] = substitute(prt[2], '^.', '', '') + cal s:BuildPrompt(1) +endf + +fu! s:PrtDeleteWord() + if !s:focus | retu | en + unl! s:hstgot + let [str, s:matches] = [s:prompt[0], 1] + let str = str =~ '\W\w\+$' ? matchstr(str, '^.\+\W\ze\w\+$') + \ : str =~ '\w\W\+$' ? matchstr(str, '^.\+\w\ze\W\+$') + \ : str =~ '\s\+$' ? matchstr(str, '^.*\S\ze\s\+$') + \ : str =~ '\v^(\S+|\s+)$' ? '' : str + let s:prompt[0] = str + cal s:BuildPrompt(1) +endf + +fu! s:PrtInsert(...) + if !s:focus | retu | en + let type = !a:0 ? '' : a:1 + if !a:0 + let type = s:insertstr() + if type == 'cancel' | retu | en + en + if type ==# 'r' + let regcont = s:getregs() + if regcont < 0 | retu | en + en + unl! s:hstgot + let s:act_add = 1 + let s:prompt[0] .= type ==# 'w' ? s:crword + \ : type ==# 'f' ? s:crgfile + \ : type ==# 's' ? s:regisfilter('/') + \ : type ==# 'v' ? s:crvisual + \ : type ==# 'c' ? s:regisfilter('+') + \ : type ==# 'r' ? regcont : '' + cal s:BuildPrompt(1) + unl s:act_add +endf + +fu! s:PrtExpandDir() + if !s:focus | retu | en + let str = s:getinput('c') + if str =~ '\v^\@(cd|lc[hd]?|chd)\s.+' && s:spi + let hasat = split(str, '\v^\@(cd|lc[hd]?|chd)\s*\zs') + let str = get(hasat, 1, '') + if str =~# '\v^[~$]\i{-}[\/]?|^#(\):(p|h|8|\~|\.|g?s+)' + let spc = str =~# '^%' ? s:crfile + \ : str =~# '^' ? s:crgfile + \ : str =~# '^' ? s:crword + \ : str =~# '^' ? s:crnbword : '' + let pat = '(:(p|h|8|\~|\.|g?s(.)[^\3]*\3[^\3]*\3))+' + let mdr = matchstr(str, '\v^[^:]+\zs'.pat) + let nmd = matchstr(str, '\v^[^:]+'.pat.'\zs.{-}$') + let str = fnamemodify(s:fnesc(spc, 'g'), mdr).nmd + en + en + if str == '' | retu | en + unl! s:hstgot + let s:act_add = 1 + let [base, seed] = s:headntail(str) + if str =~# '^[\/]' + let base = expand('/').base + en + let dirs = s:dircompl(base, seed) + if len(dirs) == 1 + let str = dirs[0] + elsei len(dirs) > 1 + let str .= s:findcommon(dirs, str) + en + let s:prompt[0] = exists('hasat') ? hasat[0].str : str + cal s:BuildPrompt(1) + unl s:act_add +endf +" Movement {{{2 +fu! s:PrtCurLeft() + if !s:focus | retu | en + let prt = s:prompt + if !empty(prt[0]) + let s:prompt = [substitute(prt[0], '.$', '', ''), matchstr(prt[0], '.$'), + \ prt[1] . prt[2]] + en + cal s:BuildPrompt(0) +endf + +fu! s:PrtCurRight() + if !s:focus | retu | en + let prt = s:prompt + let s:prompt = [prt[0] . prt[1], matchstr(prt[2], '^.'), + \ substitute(prt[2], '^.', '', '')] + cal s:BuildPrompt(0) +endf + +fu! s:PrtCurStart() + if !s:focus | retu | en + let str = join(s:prompt, '') + let s:prompt = ['', matchstr(str, '^.'), substitute(str, '^.', '', '')] + cal s:BuildPrompt(0) +endf + +fu! s:PrtCurEnd() + if !s:focus | retu | en + let s:prompt = [join(s:prompt, ''), '', ''] + cal s:BuildPrompt(0) +endf + +fu! s:PrtSelectMove(dir) + let wht = winheight(0) + let dirs = {'t': 'gg','b': 'G','j': 'j','k': 'k','u': wht.'k','d': wht.'j'} + exe 'keepj norm!' dirs[a:dir] + if s:nolim != 1 | let s:cline = line('.') | en + if line('$') > winheight(0) | cal s:BuildPrompt(0) | en +endf + +fu! s:PrtSelectJump(char) + let lines = copy(s:lines) + if s:byfname() + cal map(lines, 'split(v:val, ''[\/]\ze[^\/]\+$'')[-1]') + en + " Cycle through matches, use s:jmpchr to store last jump + let chr = escape(matchstr(a:char, '^.'), '.~') + let smartcs = &scs && chr =~ '\u' ? '\C' : '' + if match(lines, smartcs.'^'.chr) >= 0 + " If not exists or does but not for the same char + let pos = match(lines, smartcs.'^'.chr) + if !exists('s:jmpchr') || ( exists('s:jmpchr') && s:jmpchr[0] != chr ) + let [jmpln, s:jmpchr] = [pos, [chr, pos]] + elsei exists('s:jmpchr') && s:jmpchr[0] == chr + " Start of lines + if s:jmpchr[1] == -1 | let s:jmpchr[1] = pos | en + let npos = match(lines, smartcs.'^'.chr, s:jmpchr[1] + 1) + let [jmpln, s:jmpchr] = [npos == -1 ? pos : npos, [chr, npos]] + en + exe 'keepj norm!' ( jmpln + 1 ).'G' + if s:nolim != 1 | let s:cline = line('.') | en + if line('$') > winheight(0) | cal s:BuildPrompt(0) | en + en +endf +" Misc {{{2 +fu! s:PrtFocusMap(char) + cal call(( s:focus ? 's:PrtAdd' : 's:PrtSelectJump' ), [a:char]) +endf + +fu! s:PrtClearCache() + if s:itemtype == 0 + cal ctrlp#clr() + elsei s:itemtype > 2 + cal ctrlp#clr(s:statypes[s:itemtype][1]) + en + if s:itemtype == 2 + let g:ctrlp_lines = ctrlp#mrufiles#refresh() + el + cal ctrlp#setlines() + en + let s:force = 1 + cal s:BuildPrompt(1) + unl s:force +endf + +fu! s:PrtDeleteEnt() + if s:itemtype == 2 + cal s:PrtDeleteMRU() + elsei type(s:getextvar('wipe')) == 1 + cal s:delent(s:getextvar('wipe')) + en +endf + +fu! s:PrtDeleteMRU() + if s:itemtype == 2 + cal s:delent('ctrlp#mrufiles#remove') + en +endf + +fu! s:PrtExit() + if bufnr('%') == s:bufnr && bufname('%') == 'ControlP' + noa cal s:Close() + noa winc p + en +endf + +fu! s:PrtHistory(...) + if !s:focus || !s:maxhst | retu | en + let [str, hst, s:matches] = [join(s:prompt, ''), s:hstry, 1] + " Save to history if not saved before + let [hst[0], hslen] = [exists('s:hstgot') ? hst[0] : str, len(hst)] + let idx = exists('s:hisidx') ? s:hisidx + a:1 : a:1 + " Limit idx within 0 and hslen + let idx = idx < 0 ? 0 : idx >= hslen ? hslen > 1 ? hslen - 1 : 0 : idx + let s:prompt = [hst[idx], '', ''] + let [s:hisidx, s:hstgot, s:force] = [idx, 1, 1] + cal s:BuildPrompt(1) + unl s:force +endf +"}}}1 +" * Mappings {{{1 +fu! s:MapNorms() + if exists('s:nmapped') && s:nmapped == s:bufnr | retu | en + let pcmd = "nn \ \ \ :\cal \%s(\"%s\")\" + let cmd = substitute(pcmd, 'k%s', 'char-%d', '') + let pfunc = 'PrtFocusMap' + let ranges = [32, 33, 125, 126] + range(35, 91) + range(93, 123) + for each in [34, 92, 124] + exe printf(cmd, each, pfunc, escape(nr2char(each), '"|\')) + endfo + for each in ranges + exe printf(cmd, each, pfunc, nr2char(each)) + endfo + for each in range(0, 9) + exe printf(pcmd, each, pfunc, each) + endfo + for [ke, va] in items(s:kprange) + exe printf(pcmd, ke, pfunc, va) + endfo + let s:nmapped = s:bufnr +endf + +fu! s:MapSpecs() + if !( exists('s:smapped') && s:smapped == s:bufnr ) + " Correct arrow keys in terminal + if ( has('termresponse') && v:termresponse =~ "\" ) + \ || &term =~? '\vxterm|','\B ','\C ','\D '] + exe s:lcmap.' ['.each + endfo + en + en + for [ke, va] in items(s:prtmaps) | for kp in va + exe s:lcmap kp ':cal '.ke.'' + endfo | endfo + let s:smapped = s:bufnr +endf + +fu! s:KeyLoop() + wh exists('s:init') && s:keyloop + redr + let nr = getchar() + let chr = !type(nr) ? nr2char(nr) : nr + if nr >=# 0x20 + cal s:PrtFocusMap(chr) + el + let cmd = matchstr(maparg(chr), ':\zs.\+\ze$') + exe ( cmd != '' ? cmd : 'norm '.chr ) + en + endw +endf +" * Toggling {{{1 +fu! s:ToggleFocus() + let s:focus = !s:focus + cal s:BuildPrompt(0) +endf + +fu! s:ToggleRegex() + let s:regexp = !s:regexp + cal s:PrtSwitcher() +endf + +fu! s:ToggleByFname() + if s:ispath + let s:byfname = !s:byfname + let s:mfunc = s:mfunc() + cal s:PrtSwitcher() + en +endf + +fu! s:ToggleType(dir) + let max = len(g:ctrlp_ext_vars) + 2 + let next = s:walker(max, s:itemtype, a:dir) + cal ctrlp#syntax() + cal ctrlp#setlines(next) + cal s:PrtSwitcher() +endf + +fu! s:ToggleKeyLoop() + let s:keyloop = !s:keyloop + if exists('+imd') + let &imd = !s:keyloop + en + if s:keyloop + let [&ut, s:lazy] = [0, 0] + cal s:KeyLoop() + elsei has_key(s:glbs, 'ut') + let [&ut, s:lazy] = [s:glbs['ut'], 1] + en +endf + +fu! s:ToggleMRURelative() + cal ctrlp#mrufiles#tgrel() + cal s:PrtClearCache() +endf + +fu! s:PrtSwitcher() + let [s:force, s:matches] = [1, 1] + cal s:BuildPrompt(1) + unl s:force +endf +" - SetWD() {{{1 +fu! s:SetWD(args) + if has_key(a:args, 'args') && stridx(a:args['args'], '--dir') >= 0 + \ && exists('s:dyncwd') + cal ctrlp#setdir(s:dyncwd) | retu + en + if has_key(a:args, 'dir') && a:args['dir'] != '' + cal ctrlp#setdir(a:args['dir']) | retu + en + let pmode = has_key(a:args, 'mode') ? a:args['mode'] : s:pathmode + let [s:crfilerel, s:dyncwd] = [fnamemodify(s:crfile, ':.'), getcwd()] + if s:crfile =~ '^.\+://' | retu | en + if pmode =~ 'c' || ( pmode =~ 'a' && stridx(s:crfpath, s:cwd) < 0 ) + \ || ( !type(pmode) && pmode ) + if exists('+acd') | let [s:glb_acd, &acd] = [&acd, 0] | en + cal ctrlp#setdir(s:crfpath) + en + if pmode =~ 'r' || pmode == 2 + let markers = ['.git', '.hg', '.svn', '.bzr', '_darcs'] + let spath = pmode =~ 'd' ? s:dyncwd : pmode =~ 'w' ? s:cwd : s:crfpath + if type(s:rmarkers) == 3 && !empty(s:rmarkers) + if s:findroot(spath, s:rmarkers, 0, 0) != [] | retu | en + cal filter(markers, 'index(s:rmarkers, v:val) < 0') + en + cal s:findroot(spath, markers, 0, 0) + en +endf +" * AcceptSelection() {{{1 +fu! ctrlp#acceptfile(...) + let useb = 0 + if a:0 == 1 && type(a:1) == 4 + let [md, line] = [a:1['action'], a:1['line']] + let atl = has_key(a:1, 'tail') ? a:1['tail'] : '' + el + let [md, line] = [a:1, a:2] + let atl = a:0 > 2 ? a:3 : '' + en + if !type(line) + let [filpath, bufnr, useb] = [line, line, 1] + el + let filpath = fnamemodify(line, ':p') + if s:nonamecond(line, filpath) + let bufnr = str2nr(matchstr(line, '[\/]\?\[\zs\d\+\ze\*No Name\]$')) + let [filpath, useb] = [bufnr, 1] + el + let bufnr = bufnr('^'.filpath.'$') + en + en + cal s:PrtExit() + let tail = s:tail() + let j2l = atl != '' ? atl : matchstr(tail, '^ +\zs\d\+$') + if ( s:jmptobuf =~ md || ( s:jmptobuf && md =~ '[et]' ) ) && bufnr > 0 + \ && !( md == 'e' && bufnr == bufnr('%') ) + let [jmpb, bufwinnr] = [1, bufwinnr(bufnr)] + let buftab = ( s:jmptobuf =~# '[tTVH]' || s:jmptobuf > 1 ) + \ ? s:buftab(bufnr, md) : [0, 0] + en + " Switch to existing buffer or open new one + if exists('jmpb') && bufwinnr > 0 + \ && !( md == 't' && ( s:jmptobuf !~# toupper(md) || buftab[0] ) ) + exe bufwinnr.'winc w' + if j2l | cal ctrlp#j2l(j2l) | en + elsei exists('jmpb') && buftab[0] + \ && !( md =~ '[evh]' && s:jmptobuf !~# toupper(md) ) + exe 'tabn' buftab[0] + exe buftab[1].'winc w' + if j2l | cal ctrlp#j2l(j2l) | en + el + " Determine the command to use + let useb = bufnr > 0 && buflisted(bufnr) && ( empty(tail) || useb ) + let cmd = + \ md == 't' || s:splitwin == 1 ? ( useb ? 'tab sb' : 'tabe' ) : + \ md == 'h' || s:splitwin == 2 ? ( useb ? 'sb' : 'new' ) : + \ md == 'v' || s:splitwin == 3 ? ( useb ? 'vert sb' : 'vne' ) : + \ call('ctrlp#normcmd', useb ? ['b', 'bo vert sb'] : ['e']) + " Reset &switchbuf option + let [swb, &swb] = [&swb, ''] + " Open new window/buffer + let [fid, tail] = [( useb ? bufnr : filpath ), ( atl != '' ? ' +'.atl : tail )] + let args = [cmd, fid, tail, 1, [useb, j2l]] + cal call('s:openfile', args) + let &swb = swb + en +endf + +fu! s:SpecInputs(str) + if a:str =~ '\v^(\.\.([\/]\.\.)*[\/]?[.\/]*)$' && s:spi + let cwd = s:dyncwd + cal ctrlp#setdir(a:str =~ '^\.\.\.*$' ? + \ '../'.repeat('../', strlen(a:str) - 2) : a:str) + if cwd != s:dyncwd | cal ctrlp#setlines() | en + cal s:PrtClear() + retu 1 + elsei a:str == s:lash && s:spi + cal s:SetWD({ 'mode': 'rd' }) + cal ctrlp#setlines() + cal s:PrtClear() + retu 1 + elsei a:str =~ '^@.\+' && s:spi + retu s:at(a:str) + elsei a:str == '?' + cal s:PrtExit() + let hlpwin = &columns > 159 ? '| vert res 80' : '' + sil! exe 'bo vert h ctrlp-mappings' hlpwin '| norm! 0' + retu 1 + en + retu 0 +endf + +fu! s:AcceptSelection(action) + let [md, icr] = [a:action[0], match(a:action, 'r') >= 0] + let subm = icr || ( !icr && md == 'e' ) + if !subm && s:OpenMulti(md) != -1 | retu | en + let str = s:getinput() + if subm | if s:SpecInputs(str) | retu | en | en + " Get the selected line + let line = ctrlp#getcline() + if !subm && !s:itemtype && line == '' && line('.') > s:offset + \ && str !~ '\v^(\.\.([\/]\.\.)*[\/]?[.\/]*|/|\\|\?|\@.+)$' + cal s:CreateNewFile(md) | retu + en + if empty(line) | retu | en + " Do something with it + if s:openfunc != {} && has_key(s:openfunc, s:ctype) + let actfunc = s:openfunc[s:ctype] + let type = has_key(s:openfunc, 'arg_type') ? s:openfunc['arg_type'] : 'list' + el + if s:itemtype < 3 + let [actfunc, type] = ['ctrlp#acceptfile', 'dict'] + el + let [actfunc, exttype] = [s:getextvar('accept'), s:getextvar('act_farg')] + let type = exttype == 'dict' ? exttype : 'list' + en + en + let actargs = type == 'dict' ? [{ 'action': md, 'line': line, 'icr': icr }] + \ : [md, line] + cal call(actfunc, actargs) +endf +" - CreateNewFile() {{{1 +fu! s:CreateNewFile(...) + let [md, str] = ['', s:getinput('n')] + if empty(str) | retu | en + if s:argmap && !a:0 + " Get the extra argument + let md = s:argmaps(md, 1) + if md == 'cancel' | retu | en + en + let str = s:sanstail(str) + let [base, fname] = s:headntail(str) + if fname =~ '^[\/]$' | retu | en + if exists('s:marked') && len(s:marked) + " Use the first marked file's path + let path = fnamemodify(values(s:marked)[0], ':p:h') + let base = path.s:lash(path).base + let str = fnamemodify(base.s:lash.fname, ':.') + en + if base != '' | if isdirectory(ctrlp#utils#mkdir(base)) + let optyp = str | en | el | let optyp = fname + en + if !exists('optyp') | retu | en + let [filpath, tail] = [fnamemodify(optyp, ':p'), s:tail()] + if !stridx(filpath, s:dyncwd) | cal s:insertcache(str) | en + cal s:PrtExit() + let cmd = md == 'r' ? ctrlp#normcmd('e') : + \ s:newfop =~ '1\|t' || ( a:0 && a:1 == 't' ) || md == 't' ? 'tabe' : + \ s:newfop =~ '2\|h' || ( a:0 && a:1 == 'h' ) || md == 'h' ? 'new' : + \ s:newfop =~ '3\|v' || ( a:0 && a:1 == 'v' ) || md == 'v' ? 'vne' : + \ ctrlp#normcmd('e') + cal s:openfile(cmd, filpath, tail, 1) +endf +" * OpenMulti() {{{1 +fu! s:MarkToOpen() + if s:bufnr <= 0 || s:opmul == '0' + \ || ( s:itemtype > 2 && s:getextvar('opmul') != 1 ) + retu + en + let line = ctrlp#getcline() + if empty(line) | retu | en + let filpath = s:ispath ? fnamemodify(line, ':p') : line + if exists('s:marked') && s:dictindex(s:marked, filpath) > 0 + " Unmark and remove the file from s:marked + let key = s:dictindex(s:marked, filpath) + cal remove(s:marked, key) + if empty(s:marked) | unl s:marked | en + if has('signs') + exe 'sign unplace' key 'buffer='.s:bufnr + en + el + " Add to s:marked and place a new sign + if exists('s:marked') + let vac = s:vacantdict(s:marked) + let key = empty(vac) ? len(s:marked) + 1 : vac[0] + let s:marked = extend(s:marked, { key : filpath }) + el + let [key, s:marked] = [1, { 1 : filpath }] + en + if has('signs') + exe 'sign place' key 'line='.line('.').' name=ctrlpmark buffer='.s:bufnr + en + en + sil! cal ctrlp#statusline() +endf + +fu! s:OpenMulti(...) + let has_marked = exists('s:marked') + if ( !has_marked && a:0 ) || s:opmul == '0' || !s:ispath + \ || ( s:itemtype > 2 && s:getextvar('opmul') != 1 ) + retu -1 + en + " Get the options + let [nr, md] = [matchstr(s:opmul, '\d\+'), matchstr(s:opmul, '[thvi]')] + let [ur, jf] = [s:opmul =~ 'r', s:opmul =~ 'j'] + let md = a:0 ? a:1 : ( md == '' ? 'v' : md ) + let nopt = exists('g:ctrlp_open_multiple_files') + if !has_marked + let line = ctrlp#getcline() + if line == '' | retu | en + let marked = { 1 : fnamemodify(line, ':p') } + let [nr, ur, jf, nopt] = ['1', 0, 0, 1] + en + if ( s:argmap || !has_marked ) && !a:0 + let md = s:argmaps(md, !has_marked ? 2 : 0) + if md == 'c' + cal s:unmarksigns() + unl! s:marked + cal s:BuildPrompt(0) + elsei !has_marked && md =~ '[axd]' + retu s:OpenNoMarks(md, line) + en + if md =~ '\v^c(ancel)?$' | retu | en + let nr = nr == '0' ? ( nopt ? '' : '1' ) : nr + let ur = !has_marked && md == 'r' ? 1 : ur + en + let mkd = values(has_marked ? s:marked : marked) + cal s:sanstail(join(s:prompt, '')) + cal s:PrtExit() + if nr == '0' || md == 'i' + retu map(mkd, "s:openfile('bad', v:val, '', 0)") + en + let tail = s:tail() + let [emptytail, bufnr] = [empty(tail), bufnr('^'.mkd[0].'$')] + let useb = bufnr > 0 && buflisted(bufnr) && emptytail + " Move to a replaceable window + let ncmd = ( useb ? ['b', 'bo vert sb'] : ['e', 'bo vne'] ) + \ + ( ur ? [] : ['ignruw'] ) + let fst = call('ctrlp#normcmd', ncmd) + " Check if the current window has a replaceable buffer + let repabl = !( md == 't' && !ur ) && empty(bufname('%')) && empty(&l:ft) + " Commands for the rest of the files + let [ic, cmds] = [1, { 'v': ['vert sb', 'vne'], 'h': ['sb', 'new'], + \ 't': ['tab sb', 'tabe'] }] + let [swb, &swb] = [&swb, ''] + if md == 't' && ctrlp#tabcount() < tabpagenr() + let s:tabct = ctrlp#tabcount() + en + " Open the files + for va in mkd + let bufnr = bufnr('^'.va.'$') + if bufnr < 0 && getftype(va) == '' | con | en + let useb = bufnr > 0 && buflisted(bufnr) && emptytail + let snd = md != '' && has_key(cmds, md) ? + \ ( useb ? cmds[md][0] : cmds[md][1] ) : ( useb ? 'vert sb' : 'vne' ) + let cmd = ic == 1 && ( !( !ur && fst =~ '^[eb]$' ) || repabl ) ? fst : snd + let conds = [( nr != '' && nr > 1 && nr < ic ) || ( nr == '' && ic > 1 ), + \ nr != '' && nr < ic] + if conds[nopt] + if !buflisted(bufnr) | cal s:openfile('bad', va, '', 0) | en + el + cal s:openfile(cmd, useb ? bufnr : va, tail, ic == 1) + if jf | if ic == 1 + let crpos = [tabpagenr(), winnr()] + el + let crpos[0] += tabpagenr() <= crpos[0] + let crpos[1] += winnr() <= crpos[1] + en | en + let ic += 1 + en + endfo + if jf && exists('crpos') && ic > 2 + exe ( md == 't' ? 'tabn '.crpos[0] : crpos[1].'winc w' ) + en + let &swb = swb + unl! s:tabct +endf + +fu! s:OpenNoMarks(md, line) + if a:md == 'a' + let [s:marked, key] = [{}, 1] + for line in s:lines + let s:marked = extend(s:marked, { key : fnamemodify(line, ':p') }) + let key += 1 + endfo + cal s:remarksigns() + cal s:BuildPrompt(0) + elsei a:md == 'x' + let type = has_key(s:openfunc, 'arg_type') ? s:openfunc['arg_type'] : 'dict' + let argms = type == 'dict' ? [{ 'action': a:md, 'line': a:line }] + \ : [a:md, a:line] + cal call(s:openfunc[s:ctype], argms, s:openfunc) + elsei a:md == 'd' + let dir = fnamemodify(a:line, ':h') + if isdirectory(dir) + cal ctrlp#setdir(dir) + cal ctrlp#switchtype(0) + cal ctrlp#recordhist() + cal s:PrtClear() + en + en +endf +" ** Helper functions {{{1 +" Sorting {{{2 +fu! ctrlp#complen(...) + " By length + let [len1, len2] = [strlen(a:1), strlen(a:2)] + retu len1 == len2 ? 0 : len1 > len2 ? 1 : -1 +endf + +fu! s:compmatlen(...) + " By match length + let mln1 = s:shortest(s:matchlens(a:1, s:compat)) + let mln2 = s:shortest(s:matchlens(a:2, s:compat)) + retu mln1 == mln2 ? 0 : mln1 > mln2 ? 1 : -1 +endf + +fu! s:comptime(...) + " By last modified time + let [time1, time2] = [getftime(a:1), getftime(a:2)] + retu time1 == time2 ? 0 : time1 < time2 ? 1 : -1 +endf + +fu! s:compmreb(...) + " By last entered time (bufnr) + let [id1, id2] = [index(s:mrbs, a:1), index(s:mrbs, a:2)] + retu id1 == id2 ? 0 : id1 > id2 ? 1 : -1 +endf + +fu! s:compmref(...) + " By last entered time (MRU) + let [id1, id2] = [index(g:ctrlp_lines, a:1), index(g:ctrlp_lines, a:2)] + retu id1 == id2 ? 0 : id1 > id2 ? 1 : -1 +endf + +fu! s:comparent(...) + " By same parent dir + if !stridx(s:crfpath, s:dyncwd) + let [as1, as2] = [s:dyncwd.s:lash().a:1, s:dyncwd.s:lash().a:2] + let [loc1, loc2] = [s:getparent(as1), s:getparent(as2)] + if loc1 == s:crfpath && loc2 != s:crfpath | retu -1 | en + if loc2 == s:crfpath && loc1 != s:crfpath | retu 1 | en + retu 0 + en + retu 0 +endf + +fu! s:compfnlen(...) + " By filename length + let len1 = strlen(split(a:1, s:lash)[-1]) + let len2 = strlen(split(a:2, s:lash)[-1]) + retu len1 == len2 ? 0 : len1 > len2 ? 1 : -1 +endf + +fu! s:matchlens(str, pat, ...) + if empty(a:pat) || index(['^', '$'], a:pat) >= 0 | retu {} | en + let st = a:0 ? a:1 : 0 + let lens = a:0 >= 2 ? a:2 : {} + let nr = a:0 >= 3 ? a:3 : 0 + if nr > 20 | retu {} | en + if match(a:str, a:pat, st) >= 0 + let [mst, mnd] = [matchstr(a:str, a:pat, st), matchend(a:str, a:pat, st)] + let lens = extend(lens, { nr : [strlen(mst), mst] }) + let lens = s:matchlens(a:str, a:pat, mnd, lens, nr + 1) + en + retu lens +endf + +fu! s:shortest(lens) + retu min(map(values(a:lens), 'v:val[0]')) +endf + +fu! s:mixedsort(...) + if s:itemtype == 1 + let pat = '[\/]\?\[\d\+\*No Name\]$' + if a:1 =~# pat && a:2 =~# pat | retu 0 + elsei a:1 =~# pat | retu 1 + elsei a:2 =~# pat | retu -1 | en + en + let [cln, cml] = [ctrlp#complen(a:1, a:2), s:compmatlen(a:1, a:2)] + if s:ispath + let ms = [] + if s:res_count < 21 + let ms += [s:compfnlen(a:1, a:2)] + if s:itemtype !~ '^[12]$' | let ms += [s:comptime(a:1, a:2)] | en + if !s:itemtype | let ms += [s:comparent(a:1, a:2)] | en + en + if s:itemtype =~ '^[12]$' + let ms += [s:compmref(a:1, a:2)] + let cln = cml ? cln : 0 + en + let ms += [cml, 0, 0, 0] + let mp = call('s:multipliers', ms[:3]) + retu cln + ms[0] * mp[0] + ms[1] * mp[1] + ms[2] * mp[2] + ms[3] * mp[3] + en + retu cln + cml * 2 +endf + +fu! s:multipliers(...) + let mp0 = !a:1 ? 0 : 2 + let mp1 = !a:2 ? 0 : 1 + ( !mp0 ? 1 : mp0 ) + let mp2 = !a:3 ? 0 : 1 + ( !( mp0 + mp1 ) ? 1 : ( mp0 + mp1 ) ) + let mp3 = !a:4 ? 0 : 1 + ( !( mp0 + mp1 + mp2 ) ? 1 : ( mp0 + mp1 + mp2 ) ) + retu [mp0, mp1, mp2, mp3] +endf + +fu! s:compval(...) + retu a:1 - a:2 +endf +" Statusline {{{2 +fu! ctrlp#statusline() + if !exists('s:statypes') + let s:statypes = [ + \ ['files', 'fil'], + \ ['buffers', 'buf'], + \ ['mru files', 'mru'], + \ ] + if !empty(g:ctrlp_ext_vars) + cal map(copy(g:ctrlp_ext_vars), + \ 'add(s:statypes, [ v:val["lname"], v:val["sname"] ])') + en + en + let tps = s:statypes + let max = len(tps) - 1 + let nxt = tps[s:walker(max, s:itemtype, 1)][1] + let prv = tps[s:walker(max, s:itemtype, -1)][1] + let s:ctype = tps[s:itemtype][0] + let focus = s:focus ? 'prt' : 'win' + let byfname = s:ispath ? s:byfname ? 'file' : 'path' : 'line' + let marked = s:opmul != '0' ? + \ exists('s:marked') ? ' <'.s:dismrk().'>' : ' <->' : '' + if s:status != {} + let argms = + \ has_key(s:status, 'arg_type') && s:status['arg_type'] == 'dict' ? [{ + \ 'focus': focus, + \ 'byfname': byfname, + \ 'regex': s:regexp, + \ 'prev': prv, + \ 'item': s:ctype, + \ 'next': nxt, + \ 'marked': marked, + \ }] : [focus, byfname, s:regexp, prv, s:ctype, nxt, marked] + let &l:stl = call(s:status['main'], argms, s:status) + el + let item = '%#CtrlPMode1# '.s:ctype.' %*' + let focus = '%#CtrlPMode2# '.focus.' %*' + let byfname = '%#CtrlPMode1# '.byfname.' %*' + let regex = s:regexp ? '%#CtrlPMode2# regex %*' : '' + let slider = ' <'.prv.'>={'.item.'}=<'.nxt.'>' + let dir = ' %=%<%#CtrlPMode2# %{getcwd()} %*' + let &l:stl = focus.byfname.regex.slider.marked.dir + en +endf + +fu! s:dismrk() + retu has('signs') ? len(s:marked) : + \ '%<'.join(values(map(copy(s:marked), 'split(v:val, "[\\/]")[-1]')), ', ') +endf + +fu! ctrlp#progress(enum, ...) + if has('macunix') || has('mac') | sl 1m | en + let txt = a:0 ? '(press ctrl-c to abort)' : '' + if s:status != {} + let argms = has_key(s:status, 'arg_type') && s:status['arg_type'] == 'dict' + \ ? [{ 'str': a:enum }] : [a:enum] + let &l:stl = call(s:status['prog'], argms, s:status) + el + let &l:stl = '%#CtrlPStats# '.a:enum.' %* '.txt.'%=%<%#CtrlPMode2# %{getcwd()} %*' + en + redraws +endf +" *** Paths {{{2 +" Line formatting {{{3 +fu! s:formatline(str) + let str = a:str + if s:itemtype == 1 + let filpath = fnamemodify(str, ':p') + let bufnr = s:nonamecond(str, filpath) + \ ? str2nr(matchstr(str, '[\/]\?\[\zs\d\+\ze\*No Name\]$')) + \ : bufnr('^'.filpath.'$') + let idc = ( bufnr == bufnr('#') ? '#' : '' ) + \ . ( getbufvar(bufnr, '&ma') ? '' : '-' ) + \ . ( getbufvar(bufnr, '&ro') ? '=' : '' ) + \ . ( getbufvar(bufnr, '&mod') ? '+' : '' ) + let str .= idc != '' ? ' '.idc : '' + en + let cond = s:ispath && ( s:winw - 4 ) < s:strwidth(str) + retu '> '.( cond ? s:pathshorten(str) : str ) +endf + +fu! s:pathshorten(str) + retu matchstr(a:str, '^.\{9}').'...' + \ .matchstr(a:str, '.\{'.( s:winw - 16 ).'}$') +endf + +fu! s:offset(lines, height) + let s:offset = s:mw_order == 'btt' ? ( a:height - s:res_count ) : 0 + retu s:offset > 0 ? ( repeat([''], s:offset) + a:lines ) : a:lines +endf +" Directory completion {{{3 +fu! s:dircompl(be, sd) + if a:sd == '' | retu [] | en + if a:be == '' + let [be, sd] = [s:dyncwd, a:sd] + el + let be = a:be.s:lash(a:be) + let sd = be.a:sd + en + let dirs = split(globpath(s:fnesc(be, 'g', ','), a:sd.'*/'), "\n") + if a:be == '' + let dirs = ctrlp#rmbasedir(dirs) + en + cal filter(dirs, '!match(v:val, escape(sd, ''~$.\''))' + \ . ' && v:val !~ ''\v(^|[\/])\.{1,2}[\/]$''') + retu dirs +endf + +fu! s:findcommon(items, seed) + let [items, id, cmn, ic] = [copy(a:items), strlen(a:seed), '', 0] + cal map(items, 'strpart(v:val, id)') + for char in split(items[0], '\zs') + for item in items[1:] + if item[ic] != char | let brk = 1 | brea | en + endfo + if exists('brk') | brea | en + let cmn .= char + let ic += 1 + endfo + retu cmn +endf +" Misc {{{3 +fu! s:headntail(str) + let parts = split(a:str, '[\/]\ze[^\/]\+[\/:]\?$') + retu len(parts) == 1 ? ['', parts[0]] : len(parts) == 2 ? parts : [] +endf + +fu! s:lash(...) + retu ( a:0 ? a:1 : s:dyncwd ) !~ '[\/]$' ? s:lash : '' +endf + +fu! s:ispathitem() + retu s:itemtype < 3 || ( s:itemtype > 2 && s:getextvar('type') == 'path' ) +endf + +fu! ctrlp#igncwd(cwd) + retu ctrlp#utils#glob(a:cwd, 0) == '' || + \ ( s:igntype >= 0 && s:usrign(a:cwd, getftype(a:cwd)) ) +endf + +fu! ctrlp#dirnfile(entries) + let [items, cwd] = [[[], []], s:dyncwd.s:lash()] + for each in a:entries + let etype = getftype(each) + if s:igntype >= 0 && s:usrign(each, etype) | con | en + if etype == 'dir' + if s:showhidden | if each !~ '[\/]\.\{1,2}$' + cal add(items[0], each) + en | el + cal add(items[0], each) + en + elsei etype == 'link' + if s:folsym + let isfile = !isdirectory(each) + if s:folsym == 2 || !s:samerootsyml(each, isfile, cwd) + cal add(items[isfile], each) + en + en + elsei etype == 'file' + cal add(items[1], each) + en + endfo + retu items +endf + +fu! s:usrign(item, type) + retu s:igntype == 1 ? a:item =~ s:usrign + \ : s:igntype == 4 && has_key(s:usrign, a:type) && s:usrign[a:type] != '' + \ ? a:item =~ s:usrign[a:type] : 0 +endf + +fu! s:samerootsyml(each, isfile, cwd) + let resolve = fnamemodify(resolve(a:each), ':p:h') + let resolve .= s:lash(resolve) + retu !( stridx(resolve, a:cwd) && ( stridx(a:cwd, resolve) || a:isfile ) ) +endf + +fu! ctrlp#rmbasedir(items) + let cwd = s:dyncwd.s:lash() + if a:items != [] && !stridx(a:items[0], cwd) + let idx = strlen(cwd) + retu map(a:items, 'strpart(v:val, idx)') + en + retu a:items +endf +" Working directory {{{3 +fu! s:getparent(item) + let parent = substitute(a:item, '[\/][^\/]\+[\/:]\?$', '', '') + if parent == '' || parent !~ '[\/]' + let parent .= s:lash + en + retu parent +endf + +fu! s:findroot(curr, mark, depth, type) + let [depth, fnd] = [a:depth + 1, 0] + if type(a:mark) == 1 + let fnd = s:glbpath(s:fnesc(a:curr, 'g', ','), a:mark, 1) != '' + elsei type(a:mark) == 3 + for markr in a:mark + if s:glbpath(s:fnesc(a:curr, 'g', ','), markr, 1) != '' + let fnd = 1 + brea + en + endfo + en + if fnd + if !a:type | cal ctrlp#setdir(a:curr) | en + retu [exists('markr') ? markr : a:mark, a:curr] + elsei depth > s:maxdepth + cal ctrlp#setdir(s:cwd) + el + let parent = s:getparent(a:curr) + if parent != a:curr + retu s:findroot(parent, a:mark, depth, a:type) + en + en + retu [] +endf + +fu! ctrlp#setdir(path, ...) + let cmd = a:0 ? a:1 : 'lc!' + sil! exe cmd s:fnesc(a:path, 'c') + let [s:crfilerel, s:dyncwd] = [fnamemodify(s:crfile, ':.'), getcwd()] +endf +" Fallbacks {{{3 +fu! s:glbpath(...) + retu call('ctrlp#utils#globpath', a:000) +endf + +fu! s:fnesc(...) + retu call('ctrlp#utils#fnesc', a:000) +endf + +fu! ctrlp#setlcdir() + if exists('*haslocaldir') + cal ctrlp#setdir(getcwd(), haslocaldir() ? 'lc!' : 'cd!') + en +endf +" Highlighting {{{2 +fu! ctrlp#syntax() + if ctrlp#nosy() | retu | en + for [ke, va] in items(s:hlgrps) | cal ctrlp#hicheck('CtrlP'.ke, va) | endfo + if synIDattr(synIDtrans(hlID('Normal')), 'bg') !~ '^-1$\|^$' + sil! exe 'hi CtrlPLinePre '.( has("gui_running") ? 'gui' : 'cterm' ).'fg=bg' + en + sy match CtrlPNoEntries '^ == NO ENTRIES ==$' + if hlexists('CtrlPLinePre') + sy match CtrlPLinePre '^>' + en +endf + +fu! s:highlight(pat, grp) + if s:matcher != {} | retu | en + cal clearmatches() + if !empty(a:pat) && s:ispath + let pat = s:regexp ? substitute(a:pat, '\\\@ \\zs', 'g') : a:pat + if s:byfname + let pat = substitute(pat, '\[\^\(.\{-}\)\]\\{-}', '[^\\/\1]\\{-}', 'g') + let pat = substitute(pat, '\$\@') + en +endf + +fu! s:dohighlight() + retu s:mathi[0] && exists('*clearmatches') && !ctrlp#nosy() +endf +" Prompt history {{{2 +fu! s:gethistloc() + let utilcadir = ctrlp#utils#cachedir() + let cache_dir = utilcadir.s:lash(utilcadir).'hist' + retu [cache_dir, cache_dir.s:lash(cache_dir).'cache.txt'] +endf + +fu! s:gethistdata() + retu ctrlp#utils#readfile(s:gethistloc()[1]) +endf + +fu! ctrlp#recordhist() + let str = join(s:prompt, '') + if empty(str) || !s:maxhst | retu | en + let hst = s:hstry + if len(hst) > 1 && hst[1] == str | retu | en + cal extend(hst, [str], 1) + if len(hst) > s:maxhst | cal remove(hst, s:maxhst, -1) | en + cal ctrlp#utils#writecache(hst, s:gethistloc()[0], s:gethistloc()[1]) +endf +" Signs {{{2 +fu! s:unmarksigns() + if !s:dosigns() | retu | en + for key in keys(s:marked) + exe 'sign unplace' key 'buffer='.s:bufnr + endfo +endf + +fu! s:remarksigns() + if !s:dosigns() | retu | en + for ic in range(1, len(s:lines)) + let line = s:ispath ? fnamemodify(s:lines[ic - 1], ':p') : s:lines[ic - 1] + let key = s:dictindex(s:marked, line) + if key > 0 + exe 'sign place' key 'line='.ic.' name=ctrlpmark buffer='.s:bufnr + en + endfo +endf + +fu! s:dosigns() + retu exists('s:marked') && s:bufnr > 0 && s:opmul != '0' && has('signs') +endf +" Lists & Dictionaries {{{2 +fu! s:ifilter(list, str) + let [rlist, estr] = [[], substitute(a:str, 'v:val', 'each', 'g')] + for each in a:list + try + if eval(estr) + cal add(rlist, each) + en + cat | con | endt + endfo + retu rlist +endf + +fu! s:dictindex(dict, expr) + for key in keys(a:dict) + if a:dict[key] == a:expr | retu key | en + endfo + retu -1 +endf + +fu! s:vacantdict(dict) + retu filter(range(1, max(keys(a:dict))), '!has_key(a:dict, v:val)') +endf + +fu! s:sublist(l, s, e) + retu v:version > 701 ? a:l[(a:s):(a:e)] : s:sublist7071(a:l, a:s, a:e) +endf + +fu! s:sublist7071(l, s, e) + let [newlist, id, ae] = [[], a:s, a:e == -1 ? len(a:l) - 1 : a:e] + wh id <= ae + cal add(newlist, get(a:l, id)) + let id += 1 + endw + retu newlist +endf +" Buffers {{{2 +fu! s:buftab(bufnr, md) + for tabnr in range(1, tabpagenr('$')) + if tabpagenr() == tabnr && a:md == 't' | con | en + let buflist = tabpagebuflist(tabnr) + if index(buflist, a:bufnr) >= 0 + for winnr in range(1, tabpagewinnr(tabnr, '$')) + if buflist[winnr - 1] == a:bufnr | retu [tabnr, winnr] | en + endfo + en + endfo + retu [0, 0] +endf + +fu! s:bufwins(bufnr) + let winns = 0 + for tabnr in range(1, tabpagenr('$')) + let winns += count(tabpagebuflist(tabnr), a:bufnr) + endfo + retu winns +endf + +fu! s:nonamecond(str, filpath) + retu a:str =~ '[\/]\?\[\d\+\*No Name\]$' && !filereadable(a:filpath) + \ && bufnr('^'.a:filpath.'$') < 1 +endf + +fu! ctrlp#normcmd(cmd, ...) + if a:0 < 2 && s:nosplit() | retu a:cmd | en + let norwins = filter(range(1, winnr('$')), + \ 'empty(getbufvar(winbufnr(v:val), "&bt"))') + for each in norwins + let bufnr = winbufnr(each) + if empty(bufname(bufnr)) && empty(getbufvar(bufnr, '&ft')) + let fstemp = each | brea + en + endfo + let norwin = empty(norwins) ? 0 : norwins[0] + if norwin + if index(norwins, winnr()) < 0 + exe ( exists('fstemp') ? fstemp : norwin ).'winc w' + en + retu a:cmd + en + retu a:0 ? a:1 : 'bo vne' +endf + +fu! ctrlp#modfilecond(w) + retu &mod && !&hid && &bh != 'hide' && s:bufwins(bufnr('%')) == 1 && !&cf && + \ ( ( !&awa && a:w ) || filewritable(fnamemodify(bufname('%'), ':p')) != 1 ) +endf + +fu! s:nosplit() + retu !empty(s:nosplit) && match([bufname('%'), &l:ft, &l:bt], s:nosplit) >= 0 +endf + +fu! s:setupblank() + setl noswf nonu nobl nowrap nolist nospell nocuc wfh + setl fdc=0 fdl=99 tw=0 bt=nofile bh=unload + if v:version > 702 + setl nornu noudf cc=0 + en +endf + +fu! s:leavepre() + if exists('s:bufnr') && s:bufnr == bufnr('%') | bw! | en + if !( exists(s:ccex) && !{s:ccex} ) + \ && !( has('clientserver') && len(split(serverlist(), "\n")) > 1 ) + cal ctrlp#clra() + en +endf + +fu! s:checkbuf() + if !exists('s:init') && exists('s:bufnr') && s:bufnr > 0 + exe s:bufnr.'bw!' + en +endf + +fu! s:iscmdwin() + let ermsg = v:errmsg + sil! noa winc p + sil! noa winc p + let [v:errmsg, ermsg] = [ermsg, v:errmsg] + retu ermsg =~ '^E11:' +endf +" Arguments {{{2 +fu! s:at(str) + if a:str =~ '\v^\@(cd|lc[hd]?|chd).*' + let str = substitute(a:str, '\v^\@(cd|lc[hd]?|chd)\s*', '', '') + if str == '' | retu 1 | en + let str = str =~ '^%:.\+' ? fnamemodify(s:crfile, str[1:]) : str + let path = fnamemodify(expand(str, 1), ':p') + if isdirectory(path) + if path != s:dyncwd + cal ctrlp#setdir(path) + cal ctrlp#setlines() + en + cal ctrlp#recordhist() + cal s:PrtClear() + en + retu 1 + en + retu 0 +endf + +fu! s:tail() + if exists('s:optail') && !empty('s:optail') + let tailpref = s:optail !~ '^\s*+' ? ' +' : ' ' + retu tailpref.s:optail + en + retu '' +endf + +fu! s:sanstail(str) + let str = s:spi ? + \ substitute(a:str, '^\(@.*$\|\\\\\ze@\|\.\.\zs[.\/]\+$\)', '', 'g') : a:str + let [str, pat] = [substitute(str, '\\\\', '\', 'g'), '\([^:]\|\\:\)*$'] + unl! s:optail + if str =~ '\\\@= 0 + retu char + elsei char =~# "\\v\|\|\|\|\|\" + cal s:BuildPrompt(0) + retu 'cancel' + elsei char =~# "\" && a:args != [] + retu a:args[0] + en + retu call(a:func, a:args) +endf + +fu! s:getregs() + let char = s:textdialog('Insert from register: ') + if char =~# "\\v\|\|\|\|\|\" + cal s:BuildPrompt(0) + retu -1 + elsei char =~# "\" + retu s:getregs() + en + retu s:regisfilter(char) +endf + +fu! s:regisfilter(reg) + retu substitute(getreg(a:reg), "[\t\n]", ' ', 'g') +endf +" Misc {{{2 +fu! s:modevar() + let s:matchtype = s:mtype() + let s:ispath = s:ispathitem() + let s:mfunc = s:mfunc() + let s:nolim = s:getextvar('nolim') + let s:dosort = s:getextvar('sort') + let s:spi = !s:itemtype || s:getextvar('specinput') > 0 +endf + +fu! s:nosort() + retu s:matcher != {} || s:nolim == 1 || ( s:itemtype == 2 && s:mrudef ) + \ || ( s:itemtype =~ '\v^(1|2)$' && s:prompt == ['', '', ''] ) || !s:dosort +endf + +fu! s:byfname() + retu s:ispath && s:byfname +endf + +fu! s:narrowable() + retu exists('s:act_add') && exists('s:matched') && s:matched != [] + \ && exists('s:mdata') && s:mdata[:2] == [s:dyncwd, s:itemtype, s:regexp] + \ && s:matcher == {} && !exists('s:did_exp') +endf + +fu! s:getinput(...) + let [prt, spi] = [s:prompt, ( a:0 ? a:1 : '' )] + if s:abbrev != {} + let gmd = has_key(s:abbrev, 'gmode') ? s:abbrev['gmode'] : '' + let str = ( gmd =~ 't' && !a:0 ) || spi == 'c' ? prt[0] : join(prt, '') + if gmd =~ 't' && gmd =~ 'k' && !a:0 && matchstr(str, '.$') =~ '\k' + retu join(prt, '') + en + let [pf, rz] = [( s:byfname() ? 'f' : 'p' ), ( s:regexp ? 'r' : 'z' )] + for dict in s:abbrev['abbrevs'] + let dmd = has_key(dict, 'mode') ? dict['mode'] : '' + let pat = escape(dict['pattern'], '~') + if ( dmd == '' || ( dmd =~ pf && dmd =~ rz && !a:0 ) + \ || dmd =~ '['.spi.']' ) && str =~ pat + let [str, s:did_exp] = [join(split(str, pat, 1), dict['expanded']), 1] + en + endfo + if gmd =~ 't' && !a:0 + let prt[0] = str + el + retu str + en + en + retu spi == 'c' ? prt[0] : join(prt, '') +endf + +fu! s:migemo(str) + let [str, rtp] = [a:str, s:fnesc(&rtp, 'g')] + let dict = s:glbpath(rtp, printf("dict/%s/migemo-dict", &enc), 1) + if !len(dict) + let dict = s:glbpath(rtp, "dict/migemo-dict", 1) + en + if len(dict) + let [tokens, str, cmd] = [split(str, '\s'), '', 'cmigemo -v -w %s -d %s'] + for token in tokens + let rtn = system(printf(cmd, shellescape(token), shellescape(dict))) + let str .= !v:shell_error && strlen(rtn) > 0 ? '.*'.rtn : token + endfo + en + retu str +endf + +fu! s:strwidth(str) + retu exists('*strdisplaywidth') ? strdisplaywidth(a:str) : strlen(a:str) +endf + +fu! ctrlp#j2l(nr) + exe 'norm!' a:nr.'G' + sil! norm! zvzz +endf + +fu! s:maxf(len) + retu s:maxfiles && a:len > s:maxfiles +endf + +fu! s:regexfilter(str) + let str = a:str + for key in keys(s:fpats) | if str =~ key + let str = substitute(str, s:fpats[key], '', 'g') + en | endfo + retu str +endf + +fu! s:walker(m, p, d) + retu a:d >= 0 ? a:p < a:m ? a:p + a:d : 0 : a:p > 0 ? a:p + a:d : a:m +endf + +fu! s:delent(rfunc) + if a:rfunc == '' | retu | en + let [s:force, tbrem] = [1, []] + if exists('s:marked') + let tbrem = values(s:marked) + cal s:unmarksigns() + unl s:marked + en + if tbrem == [] && ( has('dialog_gui') || has('dialog_con') ) && + \ confirm("Wipe all entries?", "&OK\n&Cancel") != 1 + unl s:force + cal s:BuildPrompt(0) + retu + en + let g:ctrlp_lines = call(a:rfunc, [tbrem]) + cal s:BuildPrompt(1) + unl s:force +endf +" Entering & Exiting {{{2 +fu! s:getenv() + let [s:cwd, s:winres] = [getcwd(), [winrestcmd(), &lines, winnr('$')]] + let [s:crword, s:crnbword] = [expand('', 1), expand('', 1)] + let [s:crgfile, s:crline] = [expand('', 1), getline('.')] + let [s:winmaxh, s:crcursor] = [min([s:mw_max, &lines]), getpos('.')] + let [s:crbufnr, s:crvisual] = [bufnr('%'), s:lastvisual()] + let s:crfile = bufname('%') == '' + \ ? '['.s:crbufnr.'*No Name]' : expand('%:p', 1) + let s:crfpath = expand('%:p:h', 1) + let s:mrbs = ctrlp#mrufiles#bufs() +endf + +fu! s:lastvisual() + let cview = winsaveview() + let [ovreg, ovtype] = [getreg('v'), getregtype('v')] + let [oureg, outype] = [getreg('"'), getregtype('"')] + sil! norm! gv"vy + let selected = s:regisfilter('v') + cal setreg('v', ovreg, ovtype) + cal setreg('"', oureg, outype) + cal winrestview(cview) + retu selected +endf + +fu! s:log(m) + if exists('g:ctrlp_log') && g:ctrlp_log | if a:m + let cadir = ctrlp#utils#cachedir() + let apd = g:ctrlp_log > 1 ? '>' : '' + sil! exe 'redi! >'.apd cadir.s:lash(cadir).'ctrlp.log' + el + sil! redi END + en | en +endf + +fu! s:buffunc(e) + if a:e && has_key(s:buffunc, 'enter') + cal call(s:buffunc['enter'], [], s:buffunc) + elsei !a:e && has_key(s:buffunc, 'exit') + cal call(s:buffunc['exit'], [], s:buffunc) + en +endf + +fu! s:openfile(cmd, fid, tail, chkmod, ...) + let cmd = a:cmd + if a:chkmod && cmd =~ '^[eb]$' && ctrlp#modfilecond(!( cmd == 'b' && &aw )) + let cmd = cmd == 'b' ? 'sb' : 'sp' + en + let cmd = cmd =~ '^tab' ? ctrlp#tabcount().cmd : cmd + let j2l = a:0 && a:1[0] ? a:1[1] : 0 + exe cmd.( a:0 && a:1[0] ? '' : a:tail ) s:fnesc(a:fid, 'f') + if j2l + cal ctrlp#j2l(j2l) + en + if !empty(a:tail) + sil! norm! zvzz + en + if cmd != 'bad' + cal ctrlp#setlcdir() + en +endf + +fu! ctrlp#tabcount() + if exists('s:tabct') + let tabct = s:tabct + let s:tabct += 1 + elsei !type(s:tabpage) + let tabct = s:tabpage + elsei type(s:tabpage) == 1 + let tabpos = + \ s:tabpage =~ 'c' ? tabpagenr() : + \ s:tabpage =~ 'f' ? 1 : + \ s:tabpage =~ 'l' ? tabpagenr('$') : + \ tabpagenr() + let tabct = + \ s:tabpage =~ 'a' ? tabpos : + \ s:tabpage =~ 'b' ? tabpos - 1 : + \ tabpos + en + retu tabct < 0 ? 0 : tabct +endf + +fu! s:settype(type) + retu a:type < 0 ? exists('s:itemtype') ? s:itemtype : 0 : a:type +endf +" Matching {{{2 +fu! s:matchfname(item, pat) + let parts = split(a:item, '[\/]\ze[^\/]\+$') + let mfn = match(parts[-1], a:pat[0]) + retu len(a:pat) == 1 ? mfn : len(a:pat) == 2 ? + \ ( mfn >= 0 && ( len(parts) == 2 ? match(parts[0], a:pat[1]) : -1 ) >= 0 + \ ? 0 : -1 ) : -1 + en +endf + +fu! s:matchtabs(item, pat) + retu match(split(a:item, '\t\+')[0], a:pat) +endf + +fu! s:matchtabe(item, pat) + retu match(split(a:item, '\t\+[^\t]\+$')[0], a:pat) +endf + +fu! s:buildpat(lst) + let pat = a:lst[0] + for item in range(1, len(a:lst) - 1) + let pat .= '[^'.a:lst[item - 1].']\{-}'.a:lst[item] + endfo + retu pat +endf + +fu! s:mfunc() + let mfunc = 'match' + if s:byfname() + let mfunc = 's:matchfname' + elsei s:itemtype > 2 + let matchtypes = { 'tabs': 's:matchtabs', 'tabe': 's:matchtabe' } + if has_key(matchtypes, s:matchtype) + let mfunc = matchtypes[s:matchtype] + en + en + retu mfunc +endf + +fu! s:mmode() + let matchmodes = { + \ 'match': 'full-line', + \ 's:matchfname': 'filename-only', + \ 's:matchtabs': 'first-non-tab', + \ 's:matchtabe': 'until-last-tab', + \ } + retu matchmodes[s:mfunc] +endf +" Cache {{{2 +fu! s:writecache(cafile) + if ( g:ctrlp_newcache || !filereadable(a:cafile) ) && !s:nocache() + cal ctrlp#utils#writecache(g:ctrlp_allfiles) + let g:ctrlp_newcache = 0 + en +endf + +fu! s:nocache(...) + if !s:caching + retu 1 + elsei s:caching > 1 + if !( exists(s:ccex) && !{s:ccex} ) || has_key(s:ficounts, s:dyncwd) + retu get(s:ficounts, s:dyncwd, [0, 0])[0] < s:caching + elsei a:0 && filereadable(a:1) + retu len(ctrlp#utils#readfile(a:1)) < s:caching + en + retu 1 + en + retu 0 +endf + +fu! s:insertcache(str) + let [data, g:ctrlp_newcache, str] = [g:ctrlp_allfiles, 1, a:str] + if data == [] || strlen(str) <= strlen(data[0]) + let pos = 0 + elsei strlen(str) >= strlen(data[-1]) + let pos = len(data) - 1 + el + let pos = 0 + for each in data + if strlen(each) > strlen(str) | brea | en + let pos += 1 + endfo + en + cal insert(data, str, pos) + cal s:writecache(ctrlp#utils#cachefile()) +endf +" Extensions {{{2 +fu! s:mtype() + retu s:itemtype > 2 ? s:getextvar('type') : 'path' +endf + +fu! s:execextvar(key) + if !empty(g:ctrlp_ext_vars) + cal map(filter(copy(g:ctrlp_ext_vars), + \ 'has_key(v:val, a:key)'), 'eval(v:val[a:key])') + en +endf + +fu! s:getextvar(key) + if s:itemtype > 2 + let vars = g:ctrlp_ext_vars[s:itemtype - 3] + retu has_key(vars, a:key) ? vars[a:key] : -1 + en + retu -1 +endf + +fu! ctrlp#getcline() + let [linenr, offset] = [line('.'), ( s:offset > 0 ? s:offset : 0 )] + retu !empty(s:lines) && !( offset && linenr <= offset ) + \ ? s:lines[linenr - 1 - offset] : '' +endf + +fu! ctrlp#getmarkedlist() + retu exists('s:marked') ? values(s:marked) : [] +endf + +fu! ctrlp#exit() + cal s:PrtExit() +endf + +fu! ctrlp#prtclear() + cal s:PrtClear() +endf + +fu! ctrlp#switchtype(id) + cal s:ToggleType(a:id - s:itemtype) +endf + +fu! ctrlp#nosy() + retu !( has('syntax') && exists('g:syntax_on') ) +endf + +fu! ctrlp#hicheck(grp, defgrp) + if !hlexists(a:grp) + exe 'hi link' a:grp a:defgrp + en +endf + +fu! ctrlp#call(func, ...) + retu call(a:func, a:000) +endf + +fu! ctrlp#getvar(var) + retu {a:var} +endf +"}}}1 +" * Initialization {{{1 +fu! ctrlp#setlines(...) + if a:0 | let s:itemtype = a:1 | en + cal s:modevar() + let types = ['ctrlp#files()', 'ctrlp#buffers()', 'ctrlp#mrufiles#list()'] + if !empty(g:ctrlp_ext_vars) + cal map(copy(g:ctrlp_ext_vars), 'add(types, v:val["init"])') + en + let g:ctrlp_lines = eval(types[s:itemtype]) +endf + +fu! ctrlp#init(type, ...) + if exists('s:init') || s:iscmdwin() | retu | en + let [s:ermsg, v:errmsg] = [v:errmsg, ''] + let [s:matches, s:init] = [1, 1] + cal s:Reset(a:0 ? a:1 : {}) + noa cal s:Open() + cal s:SetWD(a:0 ? a:1 : {}) + cal s:MapNorms() + cal s:MapSpecs() + cal ctrlp#syntax() + cal ctrlp#setlines(s:settype(a:type)) + cal s:SetDefTxt() + cal s:BuildPrompt(1) + if s:keyloop | cal s:KeyLoop() | en +endf +" - Autocmds {{{1 +if has('autocmd') + aug CtrlPAug + au! + au BufEnter ControlP cal s:checkbuf() + au BufLeave ControlP noa cal s:Close() + au VimLeavePre * cal s:leavepre() + aug END +en + +fu! s:autocmds() + if !has('autocmd') | retu | en + if exists('#CtrlPLazy') + au! CtrlPLazy + en + if s:lazy + aug CtrlPLazy + au! + au CursorHold ControlP cal s:ForceUpdate() + aug END + en +endf +"}}} + +" vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 diff --git a/vim/bundle/ctrlp.vim/autoload/ctrlp/bookmarkdir.vim b/vim/bundle/ctrlp.vim/autoload/ctrlp/bookmarkdir.vim new file mode 100644 index 0000000..89bda89 --- /dev/null +++ b/vim/bundle/ctrlp.vim/autoload/ctrlp/bookmarkdir.vim @@ -0,0 +1,140 @@ +" ============================================================================= +" File: autoload/ctrlp/bookmarkdir.vim +" Description: Bookmarked directories extension +" Author: Kien Nguyen +" ============================================================================= + +" Init {{{1 +if exists('g:loaded_ctrlp_bookmarkdir') && g:loaded_ctrlp_bookmarkdir + fini +en +let g:loaded_ctrlp_bookmarkdir = 1 + +cal add(g:ctrlp_ext_vars, { + \ 'init': 'ctrlp#bookmarkdir#init()', + \ 'accept': 'ctrlp#bookmarkdir#accept', + \ 'lname': 'bookmarked dirs', + \ 'sname': 'bkd', + \ 'type': 'tabs', + \ 'opmul': 1, + \ 'nolim': 1, + \ 'wipe': 'ctrlp#bookmarkdir#remove', + \ }) + +let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) +" Utilities {{{1 +fu! s:getinput(str, ...) + echoh Identifier + cal inputsave() + let input = call('input', a:0 ? [a:str] + a:000 : [a:str]) + cal inputrestore() + echoh None + retu input +endf + +fu! s:cachefile() + if !exists('s:cadir') || !exists('s:cafile') + let s:cadir = ctrlp#utils#cachedir().ctrlp#utils#lash().'bkd' + let s:cafile = s:cadir.ctrlp#utils#lash().'cache.txt' + en + retu s:cafile +endf + +fu! s:writecache(lines) + cal ctrlp#utils#writecache(a:lines, s:cadir, s:cafile) +endf + +fu! s:getbookmarks() + retu ctrlp#utils#readfile(s:cachefile()) +endf + +fu! s:savebookmark(name, cwd) + let cwds = exists('+ssl') ? [tr(a:cwd, '\', '/'), tr(a:cwd, '/', '\')] : [a:cwd] + let entries = filter(s:getbookmarks(), 'index(cwds, s:parts(v:val)[1]) < 0') + cal s:writecache(insert(entries, a:name.' '.a:cwd)) +endf + +fu! s:setentries() + let time = getftime(s:cachefile()) + if !( exists('s:bookmarks') && time == s:bookmarks[0] ) + let s:bookmarks = [time, s:getbookmarks()] + en +endf + +fu! s:parts(str) + let mlist = matchlist(a:str, '\v([^\t]+)\t(.*)$') + retu mlist != [] ? mlist[1:2] : ['', ''] +endf + +fu! s:process(entries, type) + retu map(a:entries, 's:modify(v:val, a:type)') +endf + +fu! s:modify(entry, type) + let [name, dir] = s:parts(a:entry) + let dir = fnamemodify(dir, a:type) + retu name.' '.( dir == '' ? '.' : dir ) +endf + +fu! s:msg(name, cwd) + redr + echoh Identifier | echon 'Bookmarked ' | echoh Constant + echon a:name.' ' | echoh Directory | echon a:cwd + echoh None +endf + +fu! s:syntax() + if !ctrlp#nosy() + cal ctrlp#hicheck('CtrlPBookmark', 'Identifier') + cal ctrlp#hicheck('CtrlPTabExtra', 'Comment') + sy match CtrlPBookmark '^> [^\t]\+' contains=CtrlPLinePre + sy match CtrlPTabExtra '\zs\t.*\ze$' + en +endf +" Public {{{1 +fu! ctrlp#bookmarkdir#init() + cal s:setentries() + cal s:syntax() + retu s:process(copy(s:bookmarks[1]), ':.') +endf + +fu! ctrlp#bookmarkdir#accept(mode, str) + let parts = s:parts(s:modify(a:str, ':p')) + cal call('s:savebookmark', parts) + if a:mode =~ 't\|v\|h' + cal ctrlp#exit() + en + cal ctrlp#setdir(parts[1], a:mode =~ 't\|h' ? 'chd!' : 'lc!') + if a:mode == 'e' + cal ctrlp#switchtype(0) + cal ctrlp#recordhist() + cal ctrlp#prtclear() + en +endf + +fu! ctrlp#bookmarkdir#add(dir, ...) + let str = 'Directory to bookmark: ' + let cwd = a:dir != '' ? a:dir : s:getinput(str, getcwd(), 'dir') + if cwd == '' | retu | en + let cwd = fnamemodify(cwd, ':p') + let name = a:0 && a:1 != '' ? a:1 : s:getinput('Bookmark as: ', cwd) + if name == '' | retu | en + let name = tr(name, ' ', ' ') + cal s:savebookmark(name, cwd) + cal s:msg(name, cwd) +endf + +fu! ctrlp#bookmarkdir#remove(entries) + cal s:process(a:entries, ':p') + cal s:writecache(a:entries == [] ? [] : + \ filter(s:getbookmarks(), 'index(a:entries, v:val) < 0')) + cal s:setentries() + retu s:process(copy(s:bookmarks[1]), ':.') +endf + +fu! ctrlp#bookmarkdir#id() + retu s:id +endf +"}}} + +" vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 diff --git a/vim/bundle/ctrlp.vim/autoload/ctrlp/buffertag.vim b/vim/bundle/ctrlp.vim/autoload/ctrlp/buffertag.vim new file mode 100644 index 0000000..a38cad5 --- /dev/null +++ b/vim/bundle/ctrlp.vim/autoload/ctrlp/buffertag.vim @@ -0,0 +1,264 @@ +" ============================================================================= +" File: autoload/ctrlp/buffertag.vim +" Description: Buffer Tag extension +" Maintainer: Kien Nguyen +" Credits: Much of the code was taken from tagbar.vim by Jan Larres, plus +" a few lines from taglist.vim by Yegappan Lakshmanan and from +" buffertag.vim by Takeshi Nishida. +" ============================================================================= + +" Init {{{1 +if exists('g:loaded_ctrlp_buftag') && g:loaded_ctrlp_buftag + fini +en +let g:loaded_ctrlp_buftag = 1 + +cal add(g:ctrlp_ext_vars, { + \ 'init': 'ctrlp#buffertag#init(s:crfile)', + \ 'accept': 'ctrlp#buffertag#accept', + \ 'lname': 'buffer tags', + \ 'sname': 'bft', + \ 'exit': 'ctrlp#buffertag#exit()', + \ 'type': 'tabs', + \ 'opts': 'ctrlp#buffertag#opts()', + \ }) + +let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) + +let [s:pref, s:opts] = ['g:ctrlp_buftag_', { + \ 'systemenc': ['s:enc', &enc], + \ 'ctags_bin': ['s:bin', ''], + \ 'types': ['s:usr_types', {}], + \ }] + +let s:bins = [ + \ 'ctags-exuberant', + \ 'exuberant-ctags', + \ 'exctags', + \ '/usr/local/bin/ctags', + \ '/opt/local/bin/ctags', + \ 'ctags', + \ 'ctags.exe', + \ 'tags', + \ ] + +let s:types = { + \ 'asm' : '%sasm%sasm%sdlmt', + \ 'aspperl': '%sasp%sasp%sfsv', + \ 'aspvbs' : '%sasp%sasp%sfsv', + \ 'awk' : '%sawk%sawk%sf', + \ 'beta' : '%sbeta%sbeta%sfsv', + \ 'c' : '%sc%sc%sdgsutvf', + \ 'cpp' : '%sc++%sc++%snvdtcgsuf', + \ 'cs' : '%sc#%sc#%sdtncEgsipm', + \ 'cobol' : '%scobol%scobol%sdfgpPs', + \ 'eiffel' : '%seiffel%seiffel%scf', + \ 'erlang' : '%serlang%serlang%sdrmf', + \ 'expect' : '%stcl%stcl%scfp', + \ 'fortran': '%sfortran%sfortran%spbceiklmntvfs', + \ 'html' : '%shtml%shtml%saf', + \ 'java' : '%sjava%sjava%spcifm', + \ 'javascript': '%sjavascript%sjavascript%sf', + \ 'lisp' : '%slisp%slisp%sf', + \ 'lua' : '%slua%slua%sf', + \ 'make' : '%smake%smake%sm', + \ 'ocaml' : '%socaml%socaml%scmMvtfCre', + \ 'pascal' : '%spascal%spascal%sfp', + \ 'perl' : '%sperl%sperl%sclps', + \ 'php' : '%sphp%sphp%scdvf', + \ 'python' : '%spython%spython%scmf', + \ 'rexx' : '%srexx%srexx%ss', + \ 'ruby' : '%sruby%sruby%scfFm', + \ 'scheme' : '%sscheme%sscheme%ssf', + \ 'sh' : '%ssh%ssh%sf', + \ 'csh' : '%ssh%ssh%sf', + \ 'zsh' : '%ssh%ssh%sf', + \ 'slang' : '%sslang%sslang%snf', + \ 'sml' : '%ssml%ssml%secsrtvf', + \ 'sql' : '%ssql%ssql%scFPrstTvfp', + \ 'tcl' : '%stcl%stcl%scfmp', + \ 'vera' : '%svera%svera%scdefgmpPtTvx', + \ 'verilog': '%sverilog%sverilog%smcPertwpvf', + \ 'vim' : '%svim%svim%savf', + \ 'yacc' : '%syacc%syacc%sl', + \ } + +cal map(s:types, 'printf(v:val, "--language-force=", " --", "-types=")') + +if executable('jsctags') + cal extend(s:types, { 'javascript': { 'args': '-f -', 'bin': 'jsctags' } }) +en + +fu! ctrlp#buffertag#opts() + for [ke, va] in items(s:opts) + let {va[0]} = exists(s:pref.ke) ? {s:pref.ke} : va[1] + endfo + " Ctags bin + if empty(s:bin) + for bin in s:bins | if executable(bin) + let s:bin = bin + brea + en | endfo + el + let s:bin = expand(s:bin, 1) + en + " Types + cal extend(s:types, s:usr_types) +endf +" Utilities {{{1 +fu! s:validfile(fname, ftype) + if ( !empty(a:fname) || !empty(a:ftype) ) && filereadable(a:fname) + \ && index(keys(s:types), a:ftype) >= 0 | retu 1 | en + retu 0 +endf + +fu! s:exectags(cmd) + if exists('+ssl') + let [ssl, &ssl] = [&ssl, 0] + en + if &sh =~ 'cmd\.exe' + let [sxq, &sxq, shcf, &shcf] = [&sxq, '"', &shcf, '/s /c'] + en + let output = system(a:cmd) + if &sh =~ 'cmd\.exe' + let [&sxq, &shcf] = [sxq, shcf] + en + if exists('+ssl') + let &ssl = ssl + en + retu output +endf + +fu! s:exectagsonfile(fname, ftype) + let [ags, ft] = ['-f - --sort=no --excmd=pattern --fields=nKs ', a:ftype] + if type(s:types[ft]) == 1 + let ags .= s:types[ft] + let bin = s:bin + elsei type(s:types[ft]) == 4 + let ags = s:types[ft]['args'] + let bin = expand(s:types[ft]['bin'], 1) + en + if empty(bin) | retu '' | en + let cmd = s:esctagscmd(bin, ags, a:fname) + if empty(cmd) | retu '' | en + let output = s:exectags(cmd) + if v:shell_error || output =~ 'Warning: cannot open' | retu '' | en + retu output +endf + +fu! s:esctagscmd(bin, args, ...) + if exists('+ssl') + let [ssl, &ssl] = [&ssl, 0] + en + let fname = a:0 ? shellescape(a:1) : '' + let cmd = shellescape(a:bin).' '.a:args.' '.fname + if &sh =~ 'cmd\.exe' + let cmd = substitute(cmd, '[&()@^<>|]', '^\0', 'g') + en + if exists('+ssl') + let &ssl = ssl + en + if has('iconv') + let last = s:enc != &enc ? s:enc : !empty( $LANG ) ? $LANG : &enc + let cmd = iconv(cmd, &enc, last) + en + retu cmd +endf + +fu! s:process(fname, ftype) + if !s:validfile(a:fname, a:ftype) | retu [] | endif + let ftime = getftime(a:fname) + if has_key(g:ctrlp_buftags, a:fname) + \ && g:ctrlp_buftags[a:fname]['time'] >= ftime + let lines = g:ctrlp_buftags[a:fname]['lines'] + el + let data = s:exectagsonfile(a:fname, a:ftype) + let [raw, lines] = [split(data, '\n\+'), []] + for line in raw + if line !~# '^!_TAG_' && len(split(line, ';"')) == 2 + let parsed_line = s:parseline(line) + if parsed_line != '' + cal add(lines, parsed_line) + en + en + endfo + let cache = { a:fname : { 'time': ftime, 'lines': lines } } + cal extend(g:ctrlp_buftags, cache) + en + retu lines +endf + +fu! s:parseline(line) + let vals = matchlist(a:line, + \ '\v^([^\t]+)\t(.+)\t[?/]\^?(.{-1,})\$?[?/]\;\"\t(.+)\tline(no)?\:(\d+)') + if vals == [] | retu '' | en + let [bufnr, bufname] = [bufnr('^'.vals[2].'$'), fnamemodify(vals[2], ':p:t')] + retu vals[1].' '.vals[4].'|'.bufnr.':'.bufname.'|'.vals[6].'| '.vals[3] +endf + +fu! s:syntax() + if !ctrlp#nosy() + cal ctrlp#hicheck('CtrlPTagKind', 'Title') + cal ctrlp#hicheck('CtrlPBufName', 'Directory') + cal ctrlp#hicheck('CtrlPTabExtra', 'Comment') + sy match CtrlPTagKind '\zs[^\t|]\+\ze|\d\+:[^|]\+|\d\+|' + sy match CtrlPBufName '|\d\+:\zs[^|]\+\ze|\d\+|' + sy match CtrlPTabExtra '\zs\t.*\ze$' contains=CtrlPBufName,CtrlPTagKind + en +endf + +fu! s:chknearby(pat) + if match(getline('.'), a:pat) < 0 + let [int, forw, maxl] = [1, 1, line('$')] + wh !search(a:pat, 'W'.( forw ? '' : 'b' )) + if !forw + if int > maxl | brea | en + let int += int + en + let forw = !forw + endw + en +endf +" Public {{{1 +fu! ctrlp#buffertag#init(fname) + let bufs = exists('s:btmode') && s:btmode + \ ? filter(ctrlp#buffers(), 'filereadable(v:val)') + \ : [exists('s:bufname') ? s:bufname : a:fname] + let lines = [] + for each in bufs + let bname = fnamemodify(each, ':p') + let tftype = get(split(getbufvar('^'.bname.'$', '&ft'), '\.'), 0, '') + cal extend(lines, s:process(bname, tftype)) + endfo + cal s:syntax() + retu lines +endf + +fu! ctrlp#buffertag#accept(mode, str) + let vals = matchlist(a:str, + \ '\v^[^\t]+\t+[^\t|]+\|(\d+)\:[^\t|]+\|(\d+)\|\s(.+)$') + let bufnr = str2nr(get(vals, 1)) + if bufnr + cal ctrlp#acceptfile(a:mode, bufnr) + exe 'norm!' str2nr(get(vals, 2, line('.'))).'G' + cal s:chknearby('\V\C'.get(vals, 3, '')) + sil! norm! zvzz + en +endf + +fu! ctrlp#buffertag#cmd(mode, ...) + let s:btmode = a:mode + if a:0 && !empty(a:1) + let s:btmode = 0 + let bname = a:1 =~# '^%$\|^#\d*$' ? expand(a:1) : a:1 + let s:bufname = fnamemodify(bname, ':p') + en + retu s:id +endf + +fu! ctrlp#buffertag#exit() + unl! s:btmode s:bufname +endf +"}}} + +" vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 diff --git a/vim/bundle/ctrlp.vim/autoload/ctrlp/changes.vim b/vim/bundle/ctrlp.vim/autoload/ctrlp/changes.vim new file mode 100644 index 0000000..313d8c2 --- /dev/null +++ b/vim/bundle/ctrlp.vim/autoload/ctrlp/changes.vim @@ -0,0 +1,98 @@ +" ============================================================================= +" File: autoload/ctrlp/changes.vim +" Description: Change list extension +" Author: Kien Nguyen +" ============================================================================= + +" Init {{{1 +if exists('g:loaded_ctrlp_changes') && g:loaded_ctrlp_changes + fini +en +let g:loaded_ctrlp_changes = 1 + +cal add(g:ctrlp_ext_vars, { + \ 'init': 'ctrlp#changes#init(s:bufnr, s:crbufnr)', + \ 'accept': 'ctrlp#changes#accept', + \ 'lname': 'changes', + \ 'sname': 'chs', + \ 'exit': 'ctrlp#changes#exit()', + \ 'type': 'tabe', + \ 'sort': 0, + \ 'nolim': 1, + \ }) + +let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) +" Utilities {{{1 +fu! s:changelist(bufnr) + sil! exe 'noa hid b' a:bufnr + redi => result + sil! changes + redi END + retu map(split(result, "\n")[1:], 'tr(v:val, " ", " ")') +endf + +fu! s:process(clines, ...) + let [clines, evas] = [[], []] + for each in a:clines + let parts = matchlist(each, '\v^.\s*\d+\s+(\d+)\s+(\d+)\s(.*)$') + if !empty(parts) + if parts[3] == '' | let parts[3] = ' ' | en + cal add(clines, parts[3].' |'.a:1.':'.a:2.'|'.parts[1].':'.parts[2].'|') + en + endfo + retu reverse(filter(clines, 'count(clines, v:val) == 1')) +endf + +fu! s:syntax() + if !ctrlp#nosy() + cal ctrlp#hicheck('CtrlPBufName', 'Directory') + cal ctrlp#hicheck('CtrlPTabExtra', 'Comment') + sy match CtrlPBufName '\t|\d\+:\zs[^|]\+\ze|\d\+:\d\+|$' + sy match CtrlPTabExtra '\zs\t.*\ze$' contains=CtrlPBufName + en +endf +" Public {{{1 +fu! ctrlp#changes#init(original_bufnr, bufnr) + let bufnr = exists('s:bufnr') ? s:bufnr : a:bufnr + let bufs = exists('s:clmode') && s:clmode ? ctrlp#buffers('id') : [bufnr] + cal filter(bufs, 'v:val > 0') + let [swb, &swb] = [&swb, ''] + let lines = [] + for each in bufs + let bname = bufname(each) + let fnamet = fnamemodify(bname == '' ? '[No Name]' : bname, ':t') + cal extend(lines, s:process(s:changelist(each), each, fnamet)) + endfo + sil! exe 'noa hid b' a:original_bufnr + let &swb = swb + cal ctrlp#syntax() + cal s:syntax() + retu lines +endf + +fu! ctrlp#changes#accept(mode, str) + let info = matchlist(a:str, '\t|\(\d\+\):[^|]\+|\(\d\+\):\(\d\+\)|$') + let bufnr = str2nr(get(info, 1)) + if bufnr + cal ctrlp#acceptfile(a:mode, bufnr) + cal cursor(get(info, 2), get(info, 3)) + sil! norm! zvzz + en +endf + +fu! ctrlp#changes#cmd(mode, ...) + let s:clmode = a:mode + if a:0 && !empty(a:1) + let s:clmode = 0 + let bname = a:1 =~# '^%$\|^#\d*$' ? expand(a:1) : a:1 + let s:bufnr = bufnr('^'.fnamemodify(bname, ':p').'$') + en + retu s:id +endf + +fu! ctrlp#changes#exit() + unl! s:clmode s:bufnr +endf +"}}} + +" vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 diff --git a/vim/bundle/ctrlp.vim/autoload/ctrlp/dir.vim b/vim/bundle/ctrlp.vim/autoload/ctrlp/dir.vim new file mode 100644 index 0000000..4e6d4ad --- /dev/null +++ b/vim/bundle/ctrlp.vim/autoload/ctrlp/dir.vim @@ -0,0 +1,95 @@ +" ============================================================================= +" File: autoload/ctrlp/dir.vim +" Description: Directory extension +" Author: Kien Nguyen +" ============================================================================= + +" Init {{{1 +if exists('g:loaded_ctrlp_dir') && g:loaded_ctrlp_dir + fini +en +let [g:loaded_ctrlp_dir, g:ctrlp_newdir] = [1, 0] + +let s:ars = ['s:maxdepth', 's:maxfiles', 's:compare_lim', 's:glob', 's:caching'] + +cal add(g:ctrlp_ext_vars, { + \ 'init': 'ctrlp#dir#init('.join(s:ars, ', ').')', + \ 'accept': 'ctrlp#dir#accept', + \ 'lname': 'dirs', + \ 'sname': 'dir', + \ 'type': 'path', + \ 'specinput': 1, + \ }) + +let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) + +let s:dircounts = {} +" Utilities {{{1 +fu! s:globdirs(dirs, depth) + let entries = split(globpath(a:dirs, s:glob), "\n") + let [dirs, depth] = [ctrlp#dirnfile(entries)[0], a:depth + 1] + cal extend(g:ctrlp_alldirs, dirs) + let nr = len(g:ctrlp_alldirs) + if !empty(dirs) && !s:max(nr, s:maxfiles) && depth <= s:maxdepth + sil! cal ctrlp#progress(nr) + cal map(dirs, 'ctrlp#utils#fnesc(v:val, "g", ",")') + cal s:globdirs(join(dirs, ','), depth) + en +endf + +fu! s:max(len, max) + retu a:max && a:len > a:max +endf + +fu! s:nocache() + retu !s:caching || ( s:caching > 1 && get(s:dircounts, s:cwd) < s:caching ) +endf +" Public {{{1 +fu! ctrlp#dir#init(...) + let s:cwd = getcwd() + for each in range(len(s:ars)) + let {s:ars[each]} = a:{each + 1} + endfo + let cadir = ctrlp#utils#cachedir().ctrlp#utils#lash().'dir' + let cafile = cadir.ctrlp#utils#lash().ctrlp#utils#cachefile('dir') + if g:ctrlp_newdir || s:nocache() || !filereadable(cafile) + let [s:initcwd, g:ctrlp_alldirs] = [s:cwd, []] + if !ctrlp#igncwd(s:cwd) + cal s:globdirs(ctrlp#utils#fnesc(s:cwd, 'g', ','), 0) + en + cal ctrlp#rmbasedir(g:ctrlp_alldirs) + if len(g:ctrlp_alldirs) <= s:compare_lim + cal sort(g:ctrlp_alldirs, 'ctrlp#complen') + en + cal ctrlp#utils#writecache(g:ctrlp_alldirs, cadir, cafile) + let g:ctrlp_newdir = 0 + el + if !( exists('s:initcwd') && s:initcwd == s:cwd ) + let s:initcwd = s:cwd + let g:ctrlp_alldirs = ctrlp#utils#readfile(cafile) + en + en + cal extend(s:dircounts, { s:cwd : len(g:ctrlp_alldirs) }) + retu g:ctrlp_alldirs +endf + +fu! ctrlp#dir#accept(mode, str) + let path = a:mode == 'h' ? getcwd() : s:cwd.ctrlp#call('s:lash', s:cwd).a:str + if a:mode =~ 't\|v\|h' + cal ctrlp#exit() + en + cal ctrlp#setdir(path, a:mode =~ 't\|h' ? 'chd!' : 'lc!') + if a:mode == 'e' + sil! cal ctrlp#statusline() + cal ctrlp#setlines(s:id) + cal ctrlp#recordhist() + cal ctrlp#prtclear() + en +endf + +fu! ctrlp#dir#id() + retu s:id +endf +"}}} + +" vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 diff --git a/vim/bundle/ctrlp.vim/autoload/ctrlp/line.vim b/vim/bundle/ctrlp.vim/autoload/ctrlp/line.vim new file mode 100644 index 0000000..5bec47e --- /dev/null +++ b/vim/bundle/ctrlp.vim/autoload/ctrlp/line.vim @@ -0,0 +1,72 @@ +" ============================================================================= +" File: autoload/ctrlp/line.vim +" Description: Line extension +" Author: Kien Nguyen +" ============================================================================= + +" Init {{{1 +if exists('g:loaded_ctrlp_line') && g:loaded_ctrlp_line + fini +en +let g:loaded_ctrlp_line = 1 + +cal add(g:ctrlp_ext_vars, { + \ 'init': 'ctrlp#line#init(s:crbufnr)', + \ 'accept': 'ctrlp#line#accept', + \ 'lname': 'lines', + \ 'sname': 'lns', + \ 'type': 'tabe', + \ }) + +let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) +" Utilities {{{1 +fu! s:syntax() + if !ctrlp#nosy() + cal ctrlp#hicheck('CtrlPBufName', 'Directory') + cal ctrlp#hicheck('CtrlPTabExtra', 'Comment') + sy match CtrlPBufName '\t|\zs[^|]\+\ze|\d\+:\d\+|$' + sy match CtrlPTabExtra '\zs\t.*\ze$' contains=CtrlPBufName + en +endf +" Public {{{1 +fu! ctrlp#line#init(bufnr) + let [lines, bufnr] = [[], exists('s:bufnr') ? s:bufnr : a:bufnr] + let bufs = exists('s:lnmode') && s:lnmode ? ctrlp#buffers('id') : [bufnr] + for bufnr in bufs + let [lfb, bufn] = [getbufline(bufnr, 1, '$'), bufname(bufnr)] + if lfb == [] && bufn != '' + let lfb = ctrlp#utils#readfile(fnamemodify(bufn, ':p')) + en + cal map(lfb, 'tr(v:val, '' '', '' '')') + let [linenr, len_lfb] = [1, len(lfb)] + let buft = bufn == '' ? '[No Name]' : fnamemodify(bufn, ':t') + wh linenr <= len_lfb + let lfb[linenr - 1] .= ' |'.buft.'|'.bufnr.':'.linenr.'|' + let linenr += 1 + endw + cal extend(lines, filter(lfb, 'v:val !~ ''^\s*\t|[^|]\+|\d\+:\d\+|$''')) + endfo + cal s:syntax() + retu lines +endf + +fu! ctrlp#line#accept(mode, str) + let info = matchlist(a:str, '\t|[^|]\+|\(\d\+\):\(\d\+\)|$') + let bufnr = str2nr(get(info, 1)) + if bufnr + cal ctrlp#acceptfile(a:mode, bufnr, get(info, 2)) + en +endf + +fu! ctrlp#line#cmd(mode, ...) + let s:lnmode = a:mode + if a:0 && !empty(a:1) + let s:lnmode = 0 + let bname = a:1 =~# '^%$\|^#\d*$' ? expand(a:1) : a:1 + let s:bufnr = bufnr('^'.fnamemodify(bname, ':p').'$') + en + retu s:id +endf +"}}} + +" vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 diff --git a/vim/bundle/ctrlp.vim/autoload/ctrlp/mixed.vim b/vim/bundle/ctrlp.vim/autoload/ctrlp/mixed.vim new file mode 100644 index 0000000..74d904d --- /dev/null +++ b/vim/bundle/ctrlp.vim/autoload/ctrlp/mixed.vim @@ -0,0 +1,88 @@ +" ============================================================================= +" File: autoload/ctrlp/mixed.vim +" Description: Mixing Files + MRU + Buffers +" Author: Kien Nguyen +" ============================================================================= + +" Init {{{1 +if exists('g:loaded_ctrlp_mixed') && g:loaded_ctrlp_mixed + fini +en +let [g:loaded_ctrlp_mixed, g:ctrlp_newmix] = [1, 0] + +cal add(g:ctrlp_ext_vars, { + \ 'init': 'ctrlp#mixed#init(s:compare_lim)', + \ 'accept': 'ctrlp#acceptfile', + \ 'lname': 'fil + mru + buf', + \ 'sname': 'mix', + \ 'type': 'path', + \ 'opmul': 1, + \ 'specinput': 1, + \ }) + +let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) +" Utilities {{{1 +fu! s:newcache(cwd) + if g:ctrlp_newmix || !has_key(g:ctrlp_allmixes, 'data') | retu 1 | en + retu g:ctrlp_allmixes['cwd'] != a:cwd + \ || g:ctrlp_allmixes['filtime'] < getftime(ctrlp#utils#cachefile()) + \ || g:ctrlp_allmixes['mrutime'] < getftime(ctrlp#mrufiles#cachefile()) + \ || g:ctrlp_allmixes['bufs'] < len(ctrlp#mrufiles#bufs()) +endf + +fu! s:getnewmix(cwd, clim) + if g:ctrlp_newmix + cal ctrlp#mrufiles#refresh('raw') + let g:ctrlp_newcache = 1 + en + let g:ctrlp_lines = copy(ctrlp#files()) + cal ctrlp#progress('Mixing...') + let mrufs = copy(ctrlp#mrufiles#list('raw')) + if exists('+ssl') && &ssl + cal map(mrufs, 'tr(v:val, "\\", "/")') + en + let allbufs = map(ctrlp#buffers(), 'fnamemodify(v:val, ":p")') + let [bufs, ubufs] = [[], []] + for each in allbufs + cal add(filereadable(each) ? bufs : ubufs, each) + endfo + let mrufs = bufs + filter(mrufs, 'index(bufs, v:val) < 0') + if len(mrufs) > len(g:ctrlp_lines) + cal filter(mrufs, 'stridx(v:val, a:cwd)') + el + let cwd_mrufs = filter(copy(mrufs), '!stridx(v:val, a:cwd)') + let cwd_mrufs = ctrlp#rmbasedir(cwd_mrufs) + for each in cwd_mrufs + let id = index(g:ctrlp_lines, each) + if id >= 0 | cal remove(g:ctrlp_lines, id) | en + endfo + en + let mrufs += ubufs + cal map(mrufs, 'fnamemodify(v:val, ":.")') + let g:ctrlp_lines = len(mrufs) > len(g:ctrlp_lines) + \ ? g:ctrlp_lines + mrufs : mrufs + g:ctrlp_lines + if len(g:ctrlp_lines) <= a:clim + cal sort(g:ctrlp_lines, 'ctrlp#complen') + en + let g:ctrlp_allmixes = { 'filtime': getftime(ctrlp#utils#cachefile()), + \ 'mrutime': getftime(ctrlp#mrufiles#cachefile()), 'cwd': a:cwd, + \ 'bufs': len(ctrlp#mrufiles#bufs()), 'data': g:ctrlp_lines } +endf +" Public {{{1 +fu! ctrlp#mixed#init(clim) + let cwd = getcwd() + if s:newcache(cwd) + cal s:getnewmix(cwd, a:clim) + el + let g:ctrlp_lines = g:ctrlp_allmixes['data'] + en + let g:ctrlp_newmix = 0 + retu g:ctrlp_lines +endf + +fu! ctrlp#mixed#id() + retu s:id +endf +"}}} + +" vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 diff --git a/vim/bundle/ctrlp.vim/autoload/ctrlp/mrufiles.vim b/vim/bundle/ctrlp.vim/autoload/ctrlp/mrufiles.vim new file mode 100644 index 0000000..a182111 --- /dev/null +++ b/vim/bundle/ctrlp.vim/autoload/ctrlp/mrufiles.vim @@ -0,0 +1,154 @@ +" ============================================================================= +" File: autoload/ctrlp/mrufiles.vim +" Description: Most Recently Used Files extension +" Author: Kien Nguyen +" ============================================================================= + +" Static variables {{{1 +let [s:mrbs, s:mrufs] = [[], []] + +fu! ctrlp#mrufiles#opts() + let [pref, opts] = ['g:ctrlp_mruf_', { + \ 'max': ['s:max', 250], + \ 'include': ['s:in', ''], + \ 'exclude': ['s:ex', ''], + \ 'case_sensitive': ['s:cseno', 1], + \ 'relative': ['s:re', 0], + \ 'save_on_update': ['s:soup', 1], + \ }] + for [ke, va] in items(opts) + let [{va[0]}, {pref.ke}] = [pref.ke, exists(pref.ke) ? {pref.ke} : va[1]] + endfo +endf +cal ctrlp#mrufiles#opts() +" Utilities {{{1 +fu! s:excl(fn) + retu !empty({s:ex}) && a:fn =~# {s:ex} +endf + +fu! s:mergelists() + let diskmrufs = ctrlp#utils#readfile(ctrlp#mrufiles#cachefile()) + cal filter(diskmrufs, 'index(s:mrufs, v:val) < 0') + let mrufs = s:mrufs + diskmrufs + retu s:chop(mrufs) +endf + +fu! s:chop(mrufs) + if len(a:mrufs) > {s:max} | cal remove(a:mrufs, {s:max}, -1) | en + retu a:mrufs +endf + +fu! s:reformat(mrufs, ...) + let cwd = getcwd() + let cwd .= cwd !~ '[\/]$' ? ctrlp#utils#lash() : '' + if {s:re} + let cwd = exists('+ssl') ? tr(cwd, '/', '\') : cwd + cal filter(a:mrufs, '!stridx(v:val, cwd)') + en + if a:0 && a:1 == 'raw' | retu a:mrufs | en + let idx = strlen(cwd) + if exists('+ssl') && &ssl + let cwd = tr(cwd, '\', '/') + cal map(a:mrufs, 'tr(v:val, "\\", "/")') + en + retu map(a:mrufs, '!stridx(v:val, cwd) ? strpart(v:val, idx) : v:val') +endf + +fu! s:record(bufnr) + if s:locked | retu | en + let bufnr = a:bufnr + 0 + let bufname = bufname(bufnr) + if bufnr > 0 && !empty(bufname) + cal filter(s:mrbs, 'v:val != bufnr') + cal insert(s:mrbs, bufnr) + cal s:addtomrufs(bufname) + en +endf + +fu! s:addtomrufs(fname) + let fn = fnamemodify(a:fname, ':p') + let fn = exists('+ssl') ? tr(fn, '/', '\') : fn + if ( !empty({s:in}) && fn !~# {s:in} ) || ( !empty({s:ex}) && fn =~# {s:ex} ) + \ || !empty(getbufvar('^'.fn.'$', '&bt')) || !filereadable(fn) | retu + en + let idx = index(s:mrufs, fn, 0, !{s:cseno}) + if idx + cal filter(s:mrufs, 'v:val !='.( {s:cseno} ? '#' : '?' ).' fn') + cal insert(s:mrufs, fn) + if {s:soup} && idx < 0 + cal s:savetofile(s:mergelists()) + en + en +endf + +fu! s:savetofile(mrufs) + cal ctrlp#utils#writecache(a:mrufs, s:cadir, s:cafile) +endf +" Public {{{1 +fu! ctrlp#mrufiles#refresh(...) + let mrufs = s:mergelists() + cal filter(mrufs, '!empty(ctrlp#utils#glob(v:val, 1)) && !s:excl(v:val)') + if exists('+ssl') + cal map(mrufs, 'tr(v:val, "/", "\\")') + cal map(s:mrufs, 'tr(v:val, "/", "\\")') + let cond = 'count(mrufs, v:val, !{s:cseno}) == 1' + cal filter(mrufs, cond) + cal filter(s:mrufs, cond) + en + cal s:savetofile(mrufs) + retu a:0 && a:1 == 'raw' ? [] : s:reformat(mrufs) +endf + +fu! ctrlp#mrufiles#remove(files) + let mrufs = [] + if a:files != [] + let mrufs = s:mergelists() + let cond = 'index(a:files, v:val, 0, !{s:cseno}) < 0' + cal filter(mrufs, cond) + cal filter(s:mrufs, cond) + en + cal s:savetofile(mrufs) + retu s:reformat(mrufs) +endf + +fu! ctrlp#mrufiles#add(fn) + if !empty(a:fn) + cal s:addtomrufs(a:fn) + en +endf + +fu! ctrlp#mrufiles#list(...) + retu a:0 ? a:1 == 'raw' ? s:reformat(s:mergelists(), a:1) : 0 + \ : s:reformat(s:mergelists()) +endf + +fu! ctrlp#mrufiles#bufs() + retu s:mrbs +endf + +fu! ctrlp#mrufiles#tgrel() + let {s:re} = !{s:re} +endf + +fu! ctrlp#mrufiles#cachefile() + if !exists('s:cadir') || !exists('s:cafile') + let s:cadir = ctrlp#utils#cachedir().ctrlp#utils#lash().'mru' + let s:cafile = s:cadir.ctrlp#utils#lash().'cache.txt' + en + retu s:cafile +endf + +fu! ctrlp#mrufiles#init() + if !has('autocmd') | retu | en + let s:locked = 0 + aug CtrlPMRUF + au! + au BufAdd,BufEnter,BufLeave,BufWritePost * cal s:record(expand('', 1)) + au QuickFixCmdPre *vimgrep* let s:locked = 1 + au QuickFixCmdPost *vimgrep* let s:locked = 0 + au VimLeavePre * cal s:savetofile(s:mergelists()) + aug END +endf +"}}} + +" vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 diff --git a/vim/bundle/ctrlp.vim/autoload/ctrlp/quickfix.vim b/vim/bundle/ctrlp.vim/autoload/ctrlp/quickfix.vim new file mode 100644 index 0000000..03ab921 --- /dev/null +++ b/vim/bundle/ctrlp.vim/autoload/ctrlp/quickfix.vim @@ -0,0 +1,59 @@ +" ============================================================================= +" File: autoload/ctrlp/quickfix.vim +" Description: Quickfix extension +" Author: Kien Nguyen +" ============================================================================= + +" Init {{{1 +if exists('g:loaded_ctrlp_quickfix') && g:loaded_ctrlp_quickfix + fini +en +let g:loaded_ctrlp_quickfix = 1 + +cal add(g:ctrlp_ext_vars, { + \ 'init': 'ctrlp#quickfix#init()', + \ 'accept': 'ctrlp#quickfix#accept', + \ 'lname': 'quickfix', + \ 'sname': 'qfx', + \ 'type': 'line', + \ 'sort': 0, + \ 'nolim': 1, + \ }) + +let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) + +fu! s:lineout(dict) + retu printf('%s|%d:%d| %s', bufname(a:dict['bufnr']), a:dict['lnum'], + \ a:dict['col'], matchstr(a:dict['text'], '\s*\zs.*\S')) +endf +" Utilities {{{1 +fu! s:syntax() + if !ctrlp#nosy() + cal ctrlp#hicheck('CtrlPqfLineCol', 'Search') + sy match CtrlPqfLineCol '|\zs\d\+:\d\+\ze|' + en +endf +" Public {{{1 +fu! ctrlp#quickfix#init() + cal s:syntax() + retu map(getqflist(), 's:lineout(v:val)') +endf + +fu! ctrlp#quickfix#accept(mode, str) + let vals = matchlist(a:str, '^\([^|]\+\ze\)|\(\d\+\):\(\d\+\)|') + if vals == [] || vals[1] == '' | retu | en + cal ctrlp#acceptfile(a:mode, vals[1]) + let cur_pos = getpos('.')[1:2] + if cur_pos != [1, 1] && cur_pos != map(vals[2:3], 'str2nr(v:val)') + mark ' + en + cal cursor(vals[2], vals[3]) + sil! norm! zvzz +endf + +fu! ctrlp#quickfix#id() + retu s:id +endf +"}}} + +" vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 diff --git a/vim/bundle/ctrlp.vim/autoload/ctrlp/rtscript.vim b/vim/bundle/ctrlp.vim/autoload/ctrlp/rtscript.vim new file mode 100644 index 0000000..eed21c6 --- /dev/null +++ b/vim/bundle/ctrlp.vim/autoload/ctrlp/rtscript.vim @@ -0,0 +1,59 @@ +" ============================================================================= +" File: autoload/ctrlp/rtscript.vim +" Description: Runtime scripts extension +" Author: Kien Nguyen +" ============================================================================= + +" Init {{{1 +if exists('g:loaded_ctrlp_rtscript') && g:loaded_ctrlp_rtscript + fini +en +let [g:loaded_ctrlp_rtscript, g:ctrlp_newrts] = [1, 0] + +cal add(g:ctrlp_ext_vars, { + \ 'init': 'ctrlp#rtscript#init(s:caching)', + \ 'accept': 'ctrlp#acceptfile', + \ 'lname': 'runtime scripts', + \ 'sname': 'rts', + \ 'type': 'path', + \ 'opmul': 1, + \ }) + +let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) + +let s:filecounts = {} +" Utilities {{{1 +fu! s:nocache() + retu g:ctrlp_newrts || + \ !s:caching || ( s:caching > 1 && get(s:filecounts, s:cwd) < s:caching ) +endf +" Public {{{1 +fu! ctrlp#rtscript#init(caching) + let [s:caching, s:cwd] = [a:caching, getcwd()] + if s:nocache() || + \ !( exists('g:ctrlp_rtscache') && g:ctrlp_rtscache[0] == &rtp ) + sil! cal ctrlp#progress('Indexing...') + let entries = split(globpath(ctrlp#utils#fnesc(&rtp, 'g'), '**/*.*'), "\n") + cal filter(entries, 'count(entries, v:val) == 1') + let [entries, echoed] = [ctrlp#dirnfile(entries)[1], 1] + el + let [entries, results] = g:ctrlp_rtscache[2:3] + en + if s:nocache() || + \ !( exists('g:ctrlp_rtscache') && g:ctrlp_rtscache[:1] == [&rtp, s:cwd] ) + if !exists('echoed') + sil! cal ctrlp#progress('Processing...') + en + let results = map(copy(entries), 'fnamemodify(v:val, '':.'')') + en + let [g:ctrlp_rtscache, g:ctrlp_newrts] = [[&rtp, s:cwd, entries, results], 0] + cal extend(s:filecounts, { s:cwd : len(results) }) + retu results +endf + +fu! ctrlp#rtscript#id() + retu s:id +endf +"}}} + +" vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 diff --git a/vim/bundle/ctrlp.vim/autoload/ctrlp/tag.vim b/vim/bundle/ctrlp.vim/autoload/ctrlp/tag.vim new file mode 100644 index 0000000..626363a --- /dev/null +++ b/vim/bundle/ctrlp.vim/autoload/ctrlp/tag.vim @@ -0,0 +1,138 @@ +" ============================================================================= +" File: autoload/ctrlp/tag.vim +" Description: Tag file extension +" Author: Kien Nguyen +" ============================================================================= + +" Init {{{1 +if exists('g:loaded_ctrlp_tag') && g:loaded_ctrlp_tag + fini +en +let g:loaded_ctrlp_tag = 1 + +cal add(g:ctrlp_ext_vars, { + \ 'init': 'ctrlp#tag#init()', + \ 'accept': 'ctrlp#tag#accept', + \ 'lname': 'tags', + \ 'sname': 'tag', + \ 'enter': 'ctrlp#tag#enter()', + \ 'type': 'tabs', + \ }) + +let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) +" Utilities {{{1 +fu! s:findcount(str) + let [tg, ofname] = split(a:str, '\t\+\ze[^\t]\+$') + let tgs = taglist('^'.tg.'$') + if len(tgs) < 2 + retu [0, 0, 0, 0] + en + let bname = fnamemodify(bufname('%'), ':p') + let fname = expand(fnamemodify(simplify(ofname), ':s?^[.\/]\+??:p:.'), 1) + let [fnd, cnt, pos, ctgs, otgs] = [0, 0, 0, [], []] + for tgi in tgs + let lst = bname == fnamemodify(tgi["filename"], ':p') ? 'ctgs' : 'otgs' + cal call('add', [{lst}, tgi]) + endfo + let ntgs = ctgs + otgs + for tgi in ntgs + let cnt += 1 + let fulname = fnamemodify(tgi["filename"], ':p') + if stridx(fulname, fname) >= 0 + \ && strlen(fname) + stridx(fulname, fname) == strlen(fulname) + let fnd += 1 + let pos = cnt + en + endfo + let cnt = 0 + for tgi in ntgs + let cnt += 1 + if tgi["filename"] == ofname + let [fnd, pos] = [0, cnt] + en + endfo + retu [1, fnd, pos, len(ctgs)] +endf + +fu! s:filter(tags) + let nr = 0 + wh 0 < 1 + if a:tags == [] | brea | en + if a:tags[nr] =~ '^!' && a:tags[nr] !~# '^!_TAG_' + let nr += 1 + con + en + if a:tags[nr] =~# '^!_TAG_' && len(a:tags) > nr + cal remove(a:tags, nr) + el + brea + en + endw + retu a:tags +endf + +fu! s:syntax() + if !ctrlp#nosy() + cal ctrlp#hicheck('CtrlPTabExtra', 'Comment') + sy match CtrlPTabExtra '\zs\t.*\ze$' + en +endf +" Public {{{1 +fu! ctrlp#tag#init() + if empty(s:tagfiles) | retu [] | en + let g:ctrlp_alltags = [] + let tagfiles = sort(filter(s:tagfiles, 'count(s:tagfiles, v:val) == 1')) + for each in tagfiles + let alltags = s:filter(ctrlp#utils#readfile(each)) + cal extend(g:ctrlp_alltags, alltags) + endfo + cal s:syntax() + retu g:ctrlp_alltags +endf + +fu! ctrlp#tag#accept(mode, str) + cal ctrlp#exit() + let str = matchstr(a:str, '^[^\t]\+\t\+[^\t]\+\ze\t') + let [tg, fdcnt] = [split(str, '^[^\t]\+\zs\t')[0], s:findcount(str)] + let cmds = { + \ 't': ['tab sp', 'tab stj'], + \ 'h': ['sp', 'stj'], + \ 'v': ['vs', 'vert stj'], + \ 'e': ['', 'tj'], + \ } + let utg = fdcnt[3] < 2 && fdcnt[0] == 1 && fdcnt[1] == 1 + let cmd = !fdcnt[0] || utg ? cmds[a:mode][0] : cmds[a:mode][1] + let cmd = a:mode == 'e' && ctrlp#modfilecond(!&aw) + \ ? ( cmd == 'tj' ? 'stj' : 'sp' ) : cmd + let cmd = a:mode == 't' ? ctrlp#tabcount().cmd : cmd + if !fdcnt[0] || utg + if cmd != '' + exe cmd + en + let save_cst = &cst + set cst& + cal feedkeys(":".( utg ? fdcnt[2] : "" )."ta ".tg."\r", 'nt') + let &cst = save_cst + el + let ext = "" + if fdcnt[1] < 2 && fdcnt[2] + let [sav_more, &more] = [&more, 0] + let ext = fdcnt[2]."\r".":let &more = ".sav_more."\r" + en + cal feedkeys(":".cmd." ".tg."\r".ext, 'nt') + en + cal ctrlp#setlcdir() +endf + +fu! ctrlp#tag#id() + retu s:id +endf + +fu! ctrlp#tag#enter() + let tfs = tagfiles() + let s:tagfiles = tfs != [] ? filter(map(tfs, 'fnamemodify(v:val, ":p")'), + \ 'filereadable(v:val)') : [] +endf +"}}} + +" vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 diff --git a/vim/bundle/ctrlp.vim/autoload/ctrlp/undo.vim b/vim/bundle/ctrlp.vim/autoload/ctrlp/undo.vim new file mode 100644 index 0000000..dee705e --- /dev/null +++ b/vim/bundle/ctrlp.vim/autoload/ctrlp/undo.vim @@ -0,0 +1,154 @@ +" ============================================================================= +" File: autoload/ctrlp/undo.vim +" Description: Undo extension +" Author: Kien Nguyen +" ============================================================================= + +" Init {{{1 +if ( exists('g:loaded_ctrlp_undo') && g:loaded_ctrlp_undo ) + fini +en +let g:loaded_ctrlp_undo = 1 + +cal add(g:ctrlp_ext_vars, { + \ 'init': 'ctrlp#undo#init()', + \ 'accept': 'ctrlp#undo#accept', + \ 'lname': 'undo', + \ 'sname': 'udo', + \ 'enter': 'ctrlp#undo#enter()', + \ 'exit': 'ctrlp#undo#exit()', + \ 'type': 'line', + \ 'sort': 0, + \ 'nolim': 1, + \ }) + +let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) + +let s:text = map(['second', 'seconds', 'minutes', 'hours', 'days', 'weeks', + \ 'months', 'years'], '" ".v:val." ago"') +" Utilities {{{1 +fu! s:getundo() + if exists('*undotree') + \ && ( v:version > 703 || ( v:version == 703 && has('patch005') ) ) + retu [1, undotree()] + el + redi => result + sil! undol + redi END + retu [0, split(result, "\n")[1:]] + en +endf + +fu! s:flatten(tree, cur) + let flatdict = {} + for each in a:tree + let saved = has_key(each, 'save') ? 'saved' : '' + let current = each['seq'] == a:cur ? 'current' : '' + cal extend(flatdict, { each['seq'] : [each['time'], saved, current] }) + if has_key(each, 'alt') + cal extend(flatdict, s:flatten(each['alt'], a:cur)) + en + endfo + retu flatdict +endf + +fu! s:elapsed(nr) + let [text, time] = [s:text, localtime() - a:nr] + let mins = time / 60 + let hrs = time / 3600 + let days = time / 86400 + let wks = time / 604800 + let mons = time / 2592000 + let yrs = time / 31536000 + if yrs > 1 + retu yrs.text[7] + elsei mons > 1 + retu mons.text[6] + elsei wks > 1 + retu wks.text[5] + elsei days > 1 + retu days.text[4] + elsei hrs > 1 + retu hrs.text[3] + elsei mins > 1 + retu mins.text[2] + elsei time == 1 + retu time.text[0] + elsei time < 120 + retu time.text[1] + en +endf + +fu! s:syntax() + if ctrlp#nosy() | retu | en + for [ke, va] in items({'T': 'Directory', 'Br': 'Comment', 'Nr': 'String', + \ 'Sv': 'Comment', 'Po': 'Title'}) + cal ctrlp#hicheck('CtrlPUndo'.ke, va) + endfo + sy match CtrlPUndoT '\v\d+ \zs[^ ]+\ze|\d+:\d+:\d+' + sy match CtrlPUndoBr '\[\|\]' + sy match CtrlPUndoNr '\[\d\+\]' contains=CtrlPUndoBr + sy match CtrlPUndoSv 'saved' + sy match CtrlPUndoPo 'current' +endf + +fu! s:dict2list(dict) + for ke in keys(a:dict) + let a:dict[ke][0] = s:elapsed(a:dict[ke][0]) + endfo + retu map(keys(a:dict), 'eval(''[v:val, a:dict[v:val]]'')') +endf + +fu! s:compval(...) + retu a:2[0] - a:1[0] +endf + +fu! s:format(...) + let saved = !empty(a:1[1][1]) ? ' '.a:1[1][1] : '' + let current = !empty(a:1[1][2]) ? ' '.a:1[1][2] : '' + retu a:1[1][0].' ['.a:1[0].']'.saved.current +endf + +fu! s:formatul(...) + let parts = matchlist(a:1, + \ '\v^\s+(\d+)\s+\d+\s+([^ ]+\s?[^ ]+|\d+\s\w+\s\w+)(\s*\d*)$') + retu parts == [] ? '----' + \ : parts[2].' ['.parts[1].']'.( parts[3] != '' ? ' saved' : '' ) +endf +" Public {{{1 +fu! ctrlp#undo#init() + let entries = s:undos[0] ? s:undos[1]['entries'] : s:undos[1] + if empty(entries) | retu [] | en + if !exists('s:lines') + if s:undos[0] + let entries = s:dict2list(s:flatten(entries, s:undos[1]['seq_cur'])) + let s:lines = map(sort(entries, 's:compval'), 's:format(v:val)') + el + let s:lines = map(reverse(entries), 's:formatul(v:val)') + en + en + cal s:syntax() + retu s:lines +endf + +fu! ctrlp#undo#accept(mode, str) + let undon = matchstr(a:str, '\[\zs\d\+\ze\]') + if empty(undon) | retu | en + cal ctrlp#exit() + exe 'u' undon +endf + +fu! ctrlp#undo#id() + retu s:id +endf + +fu! ctrlp#undo#enter() + let s:undos = s:getundo() +endf + +fu! ctrlp#undo#exit() + unl! s:lines +endf +"}}} + +" vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 diff --git a/vim/bundle/ctrlp.vim/autoload/ctrlp/utils.vim b/vim/bundle/ctrlp.vim/autoload/ctrlp/utils.vim new file mode 100644 index 0000000..91b9f24 --- /dev/null +++ b/vim/bundle/ctrlp.vim/autoload/ctrlp/utils.vim @@ -0,0 +1,110 @@ +" ============================================================================= +" File: autoload/ctrlp/utils.vim +" Description: Utilities +" Author: Kien Nguyen +" ============================================================================= + +" Static variables {{{1 +fu! ctrlp#utils#lash() + retu &ssl || !exists('+ssl') ? '/' : '\' +endf + +fu! s:lash(...) + retu ( a:0 ? a:1 : getcwd() ) !~ '[\/]$' ? s:lash : '' +endf + +fu! ctrlp#utils#opts() + let s:lash = ctrlp#utils#lash() + let usrhome = $HOME . s:lash( $HOME ) + let cahome = exists('$XDG_CACHE_HOME') ? $XDG_CACHE_HOME : usrhome.'.cache' + let cadir = isdirectory(usrhome.'.ctrlp_cache') + \ ? usrhome.'.ctrlp_cache' : cahome.s:lash(cahome).'ctrlp' + if exists('g:ctrlp_cache_dir') + let cadir = expand(g:ctrlp_cache_dir, 1) + if isdirectory(cadir.s:lash(cadir).'.ctrlp_cache') + let cadir = cadir.s:lash(cadir).'.ctrlp_cache' + en + en + let s:cache_dir = cadir +endf +cal ctrlp#utils#opts() + +let s:wig_cond = v:version > 702 || ( v:version == 702 && has('patch051') ) +" Files and Directories {{{1 +fu! ctrlp#utils#cachedir() + retu s:cache_dir +endf + +fu! ctrlp#utils#cachefile(...) + let [tail, dir] = [a:0 == 1 ? '.'.a:1 : '', a:0 == 2 ? a:1 : getcwd()] + let cache_file = substitute(dir, '\([\/]\|^\a\zs:\)', '%', 'g').tail.'.txt' + retu a:0 == 1 ? cache_file : s:cache_dir.s:lash(s:cache_dir).cache_file +endf + +fu! ctrlp#utils#readfile(file) + if filereadable(a:file) + let data = readfile(a:file) + if empty(data) || type(data) != 3 + unl data + let data = [] + en + retu data + en + retu [] +endf + +fu! ctrlp#utils#mkdir(dir) + if exists('*mkdir') && !isdirectory(a:dir) + sil! cal mkdir(a:dir, 'p') + en + retu a:dir +endf + +fu! ctrlp#utils#writecache(lines, ...) + if isdirectory(ctrlp#utils#mkdir(a:0 ? a:1 : s:cache_dir)) + sil! cal writefile(a:lines, a:0 >= 2 ? a:2 : ctrlp#utils#cachefile()) + en +endf + +fu! ctrlp#utils#glob(...) + let path = ctrlp#utils#fnesc(a:1, 'g') + retu s:wig_cond ? glob(path, a:2) : glob(path) +endf + +fu! ctrlp#utils#globpath(...) + retu call('globpath', s:wig_cond ? a:000 : a:000[:1]) +endf + +fu! ctrlp#utils#fnesc(path, type, ...) + if exists('*fnameescape') + if exists('+ssl') + if a:type == 'c' + let path = escape(a:path, '%#') + elsei a:type == 'f' + let path = fnameescape(a:path) + elsei a:type == 'g' + let path = escape(a:path, '?*') + en + let path = substitute(path, '[', '[[]', 'g') + el + let path = fnameescape(a:path) + en + el + if exists('+ssl') + if a:type == 'c' + let path = escape(a:path, '%#') + elsei a:type == 'f' + let path = escape(a:path, " \t\n%#*?|<\"") + elsei a:type == 'g' + let path = escape(a:path, '?*') + en + let path = substitute(path, '[', '[[]', 'g') + el + let path = escape(a:path, " \t\n*?[{`$\\%#'\"|!<") + en + en + retu a:0 ? escape(path, a:1) : path +endf +"}}} + +" vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 diff --git a/vim/bundle/ctrlp.vim/doc/ctrlp.txt b/vim/bundle/ctrlp.vim/doc/ctrlp.txt new file mode 100644 index 0000000..e697b93 --- /dev/null +++ b/vim/bundle/ctrlp.vim/doc/ctrlp.txt @@ -0,0 +1,1451 @@ +*ctrlp.txt* Fuzzy file, buffer, mru, tag, ... finder. v1.79 +*CtrlP* *ControlP* *'ctrlp'* *'ctrl-p'* +=============================================================================== +# # +# :::::::: ::::::::::: ::::::::: ::: ::::::::: # +# :+: :+: :+: :+: :+: :+: :+: :+: # +# +:+ +:+ +:+ +:+ +:+ +:+ +:+ # +# +#+ +#+ +#++:++#: +#+ +#++:++#+ # +# +#+ +#+ +#+ +#+ +#+ +#+ # +# #+# #+# #+# #+# #+# #+# #+# # +# ######## ### ### ### ########## ### # +# # +=============================================================================== +CONTENTS *ctrlp-contents* + + 1. Intro........................................|ctrlp-intro| + 2. Options......................................|ctrlp-options| + 3. Commands.....................................|ctrlp-commands| + 4. Mappings.....................................|ctrlp-mappings| + 5. Input Formats................................|ctrlp-input-formats| + 6. Extensions...................................|ctrlp-extensions| + +=============================================================================== +INTRO *ctrlp-intro* + +Full path fuzzy file, buffer, mru, tag, ... finder with an intuitive interface. +Written in pure Vimscript for MacVim, gVim and Vim version 7.0+. Has full +support for Vim's |regexp| as search pattern, built-in MRU files monitoring, +project's root finder, and more. + +To enable optional extensions (tag, dir, rtscript...), see |ctrlp-extensions|. + +=============================================================================== +OPTIONS *ctrlp-options* + +Overview:~ + + |loaded_ctrlp|................Disable the plugin. + |ctrlp_map|...................Default mapping. + |ctrlp_cmd|...................Default command used for the default mapping. + |ctrlp_by_filename|...........Default to filename mode or not. + |ctrlp_regexp|................Default to regexp mode or not. + |ctrlp_match_window|..........Order, height and position of the match window. + |ctrlp_switch_buffer|.........Jump to an open buffer if already opened. + |ctrlp_reuse_window|..........Reuse special windows (help, quickfix, etc). + |ctrlp_tabpage_position|......Where to put the new tab page. + |ctrlp_working_path_mode|.....How to set CtrlP's local working directory. + |ctrlp_root_markers|..........Additional, high priority root markers. + |ctrlp_use_caching|...........Use per-session caching or not. + |ctrlp_clear_cache_on_exit|...Keep cache after exiting Vim or not. + |ctrlp_cache_dir|.............Location of the cache directory. + |ctrlp_show_hidden|...........Ignore dotfiles and dotdirs or not. + |ctrlp_custom_ignore|.........Hide stuff when using |globpath()|. + |ctrlp_max_files|.............Number of files to scan initially. + |ctrlp_max_depth|.............Directory depth to recurse into when scanning. + |ctrlp_user_command|..........Use an external scanner. + |ctrlp_max_history|...........Number of entries saved in the prompt history. + |ctrlp_open_new_file|.........How to open a file created by . + |ctrlp_open_multiple_files|...How to open files selected by . + |ctrlp_arg_map|...............Intercept and or not. + |ctrlp_follow_symlinks|.......Follow symbolic links or not. + |ctrlp_lazy_update|...........Only update when typing has stopped. + |ctrlp_default_input|.........Seed the prompt with an initial string. + |ctrlp_abbrev|................Input abbreviations. + |ctrlp_key_loop|..............Use input looping for multi-byte input. + |ctrlp_use_migemo|............Use Migemo patterns for Japanese filenames. + |ctrlp_prompt_mappings|.......Change the mappings inside the prompt. + + MRU mode: + |ctrlp_mruf_max|..............Max MRU entries to remember. + |ctrlp_mruf_exclude|..........Files that shouldn't be remembered. + |ctrlp_mruf_include|..........Files to be remembered. + |ctrlp_mruf_relative|.........Show only MRU files in the working directory. + |ctrlp_mruf_default_order|....Disable sorting. + |ctrlp_mruf_case_sensitive|...MRU files are case sensitive or not. + |ctrlp_mruf_save_on_update|...Save to disk whenever a new entry is added. + + BufferTag mode: (to enable, see |ctrlp-extensions|) + |g:ctrlp_buftag_ctags_bin|....The location of the ctags-compatible binary. + |g:ctrlp_buftag_systemenc|....The encoding used for the ctags command. + |g:ctrlp_buftag_types|........Add new filetypes and set the cmd arguments. + + Advanced options: + |ctrlp_open_func|.............Use custom file opening functions. + |ctrlp_status_func|...........Change CtrlP's two statuslines. + |ctrlp_buffer_func|...........Call custom functions in the CtrlP buffer. + |ctrlp_match_func|............Replace the built-in matching algorithm. + +------------------------------------------------------------------------------- +Detailed descriptions and default values:~ + + *'g:ctrlp_map'* +Use this option to change the mapping to invoke CtrlP in |Normal| mode: > + let g:ctrlp_map = '' +< + + *'g:ctrlp_cmd'* +Set the default opening command to use when pressing the above mapping: > + let g:ctrlp_cmd = 'CtrlP' +< + + *'g:loaded_ctrlp'* +Use this to disable the plugin completely: > + let g:loaded_ctrlp = 1 +< + + *'g:ctrlp_by_filename'* +Set this to 1 to set searching by filename (as opposed to full path) as the +default: > + let g:ctrlp_by_filename = 0 +< +Can be toggled on/off by pressing inside the prompt. + + *'g:ctrlp_regexp'* +Set this to 1 to set regexp search as the default: > + let g:ctrlp_regexp = 0 +< +Can be toggled on/off by pressing inside the prompt. + + *'g:ctrlp_match_window'* +Change the postion, the listing order of results, the minimum and the maximum +heights of the match window: > + let g:ctrlp_match_window = '' +< +Example: > + let g:ctrlp_match_window = 'bottom,order:btt,min:1,max:10,results:10' +< +The position: (default: bottom) + top - show the match window at the top of the screen. + bottom - show the match window at the bottom of the screen. + +The listing order of results: (default: btt) + order:ttb - from top to bottom. + order:btt - from bottom to top. + +The minimum and maximum heights: + min:{n} - show minimum {n} lines (default: 1). + max:{n} - show maximum {n} lines (default: 10). + +The maximum number of results: + results:{n} - list maximum {n} results (default: sync with max height). + +Note: When a setting isn't set, its default value will be used. + + *'g:ctrlp_switch_buffer'* +When opening a file, if it's already open in a window somewhere, CtrlP will try +to jump to it instead of opening a new instance: > + let g:ctrlp_switch_buffer = 'Et' +< + e - jump when is pressed, but only to windows in the current tab. + t - jump when is pressed, but only to windows in another tab. + v - like "e", but jump when is pressed. + h - like "e", but jump when is pressed. + E, T, V, H - like "e", "t", "v", and "h", but jump to windows anywhere. + 0 or - disable this feature. + + *'g:ctrlp_reuse_window'* +When opening a file with , CtrlP avoids opening it in windows created by +plugins, help and quickfix. Use this to setup some exceptions: > + let g:ctrlp_reuse_window = 'netrw' +< +Acceptable values are partial name, filetype or buftype of the special buffers. +Use regexp to specify the pattern. +Example: > + let g:ctrlp_reuse_window = 'netrw\|help\|quickfix' +< + + *'g:ctrlp_tabpage_position'* +Where to put the new tab page when opening one: > + let g:ctrlp_tabpage_position = 'ac' +< + a - after. + b - before. + c - the current tab page. + l - the last tab page. + f - the first tab page. + + *'g:ctrlp_working_path_mode'* +When starting up, CtrlP sets its local working directory according to this +variable: > + let g:ctrlp_working_path_mode = 'ra' +< + c - the directory of the current file. + a - like "c", but only applies when the current working directory outside of + CtrlP isn't a direct ancestor of the directory of the current file. + r - the nearest ancestor that contains one of these directories or files: + .git .hg .svn .bzr _darcs + w - begin finding a root from the current working directory outside of CtrlP + instead of from the directory of the current file (default). Only applies + when "r" is also present. + 0 or - disable this feature. + +Note #1: if "a" or "c" is included with "r", use the behavior of "a" or "c" (as +a fallback) when a root can't be found. + +Note #2: you can use a |b:var| to set this option on a per buffer basis. + + *'g:ctrlp_root_markers'* +Use this to set your own root markers in addition to the default ones (.git, +.hg, .svn, .bzr, and _darcs). Your markers will take precedence: > + let g:ctrlp_root_markers = [''] +< +Note: you can use a |b:var| to set this option on a per buffer basis. + + *'g:ctrlp_use_caching'* +Enable/Disable per-session caching: > + let g:ctrlp_use_caching = 1 +< + 0 - Disable caching. + 1 - Enable caching. + n - When bigger than 1, disable caching and use the number as the limit to + enable caching again. + +Note: you can quickly purge the cache by pressing while inside CtrlP. + + *'g:ctrlp_clear_cache_on_exit'* +Set this to 0 to enable cross-session caching by not deleting the cache files +upon exiting Vim: > + let g:ctrlp_clear_cache_on_exit = 1 +< + + *'g:ctrlp_cache_dir'* +Set the directory to store the cache files: > + let g:ctrlp_cache_dir = $HOME.'/.cache/ctrlp' +< + + *'g:ctrlp_show_hidden'* +Set this to 1 if you want CtrlP to scan for dotfiles and dotdirs: > + let g:ctrlp_show_hidden = 0 +< +Note: does not apply when a command defined with |g:ctrlp_user_command| is +being used. + + *'ctrlp-wildignore'* +You can use Vim's |'wildignore'| to exclude files and directories from the +results. +Examples: > + " Excluding version control directories + set wildignore+=*/.git/*,*/.hg/*,*/.svn/* " Linux/MacOSX + set wildignore+=*\\.git\\*,*\\.hg\\*,*\\.svn\\* " Windows ('noshellslash') +< +Note #1: the `*/` in front of each directory glob is required. + +Note #2: |wildignore| influences the result of |expand()|, |globpath()| and +|glob()| which many plugins use to find stuff on the system (e.g. VCS related +plugins look for .git/, .hg/,... some other plugins look for external *.exe +tools on Windows). So be a little mindful of what you put in your |wildignore|. + + *'g:ctrlp_custom_ignore'* +In addition to |'wildignore'|, use this for files and directories you want only +CtrlP to not show. Use regexp to specify the patterns: > + let g:ctrlp_custom_ignore = '' +< +Examples: > + let g:ctrlp_custom_ignore = '\v[\/]\.(git|hg|svn)$' + let g:ctrlp_custom_ignore = { + \ 'dir': '\v[\/]\.(git|hg|svn)$', + \ 'file': '\v\.(exe|so|dll)$', + \ 'link': 'SOME_BAD_SYMBOLIC_LINKS', + \ } + let g:ctrlp_custom_ignore = { + \ 'file': '\v(\.cpp|\.h|\.hh|\.cxx)@ + let g:ctrlp_max_files = 10000 +< +Note: does not apply when a command defined with |g:ctrlp_user_command| is +being used. + + *'g:ctrlp_max_depth'* +The maximum depth of a directory tree to recurse into: > + let g:ctrlp_max_depth = 40 +< +Note: does not apply when a command defined with |g:ctrlp_user_command| is +being used. + + *'g:ctrlp_user_command'* +Specify an external tool to use for listing files instead of using Vim's +|globpath()|. Use %s in place of the target directory: > + let g:ctrlp_user_command = '' +< +Examples: > + let g:ctrlp_user_command = 'find %s -type f' " MacOSX/Linux + let g:ctrlp_user_command = 'dir %s /-n /b /s /a-d' " Windows +< +You can also use 'grep', 'findstr' or something else to filter the results. +Examples: > + let g:ctrlp_user_command = + \ 'find %s -type f | grep -v -P "\.jpg$|/tmp/"' " MacOSX/Linux + let g:ctrlp_user_command = + \ 'dir %s /-n /b /s /a-d | findstr /v /l ".jpg \\tmp\\"' " Windows +< +Use a version control listing command when inside a repository, this is faster +when scanning large projects: > + let g:ctrlp_user_command = [root_marker, listing_command, fallback_command] + let g:ctrlp_user_command = { + \ 'types': { + \ 1: [root_marker_1, listing_command_1], + \ n: [root_marker_n, listing_command_n], + \ }, + \ 'fallback': fallback_command, + \ 'ignore': 0 or 1 + \ } +< +Some examples: > + " Single VCS, listing command does not list untracked files: + let g:ctrlp_user_command = ['.git', 'cd %s && git ls-files'] + let g:ctrlp_user_command = ['.hg', 'hg --cwd %s locate -I .'] + + " Multiple VCS's: + let g:ctrlp_user_command = { + \ 'types': { + \ 1: ['.git', 'cd %s && git ls-files'], + \ 2: ['.hg', 'hg --cwd %s locate -I .'], + \ }, + \ 'fallback': 'find %s -type f' + \ } + + " Single VCS, listing command lists untracked files (slower): + let g:ctrlp_user_command = + \ ['.git', 'cd %s && git ls-files . -co --exclude-standard'] + + let g:ctrlp_user_command = + \ ['.hg', 'hg --cwd %s status -numac -I . $(hg root)'] " MacOSX/Linux + + let g:ctrlp_user_command = ['.hg', 'for /f "tokens=1" %%a in (''hg root'') ' + \ . 'do hg --cwd %s status -numac -I . %%a'] " Windows +< +Note #1: in the |Dictionary| format, 'fallback' and 'ignore' are optional. In +the |List| format, fallback_command is optional. + +Note #2: if the fallback_command is empty or the 'fallback' key is not defined, +|globpath()| will then be used when scanning outside of a repository. + +Note #3: unless the |Dictionary| format is used and 'ignore' is defined and set +to 1, the |wildignore| and |g:ctrlp_custom_ignore| options do not apply when +these custom commands are being used. When not present, 'ignore' is set to 0 by +default to retain the performance advantage of using external commands. + +Note #4: when changing the option's variable type, remember to |:unlet| it +first or restart Vim to avoid the "E706: Variable type mismatch" error. + +Note #5: you can use a |b:var| to set this option on a per buffer basis. + + *'g:ctrlp_max_history'* +The maximum number of input strings you want CtrlP to remember. The default +value mirrors Vim's global |'history'| option: > + let g:ctrlp_max_history = &history +< +Set to 0 to disable prompt's history. Browse the history with and . + + *'g:ctrlp_open_new_file'* +Use this option to specify how the newly created file is to be opened when +pressing : > + let g:ctrlp_open_new_file = 'v' +< + t - in a new tab. + h - in a new horizontal split. + v - in a new vertical split. + r - in the current window. + + *'g:ctrlp_open_multiple_files'* +If non-zero, this will enable opening multiple files with and : > + let g:ctrlp_open_multiple_files = 'v' +< +Example: > + let g:ctrlp_open_multiple_files = '2vjr' +< +For the number: + - If given, it'll be used as the maximum number of windows or tabs to create + when opening the files (the rest will be opened as hidden buffers). + - If not given, will open all files, each in a new window or new tab. + +For the letters: + t - each file in a new tab. + h - each file in a new horizontal split. + v - each file in a new vertical split. + i - all files as hidden buffers. + j - after opening, jump to the first opened tab or window. + r - open the first file in the current window, then the remaining files in + new splits or new tabs depending on which of "h", "v" and "t" is also + present. + + *'g:ctrlp_arg_map'* +When this is set to 1, the and mappings will accept one extra key +as an argument to override their default behavior: > + let g:ctrlp_arg_map = 0 +< +Pressing or will then prompt for a keypress. The key can be: + t - open in tab(s) + h - open in horizontal split(s) + v - open in vertical split(s) + i - open as hidden buffers (for only) + c - clear the marked files (for only) + r - open in the current window (for only) + , , - cancel and go back to the prompt. + - use the default behavior specified with |g:ctrlp_open_new_file| and + |g:ctrlp_open_multiple_files|. + + *'g:ctrlp_follow_symlinks'* +If non-zero, CtrlP will follow symbolic links when listing files: > + let g:ctrlp_follow_symlinks = 0 +< + 0 - don't follow symbolic links. + 1 - follow but ignore looped internal symlinks to avoid duplicates. + 2 - follow all symlinks indiscriminately. + +Note: does not apply when a command defined with |g:ctrlp_user_command| is +being used. + + *'g:ctrlp_lazy_update'* +Set this to 1 to enable the lazy-update feature: only update the match window +after typing's been stopped for a certain amount of time: > + let g:ctrlp_lazy_update = 0 +< +If is 1, update after 250ms. If bigger than 1, the number will be used as the +delay time in milliseconds. + + *'g:ctrlp_default_input'* +Set this to 1 to enable seeding the prompt with the current file's relative +path: > + let g:ctrlp_default_input = 0 +< +Instead of 1 or 0, if the value of the option is a string, it'll be used as-is +as the default input: > + let g:ctrlp_default_input = 'anystring' +< + + *'g:ctrlp_abbrev'* +Define input abbreviations that can be expanded (either internally or visibly) +in the prompt: > + let g:ctrlp_abbrev = {} +< +Examples: > + let g:ctrlp_abbrev = { + \ 'gmode': 'i', + \ 'abbrevs': [ + \ { + \ 'pattern': '^cd b', + \ 'expanded': '@cd ~/.vim/bundle', + \ 'mode': 'pfrz', + \ }, + \ { + \ 'pattern': '\(^@.\+\|\\\@ (use the expanded string in the + new filename). + c - only when auto-completing directory names with (expand the pattern + immediately before doing the auto-completion). + or not defined - always enable. + +Note: the abbrev entries are evaluated in sequence, so a later entry can be +evaluated against the expanded result of a previous entry; this includes itself +when 'gmode' is "t". + + *'g:ctrlp_key_loop'* +An experimental feature. Set this to 1 to enable input looping for the typing +of multi-byte characters: > + let g:ctrlp_key_loop = 0 +< +Note #1: when set, this option resets the |g:ctrlp_lazy_update| option. + +Note #2: you can toggle this feature inside the prompt with a custom mapping: > + let g:ctrlp_prompt_mappings = { 'ToggleKeyLoop()': [''] } +< + + *'g:ctrlp_use_migemo'* +Set this to 1 to use Migemo Pattern for Japanese filenames. Migemo Search only +works in regexp mode. To split the pattern, separate words with space: > + let g:ctrlp_use_migemo = 0 +< + + *'g:ctrlp_prompt_mappings'* +Use this to customize the mappings inside CtrlP's prompt to your liking. You +only need to keep the lines that you've changed the values (inside []): > + let g:ctrlp_prompt_mappings = { + \ 'PrtBS()': ['', ''], + \ 'PrtDelete()': [''], + \ 'PrtDeleteWord()': [''], + \ 'PrtClear()': [''], + \ 'PrtSelectMove("j")': ['', ''], + \ 'PrtSelectMove("k")': ['', ''], + \ 'PrtSelectMove("t")': ['', ''], + \ 'PrtSelectMove("b")': ['', ''], + \ 'PrtSelectMove("u")': ['', ''], + \ 'PrtSelectMove("d")': ['', ''], + \ 'PrtHistory(-1)': [''], + \ 'PrtHistory(1)': [''], + \ 'AcceptSelection("e")': ['', '<2-LeftMouse>'], + \ 'AcceptSelection("h")': ['', '', ''], + \ 'AcceptSelection("t")': [''], + \ 'AcceptSelection("v")': ['', ''], + \ 'ToggleFocus()': [''], + \ 'ToggleRegex()': [''], + \ 'ToggleByFname()': [''], + \ 'ToggleType(1)': ['', ''], + \ 'ToggleType(-1)': ['', ''], + \ 'PrtExpandDir()': [''], + \ 'PrtInsert("c")': ['', ''], + \ 'PrtInsert()': [''], + \ 'PrtCurStart()': [''], + \ 'PrtCurEnd()': [''], + \ 'PrtCurLeft()': ['', '', ''], + \ 'PrtCurRight()': ['', ''], + \ 'PrtClearCache()': [''], + \ 'PrtDeleteEnt()': [''], + \ 'CreateNewFile()': [''], + \ 'MarkToOpen()': [''], + \ 'OpenMulti()': [''], + \ 'PrtExit()': ['', '', ''], + \ } +< +Note: if pressing moves the cursor one character to the left instead of +deleting a character for you, add this to your |.vimrc| to disable the plugin's +default mapping: > + let g:ctrlp_prompt_mappings = { 'PrtCurLeft()': ['', ''] } +< + +---------------------------------------- +MRU mode options:~ + + *'g:ctrlp_mruf_max'* +Specify the number of recently opened files you want CtrlP to remember: > + let g:ctrlp_mruf_max = 250 +< + + *'g:ctrlp_mruf_exclude'* +Files you don't want CtrlP to remember. Use regexp to specify the patterns: > + let g:ctrlp_mruf_exclude = '' +< +Examples: > + let g:ctrlp_mruf_exclude = '/tmp/.*\|/temp/.*' " MacOSX/Linux + let g:ctrlp_mruf_exclude = '^C:\\dev\\tmp\\.*' " Windows +< + + *'g:ctrlp_mruf_include'* +And if you want CtrlP to only remember some files, specify them here: > + let g:ctrlp_mruf_include = '' +< +Example: > + let g:ctrlp_mruf_include = '\.py$\|\.rb$' +< + + *'g:ctrlp_mruf_relative'* +Set this to 1 to show only MRU files in the current working directory: > + let g:ctrlp_mruf_relative = 0 +< +Note: you can use a custom mapping to toggle this option inside the prompt: > + let g:ctrlp_prompt_mappings = { 'ToggleMRURelative()': [''] } +< + + *'g:ctrlp_mruf_default_order'* +Set this to 1 to disable sorting when searching in MRU mode: > + let g:ctrlp_mruf_default_order = 0 +< + + *'g:ctrlp_mruf_case_sensitive'* +Match this with your file system case-sensitivity setting to avoid duplicate +MRU entries: > + let g:ctrlp_mruf_case_sensitive = 1 +< + + *'g:ctrlp_mruf_save_on_update'* +Set this to 0 to disable saving of the MRU list to hard drive whenever a new +entry is added, saving will then only occur when exiting Vim: > + let g:ctrlp_mruf_save_on_update = 1 +< + +---------------------------------------- +Advanced options:~ + + *'g:ctrlp_open_func'* +Define a custom function to open the selected file: > + let g:ctrlp_open_func = {} +< +Example: > + let g:ctrlp_open_func = { + \ 'files' : 'Function_Name_1', + \ 'buffers' : 'Function_Name_2', + \ 'mru files' : 'Function_Name_3', + \ } +< +Structure of the functions: > + function! Function_Name(action, line) + " Arguments: + " | + " +- a:action : The opening action: + " | + 'e' : user pressed (default) + " | + 'h' : user pressed (default) + " | + 'v' : user pressed (default) + " | + 't' : user pressed (default) + " | + 'x' : user used the console dialog (default) and + " | chose "e[x]ternal". + " | + " +- a:line : The selected line. + + endfunction +< +Note: does not apply when opening multiple files with and . + +Example: open HTML files in the default web browser when is pressed and +in Vim otherwise > + function! HTMLOpenFunc(action, line) + if a:action =~ '^[tx]$' && fnamemodify(a:line, ':e') =~? '^html\?$' + + " Get the filename + let filename = fnameescape(fnamemodify(a:line, ':p')) + + " Close CtrlP + call ctrlp#exit() + + " Open the file + silent! execute '!xdg-open' filename + + elseif a:action == 'x' && fnamemodify(a:line, ':e') !~? '^html\?$' + + " Not a HTML file, simulate pressing again and wait for new input + call feedkeys("\") + + else + + " Use CtrlP's default file opening function + call call('ctrlp#acceptfile', [a:action, a:line]) + + endif + endfunction + + let g:ctrlp_open_func = { 'files': 'HTMLOpenFunc' } +< + + *'g:ctrlp_status_func'* +Use this to customize the statuslines for the CtrlP window: > + let g:ctrlp_status_func = {} +< +Example: > + let g:ctrlp_status_func = { + \ 'main': 'Function_Name_1', + \ 'prog': 'Function_Name_2', + \ } +< +Structure of the functions: > + " Main statusline + function! Function_Name_1(focus, byfname, regex, prev, item, next, marked) + " Arguments: + " | + " +- a:focus : The focus of the prompt: "prt" or "win". + " | + " +- a:byfname : In filename mode or in full path mode: "file" or "path". + " | + " +- a:regex : In regex mode: 1 or 0. + " | + " +- a:prev : The previous search mode. + " | + " +- a:item : The current search mode. + " | + " +- a:next : The next search mode. + " | + " +- a:marked : The number of marked files, or a comma separated list of + " the marked filenames. + + return full_statusline + endfunction + + " Progress statusline + function! Function_Name_2(str) + " a:str : Either the number of files scanned so far, or a string indicating + " the current directory is being scanned with a user_command. + + return full_statusline + endfunction +< +See https://gist.github.com/1610859 for a working example. + + *'g:ctrlp_buffer_func'* +Specify the functions that will be called after entering and before exiting the +CtrlP buffer: > + let g:ctrlp_buffer_func = {} +< +Example: > + let g:ctrlp_buffer_func = { + \ 'enter': 'Function_Name_1', + \ 'exit': 'Function_Name_2', + \ } +< + + *'g:ctrlp_match_func'* +Set an external fuzzy matching function for CtrlP to use: > + let g:ctrlp_match_func = {} +< +Example: > + let g:ctrlp_match_func = { 'match': 'Function_Name' } +< +Structure of the function: > + function! Function_Name(items, str, limit, mmode, ispath, crfile, regex) + " Arguments: + " | + " +- a:items : The full list of items to search in. + " | + " +- a:str : The string entered by the user. + " | + " +- a:limit : The max height of the match window. Can be used to limit + " | the number of items to return. + " | + " +- a:mmode : The match mode. Can be one of these strings: + " | + "full-line": match the entire line. + " | + "filename-only": match only the filename. + " | + "first-non-tab": match until the first tab char. + " | + "until-last-tab": match until the last tab char. + " | + " +- a:ispath : Is 1 when searching in file, buffer, mru, mixed, dir, and + " | rtscript modes. Is 0 otherwise. + " | + " +- a:crfile : The file in the current window. Should be excluded from the + " | results when a:ispath == 1. + " | + " +- a:regex : In regex mode: 1 or 0. + + return list_of_matched_items + endfunction +< + +Note: you can extend any of the above options with { 'arg_type': 'dict' } to +enable passing all the function arguments in a single Dictionary argument. Use +the existing argument names as keys in this Dictionary. + +Example: > + let g:ctrlp_status_func = { + \ 'arg_type' : 'dict', + \ 'enter': 'Function_Name_1', + \ 'exit': 'Function_Name_2', + \ } + + function! Function_Name_1(dict) + " where dict == { + " \ 'focus': value, + " \ 'byfname': value, + " \ 'regex': value, + " \ ... + " } + endfunction +< + +=============================================================================== +COMMANDS *ctrlp-commands* + + *:CtrlP* +:CtrlP [starting-directory] + Open CtrlP in find file mode. + + If no argument is given, the value of |g:ctrlp_working_path_mode| will be + used to determine the starting directory. + + You can use to auto-complete the [starting-directory] when typing it. + + *:CtrlPBuffer* +:CtrlPBuffer + Open CtrlP in find buffer mode. + + *:CtrlPMRU* +:CtrlPMRU + Open CtrlP in find Most-Recently-Used file mode. + + *:CtrlPLastMode* +:CtrlPLastMode [--dir] + Open CtrlP in the last mode used. When having the "--dir" argument, also + reuse the last working directory. + + *:CtrlPRoot* +:CtrlPRoot + This acts like |:CtrlP| with |g:ctrlp_working_path_mode| = 'r' and ignores + the variable's current value. + + *:CtrlPClearCache* +:CtrlPClearCache + Flush the cache for the current working directory. The same as pressing + inside CtrlP. + To enable or disable caching, use the |g:ctrlp_use_caching| option. + + *:CtrlPClearAllCaches* +:CtrlPClearAllCaches + Delete all the cache files saved in |g:ctrlp_cache_dir| location. + +------------------------------------------------------------------------------- +For commands provided by bundled extensions, see |ctrlp-extensions|. + +=============================================================================== +MAPPINGS *ctrlp-mappings* + + *'ctrlp-'* + + Default |Normal| mode mapping to open the CtrlP prompt in find file mode. + +---------------------------------------- +Once inside the prompt:~ + + + Toggle between full-path search and filename only search. + Note: in filename mode, the prompt's base is '>d>' instead of '>>>' + + *'ctrlp-fullregexp'* + Toggle between the string mode and full regexp mode. + Note: in full regexp mode, the prompt's base is 'r>>' instead of '>>>' + + See also: |input-formats| (guide) and |g:ctrlp_regexp_search| (option). + + , 'forward' + + Scroll to the 'next' search mode in the sequence. + + , 'backward' + + Scroll to the 'previous' search mode in the sequence. + + *'ctrlp-autocompletion'* + Auto-complete directory names under the current working directory inside + the prompt. + + + Toggle the focus between the match window and the prompt. + + , + + Exit CtrlP. + +Moving:~ + + , + + Move selection down. + + , + + Move selection up. + + + Move the cursor to the 'start' of the prompt. + + + Move the cursor to the 'end' of the prompt. + + , + , + + Move the cursor one character to the 'left'. + + , + + Move the cursor one character to the 'right'. + +Editing:~ + + , + + Delete the preceding character. + + + Delete the current character. + + + Delete a preceding inner word. + + + Clear the input field. + +Browsing input history:~ + + + Next string in the prompt's history. + + + Previous string in the prompt's history. + +Opening/Creating a file:~ + + + Open the selected file in the 'current' window if possible. + + + Open the selected file in a new 'tab'. + + + Open the selected file in a 'vertical' split. + + , + , + + Open the selected file in a 'horizontal' split. + + + Create a new file and its parent directories. + +Opening multiple files:~ + + + - Mark/unmark a file to be opened with . + - Mark/unmark a file to create a new file in its directory using . + + + - Open files marked by . + - When no file has been marked by , open a console dialog with the + following options: + + Open the selected file: + t - in a tab page. + v - in a vertical split. + h - in a horizontal split. + r - in the current window. + i - as a hidden buffer. + x - (optional) with the function defined in |g:ctrlp_open_func|. + + Other options (not shown): + a - mark all files in the match window. + d - change CtrlP's local working directory to the selected file's + directory and switch to find file mode. + +Function keys:~ + + + - Refresh the match window and purge the cache for the current directory. + - Remove deleted files from the MRU list. + + + - Wipe the MRU list. + - Delete MRU entries marked by . + +Pasting:~ + + , *'ctrlp-pasting'* + + Paste the clipboard content into the prompt. + + + Open a console dialog to paste , , the content of the search + register, the last visual selection, the clipboard or any register into the + prompt. + +Choose your own mappings with |g:ctrlp_prompt_mappings|. + +---------------------------------------- +When inside the match window (press to switch):~ + + a-z + 0-9 + ~^-=;`',.+!@#$%&_(){}[] + Cycle through the lines which have the matching first character. + +=============================================================================== +INPUT FORMATS *ctrlp-input-formats* + +Formats for inputting in the prompt:~ + +a) Simple string. + + E.g. 'abc' is understood internally as 'a[^a]\{-}b[^b]\{-}c' + +b) When in regexp mode, the input string's treated as a Vim's regexp |pattern| + without any modification. + + E.g. 'abc\d*efg' will be read as 'abc\d*efg'. + + See |ctrlp-fullregexp| (keymap) and |g:ctrlp_regexp_search| (option) for + how to enable regexp mode. + +c) End the string with a colon ':' followed by a Vim command to execute that + command after opening the file. If you need to use ':' literally, escape it + with a backslash: '\:'. When opening multiple files, the command will be + executed on each opening file. + + E.g. Use ':45' to jump to line 45. + + Use ':/any\:string' to jump to the first instance of 'any:string'. + + Use ':+setf\ myfiletype|50' to set the filetype to 'myfiletype', then + jump to line 50. + + Use ':diffthis' when opening multiple files to run |:diffthis| on the + first 4 files. + + See also: Vim's |++opt| and |+cmd|. + +d) Submit two dots '..' to go upward the directory tree by 1 level. To go up + multiple levels, use one extra dot for each extra level: +> + Raw input Interpreted as + .. ../ + ... ../../ + .... ../../../ +< + Note: if the parent directories are large and uncached, this can be slow. + + You can also use '@cd path/' to change CtrlP's local working directory. + Use '@cd %:h' to change to the directory of the current file. + +e) Similarly, submit '/' or '\' to find and go to the project's root. + + If the project is large, using a VCS listing command to look for files + might help speeding up the intial scan (see |g:ctrlp_user_command| for more + details). + + Note: d) and e) only work in file, directory and mixed modes. + +f) Type the name of a non-existent file and press to create it. Mark a + file with to create the new file in the same directory as the marked + file. + + E.g. Using 'newdir/newfile.txt' will create a directory named 'newdir' as + well as a file named 'newfile.txt'. + + If an entry 'some/old/dirs/oldfile.txt' is marked with , then + 'newdir' and 'newfile.txt' will be created under 'some/old/dirs'. The + final path will then be 'some/old/dirs/newdir/newfile.txt'. + + Note: use '\' in place of '/' on Windows (if |'shellslash'| is not set). + +g) In filename mode (toggle with ), you can use one primary pattern and + one refining pattern separated by a semicolon. Both patterns work like (a), + or (b) when in regexp mode. + +h) Submit ? to open this help file. + +=============================================================================== +EXTENSIONS *ctrlp-extensions* + +Extensions are optional. To enable an extension, add its name to the variable +g:ctrlp_extensions: > + let g:ctrlp_extensions = ['tag', 'buffertag', 'quickfix', 'dir', 'rtscript', + \ 'undo', 'line', 'changes', 'mixed', 'bookmarkdir'] +< +The order of the items will be the order they appear on the statusline and when +using , . + +Available extensions:~ + + *:CtrlPTag* + * Tag mode:~ + - Name: 'tag' + - Command: ":CtrlPTag" + - Search for a tag within a generated central tags file, and jump to the + definition. Use the Vim's option |'tags'| to specify the names and the + locations of the tags file(s). + E.g. set tags+=doc/tags + + *:CtrlPBufTag* + *:CtrlPBufTagAll* + * Buffer Tag mode:~ + - Name: 'buffertag' + - Commands: ":CtrlPBufTag [buffer]", + ":CtrlPBufTagAll". + - Search for a tag within the current buffer or all listed buffers and jump + to the definition. Requires |exuberant_ctags| or compatible programs. + + *:CtrlPQuickfix* + * Quickfix mode:~ + - Name: 'quickfix' + - Command: ":CtrlPQuickfix" + - Search for an entry in the current quickfix errors and jump to it. + + *:CtrlPDir* + * Directory mode:~ + - Name: 'dir' + - Command: ":CtrlPDir [starting-directory]" + - Search for a directory and change the working directory to it. + - Mappings: + + change the local working directory for CtrlP and keep it open. + + change the global working directory (exit). + + change the local working directory for the current window (exit). + + change the global working directory to CtrlP's current local + working directory (exit). + + *:CtrlPRTS* + * Runtime script mode:~ + - Name: 'rtscript' + - Command: ":CtrlPRTS" + - Search for files (vimscripts, docs, snippets...) in runtimepath. + + *:CtrlPUndo* + * Undo mode:~ + - Name: 'undo' + - Command: ":CtrlPUndo" + - Browse undo history. + + *:CtrlPLine* + * Line mode:~ + - Name: 'line' + - Command: ":CtrlPLine [buffer]" + - Search for a line in all listed buffers or in the specified [buffer]. + + *:CtrlPChange* + *:CtrlPChangeAll* + * Change list mode:~ + - Name: 'changes' + - Commands: ":CtrlPChange [buffer]", + ":CtrlPChangeAll". + - Search for and jump to a recent change in the current buffer or in all + listed buffers. + + *:CtrlPMixed* + * Mixed mode:~ + - Name: 'mixed' + - Command: ":CtrlPMixed" + - Search in files, buffers and MRU files at the same time. + + *:CtrlPBookmarkDir* + *:CtrlPBookmarkDirAdd* + * BookmarkDir mode:~ + - Name: 'bookmarkdir' + - Commands: ":CtrlPBookmarkDir", + ":CtrlPBookmarkDirAdd [directory]". + - Search for a bookmarked directory and change the working directory to it. + - Mappings: + + change the local working directory for CtrlP, keep it open and + switch to find file mode. + + change the global working directory (exit). + + change the local working directory for the current window (exit). + + + - Wipe bookmark list. + - Delete entries marked by . + +---------------------------------------- +Buffer Tag mode options:~ + + *'g:ctrlp_buftag_ctags_bin'* +If ctags isn't in your $PATH, use this to set its location: > + let g:ctrlp_buftag_ctags_bin = '' +< + + *'g:ctrlp_buftag_systemenc'* +Match this with your OS's encoding (not Vim's). The default value mirrors Vim's +global |'encoding'| option: > + let g:ctrlp_buftag_systemenc = &encoding +< + + *'g:ctrlp_buftag_types'* +Use this to set the arguments for ctags, jsctags... for a given filetype: > + let g:ctrlp_buftag_types = '' +< +Examples: > + let g:ctrlp_buftag_types = { + \ 'erlang' : '--language-force=erlang --erlang-types=drmf', + \ 'javascript' : { + \ 'bin': 'jsctags', + \ 'args': '-f -', + \ }, + \ } +< + +=============================================================================== +CUSTOMIZATION *ctrlp-customization* + +Highlighting:~ + * For the CtrlP buffer: + CtrlPNoEntries : the message when no match is found (Error) + CtrlPMatch : the matched pattern (Identifier) + CtrlPLinePre : the line prefix '>' in the match window + CtrlPPrtBase : the prompt's base (Comment) + CtrlPPrtText : the prompt's text (|hl-Normal|) + CtrlPPrtCursor : the prompt's cursor when moving over the text (Constant) + + * In extensions: + CtrlPTabExtra : the part of each line that's not matched against (Comment) + CtrlPBufName : the buffer name an entry belongs to (|hl-Directory|) + CtrlPTagKind : the kind of the tag in buffer-tag mode (|hl-Title|) + CtrlPqfLineCol : the line and column numbers in quickfix mode (Comment) + CtrlPUndoT : the elapsed time in undo mode (|hl-Directory|) + CtrlPUndoBr : the square brackets [] in undo mode (Comment) + CtrlPUndoNr : the undo number inside [] in undo mode (String) + CtrlPUndoSv : the point where the file was saved (Comment) + CtrlPUndoPo : the current position in the undo tree (|hl-Title|) + CtrlPBookmark : the name of the bookmark (Identifier) + +Statuslines:~ + * Highlight groups: + CtrlPMode1 : 'file' or 'path' or 'line', and the current mode (Character) + CtrlPMode2 : 'prt' or 'win', 'regex', the working directory (|hl-LineNr|) + CtrlPStats : the scanning status (Function) + + For rebuilding the statuslines, see |g:ctrlp_status_func|. + +=============================================================================== +MISCELLANEOUS CONFIGS *ctrlp-miscellaneous-configs* + +* Using |wildignore| for |g:ctrlp_user_command|: +> + function! s:wig2cmd() + " Change wildignore into space or | separated groups + " e.g. .aux .out .toc .jpg .bmp .gif + " or .aux$\|.out$\|.toc$\|.jpg$\|.bmp$\|.gif$ + let pats = ['[*\/]*\([?_.0-9A-Za-z]\+\)\([*\/]*\)\(\\\@) + +* A standalone function to set the working directory to the project's root, or + to the parent directory of the current file if a root can't be found: +> + function! s:setcwd() + let cph = expand('%:p:h', 1) + if cph =~ '^.\+://' | retu | en + for mkr in ['.git/', '.hg/', '.svn/', '.bzr/', '_darcs/', '.vimprojects'] + let wd = call('find'.(mkr =~ '/$' ? 'dir' : 'file'), [mkr, cph.';']) + if wd != '' | let &acd = 0 | brea | en + endfo + exe 'lc!' fnameescape(wd == '' ? cph : substitute(wd, mkr.'$', '.', '')) + endfunction + + autocmd BufEnter * call s:setcwd() +< +(requires Vim 7.1.299+) + +* Using a |count| to invoke different commands using the same mapping: +> + let g:ctrlp_cmd = 'exe "CtrlP".get(["", "Buffer", "MRU"], v:count)' +< + +=============================================================================== +CREDITS *ctrlp-credits* + +Developed by Kien Nguyen . Distributed under Vim's |license|. + +Project's homepage: http://kien.github.com/ctrlp.vim +Git repository: https://github.com/kien/ctrlp.vim +Mercurial repository: https://bitbucket.org/kien/ctrlp.vim + +------------------------------------------------------------------------------- +Thanks to everyone that has submitted ideas, bug reports or helped debugging on +gibhub, bitbucket, and through email. + +Special thanks:~ + + * Woojong Koh + * Simon Ruderich + * Yasuhiro Matsumoto + * Ken Earley + * Kyo Nagashima + * Zak Johnson + * Diego Viola + * Piet Delport + * Thibault Duplessis + * Kent Sibilev + * Tacahiroy + * Luca Pette + * Seth Fowler + * Lowe Thiderman + * Christopher Fredén + * Zahary Karadjov + * Jo De Boeck + * Rudi Grinberg + * Timothy Mellor + +=============================================================================== +CHANGELOG *ctrlp-changelog* + + + Combine *g:ctrlp_match_window_bottom* *g:ctrlp_match_window_reversed* and + *g:ctrlp_max_height* into |g:ctrlp_match_window|. + + New option: |g:ctrlp_match_window|. + +Before 2012/11/30~ + + + New options: |g:ctrlp_abbrev|, + |g:ctrlp_key_loop|, + |g:ctrlp_open_func|, + |g:ctrlp_tabpage_position|, + |g:ctrlp_mruf_save_on_update| + + Rename: + *g:ctrlp_dotfiles* -> |g:ctrlp_show_hidden|. + + Change |g:ctrlp_switch_buffer|'s and |g:ctrlp_working_path_mode|'s type + (old values still work). + + New key for |g:ctrlp_user_command| when it's a Dictionary: 'ignore'. + +Before 2012/06/15~ + + + New value for |g:ctrlp_follow_symlinks|: 2. + + New value for |g:ctrlp_open_multiple_files|: 'j'. + + Allow using , , to open files marked by . + + Extend '..' (|ctrlp-input-formats| (d)) + + New input format: '@cd' (|ctrlp-input-formats| (d)) + +Before 2012/04/30~ + + + New option: |g:ctrlp_mruf_default_order| + + New feature: Bookmarked directories extension. + + New commands: |:CtrlPBookmarkDir| + |:CtrlPBookmarkDirAdd| + +Before 2012/04/15~ + + + New option: |g:ctrlp_buffer_func|, callback functions for CtrlP buffer. + + Remove: g:ctrlp_mruf_last_entered, make it a default for MRU mode. + + New commands: |:CtrlPLastMode|, open CtrlP in the last mode used. + |:CtrlPMixed|, search in files, buffers and MRU files. + +Before 2012/03/31~ + + + New options: |g:ctrlp_default_input|, default input when entering CtrlP. + |g:ctrlp_match_func|, allow using a custom fuzzy matcher. + + Rename: + *ClearCtrlPCache* -> |CtrlPClearCache| + *ClearAllCtrlPCaches* -> |CtrlPClearAllCaches| + *ResetCtrlP* -> |CtrlPReload| + +Before 2012/03/02~ + + + Rename: + *g:ctrlp_regexp_search* -> |g:ctrlp_regexp|, + *g:ctrlp_dont_split* -> |g:ctrlp_reuse_window|, + *g:ctrlp_jump_to_buffer* -> |g:ctrlp_switch_buffer|. + + Rename and tweak: + *g:ctrlp_open_multi* -> |g:ctrlp_open_multiple_files|. + + Deprecate *g:ctrlp_highlight_match* + + Extend |g:ctrlp_user_command| to support multiple commands. + + New option: |g:ctrlp_mruf_last_entered| change MRU to Recently-Entered. + +Before 2012/01/15~ + + + New mapping: Switch and . is now used for completion + of directory names under the current working directory. + + New options: |g:ctrlp_arg_map| for , to accept an argument. + |g:ctrlp_status_func| custom statusline. + |g:ctrlp_mruf_relative| show only MRU files inside cwd. + + Extend g:ctrlp_open_multi with new optional values: tr, hr, vr. + + Extend |g:ctrlp_custom_ignore| to specifically filter dir, file and link. + +Before 2012/01/05~ + + + New feature: Buffer Tag extension. + + New commands: |:CtrlPBufTag|, |:CtrlPBufTagAll|. + + New options: |g:ctrlp_cmd|, + |g:ctrlp_custom_ignore| + +Before 2011/11/30~ + + + New features: Tag, Quickfix and Directory extensions. + + New commands: |:CtrlPTag|, |:CtrlPQuickfix|, |:CtrlPDir|. + + New options: |g:ctrlp_use_migemo|, + |g:ctrlp_lazy_update|, + |g:ctrlp_follow_symlinks| + +Before 2011/11/13~ + + + New special input: '/' and '\' find root (|ctrlp-input-formats| (e)) + + Remove ctrlp#SetWorkingPath(). + + Remove *g:ctrlp_mru_files* and make MRU mode permanent. + + Extend g:ctrlp_open_multi, add new ways to open files. + + New option: g:ctrlp_dont_split, + |g:ctrlp_mruf_case_sensitive| + +Before 2011/10/30~ + + + New feature: Support for custom extensions. + also removes non-existent files from MRU list. + + New option: g:ctrlp_jump_to_buffer + +Before 2011/10/12~ + + + New features: Open multiple files. + Pass Vim's |++opt| and |+cmd| to the opening file + (|ctrlp-input-formats| (c)) + Auto-complete each dir for |:CtrlP| [starting-directory] + + New mappings: mark/unmark a file to be opened with . + open all marked files. + + New option: g:ctrlp_open_multi + + Remove *g:ctrlp_persistent_input* *g:ctrlp_live_update* and . + +Before 2011/09/29~ + + + New mappings: , next/prev string in the input history. + create a new file and its parent dirs. + + New options: |g:ctrlp_open_new_file|, + |g:ctrlp_max_history| + + Added a new open-in-horizontal-split mapping: + +Before 2011/09/19~ + + + New command: ResetCtrlP + + New options: |g:ctrlp_max_files|, + |g:ctrlp_max_depth|, + g:ctrlp_live_update + + New mapping: + +Before 2011/09/12~ + + + Ability to cycle through matched lines in the match window. + + Extend the behavior of g:ctrlp_persistent_input + + Extend the behavior of |:CtrlP| + + New options: |g:ctrlp_dotfiles|, + |g:ctrlp_clear_cache_on_exit|, + g:ctrlp_highlight_match, + |g:ctrlp_user_command| + + New special input: '..' (|ctrlp-input-formats| (d)) + + New mapping: . + + New commands: |:CtrlPCurWD|, + |:CtrlPCurFile|, + |:CtrlPRoot| + + + New feature: Search in most recently used (MRU) files + + New mapping: . + + Extended the behavior of . + + New options: g:ctrlp_mru_files, + |g:ctrlp_mruf_max|, + |g:ctrlp_mruf_exclude|, + |g:ctrlp_mruf_include| + + New command: |:CtrlPMRU| + +First public release: 2011/09/06~ + +=============================================================================== +vim:ft=help:et:ts=2:sw=2:sts=2:norl diff --git a/vim/bundle/ctrlp.vim/plugin/ctrlp.vim b/vim/bundle/ctrlp.vim/plugin/ctrlp.vim new file mode 100644 index 0000000..c7b8fa3 --- /dev/null +++ b/vim/bundle/ctrlp.vim/plugin/ctrlp.vim @@ -0,0 +1,68 @@ +" ============================================================================= +" File: plugin/ctrlp.vim +" Description: Fuzzy file, buffer, mru, tag, etc finder. +" Author: Kien Nguyen +" ============================================================================= +" GetLatestVimScripts: 3736 1 :AutoInstall: ctrlp.zip + +if ( exists('g:loaded_ctrlp') && g:loaded_ctrlp ) || v:version < 700 || &cp + fini +en +let g:loaded_ctrlp = 1 + +let [g:ctrlp_lines, g:ctrlp_allfiles, g:ctrlp_alltags, g:ctrlp_alldirs, + \ g:ctrlp_allmixes, g:ctrlp_buftags, g:ctrlp_ext_vars, g:ctrlp_builtins] + \ = [[], [], [], [], {}, {}, [], 2] + +if !exists('g:ctrlp_map') | let g:ctrlp_map = '' | en +if !exists('g:ctrlp_cmd') | let g:ctrlp_cmd = 'CtrlP' | en + +com! -n=? -com=dir CtrlP cal ctrlp#init(0, { 'dir': }) +com! -n=? -com=dir CtrlPMRUFiles cal ctrlp#init(2, { 'dir': }) + +com! -bar CtrlPBuffer cal ctrlp#init(1) +com! -n=? CtrlPLastMode cal ctrlp#init(-1, { 'args': }) + +com! -bar CtrlPClearCache cal ctrlp#clr() +com! -bar CtrlPClearAllCaches cal ctrlp#clra() + +com! -bar ClearCtrlPCache cal ctrlp#clr() +com! -bar ClearAllCtrlPCaches cal ctrlp#clra() + +com! -bar CtrlPCurWD cal ctrlp#init(0, { 'mode': '' }) +com! -bar CtrlPCurFile cal ctrlp#init(0, { 'mode': 'c' }) +com! -bar CtrlPRoot cal ctrlp#init(0, { 'mode': 'r' }) + +if g:ctrlp_map != '' && !hasmapto(':'.g:ctrlp_cmd.'', 'n') + exe 'nn ' g:ctrlp_map ':'.g:ctrlp_cmd.'' +en + +cal ctrlp#mrufiles#init() + +com! -bar CtrlPTag cal ctrlp#init(ctrlp#tag#id()) +com! -bar CtrlPQuickfix cal ctrlp#init(ctrlp#quickfix#id()) + +com! -n=? -com=dir CtrlPDir + \ cal ctrlp#init(ctrlp#dir#id(), { 'dir': }) + +com! -n=? -com=buffer CtrlPBufTag + \ cal ctrlp#init(ctrlp#buffertag#cmd(0, )) + +com! -bar CtrlPBufTagAll cal ctrlp#init(ctrlp#buffertag#cmd(1)) +com! -bar CtrlPRTS cal ctrlp#init(ctrlp#rtscript#id()) +com! -bar CtrlPUndo cal ctrlp#init(ctrlp#undo#id()) + +com! -n=? -com=buffer CtrlPLine + \ cal ctrlp#init(ctrlp#line#cmd(1, )) + +com! -n=? -com=buffer CtrlPChange + \ cal ctrlp#init(ctrlp#changes#cmd(0, )) + +com! -bar CtrlPChangeAll cal ctrlp#init(ctrlp#changes#cmd(1)) +com! -bar CtrlPMixed cal ctrlp#init(ctrlp#mixed#id()) +com! -bar CtrlPBookmarkDir cal ctrlp#init(ctrlp#bookmarkdir#id()) + +com! -n=? -com=dir CtrlPBookmarkDirAdd + \ cal ctrlp#call('ctrlp#bookmarkdir#add', ) + +" vim:ts=2:sw=2:sts=2 diff --git a/vim/bundle/ctrlp.vim/readme.md b/vim/bundle/ctrlp.vim/readme.md new file mode 100644 index 0000000..bcd07c7 --- /dev/null +++ b/vim/bundle/ctrlp.vim/readme.md @@ -0,0 +1,88 @@ +# ctrlp.vim +Full path fuzzy __file__, __buffer__, __mru__, __tag__, __...__ finder for Vim. + +* Written in pure Vimscript for MacVim, gVim and Vim 7.0+. +* Full support for Vim's regexp as search patterns. +* Built-in Most Recently Used (MRU) files monitoring. +* Built-in project's root finder. +* Open multiple files at once. +* Create new files and directories. +* [Extensible][2]. + +![ctrlp][1] + +## Basic Usage +* Run `:CtrlP` or `:CtrlP [starting-directory]` to invoke CtrlP in find file mode. +* Run `:CtrlPBuffer` or `:CtrlPMRU` to invoke CtrlP in find buffer or find MRU file mode. +* Run `:CtrlPMixed` to search in Files, Buffers and MRU files at the same time. + +Check `:help ctrlp-commands` and `:help ctrlp-extensions` for other commands. + +##### Once CtrlP is open: +* Press `` to purge the cache for the current directory to get new files, remove deleted files and apply new ignore options. +* Press `` and `` to cycle between modes. +* Press `` to switch to filename only search instead of full path. +* Press `` to switch to regexp mode. +* Use ``, `` or the arrow keys to navigate the result list. +* Use `` or ``, `` to open the selected entry in a new tab or in a new split. +* Use ``, `` to select the next/previous string in the prompt's history. +* Use `` to create a new file and its parent directories. +* Use `` to mark/unmark multiple files and `` to open them. + +Run `:help ctrlp-mappings` or submit `?` in CtrlP for more mapping help. + +* Submit two or more dots `..` to go up the directory tree by one or multiple levels. +* End the input string with a colon `:` followed by a command to execute it on the opening file(s): +Use `:25` to jump to line 25. +Use `:diffthis` when opening multiple files to run `:diffthis` on the first 4 files. + +## Basic Options +* Change the default mapping and the default command to invoke CtrlP: + + ```vim + let g:ctrlp_map = '' + let g:ctrlp_cmd = 'CtrlP' + ``` + +* When invoked, unless a starting directory is specified, CtrlP will set its local working directory according to this variable: + + ```vim + let g:ctrlp_working_path_mode = 'ra' + ``` + + `'c'` - the directory of the current file. + `'r'` - the nearest ancestor that contains one of these directories or files: `.git` `.hg` `.svn` `.bzr` `_darcs` + `'a'` - like c, but only if the current working directory outside of CtrlP is not a direct ancestor of the directory of the current file. + `0` or `''` (empty string) - disable this feature. + + Define additional root markers with the `g:ctrlp_root_markers` option. + +* Exclude files and directories using Vim's `wildignore` and CtrlP's own `g:ctrlp_custom_ignore`: + + ```vim + set wildignore+=*/tmp/*,*.so,*.swp,*.zip " MacOSX/Linux + set wildignore+=*\\tmp\\*,*.swp,*.zip,*.exe " Windows + + let g:ctrlp_custom_ignore = '\v[\/]\.(git|hg|svn)$' + let g:ctrlp_custom_ignore = { + \ 'dir': '\v[\/]\.(git|hg|svn)$', + \ 'file': '\v\.(exe|so|dll)$', + \ 'link': 'some_bad_symbolic_links', + \ } + ``` + +* Use a custom file listing command: + + ```vim + let g:ctrlp_user_command = 'find %s -type f' " MacOSX/Linux + let g:ctrlp_user_command = 'dir %s /-n /b /s /a-d' " Windows + ``` + +Check `:help ctrlp-options` for other options. + +## Installation +Use your favorite method or check the homepage for a [quick installation guide][3]. + +[1]: http://i.imgur.com/yIynr.png +[2]: https://github.com/kien/ctrlp.vim/tree/extensions +[3]: http://kien.github.com/ctrlp.vim#installation diff --git a/vim/bundle/indentLine/.gitattributes b/vim/bundle/indentLine/.gitattributes new file mode 100644 index 0000000..412eeda --- /dev/null +++ b/vim/bundle/indentLine/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/vim/bundle/indentLine/.gitignore b/vim/bundle/indentLine/.gitignore new file mode 100644 index 0000000..e9b9a75 --- /dev/null +++ b/vim/bundle/indentLine/.gitignore @@ -0,0 +1,171 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Rr]elease/ +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.vspscc +.builds +*.dotCover + +## TODO: If you have NuGet Package Restore enabled, uncomment this +#packages/ + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf + +# Visual Studio profiler +*.psess +*.vsp + +# ReSharper is a .NET coding add-in +_ReSharper* + +# Installshield output folder +[Ee]xpress + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish + +# Others +[Bb]in +[Oo]bj +sql +TestResults +*.Cache +ClientBin +stylecop.* +~$* +*.dbmdl +Generated_Code #added for RIA/Silverlight projects + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML + + + +############ +## Windows +############ + +# Windows image file caches +Thumbs.db + +# Folder config file +Desktop.ini + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +dist +build +eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg + +# Mac crap +.DS_Store + + +############# +## Vim +############# + +# Exclude auto generated vim doc tags. +doc/tags diff --git a/vim/bundle/indentLine/README.md b/vim/bundle/indentLine/README.md new file mode 100644 index 0000000..9aa5052 --- /dev/null +++ b/vim/bundle/indentLine/README.md @@ -0,0 +1,58 @@ +indentLine +========== + +This plugin is used for displaying thin vertical lines at each indentation level for code indented with spaces. For code indented with tabs I think there is no need to support it, because you can use `:set list lcs=tab:\|\ ` (here is a space). + +## Requirements +This plugin takes advantage of the newly provided `conceal` feature in Vim 7.3, so this plugin will not work with lower versions of Vim. + +## Installation +To install the plugin just put the plugin files in your `~/.vim` (Linux) or `~/vimfiles` (Windows). + +If you use a plugin manager you can put the whole directory into your `~/.vim/bundle/` directory ([Pathogen][pathogen]) or add the line `Bundle 'Yggdroot/indentLine'` to your `.vimrc` ([Vundle][vundle]). + +## Customization +You can change the color of indentLines: +for Vim, set `g:indentLine_color_term` in your `.vimrc`, e.g. `let g:indentLine_color_term = 239`, +for GVim, set `g:indentLine_color_gui` in your `.vimrc`, e.g. `let g:indentLine_color_gui = '#A4E57E'` +for none X terminal, set `g:indentLine_color_tty_light` and `g:indentLine_color_tty_dark` in your `.vimrc`. e.g. `let g:indentLine_color_tty_light = 7`(default: 4), `let g:indentLine_color_dark = 1`(default: 2). + +You can also change the indentLine char: +for both Vim and GVim, set `let g:indentLine_char = 'c'` where `'c'` can be any ASCII character. You can also use one of `¦`, `┆`, `︙` or `│` to display more beautiful lines. However, these characters will only work with files whose encoding is UTF-8. + +### Font patching +If you find all the standard unicode and ASCII characters too obtrusive, you might consider patching your font with the [indentLine-dotted-guide.eps][glyph] glyph provided. [FontForge][fontforge] makes the process amazingly simple: + + 1. Download and install FontForge. + 2. Locate and open your terminal/gVim font. + 3. Open the font in FontForge, choose __Goto__ from the __View__ menu and select _Private Use Area_ from the drop down box. + 4. In the private use area, locate a blank spot for the glyph. Make a note of the code, e.g. `U+E0A3`. + 5. Double-click the selected code point to open the font drawing tool. + 6. From the __File__ menu, select __Import...__ and locate the _indentLine-dotted-guide.eps_ file. + 7. Once imported, choose __File__ -> __Generate Fonts__ and choose a location and file type for the new font. + +Once completed, your new font will contain the more subtle dotted guide and all you have to do is set that glyph to `g:indentLine_char` in your `.vimrc` file. + +[glyph]: glyph/indentLine-dotted-guide.eps +[fontforge]: http://fontforge.github.io/ + +## Self promotion +If you think this script is helpful, follow the [GitHub repository][repository], and don't forget to vote for it on Vim.org! ([vimscript #4354][script]). + +[pathogen]: https://github.com/tpope/vim-pathogen +[vundle]: https://github.com/gmarik/vundle +[repository]: https://github.com/Yggdroot/indentLine +[script]: http://www.vim.org/scripts/script.php?script_id=4354 + +## Screenshots + +### Vertical bars +![Screenshot](http://i.imgur.com/KVi0T.jpg) + +### Patched font +![Screenshot](http://i.imgur.com/2ZA7oaZ.png) + +### Leading Spaces +![Screenshot](http://i.imgur.com/tLYkb79.png) + +![Screenshot](http://i.imgur.com/07Atrrs.png) diff --git a/vim/bundle/indentLine/after/plugin/indentLine.vim b/vim/bundle/indentLine/after/plugin/indentLine.vim new file mode 100644 index 0000000..3851ffe --- /dev/null +++ b/vim/bundle/indentLine/after/plugin/indentLine.vim @@ -0,0 +1,216 @@ +" Script Name: indentLine.vim +" Author: Yggdroot +" +" Description: To show the indention levels with thin vertical lines + +scriptencoding utf-8 + +if ! has("conceal") || exists("g:indentLine_loaded") + finish +endif +let g:indentLine_loaded = 1 + + +let g:indentLine_char = get(g:,'indentLine_char',(&encoding is# "utf-8" && &term isnot# "linux" ? '¦' : '|')) +let g:indentLine_first_char = get(g:,'indentLine_first_char',(&encoding is# "utf-8" && &term isnot# "linux" ? '¦' : '|')) +let g:indentLine_indentLevel = get(g:,'indentLine_indentLevel',10) +let g:indentLine_enabled = get(g:,'indentLine_enabled',1) +let g:indentLine_fileType = get(g:,'indentLine_fileType',[]) +let g:indentLine_fileTypeExclude = get(g:,'indentLine_fileTypeExclude',[]) +let g:indentLine_bufNameExclude = get(g:,'indentLine_bufNameExclude',[]) +let g:indentLine_showFirstIndentLevel = get(g:,'indentLine_showFirstIndentLevel',0) +let g:indentLine_maxLines = get(g:,'indentLine_maxLines',3000) +let g:indentLine_setColors = get(g:,'indentLine_setColors',1) +let g:indentLine_faster = get(g:,'indentLine_faster',0) +let g:indentLine_leadingSpaceChar = get(g:,'indentLine_leadingSpaceChar',(&encoding is# "utf-8" && &term isnot# "linux" ? '˰' : '.')) +let g:indentLine_leadingSpaceEnabled = get(g:,'indentLine_leadingSpaceEnabled',0) + +"{{{1 function! s:InitColor() +function! s:InitColor() + if ! g:indentLine_setColors + return + endif + + if ! exists("g:indentLine_color_term") + if &background is# "light" + let term_color = 249 + else + let term_color = 239 + endif + else + let term_color = g:indentLine_color_term + endif + + if ! exists("g:indentLine_color_gui") + if &background is# "light" + let gui_color = "Grey70" + else + let gui_color = "Grey30" + endif + else + let gui_color = g:indentLine_color_gui + endif + + execute "highlight Conceal ctermfg=" . term_color . " ctermbg=NONE" + execute "highlight Conceal guifg=" . gui_color . " guibg=NONE" + + if &term is# "linux" + if &background is# "light" + let tty_color = exists("g:indentLine_color_tty_light") ? g:indentLine_color_tty_light : 4 + else + let tty_color = exists("g:indentLine_color_tty_dark") ? g:indentLine_color_tty_dark : 2 + endif + execute "highlight Conceal cterm=bold ctermfg=" . tty_color . " ctermbg=NONE" + endif +endfunction + +"{{{1 function! s:SetIndentLine() +function! s:SetIndentLine() + let b:indentLine_enabled = 1 + let space = &l:shiftwidth is 0 ? &l:tabstop : &l:shiftwidth + + if g:indentLine_showFirstIndentLevel + execute 'syntax match IndentLine /^ / containedin=ALL conceal cchar=' . g:indentLine_first_char + endif + + if g:indentLine_faster + execute 'syntax match IndentLineSpace /^\s\+/ containedin=ALL contains=IndentLine' + execute 'syntax match IndentLine / \{'.(space-1).'}\zs / contained conceal cchar=' . g:indentLine_char + execute 'syntax match IndentLine /\t\zs / contained conceal cchar=' . g:indentLine_char + else + let pattern = line('$') < g:indentLine_maxLines ? 'v' : 'c' + for i in range(space+1, space * g:indentLine_indentLevel + 1, space) + execute 'syntax match IndentLine /\%(^\s\+\)\@<=\%'.i.pattern.' / containedin=ALL conceal cchar=' . g:indentLine_char + endfor + endif +endfunction + +"{{{1 function! s:ResetWidth(...) +function! s:ResetWidth(...) + if 0 < a:0 + let &l:shiftwidth = a:1 + endif + + if b:indentLine_enabled + syntax clear IndentLine + endif + call s:SetIndentLine() +endfunction + +"{{{1 function! s:IndentLinesEnable() +function! s:IndentLinesEnable() + call s:SetIndentLine() +endfunction + +"{{{1 function! s:IndentLinesDisable() +function! s:IndentLinesDisable() + if b:indentLine_enabled + let b:indentLine_enabled = 0 + syntax clear IndentLine + endif +endfunction + +"{{{1 function! s:IndentLinesToggle() +function! s:IndentLinesToggle() + if b:indentLine_enabled + call s:IndentLinesDisable() + else + call s:IndentLinesEnable() + endif +endfunction + +"{{{1 function! s:Setup() +function! s:Setup() + if index(g:indentLine_fileTypeExclude, &filetype) isnot -1 + return + endif + + if len(g:indentLine_fileType) isnot 0 && index(g:indentLine_fileType, &filetype) is -1 + return + end + + for name in g:indentLine_bufNameExclude + if matchstr(bufname(''), name) is bufname('') + return + endif + endfor + + if ! exists("b:indentLine_bufNr") + let b:indentLine_bufNr = bufnr('%') + let g:indentLine_bufNr = bufnr('%') + elseif g:indentLine_bufNr != bufnr('%') && &hidden + let g:indentLine_bufNr = bufnr('%') + return + endif + + if ! exists("g:indentLine_noConcealCursor") + setlocal concealcursor=inc + endif + setlocal conceallevel=2 + + if &filetype is# "" + call s:InitColor() + endif + + if ! exists("b:indentLine_enabled") + let b:indentLine_enabled = g:indentLine_enabled + endif + + if ! exists("b:indentLine_leadingSpaceEnabled") + let b:indentLine_leadingSpaceEnabled = g:indentLine_leadingSpaceEnabled + endif + + if b:indentLine_enabled + call s:SetIndentLine() + endif + + if b:indentLine_leadingSpaceEnabled + call s:LeadingSpaceEnable() + endif +endfunction + +"{{{1 function! s:LeadingSpaceEnable() +function! s:LeadingSpaceEnable() + if g:indentLine_faster + echoerr 'LeadingSpace can not be shown when g:indentLine_faster == 1' + return + endif + let b:indentLine_leadingSpaceEnabled = 1 + execute 'syntax match IndentLineLeadingSpace /\%(^\s*\)\@<= / containedin=ALLBUT,IndentLine conceal cchar=' . g:indentLine_leadingSpaceChar +endfunction + +"{{{1 function! s:LeadingSpaceDisable() +function! s:LeadingSpaceDisable() + if b:indentLine_leadingSpaceEnabled + let b:indentLine_leadingSpaceEnabled = 0 + syntax clear IndentLineLeadingSpace + endif +endfunction + +"{{{1 function! s:LeadingSpaceToggle() +function! s:LeadingSpaceToggle() + if b:indentLine_leadingSpaceEnabled + call s:LeadingSpaceDisable() + else + call s:LeadingSpaceEnable() + endif +endfunction + +"{{{1 augroup indentLine +augroup indentLine + autocmd! + autocmd BufWinEnter * call Setup() + autocmd BufRead,BufNewFile,ColorScheme,Syntax * call InitColor() +augroup END + +"{{{1 commands +command! -nargs=? IndentLinesReset call ResetWidth() +command! IndentLinesToggle call IndentLinesToggle() +command! IndentLinesEnable call IndentLinesEnable() +command! IndentLinesDisable call IndentLinesDisable() +command! LeadingSpaceEnable call LeadingSpaceEnable() +command! LeadingSpaceDisable call LeadingSpaceDisable() +command! LeadingSpaceToggle call LeadingSpaceToggle() + +" vim:et:ts=4:sw=4:fdm=marker:fmr={{{,}}} + diff --git a/vim/bundle/indentLine/doc/indentLine.txt b/vim/bundle/indentLine/doc/indentLine.txt new file mode 100644 index 0000000..aca7399 --- /dev/null +++ b/vim/bundle/indentLine/doc/indentLine.txt @@ -0,0 +1,166 @@ +*indentLine.txt* Show vertical lines for indent with conceal feature + +CONTENTS *indentLine-contents* +Introduction |indentLine-introduction| +Config |indentLine-config| +Variables |indentLine-variables| +Commands |indentLine-commands| +FAQ |indentLine-faq| +Changelog |indentLine-changelog| +Credits |indentLine-credits| +============================================================================== +INTRODUCTION *indentLine-introduction* +This plugin is used for displaying thin vertical lines at each indentation +level for code indented with spaces. For code indented with tabs, I think +there is no need to support it, using :set list lcs=tab:\|\ (here is a space) +can achieve it. +============================================================================== +CONFIG *indentLine-config* + +============================================================================== +VARIABLES *indentLine-variables* + +g:indentLine_loaded *g:loaded_indentLine* + Whether load indentLine plugin. + Default value is 0. + +g:indentLine_char *g:indentLine_char* + Specify a character to be used as indent line. + You also can use other characters: + | ¦ ┆ │ + Default value is "|". + +g:indentLine_first_char *g:indentLine_first_char* + Specify a character to be used as indent line + on the first level. + You also can use other characters: + | ¦ ┆ │ + Default value is "|". + +g:indentLine_color_term *g:indentLine_color_term* + Specify terminal vim indent line color. + e.g. let g:indentLine_color_term = 239 + + +g:indentLine_color_gui *g:indentLine_color_gui* + Specify GUI vim indent line color. + e.g. let g:indentLine_color_gui = '#A4E57E' + +g:indentLine_color_tty_light *g:indentLine_color_tty_light* + Specify none X terminal vim indent line color in bg light. + default: 4 + e.g. let g:indentLine_color_tty_light = 7 + +g:indentLine_color_tty_dark *g:indentLine_color_tty_dark* + Specify none X terminal vim indent line color in bg dark. + default: 2 + e.g. let g:indentLine_color_tty_dark = 1 + +g:indentLine_indentLevel *g:indentLine_indentLevel* + Specify how much indent level do you want to use for + indentLine. Most program will not has bigger indent level than + 10. + Default value is 10. + +g:indentLine_showFirstIndentLevel *g:indentLine_showFirstIndentLevel* + Specify whether the first indent level should be shown. + This is useful if you use indentLine in comination with + |listchars| in order to show tabs. + Default value is 0. + +g:indentLine_enabled *g:indentLine_enabled* + Specify whether to enable indentLine plugin by default. + If value is not 0, the plugin is on by default, otherwise off. + Default value is 1. + +g:indentLine_fileType *g:indentLine_fileType* + This variable specify a list of file types. + When opening these types of files, the plugin is enabled by + default. + e.g. let g:indentLine_fileType = ['c', 'cpp'] + Default value is [] which means all file types is supported. + +g:indentLine_fileTypeExclude *g:indentLine_fileTypeExclude* + This variable specify a list of file types. + When opening these types of files, the plugin is disabled by + default. + e.g. let g:indentLine_fileTypeExclude = ['text', 'sh'] + Default value is [] which means no file types is excluded. + +g:indentLine_bufNameExclude *g:indentLine_bufNameExclude* + This variable specify a list of buffer names, which can be + regular expression. If the buffer's name fall into this list, + the indentLine won't display. + e.g. let g:indentLine_bufNameExclude = ['_.*', 'NERD_tree.*'] + Default value is []. + +g:indentLine_maxLines *g:indentLine_maxLines* + This variable specify a number, when the number of buffer's + lines exceed it, the plugin try to use another pattern to make + the performance better. + Default value is 3000. + +g:indentLine_faster *g:indentLine_faster* + If you want the performance better, you can set the value as + 1, default value is 0. But better performance may bring little + issue with it. + +g:indentLine_noConcealCursor *g:indentLine_noConcealCursor* + This variable toggles cursor lines behavior. If variable + exists, then cursorline will be above conceal chars. + Default value is not set. + +g:indentLine_leadingSpaceChar *g:indentLine_leadingSpaceChar* + Specify a character to show for leading spaces. + You also can use other characters:˽˰·· + e.g. let g:indentLine_leadingSpaceChar = '·' + +g:indentLine_leadingSpaceEnabled *g:indentLine_leadingSpaceEnabled* + Specify whether to show leading spaces by default. + Default value is 0. +============================================================================== +COMMANDS *indentLine-commands* + +*IndentLinesReset* [number] + if 'shiftwidth' changes, using this command can redraw the + indentLines. number is optional, it means the width between + two indent level, if ommited, value of 'shiftwidth' is used. + +*IndentLinesToggle* + toggle the indent lines of the current buffer. + +*IndentLinesEnable* + enable the indent lines of the current buffer. + +*IndentLinesDisable* + disable the indent lines of the current buffer. + +*LeadingSpaceEnable* + enable the leading spaces of the current buffer. + +*LeadingSpaceDisable* + disable the leading spaces of the current buffer. + +*LeadingSpaceToggle* + toggle the leading spaces of the current buffer. +============================================================================== +FAQ *indentLine-faq* + +Q. How can I make the indent line visuall similar to the line used in Sublime + Text 2? + +A. Use let g:indentLine_char = '┊' + +============================================================================== +CHANGELOG *indentLine-changelog* + +============================================================================== +CREDITS *indentLine-credits* + +Thanks to the following people for suggestions and patches: + +NagatoPain +Salman Halim +Christophe +============================================================================== +vim:tw=78:ts=8:ft=help:norl diff --git a/vim/bundle/indentLine/glyph/indentLine-dotted-guide.eps b/vim/bundle/indentLine/glyph/indentLine-dotted-guide.eps new file mode 100644 index 0000000..146309f --- /dev/null +++ b/vim/bundle/indentLine/glyph/indentLine-dotted-guide.eps @@ -0,0 +1,169 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%BoundingBox: 2.96296 -488.5 170.5 1988.5 +%%Pages: 0 +%%Title: uniE0A3 from DejaVuSansMonoForPowerline +%%Creator: FontForge +%%Author: Andy Earnshaw +%%CreationDate: 22:53 1-8-2014 +%%EndComments +%%BeginPreview: 5 74 4 74 +%013100 +%3EFE40 +%BFFFD0 +%DFFFE0 +%7FFF80 +%059600 +%000000 +%000000 +%000000 +%000000 +%048500 +%6FFF80 +%CFFFE0 +%CFFFD0 +%4EFE50 +%014100 +%000000 +%000000 +%000000 +%000000 +%19DA10 +%9FFFB0 +%DFFFE0 +%AFFFB0 +%1AEB20 +%000000 +%000000 +%000000 +%000000 +%013100 +%3EFE40 +%BFFFD0 +%DFFFE0 +%7FFF80 +%059600 +%000000 +%000000 +%000000 +%000000 +%048500 +%6FFF80 +%CFFFE0 +%CFFFD0 +%4EFF50 +%014100 +%000000 +%000000 +%000000 +%000000 +%19DA10 +%9FFFB0 +%DFFFE0 +%AFFFB0 +%1AEB20 +%000000 +%000000 +%000000 +%000000 +%013100 +%3EFE40 +%BFFFD0 +%DFFFE0 +%7FFF80 +%059600 +%000000 +%000000 +%000000 +%000000 +%048500 +%6FFF80 +%CFFFE0 +%CFFFD0 +%4EFF50 +%014100 +%%EndPreview +%%EndProlog +%%Page "uniE0A3" 1 +gsave newpath + 3 -405 moveto + 3.66667 -381.667 12 -362 28 -346 curveto + 44 -330 63.6667 -321.833 87 -321.5 curveto + 110.333 -321.833 130 -330 146 -346 curveto + 162 -362 170.167 -381.667 170.5 -405 curveto + 170.167 -428.333 162 -448 146 -464 curveto + 130 -480 110.333 -488.167 87 -488.5 curveto + 63.6667 -488.167 44 -480 28 -464 curveto + 10.6667 -446.667 2.33333 -427 3 -405 curveto + closepath + 3 255 moveto + 3.66667 278.333 12 298 28 314 curveto + 44 330 63.6667 338.167 87 338.5 curveto + 110.333 338.167 130 330 146 314 curveto + 162 298 170.167 278.333 170.5 255 curveto + 170.167 231.667 162 212 146 196 curveto + 130 180 110.333 171.833 87 171.5 curveto + 63.6667 171.833 44 180 28 196 curveto + 10.6667 213.333 2.33333 233 3 255 curveto + closepath + 3 -75 moveto + 3.66667 -51.6667 12 -32 28 -16 curveto + 44 0 63.6667 8.16667 87 8.5 curveto + 110.333 8.16667 130 0 146 -16 curveto + 162 -32 170.167 -51.6667 170.5 -75 curveto + 170.167 -98.3333 162 -118 146 -134 curveto + 130 -150 110.333 -158.167 87 -158.5 curveto + 63.6667 -158.167 44 -150 28 -134 curveto + 10.6667 -116.667 2.33333 -97 3 -75 curveto + closepath + 3 915 moveto + 3.66667 938.333 12 958 28 974 curveto + 44 990 63.6667 998.167 87 998.5 curveto + 110.333 998.167 130 990 146 974 curveto + 162 958 170.167 938.333 170.5 915 curveto + 170.167 891.667 162 872 146 856 curveto + 130 840 110.333 831.833 87 831.5 curveto + 63.6667 831.833 44 840 28 856 curveto + 10.6667 873.333 2.33333 893 3 915 curveto + closepath + 3 585 moveto + 3.66667 608.333 12 628 28 644 curveto + 44 660 63.6667 668.167 87 668.5 curveto + 110.333 668.167 130 660 146 644 curveto + 162 628 170.167 608.333 170.5 585 curveto + 170.167 561.667 162 542 146 526 curveto + 130 510 110.333 501.833 87 501.5 curveto + 63.6667 501.833 44 510 28 526 curveto + 10.6667 543.333 2.33333 563 3 585 curveto + closepath + 3 1575 moveto + 3.66667 1598.33 12 1618 28 1634 curveto + 44 1650 63.6667 1658.17 87 1658.5 curveto + 110.333 1658.17 130 1650 146 1634 curveto + 162 1618 170.167 1598.33 170.5 1575 curveto + 170.167 1551.67 162 1532 146 1516 curveto + 130 1500 110.333 1491.83 87 1491.5 curveto + 63.6667 1491.83 44 1500 28 1516 curveto + 10.6667 1533.33 2.33333 1553 3 1575 curveto + closepath + 3 1245 moveto + 3.66667 1268.33 12 1288 28 1304 curveto + 44 1320 63.6667 1328.17 87 1328.5 curveto + 110.333 1328.17 130 1320 146 1304 curveto + 162 1288 170.167 1268.33 170.5 1245 curveto + 170.167 1221.67 162 1202 146 1186 curveto + 130 1170 110.333 1161.83 87 1161.5 curveto + 63.6667 1161.83 44 1170 28 1186 curveto + 10.6667 1203.33 2.33333 1223 3 1245 curveto + closepath + 3 1905 moveto + 3.66667 1928.33 12 1948 28 1964 curveto + 44 1980 63.6667 1988.17 87 1988.5 curveto + 110.333 1988.17 130 1980 146 1964 curveto + 162 1948 170.167 1928.33 170.5 1905 curveto + 170.167 1881.67 162 1862 146 1846 curveto + 130 1830 110.333 1821.83 87 1821.5 curveto + 63.6667 1821.83 44 1830 28 1846 curveto + 10.6667 1863.33 2.33333 1883 3 1905 curveto + closepath +fill grestore +%%EOF diff --git a/vim/bundle/nerdtree/.gitignore b/vim/bundle/nerdtree/.gitignore new file mode 100644 index 0000000..3698c0e --- /dev/null +++ b/vim/bundle/nerdtree/.gitignore @@ -0,0 +1,3 @@ +*~ +*.swp +tags diff --git a/vim/bundle/nerdtree/README.markdown b/vim/bundle/nerdtree/README.markdown new file mode 100644 index 0000000..4234b54 --- /dev/null +++ b/vim/bundle/nerdtree/README.markdown @@ -0,0 +1,113 @@ +The NERD Tree +============= + +Intro +----- + +The NERD tree allows you to explore your filesystem and to open files and +directories. It presents the filesystem to you in the form of a tree which you +manipulate with the keyboard and/or mouse. It also allows you to perform +simple filesystem operations. + +The following features and functionality are provided by the NERD tree: + + * Files and directories are displayed in a hierarchical tree structure + * Different highlighting is provided for the following types of nodes: + * files + * directories + * sym-links + * windows .lnk files + * read-only files + * executable files + * Many (customisable) mappings are provided to manipulate the tree: + * Mappings to open/close/explore directory nodes + * Mappings to open files in new/existing windows/tabs + * Mappings to change the current root of the tree + * Mappings to navigate around the tree + * ... + * Directories and files can be bookmarked. + * Most NERD tree navigation can also be done with the mouse + * Filtering of tree content (can be toggled at runtime) + * custom file filters to prevent e.g. vim backup files being displayed + * optional displaying of hidden files (. files) + * files can be "turned off" so that only directories are displayed + * The position and size of the NERD tree window can be customised + * The order in which the nodes in the tree are listed can be customised. + * A model of your filesystem is created/maintained as you explore it. This + has several advantages: + * All filesystem information is cached and is only re-read on demand + * If you revisit a part of the tree that you left earlier in your + session, the directory nodes will be opened/closed as you left them + * The script remembers the cursor position and window position in the NERD + tree so you can toggle it off (or just close the tree window) and then + reopen it (with NERDTreeToggle) the NERD tree window will appear exactly + as you left it + * You can have a separate NERD tree for each tab, share trees across tabs, + or a mix of both. + * By default the script overrides the default file browser (netrw), so if + you :edit a directory a (slightly modified) NERD tree will appear in the + current window + * A programmable menu system is provided (simulates right clicking on a node) + * one default menu plugin is provided to perform basic filesystem + operations (create/delete/move/copy files/directories) + * There's an API for adding your own keymappings + +Installation +------------ + +[pathogen.vim](https://github.com/tpope/vim-pathogen) is the recommended way to install nerdtree. + + cd ~/.vim/bundle + git clone https://github.com/scrooloose/nerdtree.git + +Then reload vim, run `:Helptags`, and check out `:help NERD_tree.txt`. + + +Faq +--- + +__Q. Can I have the nerdtree on every tab automatically?__ + +A. Nope. If this is something you want then chances are you aren't using tabs + and buffers as they were intended to be used. Read this + http://stackoverflow.com/questions/102384/using-vims-tabs-like-buffers + + If you are interested in this behaviour then consider [vim-nerdtree-tabs](https://github.com/jistr/vim-nerdtree-tabs) + +__Q. How can I open a NERDTree automatically when vim starts up?__ + +A. Stick this in your vimrc: `autocmd vimenter * NERDTree` + +__Q. How can I open a NERDTree automatically when vim starts up if no files were specified?__ + +A. Stick this in your vimrc + + autocmd StdinReadPre * let s:std_in=1 + autocmd VimEnter * if argc() == 0 && !exists("s:std_in") | NERDTree | endif + +__Q. How can I map a specific key or shortcut to open NERDTree?__ + +A. Stick this in your vimrc to open NERDTree with `Ctrl+n` (you can set whatever key you want): + +`map :NERDTreeToggle` + +__Q. How can I close vim if the only window left open is a NERDTree?__ + +A. Stick this in your vimrc: + + `autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTreeType") && b:NERDTreeType == "primary") | q | endif` + + +Changelog +--------- + +4.2.0 (2011-12-28) + + * Add NERDTreeDirArrows option to make the UI use pretty arrow chars instead of the old +~| chars to define the tree structure (sickill) + * shift the syntax highlighting out into its own syntax file (gnap) * add some mac specific options to the filesystem menu - for macvim only (andersonfreitas) + * Add NERDTreeMinimalUI option to remove some non functional parts of the nerdtree ui (camthompson) + * tweak the behaviour of :NERDTreeFind - see :help :NERDTreeFind for the new behaviour (benjamingeiger) + * if no name is given to :Bookmark, make it default to the name of the target file/dir (minyoung) + * use 'file' completion when doing copying, create, and move operations (EvanDotPro) + * lots of misc bug fixes (paddyoloughlin, sdewald, camthompson, Vitaly Bogdanov, AndrewRadev, mathias, scottstvnsn, kml, wycats, me RAWR!) + diff --git a/vim/bundle/nerdtree/autoload/nerdtree.vim b/vim/bundle/nerdtree/autoload/nerdtree.vim new file mode 100644 index 0000000..539e783 --- /dev/null +++ b/vim/bundle/nerdtree/autoload/nerdtree.vim @@ -0,0 +1,407 @@ +if exists("g:loaded_nerdtree_autoload") + finish +endif +let g:loaded_nerdtree_autoload = 1 + +function! nerdtree#version() + return '4.2.0' +endfunction + +" SECTION: General Functions {{{1 +"============================================================ + +"FUNCTION: nerdtree#checkForBrowse(dir) {{{2 +"inits a secondary nerd tree in the current buffer if appropriate +function! nerdtree#checkForBrowse(dir) + if a:dir != '' && isdirectory(a:dir) + call g:NERDTreeCreator.CreateSecondary(a:dir) + endif +endfunction + +" FUNCTION: nerdtree#completeBookmarks(A,L,P) {{{2 +" completion function for the bookmark commands +function! nerdtree#completeBookmarks(A,L,P) + return filter(g:NERDTreeBookmark.BookmarkNames(), 'v:val =~# "^' . a:A . '"') +endfunction + +"FUNCTION: nerdtree#compareBookmarks(dir) {{{2 +function! nerdtree#compareBookmarks(first, second) + return a:first.compareTo(a:second) +endfunction + +"FUNCTION: nerdtree#compareNodes(dir) {{{2 +function! nerdtree#compareNodes(n1, n2) + return a:n1.path.compareTo(a:n2.path) +endfunction + +" FUNCTION: nerdtree#deprecated(func, [msg]) {{{2 +" Issue a deprecation warning for a:func. If a second arg is given, use this +" as the deprecation message +function! nerdtree#deprecated(func, ...) + let msg = a:0 ? a:func . ' ' . a:1 : a:func . ' is deprecated' + + if !exists('s:deprecationWarnings') + let s:deprecationWarnings = {} + endif + if !has_key(s:deprecationWarnings, a:func) + let s:deprecationWarnings[a:func] = 1 + echomsg msg + endif +endfunction + +" FUNCTION: nerdtree#exec(cmd) {{{2 +" same as :exec cmd but eventignore=all is set for the duration +function! nerdtree#exec(cmd) + let old_ei = &ei + set ei=all + exec a:cmd + let &ei = old_ei +endfunction + +" FUNCTION: nerdtree#has_opt(options, name) {{{2 +function! nerdtree#has_opt(options, name) + return has_key(a:options, a:name) && a:options[a:name] == 1 +endfunction + +" FUNCTION: nerdtree#loadClassFiles() {{{2 +function! nerdtree#loadClassFiles() + runtime lib/nerdtree/path.vim + runtime lib/nerdtree/menu_controller.vim + runtime lib/nerdtree/menu_item.vim + runtime lib/nerdtree/key_map.vim + runtime lib/nerdtree/bookmark.vim + runtime lib/nerdtree/tree_file_node.vim + runtime lib/nerdtree/tree_dir_node.vim + runtime lib/nerdtree/opener.vim + runtime lib/nerdtree/creator.vim + runtime lib/nerdtree/flag_set.vim + runtime lib/nerdtree/nerdtree.vim + runtime lib/nerdtree/ui.vim + runtime lib/nerdtree/event.vim + runtime lib/nerdtree/notifier.vim +endfunction + +" FUNCTION: nerdtree#postSourceActions() {{{2 +function! nerdtree#postSourceActions() + call g:NERDTreeBookmark.CacheBookmarks(0) + call nerdtree#ui_glue#createDefaultBindings() + + "load all nerdtree plugins + runtime! nerdtree_plugin/**/*.vim +endfunction + +"FUNCTION: nerdtree#runningWindows(dir) {{{2 +function! nerdtree#runningWindows() + return has("win16") || has("win32") || has("win64") +endfunction + +"FUNCTION: nerdtree#treeMarkupReg(dir) {{{2 +function! nerdtree#treeMarkupReg() + if g:NERDTreeDirArrows + return '^\([▾▸] \| \+[▾▸] \| \+\)' + endif + + return '^[ `|]*[\-+~]' +endfunction + +"FUNCTION: nerdtree#treeUpDirLine(dir) {{{2 +function! nerdtree#treeUpDirLine() + return '.. (up a dir)' +endfunction + +"FUNCTION: nerdtree#treeWid(dir) {{{2 +function! nerdtree#treeWid() + return 2 +endfunction + +" SECTION: View Functions {{{1 +"============================================================ + +"FUNCTION: nerdtree#closeTree() {{{2 +"Closes the primary NERD tree window for this tab +function! nerdtree#closeTree() + if !nerdtree#isTreeOpen() + throw "NERDTree.NoTreeFoundError: no NERDTree is open" + endif + + if winnr("$") != 1 + if winnr() == nerdtree#getTreeWinNum() + call nerdtree#exec("wincmd p") + let bufnr = bufnr("") + call nerdtree#exec("wincmd p") + else + let bufnr = bufnr("") + endif + + call nerdtree#exec(nerdtree#getTreeWinNum() . " wincmd w") + close + call nerdtree#exec(bufwinnr(bufnr) . " wincmd w") + else + close + endif +endfunction + +"FUNCTION: nerdtree#closeTreeIfOpen() {{{2 +"Closes the NERD tree window if it is open +function! nerdtree#closeTreeIfOpen() + if nerdtree#isTreeOpen() + call nerdtree#closeTree() + endif +endfunction + +"FUNCTION: nerdtree#closeTreeIfQuitOnOpen() {{{2 +"Closes the NERD tree window if the close on open option is set +function! nerdtree#closeTreeIfQuitOnOpen() + if g:NERDTreeQuitOnOpen && nerdtree#isTreeOpen() + call nerdtree#closeTree() + endif +endfunction + +"FUNCTION: nerdtree#dumpHelp {{{2 +"prints out the quick help +function! nerdtree#dumpHelp() + let old_h = @h + if b:treeShowHelp ==# 1 + let @h= "\" NERD tree (" . nerdtree#version() . ") quickhelp~\n" + let @h=@h."\" ============================\n" + let @h=@h."\" File node mappings~\n" + let @h=@h."\" ". (g:NERDTreeMouseMode ==# 3 ? "single" : "double") ."-click,\n" + let @h=@h."\" ,\n" + if b:NERDTreeType ==# "primary" + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in prev window\n" + else + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in current window\n" + endif + if b:NERDTreeType ==# "primary" + let @h=@h."\" ". g:NERDTreeMapPreview .": preview\n" + endif + let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" + let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" + let @h=@h."\" middle-click,\n" + let @h=@h."\" ". g:NERDTreeMapOpenSplit .": open split\n" + let @h=@h."\" ". g:NERDTreeMapPreviewSplit .": preview split\n" + let @h=@h."\" ". g:NERDTreeMapOpenVSplit .": open vsplit\n" + let @h=@h."\" ". g:NERDTreeMapPreviewVSplit .": preview vsplit\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Directory node mappings~\n" + let @h=@h."\" ". (g:NERDTreeMouseMode ==# 1 ? "double" : "single") ."-click,\n" + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open & close node\n" + let @h=@h."\" ". g:NERDTreeMapOpenRecursively .": recursively open node\n" + let @h=@h."\" ". g:NERDTreeMapCloseDir .": close parent of node\n" + let @h=@h."\" ". g:NERDTreeMapCloseChildren .": close all child nodes of\n" + let @h=@h."\" current node recursively\n" + let @h=@h."\" middle-click,\n" + let @h=@h."\" ". g:NERDTreeMapOpenExpl.": explore selected dir\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Bookmark table mappings~\n" + let @h=@h."\" double-click,\n" + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open bookmark\n" + let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" + let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" + let @h=@h."\" ". g:NERDTreeMapDeleteBookmark .": delete bookmark\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Tree navigation mappings~\n" + let @h=@h."\" ". g:NERDTreeMapJumpRoot .": go to root\n" + let @h=@h."\" ". g:NERDTreeMapJumpParent .": go to parent\n" + let @h=@h."\" ". g:NERDTreeMapJumpFirstChild .": go to first child\n" + let @h=@h."\" ". g:NERDTreeMapJumpLastChild .": go to last child\n" + let @h=@h."\" ". g:NERDTreeMapJumpNextSibling .": go to next sibling\n" + let @h=@h."\" ". g:NERDTreeMapJumpPrevSibling .": go to prev sibling\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Filesystem mappings~\n" + let @h=@h."\" ". g:NERDTreeMapChangeRoot .": change tree root to the\n" + let @h=@h."\" selected dir\n" + let @h=@h."\" ". g:NERDTreeMapUpdir .": move tree root up a dir\n" + let @h=@h."\" ". g:NERDTreeMapUpdirKeepOpen .": move tree root up a dir\n" + let @h=@h."\" but leave old root open\n" + let @h=@h."\" ". g:NERDTreeMapRefresh .": refresh cursor dir\n" + let @h=@h."\" ". g:NERDTreeMapRefreshRoot .": refresh current root\n" + let @h=@h."\" ". g:NERDTreeMapMenu .": Show menu\n" + let @h=@h."\" ". g:NERDTreeMapChdir .":change the CWD to the\n" + let @h=@h."\" selected dir\n" + let @h=@h."\" ". g:NERDTreeMapCWD .":change tree root to CWD\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Tree filtering mappings~\n" + let @h=@h."\" ". g:NERDTreeMapToggleHidden .": hidden files (" . (b:NERDTreeShowHidden ? "on" : "off") . ")\n" + let @h=@h."\" ". g:NERDTreeMapToggleFilters .": file filters (" . (b:NERDTreeIgnoreEnabled ? "on" : "off") . ")\n" + let @h=@h."\" ". g:NERDTreeMapToggleFiles .": files (" . (b:NERDTreeShowFiles ? "on" : "off") . ")\n" + let @h=@h."\" ". g:NERDTreeMapToggleBookmarks .": bookmarks (" . (b:NERDTreeShowBookmarks ? "on" : "off") . ")\n" + + "add quickhelp entries for each custom key map + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Custom mappings~\n" + for i in g:NERDTreeKeyMap.All() + if !empty(i.quickhelpText) + let @h=@h."\" ". i.key .": ". i.quickhelpText ."\n" + endif + endfor + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Other mappings~\n" + let @h=@h."\" ". g:NERDTreeMapQuit .": Close the NERDTree window\n" + let @h=@h."\" ". g:NERDTreeMapToggleZoom .": Zoom (maximize-minimize)\n" + let @h=@h."\" the NERDTree window\n" + let @h=@h."\" ". g:NERDTreeMapHelp .": toggle help\n" + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Bookmark commands~\n" + let @h=@h."\" :Bookmark []\n" + let @h=@h."\" :BookmarkToRoot \n" + let @h=@h."\" :RevealBookmark \n" + let @h=@h."\" :OpenBookmark \n" + let @h=@h."\" :ClearBookmarks []\n" + let @h=@h."\" :ClearAllBookmarks\n" + silent! put h + elseif g:NERDTreeMinimalUI == 0 + let @h="\" Press ". g:NERDTreeMapHelp ." for help\n" + silent! put h + endif + + let @h = old_h +endfunction + +"FUNCTION: nerdtree#echo {{{2 +"A wrapper for :echo. Appends 'NERDTree:' on the front of all messages +" +"Args: +"msg: the message to echo +function! nerdtree#echo(msg) + redraw + echomsg "NERDTree: " . a:msg +endfunction + +"FUNCTION: nerdtree#echoError {{{2 +"Wrapper for nerdtree#echo, sets the message type to errormsg for this message +"Args: +"msg: the message to echo +function! nerdtree#echoError(msg) + echohl errormsg + call nerdtree#echo(a:msg) + echohl normal +endfunction + +"FUNCTION: nerdtree#echoWarning {{{2 +"Wrapper for nerdtree#echo, sets the message type to warningmsg for this message +"Args: +"msg: the message to echo +function! nerdtree#echoWarning(msg) + echohl warningmsg + call nerdtree#echo(a:msg) + echohl normal +endfunction + +"FUNCTION: nerdtree#getTreeWinNum() {{{2 +"gets the nerd tree window number for this tab +function! nerdtree#getTreeWinNum() + if exists("t:NERDTreeBufName") + return bufwinnr(t:NERDTreeBufName) + else + return -1 + endif +endfunction + +"FUNCTION: nerdtree#isTreeOpen() {{{2 +function! nerdtree#isTreeOpen() + return nerdtree#getTreeWinNum() != -1 +endfunction + +"FUNCTION: nerdtree#putCursorOnBookmarkTable(){{{2 +"Places the cursor at the top of the bookmarks table +function! nerdtree#putCursorOnBookmarkTable() + if !b:NERDTreeShowBookmarks + throw "NERDTree.IllegalOperationError: cant find bookmark table, bookmarks arent active" + endif + + if g:NERDTreeMinimalUI + return cursor(1, 2) + endif + + let rootNodeLine = b:NERDTree.ui.getRootLineNum() + + let line = 1 + while getline(line) !~# '^>-\+Bookmarks-\+$' + let line = line + 1 + if line >= rootNodeLine + throw "NERDTree.BookmarkTableNotFoundError: didnt find the bookmarks table" + endif + endwhile + call cursor(line, 2) +endfunction + +"FUNCTION: nerdtree#putCursorInTreeWin(){{{2 +"Places the cursor in the nerd tree window +function! nerdtree#putCursorInTreeWin() + if !nerdtree#isTreeOpen() + throw "NERDTree.InvalidOperationError: cant put cursor in NERD tree window, no window exists" + endif + + call nerdtree#exec(nerdtree#getTreeWinNum() . "wincmd w") +endfunction + +"FUNCTION: nerdtree#renderBookmarks {{{2 +function! nerdtree#renderBookmarks() + + if g:NERDTreeMinimalUI == 0 + call setline(line(".")+1, ">----------Bookmarks----------") + call cursor(line(".")+1, col(".")) + endif + + for i in g:NERDTreeBookmark.Bookmarks() + call setline(line(".")+1, i.str()) + call cursor(line(".")+1, col(".")) + endfor + + call setline(line(".")+1, '') + call cursor(line(".")+1, col(".")) +endfunction + +"FUNCTION: nerdtree#renderView {{{2 +function! nerdtree#renderView() + call b:NERDTree.render() +endfunction +" +"FUNCTION: nerdtree#stripMarkupFromLine(line, removeLeadingSpaces){{{2 +"returns the given line with all the tree parts stripped off +" +"Args: +"line: the subject line +"removeLeadingSpaces: 1 if leading spaces are to be removed (leading spaces = +"any spaces before the actual text of the node) +function! nerdtree#stripMarkupFromLine(line, removeLeadingSpaces) + let line = a:line + "remove the tree parts and the leading space + let line = substitute (line, nerdtree#treeMarkupReg(),"","") + + "strip off any read only flag + let line = substitute (line, ' \[RO\]', "","") + + "strip off any bookmark flags + let line = substitute (line, ' {[^}]*}', "","") + + "strip off any executable flags + let line = substitute (line, '*\ze\($\| \)', "","") + + "strip off any generic flags + let line = substitute (line, '\[[^]]*\]', "","") + + let wasdir = 0 + if line =~# '/$' + let wasdir = 1 + endif + let line = substitute (line,' -> .*',"","") " remove link to + if wasdir ==# 1 + let line = substitute (line, '/\?$', '/', "") + endif + + if a:removeLeadingSpaces + let line = substitute (line, '^ *', '', '') + endif + + return line +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/nerdtree/autoload/nerdtree/ui_glue.vim b/vim/bundle/nerdtree/autoload/nerdtree/ui_glue.vim new file mode 100644 index 0000000..8607389 --- /dev/null +++ b/vim/bundle/nerdtree/autoload/nerdtree/ui_glue.vim @@ -0,0 +1,644 @@ +if exists("g:loaded_nerdtree_ui_glue_autoload") + finish +endif +let g:loaded_nerdtree_ui_glue_autoload = 1 + +" FUNCTION: nerdtree#ui_glue#createDefaultBindings() {{{1 +function! nerdtree#ui_glue#createDefaultBindings() + let s = '' . s:SID() . '_' + + call NERDTreeAddKeyMap({ 'key': '', 'scope': "all", 'callback': s."handleMiddleMouse" }) + call NERDTreeAddKeyMap({ 'key': '', 'scope': "all", 'callback': s."handleLeftClick" }) + call NERDTreeAddKeyMap({ 'key': '<2-LeftMouse>', 'scope': "DirNode", 'callback': s."activateDirNode" }) + call NERDTreeAddKeyMap({ 'key': '<2-LeftMouse>', 'scope': "FileNode", 'callback': s."activateFileNode" }) + call NERDTreeAddKeyMap({ 'key': '<2-LeftMouse>', 'scope': "Bookmark", 'callback': s."activateBookmark" }) + call NERDTreeAddKeyMap({ 'key': '<2-LeftMouse>', 'scope': "all", 'callback': s."activateAll" }) + + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "DirNode", 'callback': s."activateDirNode" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "FileNode", 'callback': s."activateFileNode" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "Bookmark", 'callback': s."activateBookmark" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': "all", 'callback': s."activateAll" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenSplit, 'scope': "Node", 'callback': s."openHSplit" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenVSplit, 'scope': "Node", 'callback': s."openVSplit" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenSplit, 'scope': "Bookmark", 'callback': s."openHSplit" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenVSplit, 'scope': "Bookmark", 'callback': s."openVSplit" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreview, 'scope': "Node", 'callback': s."previewNodeCurrent" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreviewVSplit, 'scope': "Node", 'callback': s."previewNodeVSplit" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreviewSplit, 'scope': "Node", 'callback': s."previewNodeHSplit" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreview, 'scope': "Bookmark", 'callback': s."previewNodeCurrent" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreviewVSplit, 'scope': "Bookmark", 'callback': s."previewNodeVSplit" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreviewSplit, 'scope': "Bookmark", 'callback': s."previewNodeHSplit" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenRecursively, 'scope': "DirNode", 'callback': s."openNodeRecursively" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapUpdir, 'scope': "all", 'callback': s."upDirCurrentRootClosed" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapUpdirKeepOpen, 'scope': "all", 'callback': s."upDirCurrentRootOpen" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapChangeRoot, 'scope': "Node", 'callback': s."chRoot" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapChdir, 'scope': "Node", 'callback': s."chCwd" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapQuit, 'scope': "all", 'callback': s."closeTreeWindow" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCWD, 'scope': "all", 'callback': "nerdtree#ui_glue#chRootCwd" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapRefreshRoot, 'scope': "all", 'callback': s."refreshRoot" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapRefresh, 'scope': "Node", 'callback': s."refreshCurrent" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapHelp, 'scope': "all", 'callback': s."displayHelp" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleZoom, 'scope': "all", 'callback': s."toggleZoom" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleHidden, 'scope': "all", 'callback': s."toggleShowHidden" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleFilters, 'scope': "all", 'callback': s."toggleIgnoreFilter" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleFiles, 'scope': "all", 'callback': s."toggleShowFiles" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleBookmarks, 'scope': "all", 'callback': s."toggleShowBookmarks" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCloseDir, 'scope': "Node", 'callback': s."closeCurrentDir" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCloseChildren, 'scope': "DirNode", 'callback': s."closeChildren" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapMenu, 'scope': "Node", 'callback': s."showMenu" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpParent, 'scope': "Node", 'callback': s."jumpToParent" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpFirstChild, 'scope': "Node", 'callback': s."jumpToFirstChild" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpLastChild, 'scope': "Node", 'callback': s."jumpToLastChild" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpRoot, 'scope': "all", 'callback': s."jumpToRoot" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpNextSibling, 'scope': "Node", 'callback': s."jumpToNextSibling" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpPrevSibling, 'scope': "Node", 'callback': s."jumpToPrevSibling" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenInTab, 'scope': "Node", 'callback': s."openInNewTab" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenInTabSilent, 'scope': "Node", 'callback': s."openInNewTabSilent" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenInTab, 'scope': "Bookmark", 'callback': s."openInNewTab" }) + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenInTabSilent, 'scope': "Bookmark", 'callback': s."openInNewTabSilent" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenExpl, 'scope': "DirNode", 'callback': s."openExplorer" }) + + call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapDeleteBookmark, 'scope': "Bookmark", 'callback': s."deleteBookmark" }) +endfunction + + +"SECTION: Interface bindings {{{1 +"============================================================ + +"FUNCTION: s:activateAll() {{{1 +"handle the user activating the updir line +function! s:activateAll() + if getline(".") ==# nerdtree#treeUpDirLine() + return nerdtree#ui_glue#upDir(0) + endif +endfunction + +"FUNCTION: s:activateDirNode() {{{1 +"handle the user activating a tree node +function! s:activateDirNode(node) + call a:node.activate({'reuse': 1}) +endfunction + +"FUNCTION: s:activateFileNode() {{{1 +"handle the user activating a tree node +function! s:activateFileNode(node) + call a:node.activate({'reuse': 1, 'where': 'p'}) +endfunction + +"FUNCTION: s:activateBookmark() {{{1 +"handle the user activating a bookmark +function! s:activateBookmark(bm) + call a:bm.activate(!a:bm.path.isDirectory ? {'where': 'p'} : {}) +endfunction + +" FUNCTION: nerdtree#ui_glue#bookmarkNode(name) {{{1 +" Associate the current node with the given name +function! nerdtree#ui_glue#bookmarkNode(...) + let currentNode = g:NERDTreeFileNode.GetSelected() + if currentNode != {} + let name = a:1 + if empty(name) + let name = currentNode.path.getLastPathComponent(0) + endif + try + call currentNode.bookmark(name) + call b:NERDTree.render() + catch /^NERDTree.IllegalBookmarkNameError/ + call nerdtree#echo("bookmark names must not contain spaces") + endtry + else + call nerdtree#echo("select a node first") + endif +endfunction + +" FUNCTION: s:chCwd(node) {{{1 +function! s:chCwd(node) + try + call a:node.path.changeToDir() + catch /^NERDTree.PathChangeError/ + call nerdtree#echoWarning("could not change cwd") + endtry +endfunction + +" FUNCTION: s:chRoot(node) {{{1 +" changes the current root to the selected one +function! s:chRoot(node) + call a:node.makeRoot() + call b:NERDTree.render() + call b:NERDTreeRoot.putCursorHere(0, 0) +endfunction + +" FUNCTION: s:nerdtree#ui_glue#chRootCwd() {{{1 +" changes the current root to CWD +function! nerdtree#ui_glue#chRootCwd() + try + let cwd = g:NERDTreePath.New(getcwd()) + catch /^NERDTree.InvalidArgumentsError/ + call nerdtree#echo("current directory does not exist.") + return + endtry + if cwd.str() == g:NERDTreeFileNode.GetRootForTab().path.str() + return + endif + call s:chRoot(g:NERDTreeDirNode.New(cwd)) +endfunction + +" FUNCTION: nnerdtree#ui_glue#clearBookmarks(bookmarks) {{{1 +function! nerdtree#ui_glue#clearBookmarks(bookmarks) + if a:bookmarks ==# '' + let currentNode = g:NERDTreeFileNode.GetSelected() + if currentNode != {} + call currentNode.clearBookmarks() + endif + else + for name in split(a:bookmarks, ' ') + let bookmark = g:NERDTreeBookmark.BookmarkFor(name) + call bookmark.delete() + endfor + endif + call b:NERDTree.render() +endfunction + +" FUNCTION: s:closeChildren(node) {{{1 +" closes all childnodes of the current node +function! s:closeChildren(node) + call a:node.closeChildren() + call b:NERDTree.render() + call a:node.putCursorHere(0, 0) +endfunction + +" FUNCTION: s:closeCurrentDir(node) {{{1 +" closes the parent dir of the current node +function! s:closeCurrentDir(node) + let parent = a:node.parent + if parent ==# {} || parent.isRoot() + call nerdtree#echo("cannot close tree root") + else + while g:NERDTreeCascadeOpenSingleChildDir && !parent.parent.isRoot() + if parent.parent.getVisibleChildCount() == 1 + call parent.close() + let parent = parent.parent + else + break + endif + endwhile + call parent.close() + call b:NERDTree.render() + call parent.putCursorHere(0, 0) + endif +endfunction + +" FUNCTION: s:closeTreeWindow() {{{1 +" close the tree window +function! s:closeTreeWindow() + if b:NERDTreeType ==# "secondary" && b:NERDTreePreviousBuf != -1 + exec "buffer " . b:NERDTreePreviousBuf + else + if winnr("$") > 1 + call nerdtree#closeTree() + else + call nerdtree#echo("Cannot close last window") + endif + endif +endfunction + +" FUNCTION: s:deleteBookmark(bm) {{{1 +" if the cursor is on a bookmark, prompt to delete +function! s:deleteBookmark(bm) + echo "Are you sure you wish to delete the bookmark:\n\"" . a:bm.name . "\" (yN):" + + if nr2char(getchar()) ==# 'y' + try + call a:bm.delete() + call b:NERDTree.render() + redraw + catch /^NERDTree/ + call nerdtree#echoWarning("Could not remove bookmark") + endtry + else + call nerdtree#echo("delete aborted" ) + endif + +endfunction + +" FUNCTION: s:displayHelp() {{{1 +" toggles the help display +function! s:displayHelp() + let b:treeShowHelp = b:treeShowHelp ? 0 : 1 + call b:NERDTree.render() + call b:NERDTree.ui.centerView() +endfunction + +" FUNCTION: s:findAndRevealPath() {{{1 +function! s:findAndRevealPath() + try + let p = g:NERDTreePath.New(expand("%:p")) + catch /^NERDTree.InvalidArgumentsError/ + call nerdtree#echo("no file for the current buffer") + return + endtry + + if p.isUnixHiddenPath() + let showhidden=g:NERDTreeShowHidden + let g:NERDTreeShowHidden = 1 + endif + + if !g:NERDTree.ExistsForTab() + try + let cwd = g:NERDTreePath.New(getcwd()) + catch /^NERDTree.InvalidArgumentsError/ + call nerdtree#echo("current directory does not exist.") + let cwd = p.getParent() + endtry + + if p.isUnder(cwd) + call g:NERDTreeCreator.CreatePrimary(cwd.str()) + else + call g:NERDTreeCreator.CreatePrimary(p.getParent().str()) + endif + else + if !p.isUnder(g:NERDTreeFileNode.GetRootForTab().path) + if !nerdtree#isTreeOpen() + call g:NERDTreeCreator.TogglePrimary('') + else + call nerdtree#putCursorInTreeWin() + endif + let b:NERDTreeShowHidden = g:NERDTreeShowHidden + call s:chRoot(g:NERDTreeDirNode.New(p.getParent())) + else + if !nerdtree#isTreeOpen() + call g:NERDTreeCreator.TogglePrimary("") + endif + endif + endif + call nerdtree#putCursorInTreeWin() + call b:NERDTreeRoot.reveal(p) + + if p.isUnixHiddenFile() + let g:NERDTreeShowHidden = showhidden + endif +endfunction + +"FUNCTION: s:handleLeftClick() {{{1 +"Checks if the click should open the current node +function! s:handleLeftClick() + let currentNode = g:NERDTreeFileNode.GetSelected() + if currentNode != {} + + "the dir arrows are multibyte chars, and vim's string functions only + "deal with single bytes - so split the line up with the hack below and + "take the line substring manually + let line = split(getline(line(".")), '\zs') + let startToCur = "" + for i in range(0,len(line)-1) + let startToCur .= line[i] + endfor + + if currentNode.path.isDirectory + if startToCur =~# nerdtree#treeMarkupReg() && startToCur =~# '[+~▾▸] \?$' + call currentNode.activate() + return + endif + endif + + if (g:NERDTreeMouseMode ==# 2 && currentNode.path.isDirectory) || g:NERDTreeMouseMode ==# 3 + let char = strpart(startToCur, strlen(startToCur)-1, 1) + if char !~# nerdtree#treeMarkupReg() + if currentNode.path.isDirectory + call currentNode.activate() + else + call currentNode.activate({'reuse': 1, 'where': 'p'}) + endif + return + endif + endif + endif +endfunction + +" FUNCTION: s:handleMiddleMouse() {{{1 +function! s:handleMiddleMouse() + let curNode = g:NERDTreeFileNode.GetSelected() + if curNode ==# {} + call nerdtree#echo("Put the cursor on a node first" ) + return + endif + + if curNode.path.isDirectory + call nerdtree#openExplorer(curNode) + else + call curNode.open({'where': 'h'}) + endif +endfunction + +" FUNCTION: s:jumpToChild(direction) {{{2 +" Args: +" direction: 0 if going to first child, 1 if going to last +function! s:jumpToChild(currentNode, direction) + if a:currentNode.isRoot() + return nerdtree#echo("cannot jump to " . (a:direction ? "last" : "first") . " child") + end + let dirNode = a:currentNode.parent + let childNodes = dirNode.getVisibleChildren() + + let targetNode = childNodes[0] + if a:direction + let targetNode = childNodes[len(childNodes) - 1] + endif + + if targetNode.equals(a:currentNode) + let siblingDir = a:currentNode.parent.findOpenDirSiblingWithVisibleChildren(a:direction) + if siblingDir != {} + let indx = a:direction ? siblingDir.getVisibleChildCount()-1 : 0 + let targetNode = siblingDir.getChildByIndex(indx, 1) + endif + endif + + call targetNode.putCursorHere(1, 0) + + call b:NERDTree.ui.centerView() +endfunction + + +" FUNCTION: nerdtree#ui_glue#invokeKeyMap(key) {{{1 +"this is needed since I cant figure out how to invoke dict functions from a +"key map +function! nerdtree#ui_glue#invokeKeyMap(key) + call g:NERDTreeKeyMap.Invoke(a:key) +endfunction + +" FUNCTION: s:jumpToFirstChild() {{{1 +" wrapper for the jump to child method +function! s:jumpToFirstChild(node) + call s:jumpToChild(a:node, 0) +endfunction + +" FUNCTION: s:jumpToLastChild() {{{1 +" wrapper for the jump to child method +function! s:jumpToLastChild(node) + call s:jumpToChild(a:node, 1) +endfunction + +" FUNCTION: s:jumpToParent(node) {{{1 +" moves the cursor to the parent of the current node +function! s:jumpToParent(node) + if !empty(a:node.parent) + call a:node.parent.putCursorHere(1, 0) + call b:NERDTree.ui.centerView() + else + call nerdtree#echo("cannot jump to parent") + endif +endfunction + +" FUNCTION: s:jumpToRoot() {{{1 +" moves the cursor to the root node +function! s:jumpToRoot() + call b:NERDTreeRoot.putCursorHere(1, 0) + call b:NERDTree.ui.centerView() +endfunction + +" FUNCTION: s:jumpToNextSibling(node) {{{1 +function! s:jumpToNextSibling(node) + call s:jumpToSibling(a:node, 1) +endfunction + +" FUNCTION: s:jumpToPrevSibling(node) {{{1 +function! s:jumpToPrevSibling(node) + call s:jumpToSibling(a:node, 0) +endfunction + +" FUNCTION: s:jumpToSibling(currentNode, forward) {{{2 +" moves the cursor to the sibling of the current node in the given direction +" +" Args: +" forward: 1 if the cursor should move to the next sibling, 0 if it should +" move back to the previous sibling +function! s:jumpToSibling(currentNode, forward) + let sibling = a:currentNode.findSibling(a:forward) + + if !empty(sibling) + call sibling.putCursorHere(1, 0) + call b:NERDTree.ui.centerView() + endif +endfunction + +" FUNCTION: nerdtree#ui_glue#openBookmark(name) {{{1 +" put the cursor on the given bookmark and, if its a file, open it +function! nerdtree#ui_glue#openBookmark(name) + try + let targetNode = g:NERDTreeBookmark.GetNodeForName(a:name, 0) + call targetNode.putCursorHere(0, 1) + redraw! + catch /^NERDTree.BookmarkedNodeNotFoundError/ + call nerdtree#echo("note - target node is not cached") + let bookmark = g:NERDTreeBookmark.BookmarkFor(a:name) + let targetNode = g:NERDTreeFileNode.New(bookmark.path) + endtry + if targetNode.path.isDirectory + call targetNode.openExplorer() + else + call targetNode.open({'where': 'p'}) + endif +endfunction + +" FUNCTION: s:openHSplit(target) {{{1 +function! s:openHSplit(target) + call a:target.activate({'where': 'h'}) +endfunction + +" FUNCTION: s:openVSplit(target) {{{1 +function! s:openVSplit(target) + call a:target.activate({'where': 'v'}) +endfunction + +" FUNCTION: s:openExplorer(node) {{{1 +function! s:openExplorer(node) + call a:node.openExplorer() +endfunction + +" FUNCTION: s:openInNewTab(target) {{{1 +function! s:openInNewTab(target) + call a:target.activate({'where': 't'}) +endfunction + +" FUNCTION: s:openInNewTabSilent(target) {{{1 +function! s:openInNewTabSilent(target) + call a:target.activate({'where': 't', 'stay': 1}) +endfunction + +" FUNCTION: s:openNodeRecursively(node) {{{1 +function! s:openNodeRecursively(node) + call nerdtree#echo("Recursively opening node. Please wait...") + call a:node.openRecursively() + call b:NERDTree.render() + redraw + call nerdtree#echo("Recursively opening node. Please wait... DONE") +endfunction + +"FUNCTION: s:previewNodeCurrent(node) {{{1 +function! s:previewNodeCurrent(node) + call a:node.open({'stay': 1, 'where': 'p', 'keepopen': 1}) +endfunction + +"FUNCTION: s:previewNodeHSplit(node) {{{1 +function! s:previewNodeHSplit(node) + call a:node.open({'stay': 1, 'where': 'h', 'keepopen': 1}) +endfunction + +"FUNCTION: s:previewNodeVSplit(node) {{{1 +function! s:previewNodeVSplit(node) + call a:node.open({'stay': 1, 'where': 'v', 'keepopen': 1}) +endfunction + +" FUNCTION: nerdtree#ui_glue#revealBookmark(name) {{{1 +" put the cursor on the node associate with the given name +function! nerdtree#ui_glue#revealBookmark(name) + try + let targetNode = g:NERDTreeBookmark.GetNodeForName(a:name, 0) + call targetNode.putCursorHere(0, 1) + catch /^NERDTree.BookmarkNotFoundError/ + call nerdtree#echo("Bookmark isnt cached under the current root") + endtry +endfunction + +" FUNCTION: s:refreshRoot() {{{1 +" Reloads the current root. All nodes below this will be lost and the root dir +" will be reloaded. +function! s:refreshRoot() + call nerdtree#echo("Refreshing the root node. This could take a while...") + call b:NERDTreeRoot.refresh() + call b:NERDTree.render() + redraw + call nerdtree#echo("Refreshing the root node. This could take a while... DONE") +endfunction + +" FUNCTION: s:refreshCurrent(node) {{{1 +" refreshes the root for the current node +function! s:refreshCurrent(node) + let node = a:node + if !node.path.isDirectory + let node = node.parent + endif + + call nerdtree#echo("Refreshing node. This could take a while...") + call node.refresh() + call b:NERDTree.render() + redraw + call nerdtree#echo("Refreshing node. This could take a while... DONE") +endfunction + +" FUNCTION: nerdtree#ui_glue#setupCommands() {{{1 +function! nerdtree#ui_glue#setupCommands() + command! -n=? -complete=dir -bar NERDTree :call g:NERDTreeCreator.CreatePrimary('') + command! -n=? -complete=dir -bar NERDTreeToggle :call g:NERDTreeCreator.TogglePrimary('') + command! -n=0 -bar NERDTreeClose :call nerdtree#closeTreeIfOpen() + command! -n=1 -complete=customlist,nerdtree#completeBookmarks -bar NERDTreeFromBookmark call g:NERDTreeCreator.CreatePrimary('') + command! -n=0 -bar NERDTreeMirror call g:NERDTreeCreator.CreateMirror() + command! -n=0 -bar NERDTreeFind call s:findAndRevealPath() + command! -n=0 -bar NERDTreeFocus call NERDTreeFocus() + command! -n=0 -bar NERDTreeCWD call NERDTreeCWD() +endfunction + +" Function: s:SID() {{{1 +function s:SID() + if !exists("s:sid") + let s:sid = matchstr(expand(''), '\zs\d\+\ze_SID$') + endif + return s:sid +endfun + +" FUNCTION: s:showMenu(node) {{{1 +function! s:showMenu(node) + let mc = g:NERDTreeMenuController.New(g:NERDTreeMenuItem.AllEnabled()) + call mc.showMenu() +endfunction + +" FUNCTION: s:toggleIgnoreFilter() {{{1 +function! s:toggleIgnoreFilter() + call b:NERDTree.ui.toggleIgnoreFilter() +endfunction + +" FUNCTION: s:toggleShowBookmarks() {{{1 +function! s:toggleShowBookmarks() + call b:NERDTree.ui.toggleShowBookmarks() +endfunction + +" FUNCTION: s:toggleShowFiles() {{{1 +function! s:toggleShowFiles() + call b:NERDTree.ui.toggleShowFiles() +endfunction + +" FUNCTION: s:toggleShowHidden() {{{1 +" toggles the display of hidden files +function! s:toggleShowHidden() + call b:NERDTree.ui.toggleShowHidden() +endfunction + +" FUNCTION: s:toggleZoom() {{{1 +function! s:toggleZoom() + call b:NERDTree.ui.toggleZoom() +endfunction + +"FUNCTION: nerdtree#ui_glue#upDir(keepState) {{{1 +"moves the tree up a level +" +"Args: +"keepState: 1 if the current root should be left open when the tree is +"re-rendered +function! nerdtree#ui_glue#upDir(keepState) + let cwd = b:NERDTreeRoot.path.str({'format': 'UI'}) + if cwd ==# "/" || cwd =~# '^[^/]..$' + call nerdtree#echo("already at top dir") + else + if !a:keepState + call b:NERDTreeRoot.close() + endif + + let oldRoot = b:NERDTreeRoot + + if empty(b:NERDTreeRoot.parent) + let path = b:NERDTreeRoot.path.getParent() + let newRoot = g:NERDTreeDirNode.New(path) + call newRoot.open() + call newRoot.transplantChild(b:NERDTreeRoot) + let b:NERDTreeRoot = newRoot + else + let b:NERDTreeRoot = b:NERDTreeRoot.parent + endif + + if g:NERDTreeChDirMode ==# 2 + call b:NERDTreeRoot.path.changeToDir() + endif + + call b:NERDTree.render() + call oldRoot.putCursorHere(0, 0) + endif +endfunction + +" FUNCTION: s:upDirCurrentRootOpen() {{{1 +function! s:upDirCurrentRootOpen() + call nerdtree#ui_glue#upDir(1) +endfunction + +" FUNCTION: s:upDirCurrentRootClosed() {{{1 +function! s:upDirCurrentRootClosed() + call nerdtree#ui_glue#upDir(0) +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/nerdtree/doc/NERD_tree.txt b/vim/bundle/nerdtree/doc/NERD_tree.txt new file mode 100644 index 0000000..5d5b3f6 --- /dev/null +++ b/vim/bundle/nerdtree/doc/NERD_tree.txt @@ -0,0 +1,1379 @@ +*NERD_tree.txt* A tree explorer plugin that owns your momma! + + + + omg its ... ~ + + ________ ________ _ ____________ ____ __________ ____________~ + /_ __/ / / / ____/ / | / / ____/ __ \/ __ \ /_ __/ __ \/ ____/ ____/~ + / / / /_/ / __/ / |/ / __/ / /_/ / / / / / / / /_/ / __/ / __/ ~ + / / / __ / /___ / /| / /___/ _, _/ /_/ / / / / _, _/ /___/ /___ ~ + /_/ /_/ /_/_____/ /_/ |_/_____/_/ |_/_____/ /_/ /_/ |_/_____/_____/ ~ + + + Reference Manual~ + + + + +============================================================================== +CONTENTS *NERDTree-contents* + + 1.Intro...................................|NERDTree| + 2.Functionality provided..................|NERDTreeFunctionality| + 2.1.Global commands...................|NERDTreeGlobalCommands| + 2.2.Bookmarks.........................|NERDTreeBookmarks| + 2.2.1.The bookmark table..........|NERDTreeBookmarkTable| + 2.2.2.Bookmark commands...........|NERDTreeBookmarkCommands| + 2.2.3.Invalid bookmarks...........|NERDTreeInvalidBookmarks| + 2.3.NERD tree mappings................|NERDTreeMappings| + 2.4.The NERD tree menu................|NERDTreeMenu| + 3.Options.................................|NERDTreeOptions| + 3.1.Option summary....................|NERDTreeOptionSummary| + 3.2.Option details....................|NERDTreeOptionDetails| + 4.The NERD tree API.......................|NERDTreeAPI| + 4.1.Key map API.......................|NERDTreeKeymapAPI| + 4.2.Menu API..........................|NERDTreeMenuAPI| + 5.About...................................|NERDTreeAbout| + 6.Changelog...............................|NERDTreeChangelog| + 7.Credits.................................|NERDTreeCredits| + 8.License.................................|NERDTreeLicense| + +============================================================================== +1. Intro *NERDTree* + +What is this "NERD tree"?? + +The NERD tree allows you to explore your filesystem and to open files and +directories. It presents the filesystem to you in the form of a tree which you +manipulate with the keyboard and/or mouse. It also allows you to perform +simple filesystem operations. + +The following features and functionality are provided by the NERD tree: + * Files and directories are displayed in a hierarchical tree structure + * Different highlighting is provided for the following types of nodes: + * files + * directories + * sym-links + * windows .lnk files + * read-only files + * executable files + * Many (customisable) mappings are provided to manipulate the tree: + * Mappings to open/close/explore directory nodes + * Mappings to open files in new/existing windows/tabs + * Mappings to change the current root of the tree + * Mappings to navigate around the tree + * ... + * Directories and files can be bookmarked. + * Most NERD tree navigation can also be done with the mouse + * Filtering of tree content (can be toggled at runtime) + * custom file filters to prevent e.g. vim backup files being displayed + * optional displaying of hidden files (. files) + * files can be "turned off" so that only directories are displayed + * The position and size of the NERD tree window can be customised + * The order in which the nodes in the tree are listed can be customised. + * A model of your filesystem is created/maintained as you explore it. This + has several advantages: + * All filesystem information is cached and is only re-read on demand + * If you revisit a part of the tree that you left earlier in your + session, the directory nodes will be opened/closed as you left them + * The script remembers the cursor position and window position in the NERD + tree so you can toggle it off (or just close the tree window) and then + reopen it (with NERDTreeToggle) the NERD tree window will appear exactly + as you left it + * You can have a separate NERD tree for each tab, share trees across tabs, + or a mix of both. + * By default the script overrides the default file browser (netrw), so if + you :edit a directory a (slightly modified) NERD tree will appear in the + current window + * A programmable menu system is provided (simulates right clicking on a + node) + * one default menu plugin is provided to perform basic filesystem + operations (create/delete/move/copy files/directories) + * There's an API for adding your own keymappings + + +============================================================================== +2. Functionality provided *NERDTreeFunctionality* + +------------------------------------------------------------------------------ +2.1. Global Commands *NERDTreeGlobalCommands* + +:NERDTree [ | ] *:NERDTree* + Opens a fresh NERD tree. The root of the tree depends on the argument + given. There are 3 cases: If no argument is given, the current directory + will be used. If a directory is given, that will be used. If a bookmark + name is given, the corresponding directory will be used. For example: > + :NERDTree /home/marty/vim7/src + :NERDTree foo (foo is the name of a bookmark) +< +:NERDTreeFromBookmark *:NERDTreeFromBookmark* + Opens a fresh NERD tree with the root initialized to the dir for + . The only reason to use this command over :NERDTree is for + the completion (which is for bookmarks rather than directories). + +:NERDTreeToggle [ | ] *:NERDTreeToggle* + If a NERD tree already exists for this tab, it is reopened and rendered + again. If no NERD tree exists for this tab then this command acts the + same as the |:NERDTree| command. + +:NERDTreeMirror *:NERDTreeMirror* + Shares an existing NERD tree, from another tab, in the current tab. + Changes made to one tree are reflected in both as they are actually the + same buffer. + + If only one other NERD tree exists, that tree is automatically mirrored. If + more than one exists, the script will ask which tree to mirror. + +:NERDTreeClose *:NERDTreeClose* + Close the NERD tree in this tab. + +:NERDTreeFind *:NERDTreeFind* + Find the current file in the tree. + + If not tree exists and the current file is under vim's CWD, then init a + tree at the CWD and reveal the file. Otherwise init a tree in the current + file's directory. + + In any case, the current file is revealed and the cursor is placed on it. + +:NERDTreeCWD *:NERDTreeCWD* + Change tree root to current directory. If no NERD tree exists for this + tab, a new tree will be opened. + +------------------------------------------------------------------------------ +2.2. Bookmarks *NERDTreeBookmarks* + +Bookmarks in the NERD tree are a way to tag files or directories of interest. +For example, you could use bookmarks to tag all of your project directories. + +------------------------------------------------------------------------------ +2.2.1. The Bookmark Table *NERDTreeBookmarkTable* + +If the bookmark table is active (see |NERDTree-B| and +|'NERDTreeShowBookmarks'|), it will be rendered above the tree. You can double +click bookmarks or use the |NERDTree-o| mapping to activate them. See also, +|NERDTree-t| and |NERDTree-T| + +------------------------------------------------------------------------------ +2.2.2. Bookmark commands *NERDTreeBookmarkCommands* + +Note that the following commands are only available in the NERD tree buffer. + +:Bookmark [] + Bookmark the current node as . If there is already a + bookmark, it is overwritten. must not contain spaces. + If is not provided, it defaults to the file or directory name. + For directories, a trailing slash is present. + +:BookmarkToRoot + Make the directory corresponding to the new root. If a treenode + corresponding to is already cached somewhere in the tree then + the current tree will be used, otherwise a fresh tree will be opened. + Note that if points to a file then its parent will be used + instead. + +:RevealBookmark + If the node is cached under the current root then it will be revealed + (i.e. directory nodes above it will be opened) and the cursor will be + placed on it. + +:OpenBookmark + must point to a file. The file is opened as though |NERDTree-o| + was applied. If the node is cached under the current root then it will be + revealed and the cursor will be placed on it. + +:ClearBookmarks [] + Remove all the given bookmarks. If no bookmarks are given then remove all + bookmarks on the current node. + +:ClearAllBookmarks + Remove all bookmarks. + +:ReadBookmarks + Re-read the bookmarks in the |'NERDTreeBookmarksFile'|. + +See also |:NERDTree| and |:NERDTreeFromBookmark|. + +------------------------------------------------------------------------------ +2.2.3. Invalid Bookmarks *NERDTreeInvalidBookmarks* + +If invalid bookmarks are detected, the script will issue an error message and +the invalid bookmarks will become unavailable for use. + +These bookmarks will still be stored in the bookmarks file (see +|'NERDTreeBookmarksFile'|), down the bottom. There will always be a blank line +after the valid bookmarks but before the invalid ones. + +Each line in the bookmarks file represents one bookmark. The proper format is: + + +After you have corrected any invalid bookmarks, either restart vim, or go +:ReadBookmarks from the NERD tree window. + +------------------------------------------------------------------------------ +2.3. NERD tree Mappings *NERDTreeMappings* + +Default Description~ help-tag~ +Key~ + +o.......Open files, directories and bookmarks....................|NERDTree-o| +go......Open selected file, but leave cursor in the NERDTree.....|NERDTree-go| +t.......Open selected node/bookmark in a new tab.................|NERDTree-t| +T.......Same as 't' but keep the focus on the current tab........|NERDTree-T| +i.......Open selected file in a split window.....................|NERDTree-i| +gi......Same as i, but leave the cursor on the NERDTree..........|NERDTree-gi| +s.......Open selected file in a new vsplit.......................|NERDTree-s| +gs......Same as s, but leave the cursor on the NERDTree..........|NERDTree-gs| +O.......Recursively open the selected directory..................|NERDTree-O| +x.......Close the current nodes parent...........................|NERDTree-x| +X.......Recursively close all children of the current node.......|NERDTree-X| +e.......Edit the current dir.....................................|NERDTree-e| + +...............same as |NERDTree-o|. +double-click.......same as the |NERDTree-o| map. +middle-click.......same as |NERDTree-i| for files, same as + |NERDTree-e| for dirs. + +D.......Delete the current bookmark .............................|NERDTree-D| + +P.......Jump to the root node....................................|NERDTree-P| +p.......Jump to current nodes parent.............................|NERDTree-p| +K.......Jump up inside directories at the current tree depth.....|NERDTree-K| +J.......Jump down inside directories at the current tree depth...|NERDTree-J| +...Jump down to the next sibling of the current directory...|NERDTree-C-J| +...Jump up to the previous sibling of the current directory.|NERDTree-C-K| + +C.......Change the tree root to the selected dir.................|NERDTree-C| +u.......Move the tree root up one directory......................|NERDTree-u| +U.......Same as 'u' except the old root node is left open........|NERDTree-U| +r.......Recursively refresh the current directory................|NERDTree-r| +R.......Recursively refresh the current root.....................|NERDTree-R| +m.......Display the NERD tree menu...............................|NERDTree-m| +cd......Change the CWD to the dir of the selected node...........|NERDTree-cd| +CD......Change tree root to the CWD..............................|NERDTree-CD| + +I.......Toggle whether hidden files displayed....................|NERDTree-I| +f.......Toggle whether the file filters are used.................|NERDTree-f| +F.......Toggle whether files are displayed.......................|NERDTree-F| +B.......Toggle whether the bookmark table is displayed...........|NERDTree-B| + +q.......Close the NERDTree window................................|NERDTree-q| +A.......Zoom (maximize/minimize) the NERDTree window.............|NERDTree-A| +?.......Toggle the display of the quick help.....................|NERDTree-?| + +------------------------------------------------------------------------------ + *NERDTree-o* +Default key: o +Map option: NERDTreeMapActivateNode +Applies to: files and directories. + +If a file node is selected, it is opened in the previous window. + +If a directory is selected it is opened or closed depending on its current +state. + +If a bookmark that links to a directory is selected then that directory +becomes the new root. + +If a bookmark that links to a file is selected then that file is opened in the +previous window. + +------------------------------------------------------------------------------ + *NERDTree-go* +Default key: go +Map option: None +Applies to: files. + +If a file node is selected, it is opened in the previous window, but the +cursor does not move. + +The key combo for this mapping is always "g" + NERDTreeMapActivateNode (see +|NERDTree-o|). + +------------------------------------------------------------------------------ + *NERDTree-t* +Default key: t +Map option: NERDTreeMapOpenInTab +Applies to: files and directories. + +Opens the selected file in a new tab. If a directory is selected, a fresh +NERD Tree for that directory is opened in a new tab. + +If a bookmark which points to a directory is selected, open a NERD tree for +that directory in a new tab. If the bookmark points to a file, open that file +in a new tab. + +------------------------------------------------------------------------------ + *NERDTree-T* +Default key: T +Map option: NERDTreeMapOpenInTabSilent +Applies to: files and directories. + +The same as |NERDTree-t| except that the focus is kept in the current tab. + +------------------------------------------------------------------------------ + *NERDTree-i* +Default key: i +Map option: NERDTreeMapOpenSplit +Applies to: files. + +Opens the selected file in a new split window and puts the cursor in the new +window. + +------------------------------------------------------------------------------ + *NERDTree-gi* +Default key: gi +Map option: None +Applies to: files. + +The same as |NERDTree-i| except that the cursor is not moved. + +The key combo for this mapping is always "g" + NERDTreeMapOpenSplit (see +|NERDTree-i|). + +------------------------------------------------------------------------------ + *NERDTree-s* +Default key: s +Map option: NERDTreeMapOpenVSplit +Applies to: files. + +Opens the selected file in a new vertically split window and puts the cursor in +the new window. + +------------------------------------------------------------------------------ + *NERDTree-gs* +Default key: gs +Map option: None +Applies to: files. + +The same as |NERDTree-s| except that the cursor is not moved. + +The key combo for this mapping is always "g" + NERDTreeMapOpenVSplit (see +|NERDTree-s|). + +------------------------------------------------------------------------------ + *NERDTree-O* +Default key: O +Map option: NERDTreeMapOpenRecursively +Applies to: directories. + +Recursively opens the selected directory. + +All files and directories are cached, but if a directory would not be +displayed due to file filters (see |'NERDTreeIgnore'| |NERDTree-f|) or the +hidden file filter (see |'NERDTreeShowHidden'|) then its contents are not +cached. This is handy, especially if you have .svn directories. + +------------------------------------------------------------------------------ + *NERDTree-x* +Default key: x +Map option: NERDTreeMapCloseDir +Applies to: files and directories. + +Closes the parent of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-X* +Default key: X +Map option: NERDTreeMapCloseChildren +Applies to: directories. + +Recursively closes all children of the selected directory. + +Tip: To quickly "reset" the tree, use |NERDTree-P| with this mapping. + +------------------------------------------------------------------------------ + *NERDTree-e* +Default key: e +Map option: NERDTreeMapOpenExpl +Applies to: files and directories. + +|:edit|s the selected directory, or the selected file's directory. This could +result in a NERD tree or a netrw being opened, depending on +|'NERDTreeHijackNetrw'|. + +------------------------------------------------------------------------------ + *NERDTree-D* +Default key: D +Map option: NERDTreeMapDeleteBookmark +Applies to: lines in the bookmarks table + +Deletes the currently selected bookmark. + +------------------------------------------------------------------------------ + *NERDTree-P* +Default key: P +Map option: NERDTreeMapJumpRoot +Applies to: no restrictions. + +Jump to the tree root. + +------------------------------------------------------------------------------ + *NERDTree-p* +Default key: p +Map option: NERDTreeMapJumpParent +Applies to: files and directories. + +Jump to the parent node of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-K* +Default key: K +Map option: NERDTreeMapJumpFirstChild +Applies to: files and directories. + +Jump to the first child of the current nodes parent. + +If the cursor is already on the first node then do the following: + * loop back thru the siblings of the current nodes parent until we find an + open dir with children + * go to the first child of that node + +------------------------------------------------------------------------------ + *NERDTree-J* +Default key: J +Map option: NERDTreeMapJumpLastChild +Applies to: files and directories. + +Jump to the last child of the current nodes parent. + +If the cursor is already on the last node then do the following: + * loop forward thru the siblings of the current nodes parent until we find + an open dir with children + * go to the last child of that node + +------------------------------------------------------------------------------ + *NERDTree-C-J* +Default key: +Map option: NERDTreeMapJumpNextSibling +Applies to: files and directories. + +Jump to the next sibling of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-C-K* +Default key: +Map option: NERDTreeMapJumpPrevSibling +Applies to: files and directories. + +Jump to the previous sibling of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-C* +Default key: C +Map option: NERDTreeMapChangeRoot +Applies to: files and directories. + +Make the selected directory node the new tree root. If a file is selected, its +parent is used. + +------------------------------------------------------------------------------ + *NERDTree-u* +Default key: u +Map option: NERDTreeMapUpdir +Applies to: no restrictions. + +Move the tree root up a dir (like doing a "cd .."). + +------------------------------------------------------------------------------ + *NERDTree-U* +Default key: U +Map option: NERDTreeMapUpdirKeepOpen +Applies to: no restrictions. + +Like |NERDTree-u| except that the old tree root is kept open. + +------------------------------------------------------------------------------ + *NERDTree-r* +Default key: r +Map option: NERDTreeMapRefresh +Applies to: files and directories. + +If a dir is selected, recursively refresh that dir, i.e. scan the filesystem +for changes and represent them in the tree. + +If a file node is selected then the above is done on it's parent. + +------------------------------------------------------------------------------ + *NERDTree-R* +Default key: R +Map option: NERDTreeMapRefreshRoot +Applies to: no restrictions. + +Recursively refresh the tree root. + +------------------------------------------------------------------------------ + *NERDTree-m* +Default key: m +Map option: NERDTreeMapMenu +Applies to: files and directories. + +Display the NERD tree menu. See |NERDTreeMenu| for details. + +------------------------------------------------------------------------------ + *NERDTree-cd* +Default key: cd +Map option: NERDTreeMapChdir +Applies to: files and directories. + +Change vims current working directory to that of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-CD* +Default key: CD +Map option: NERDTreeMapCWD +Applies to: no restrictions. + +Change tree root to vims current working directory. + +------------------------------------------------------------------------------ + *NERDTree-I* +Default key: I +Map option: NERDTreeMapToggleHidden +Applies to: no restrictions. + +Toggles whether hidden files (i.e. "dot files") are displayed. + +------------------------------------------------------------------------------ + *NERDTree-f* +Default key: f +Map option: NERDTreeMapToggleFilters +Applies to: no restrictions. + +Toggles whether file filters are used. See |'NERDTreeIgnore'| for details. + +------------------------------------------------------------------------------ + *NERDTree-F* +Default key: F +Map option: NERDTreeMapToggleFiles +Applies to: no restrictions. + +Toggles whether file nodes are displayed. + +------------------------------------------------------------------------------ + *NERDTree-B* +Default key: B +Map option: NERDTreeMapToggleBookmarks +Applies to: no restrictions. + +Toggles whether the bookmarks table is displayed. + +------------------------------------------------------------------------------ + *NERDTree-q* +Default key: q +Map option: NERDTreeMapQuit +Applies to: no restrictions. + +Closes the NERDtree window. + +------------------------------------------------------------------------------ + *NERDTree-A* +Default key: A +Map option: NERDTreeMapToggleZoom +Applies to: no restrictions. + +Maximize (zoom) and minimize the NERDtree window. + +------------------------------------------------------------------------------ + *NERDTree-?* +Default key: ? +Map option: NERDTreeMapHelp +Applies to: no restrictions. + +Toggles whether the quickhelp is displayed. + +------------------------------------------------------------------------------ +2.3. The NERD tree menu *NERDTreeMenu* + +The NERD tree has a menu that can be programmed via the an API (see +|NERDTreeMenuAPI|). The idea is to simulate the "right click" menus that most +file explorers have. + +The script comes with two default menu plugins: exec_menuitem.vim and +fs_menu.vim. fs_menu.vim adds some basic filesystem operations to the menu for +creating/deleting/moving/copying files and dirs. exec_menuitem.vim provides a +menu item to execute executable files. + +Related tags: |NERDTree-m| |NERDTreeApi| + +============================================================================== +3. Customisation *NERDTreeOptions* + + +------------------------------------------------------------------------------ +3.1. Customisation summary *NERDTreeOptionSummary* + +The script provides the following options that can customise the behaviour the +NERD tree. These options should be set in your vimrc. + +|'loaded_nerd_tree'| Turns off the script. + +|'NERDTreeAutoCenter'| Controls whether the NERD tree window centers + when the cursor moves within a specified + distance to the top/bottom of the window. + +|'NERDTreeAutoCenterThreshold'| Controls the sensitivity of autocentering. + +|'NERDTreeCaseSensitiveSort'| Tells the NERD tree whether to be case + sensitive or not when sorting nodes. + +|'NERDTreeSortHiddenFirst'| Tells the NERD tree whether to take the dot + at the beginning of the hidden file names + into account when sorting nodes. + +|'NERDTreeChDirMode'| Tells the NERD tree if/when it should change + vim's current working directory. + +|'NERDTreeHighlightCursorline'| Tell the NERD tree whether to highlight the + current cursor line. + +|'NERDTreeHijackNetrw'| Tell the NERD tree whether to replace the netrw + autocommands for exploring local directories. + +|'NERDTreeIgnore'| Tells the NERD tree which files to ignore. + +|'NERDTreeRespectWildIgnore'| Tells the NERD tree to respect |'wildignore'|. + +|'NERDTreeBookmarksFile'| Where the bookmarks are stored. + +|'NERDTreeBookmarksSort'| Whether the bookmarks list is sorted on + display. + +|'NERDTreeMouseMode'| Tells the NERD tree how to handle mouse + clicks. + +|'NERDTreeQuitOnOpen'| Closes the tree window after opening a file. + +|'NERDTreeShowBookmarks'| Tells the NERD tree whether to display the + bookmarks table on startup. + +|'NERDTreeShowFiles'| Tells the NERD tree whether to display files + in the tree on startup. + +|'NERDTreeShowHidden'| Tells the NERD tree whether to display hidden + files on startup. + +|'NERDTreeShowLineNumbers'| Tells the NERD tree whether to display line + numbers in the tree window. + +|'NERDTreeSortOrder'| Tell the NERD tree how to sort the nodes in + the tree. + +|'NERDTreeStatusline'| Set a statusline for NERD tree windows. + +|'NERDTreeWinPos'| Tells the script where to put the NERD tree + window. + +|'NERDTreeWinSize'| Sets the window size when the NERD tree is + opened. + +|'NERDTreeMinimalUI'| Disables display of the 'Bookmarks' label and + 'Press ? for help' text. + +|'NERDTreeDirArrows'| Tells the NERD tree to use arrows instead of + + ~ chars when displaying directories. + +|'NERDTreeCascadeOpenSingleChildDir'| + Cascade open while selected directory has only + one child that also is a directory. + +|'NERDTreeAutoDeleteBuffer'| Tells the NERD tree to automatically remove + a buffer when a file is being deleted or renamed + via a context menu command. + +------------------------------------------------------------------------------ +3.2. Customisation details *NERDTreeOptionDetails* + +To enable any of the below options you should put the given line in your +~/.vimrc + + *'loaded_nerd_tree'* +If this plugin is making you feel homicidal, it may be a good idea to turn it +off with this line in your vimrc: > + let loaded_nerd_tree=1 +< + +------------------------------------------------------------------------------ + *'NERDTreeAutoCenter'* +Values: 0 or 1. +Default: 1 + +If set to 1, the NERD tree window will center around the cursor if it moves to +within |'NERDTreeAutoCenterThreshold'| lines of the top/bottom of the window. + +This is ONLY done in response to tree navigation mappings, +i.e. |NERDTree-J| |NERDTree-K| |NERDTree-C-J| |NERDTree-C-K| |NERDTree-p| +|NERDTree-P| + +The centering is done with a |zz| operation. + +------------------------------------------------------------------------------ + *'NERDTreeAutoCenterThreshold'* +Values: Any natural number. +Default: 3 + +This option controls the "sensitivity" of the NERD tree auto centering. See +|'NERDTreeAutoCenter'| for details. + +------------------------------------------------------------------------------ + *'NERDTreeCaseSensitiveSort'* +Values: 0 or 1. +Default: 0. + +By default the NERD tree does not sort nodes case sensitively, i.e. nodes +could appear like this: > + bar.c + Baz.c + blarg.c + boner.c + Foo.c +< +But, if you set this option to 1 then the case of the nodes will be taken into +account. The above nodes would then be sorted like this: > + Baz.c + Foo.c + bar.c + blarg.c + boner.c +< +------------------------------------------------------------------------------ + *'NERDTreeChDirMode'* + +Values: 0, 1 or 2. +Default: 0. + +Use this option to tell the script when (if at all) to change the current +working directory (CWD) for vim. + +If it is set to 0 then the CWD is never changed by the NERD tree. + +If set to 1 then the CWD is changed when the NERD tree is first loaded to the +directory it is initialized in. For example, if you start the NERD tree with > + :NERDTree /home/marty/foobar +< +then the CWD will be changed to /home/marty/foobar and will not be changed +again unless you init another NERD tree with a similar command. + +If the option is set to 2 then it behaves the same as if set to 1 except that +the CWD is changed whenever the tree root is changed. For example, if the CWD +is /home/marty/foobar and you make the node for /home/marty/foobar/baz the new +root then the CWD will become /home/marty/foobar/baz. + +------------------------------------------------------------------------------ + *'NERDTreeHighlightCursorline'* +Values: 0 or 1. +Default: 1. + +If set to 1, the current cursor line in the NERD tree buffer will be +highlighted. This is done using the |'cursorline'| option. + +------------------------------------------------------------------------------ + *'NERDTreeHijackNetrw'* +Values: 0 or 1. +Default: 1. + +If set to 1, doing a > + :edit +< +will open up a "secondary" NERD tree instead of a netrw in the target window. + +Secondary NERD trees behaves slightly different from a regular trees in the +following respects: + 1. 'o' will open the selected file in the same window as the tree, + replacing it. + 2. you can have as many secondary tree as you want in the same tab. + +------------------------------------------------------------------------------ + *'NERDTreeIgnore'* +Values: a list of regular expressions. +Default: ['\~$']. + +This option is used to specify which files the NERD tree should ignore. It +must be a list of regular expressions. When the NERD tree is rendered, any +files/dirs that match any of the regex's in 'NERDTreeIgnore' wont be +displayed. + +For example if you put the following line in your vimrc: > + let NERDTreeIgnore=['\.vim$', '\~$'] +< +then all files ending in .vim or ~ will be ignored. + +There are 2 magic flags that can be appended to the end of each regular +expression to specify that the regex should match only files or only dirs. +These flags are "[[dir]]" and "[[file]]". Example: > + let NERDTreeIgnore=['.d$[[dir]]', '.o$[[file]]'] +< +This will cause all dirs ending in ".d" to be ignored and all files ending in +".o" to be ignored. + +Note: to tell the NERD tree not to ignore any files you must use the following +line: > + let NERDTreeIgnore=[] +< + +The file filters can be turned on and off dynamically with the |NERDTree-f| +mapping. + +------------------------------------------------------------------------------ + *'NERDTreeRespectWildIgnore'* +Values: 0 or 1. +Default: 0. + +If set to 1, the |'wildignore'| setting is respected. + +------------------------------------------------------------------------------ + *'NERDTreeBookmarksFile'* +Values: a path +Default: $HOME/.NERDTreeBookmarks + +This is where bookmarks are saved. See |NERDTreeBookmarkCommands|. + +------------------------------------------------------------------------------ + *'NERDTreeBookmarksSort'* +Values: 0 or 1 +Default: 1 + +If set to 0 then the bookmarks list is not sorted. +If set to 1 the bookmarks list is sorted. + +------------------------------------------------------------------------------ + *'NERDTreeMouseMode'* +Values: 1, 2 or 3. +Default: 1. + +If set to 1 then a double click on a node is required to open it. +If set to 2 then a single click will open directory nodes, while a double +click will still be required for file nodes. +If set to 3 then a single click will open any node. + +Note: a double click anywhere on a line that a tree node is on will +activate it, but all single-click activations must be done on name of the node +itself. For example, if you have the following node: > + | | |-application.rb +< +then (to single click activate it) you must click somewhere in +'application.rb'. + +------------------------------------------------------------------------------ + *'NERDTreeQuitOnOpen'* + +Values: 0 or 1. +Default: 0 + +If set to 1, the NERD tree window will close after opening a file with the +|NERDTree-o|, |NERDTree-i|, |NERDTree-t| and |NERDTree-T| mappings. + +------------------------------------------------------------------------------ + *'NERDTreeShowBookmarks'* +Values: 0 or 1. +Default: 0. + +If this option is set to 1 then the bookmarks table will be displayed. + +This option can be toggled dynamically, per tree, with the |NERDTree-B| +mapping. + +------------------------------------------------------------------------------ + *'NERDTreeShowFiles'* +Values: 0 or 1. +Default: 1. + +If this option is set to 1 then files are displayed in the NERD tree. If it is +set to 0 then only directories are displayed. + +This option can be toggled dynamically, per tree, with the |NERDTree-F| +mapping and is useful for drastically shrinking the tree when you are +navigating to a different part of the tree. + +------------------------------------------------------------------------------ + *'NERDTreeShowHidden'* +Values: 0 or 1. +Default: 0. + +This option tells vim whether to display hidden files by default. This option +can be dynamically toggled, per tree, with the |NERDTree-I| mapping. Use one +of the follow lines to set this option: > + let NERDTreeShowHidden=0 + let NERDTreeShowHidden=1 +< + +------------------------------------------------------------------------------ + *'NERDTreeShowLineNumbers'* +Values: 0 or 1. +Default: 0. + +This option tells vim whether to display line numbers for the NERD tree +window. Use one of the follow lines to set this option: > + let NERDTreeShowLineNumbers=0 + let NERDTreeShowLineNumbers=1 +< + +------------------------------------------------------------------------------ + *'NERDTreeSortOrder'* +Values: a list of regular expressions. +Default: ['\/$', '*', '\.swp$', '\.bak$', '\~$'] + +This option is set to a list of regular expressions which are used to +specify the order of nodes under their parent. + +For example, if the option is set to: > + ['\.vim$', '\.c$', '\.h$', '*', 'foobar'] +< +then all .vim files will be placed at the top, followed by all .c files then +all .h files. All files containing the string 'foobar' will be placed at the +end. The star is a special flag: it tells the script that every node that +doesnt match any of the other regexps should be placed here. + +If no star is present in 'NERDTreeSortOrder' then one is automatically +appended to the array. + +The regex '\/$' should be used to match directory nodes. + +After this sorting is done, the files in each group are sorted alphabetically. + +Other examples: > + (1) ['*', '\/$'] + (2) [] + (3) ['\/$', '\.rb$', '\.php$', '*', '\.swp$', '\.bak$', '\~$'] +< +1. Directories will appear last, everything else will appear above. +2. Everything will simply appear in alphabetical order. +3. Dirs will appear first, then ruby and php. Swap files, bak files and vim + backup files will appear last with everything else preceding them. + +------------------------------------------------------------------------------ + *'NERDTreeStatusline'* +Values: Any valid statusline setting. +Default: %{b:NERDTreeRoot.path.strForOS(0)} + +Tells the script what to use as the |'statusline'| setting for NERD tree +windows. + +Note that the statusline is set using |:let-&| not |:set| so escaping spaces +isn't necessary. + +Setting this option to -1 will will deactivate it so that your global +statusline setting is used instead. + +------------------------------------------------------------------------------ + *'NERDTreeWinPos'* +Values: "left" or "right" +Default: "left". + +This option is used to determine where NERD tree window is placed on the +screen. + +This option makes it possible to use two different explorer plugins +simultaneously. For example, you could have the taglist plugin on the left of +the window and the NERD tree on the right. + +------------------------------------------------------------------------------ + *'NERDTreeWinSize'* +Values: a positive integer. +Default: 31. + +This option is used to change the size of the NERD tree when it is loaded. + +------------------------------------------------------------------------------ + *'NERDTreeMinimalUI'* +Values: 0 or 1 +Default: 0 + +This options disables the 'Bookmarks' label 'Press ? for help' text. Use one +of the following lines to set this option: > + let NERDTreeMinimalUI=0 + let NERDTreeMinimalUI=1 +< + +------------------------------------------------------------------------------ + *'NERDTreeDirArrows'* +Values: 0 or 1 +Default: 0. + +This option is used to change the default look of directory nodes displayed in +the tree. When set to 0 it shows old-school bars (|), + and ~ chars. If set to +1 it shows right and down arrows. Use one of the follow lines to set this +option: > + let NERDTreeDirArrows=0 + let NERDTreeDirArrows=1 +< + +------------------------------------------------------------------------------ + *'NERDTreeCascadeOpenSingleChildDir'* +Values: 0 or 1 +Default: 1. + +When opening dir nodes, this option tells NERDTree to recursively open dirs +that have only one child which is also a dir. NERDTree will stop when it finds +a dir that contains anything but another single dir. This option also causes +the |NERDTree-x| mapping to close dirs in the same manner. This option may be +useful for Java projects. Use one of the follow lines to set this option: > + let NERDTreeCascadeOpenSingleChildDir=0 + let NERDTreeCascadeOpenSingleChildDir=1 +< + +------------------------------------------------------------------------------ + *'NERDTreeAutoDeleteBuffer'* +Values: 0 or 1 +Default: 0. + +When using a context menu to delete or rename a file you may also want to delete +the buffer which is no more valid. If the option is not set you will see a +confirmation if you really want to delete an old buffer. If you always press 'y' +then it worths to set this option to 1. Use one of the follow lines to set this +option: > + let NERDTreeAutoDeleteBuffer=0 + let NERDTreeAutoDeleteBuffer=1 +< + +============================================================================== +4. The NERD tree API *NERDTreeAPI* + +The NERD tree script allows you to add custom key mappings and menu items via +a set of API calls. Any scripts that use this API should be placed in +~/.vim/nerdtree_plugin/ (*nix) or ~/vimfiles/nerdtree_plugin (windows). + +The script exposes some prototype objects that can be used to manipulate the +tree and/or get information from it: > + g:NERDTreePath + g:NERDTreeDirNode + g:NERDTreeFileNode + g:NERDTreeBookmark +< +See the code/comments in NERD_tree.vim to find how to use these objects. The +following code conventions are used: + * class members start with a capital letter + * instance members start with a lower case letter + * private members start with an underscore + +See this blog post for more details: + http://got-ravings.blogspot.com/2008/09/vim-pr0n-prototype-based-objects.html + +------------------------------------------------------------------------------ +4.1. Key map API *NERDTreeKeymapAPI* + +NERDTreeAddKeyMap({options}) *NERDTreeAddKeyMap()* + Adds a new keymapping for all NERD tree buffers. + {options} must be a dictionary, and must contain the following keys: + "key" - the trigger key for the new mapping + "callback" - the function the new mapping will be bound to + "quickhelpText" - the text that will appear in the quickhelp (see + |NERDTree-?|) + "override" - if 1 then this new mapping will override whatever previous + mapping was defined for the key/scope combo. Useful for overriding the + default mappings. + + Additionally, a "scope" argument may be supplied. This constrains the + mapping so that it is only activated if the cursor is on a certain object. + That object is then passed into the handling method. Possible values are: + "FileNode" - a file node + "DirNode" - a directory node + "Node" - a file or directory node + "Bookmark" - A bookmark + "all" - the keymap is not constrained to any scope (default). When + thei is used, the handling function is not passed any arguments. + + + Example: > + call NERDTreeAddKeyMap({ + \ 'key': 'foo', + \ 'callback': 'NERDTreeCDHandler', + \ 'quickhelpText': 'echo full path of current node', + \ 'scope': 'DirNode' }) + + function! NERDTreeCDHandler(dirnode) + call a:dirnode.changeToDir() + endfunction +< + This code should sit in a file like ~/.vim/nerdtree_plugin/mymapping.vim. + It adds a (redundant) mapping on 'foo' which changes vim's CWD to that of + the current dir node. Note this mapping will only fire when the cursor is + on a directory node. + +------------------------------------------------------------------------------ +4.2. Menu API *NERDTreeMenuAPI* + +NERDTreeAddSubmenu({options}) *NERDTreeAddSubmenu()* + Creates and returns a new submenu. + + {options} must be a dictionary and must contain the following keys: + "text" - the text of the submenu that the user will see + "shortcut" - a shortcut key for the submenu (need not be unique) + + The following keys are optional: + "isActiveCallback" - a function that will be called to determine whether + this submenu item will be displayed or not. The callback function must return + 0 or 1. + "parent" - the parent submenu of the new submenu (returned from a previous + invocation of NERDTreeAddSubmenu()). If this key is left out then the new + submenu will sit under the top level menu. + + See below for an example. + +NERDTreeAddMenuItem({options}) *NERDTreeAddMenuItem()* + Adds a new menu item to the NERD tree menu (see |NERDTreeMenu|). + + {options} must be a dictionary and must contain the + following keys: + "text" - the text of the menu item which the user will see + "shortcut" - a shortcut key for the menu item (need not be unique) + "callback" - the function that will be called when the user activates the + menu item. + + The following keys are optional: + "isActiveCallback" - a function that will be called to determine whether + this menu item will be displayed or not. The callback function must return + 0 or 1. + "parent" - if the menu item belongs under a submenu then this key must be + specified. This value for this key will be the object that + was returned when the submenu was created with |NERDTreeAddSubmenu()|. + + See below for an example. + +NERDTreeAddMenuSeparator([{options}]) *NERDTreeAddMenuSeparator()* + Adds a menu separator (a row of dashes). + + {options} is an optional dictionary that may contain the following keys: + "isActiveCallback" - see description in |NERDTreeAddMenuItem()|. + +Below is an example of the menu API in action. > + call NERDTreeAddMenuSeparator() + + call NERDTreeAddMenuItem({ + \ 'text': 'a (t)op level menu item', + \ 'shortcut': 't', + \ 'callback': 'SomeFunction' }) + + let submenu = NERDTreeAddSubmenu({ + \ 'text': 'a (s)ub menu', + \ 'shortcut': 's' }) + + call NERDTreeAddMenuItem({ + \ 'text': '(n)ested item 1', + \ 'shortcut': 'n', + \ 'callback': 'SomeFunction', + \ 'parent': submenu }) + + call NERDTreeAddMenuItem({ + \ 'text': '(n)ested item 2', + \ 'shortcut': 'n', + \ 'callback': 'SomeFunction', + \ 'parent': submenu }) +< +This will create the following menu: > + -------------------- + a (t)op level menu item + a (s)ub menu +< +Where selecting "a (s)ub menu" will lead to a second menu: > + (n)ested item 1 + (n)ested item 2 +< +When any of the 3 concrete menu items are selected the function "SomeFunction" +will be called. + +------------------------------------------------------------------------------ +NERDTreeRender() *NERDTreeRender()* + Re-renders the NERD tree buffer. Useful if you change the state of the + tree and you want to it to be reflected in the UI. + +============================================================================== +5. About *NERDTreeAbout* + +The author of the NERD tree is a terrible terrible monster called Martyzilla +who gobbles up small children with milk and sugar for breakfast. + +He can be reached at martin.grenfell at gmail dot com. He would love to hear +from you, so feel free to send him suggestions and/or comments about this +plugin. Don't be shy --- the worst he can do is slaughter you and stuff you in +the fridge for later ;) + +The latest stable versions can be found at + http://www.vim.org/scripts/script.php?script_id=1658 + +The latest dev versions are on github + http://github.com/scrooloose/nerdtree + + +============================================================================== +6. Changelog *NERDTreeChangelog* + +Next + - add 'scope' argument to the key map API + - add NERDTreeCustomIgnoreFilter hook - needs doc + - add magic [[dir]] and [[file]] flags to NERDTreeIgnore + +4.2.0 + - Add NERDTreeDirArrows option to make the UI use pretty arrow chars + instead of the old +~| chars to define the tree structure (sickill) + - shift the syntax highlighting out into its own syntax file (gnap) + - add some mac specific options to the filesystem menu - for macvim + only (andersonfreitas) + - Add NERDTreeMinimalUI option to remove some non functional parts of the + nerdtree ui (camthompson) + - tweak the behaviour of :NERDTreeFind - see :help :NERDTreeFind for the + new behaviour (benjamingeiger) + - if no name is given to :Bookmark, make it default to the name of the + target file/dir (minyoung) + - use 'file' completion when doing copying, create, and move + operations (EvanDotPro) + - lots of misc bug fixes (paddyoloughlin, sdewald, camthompson, Vitaly + Bogdanov, AndrewRadev, mathias, scottstvnsn, kml, wycats, me RAWR!) + +4.1.0 + features: + - NERDTreeFind to reveal the node for the current buffer in the tree, + see |NERDTreeFind|. This effectively merges the FindInNERDTree plugin (by + Doug McInnes) into the script. + - make NERDTreeQuitOnOpen apply to the t/T keymaps too. Thanks to Stefan + Ritter and Rémi Prévost. + - truncate the root node if wider than the tree window. Thanks to Victor + Gonzalez. + + bugfixes: + - really fix window state restoring + - fix some win32 path escaping issues. Thanks to Stephan Baumeister, Ricky, + jfilip1024, and Chris Chambers + +4.0.0 + - add a new programmable menu system (see :help NERDTreeMenu). + - add new APIs to add menus/menu-items to the menu system as well as + custom key mappings to the NERD tree buffer (see :help NERDTreeAPI). + - removed the old API functions + - added a mapping to maximize/restore the size of nerd tree window, thanks + to Guillaume Duranceau for the patch. See :help NERDTree-A for details. + + - fix a bug where secondary nerd trees (netrw hijacked trees) and + NERDTreeQuitOnOpen didnt play nicely, thanks to Curtis Harvey. + - fix a bug where the script ignored directories whose name ended in a dot, + thanks to Aggelos Orfanakos for the patch. + - fix a bug when using the x mapping on the tree root, thanks to Bryan + Venteicher for the patch. + - fix a bug where the cursor position/window size of the nerd tree buffer + wasnt being stored on closing the window, thanks to Richard Hart. + - fix a bug where NERDTreeMirror would mirror the wrong tree + +3.1.1 + - fix a bug where a non-listed no-name buffer was getting created every + time the tree windows was created, thanks to Derek Wyatt and owen1 + - make behave the same as the 'o' mapping + - some helptag fixes in the doc, thanks strull + - fix a bug when using :set nohidden and opening a file where the previous + buf was modified. Thanks iElectric + - other minor fixes + +3.1.0 + New features: + - add mappings to open files in a vsplit, see :help NERDTree-s and :help + NERDTree-gs + - make the statusline for the nerd tree window default to something + hopefully more useful. See :help 'NERDTreeStatusline' + Bugfixes: + - make the hijack netrw functionality work when vim is started with "vim + " (thanks to Alf Mikula for the patch). + - fix a bug where the CWD wasnt being changed for some operations even when + NERDTreeChDirMode==2 (thanks to Lucas S. Buchala) + - add -bar to all the nerd tree :commands so they can chain with other + :commands (thanks to tpope) + - fix bugs when ignorecase was set (thanks to nach) + - fix a bug with the relative path code (thanks to nach) + - fix a bug where doing a :cd would cause :NERDTreeToggle to fail (thanks nach) + + +3.0.1 + Bugfixes: + - fix bugs with :NERDTreeToggle and :NERDTreeMirror when 'hidden + was not set + - fix a bug where :NERDTree would fail if was relative and + didnt start with a ./ or ../ Thanks to James Kanze. + - make the q mapping work with secondary (:e style) trees, + thanks to jamessan + - fix a bunch of small bugs with secondary trees + + More insane refactoring. + +3.0.0 + - hijack netrw so that doing an :edit will put a NERD tree in + the window rather than a netrw browser. See :help 'NERDTreeHijackNetrw' + - allow sharing of trees across tabs, see :help :NERDTreeMirror + - remove "top" and "bottom" as valid settings for NERDTreeWinPos + - change the '' mapping to 'i' + - change the 'H' mapping to 'I' + - lots of refactoring + +============================================================================== +7. Credits *NERDTreeCredits* + +Thanks to the following people for testing, bug reports, ideas etc. Without +you I probably would have got bored of the hacking the NERD tree and +just downloaded pr0n instead. + + Tim Carey-Smith (halorgium) + Vigil + Nick Brettell + Thomas Scott Urban + Terrance Cohen + Yegappan Lakshmanan + Jason Mills + Michael Geddes (frogonwheels) + Yu Jun + Michael Madsen + AOYAMA Shotaro + Zhang Weiwu + Niels Aan de Brugh + Olivier Yiptong + Zhang Shuhan + Cory Echols + Piotr Czachur + Yuan Jiang + Matan Nassau + Maxim Kim + Charlton Wang + Matt Wozniski (godlygeek) + knekk + Sean Chou + Ryan Penn + Simon Peter Nicholls + Michael Foobar + Tomasz Chomiuk + Denis Pokataev + Tim Pope (tpope) + James Kanze + James Vega (jamessan) + Frederic Chanal (nach) + Alf Mikula + Lucas S. Buchala + Curtis Harvey + Guillaume Duranceau + Richard Hart (hates) + Doug McInnes + Stefan Ritter + Rémi Prévost + Victor Gonzalez + Stephan Baumeister + Ricky + jfilip1024 + Chris Chambers + Vitaly Bogdanov + Patrick O'Loughlin (paddyoloughlin) + Cam Thompson (camthompson) + Marcin Kulik (sickill) + Steve DeWald (sdewald) + Ivan Necas (iNecas) + George Ang (gnap) + Evan Coury (EvanDotPro) + Andrew Radev (AndrewRadev) + Matt Gauger (mathias) + Scott Stevenson (scottstvnsn) + Anderson Freitas (andersonfreitas) + Kamil K. Lemański (kml) + Yehuda Katz (wycats) + Min-Young Wu (minyoung) + Benjamin Geiger (benjamingeiger) + +============================================================================== +8. License *NERDTreeLicense* + +The NERD tree is released under the wtfpl. +See http://sam.zoy.org/wtfpl/COPYING. diff --git a/vim/bundle/nerdtree/lib/nerdtree/bookmark.vim b/vim/bundle/nerdtree/lib/nerdtree/bookmark.vim new file mode 100644 index 0000000..6de9be4 --- /dev/null +++ b/vim/bundle/nerdtree/lib/nerdtree/bookmark.vim @@ -0,0 +1,319 @@ +"CLASS: Bookmark +"============================================================ +let s:Bookmark = {} +let g:NERDTreeBookmark = s:Bookmark + +" FUNCTION: Bookmark.activate() {{{1 +function! s:Bookmark.activate(...) + call self.open(a:0 ? a:1 : {}) +endfunction + +" FUNCTION: Bookmark.AddBookmark(name, path) {{{1 +" Class method to add a new bookmark to the list, if a previous bookmark exists +" with the same name, just update the path for that bookmark +function! s:Bookmark.AddBookmark(name, path) + for i in s:Bookmark.Bookmarks() + if i.name ==# a:name + let i.path = a:path + return + endif + endfor + call add(s:Bookmark.Bookmarks(), s:Bookmark.New(a:name, a:path)) + if g:NERDTreeBookmarksSort ==# 1 + call s:Bookmark.Sort() + endif +endfunction + +" FUNCTION: Bookmark.Bookmarks() {{{1 +" Class method to get all bookmarks. Lazily initializes the bookmarks global +" variable +function! s:Bookmark.Bookmarks() + if !exists("g:NERDTreeBookmarks") + let g:NERDTreeBookmarks = [] + endif + return g:NERDTreeBookmarks +endfunction + +" FUNCTION: Bookmark.BookmarkExistsFor(name) {{{1 +" class method that returns 1 if a bookmark with the given name is found, 0 +" otherwise +function! s:Bookmark.BookmarkExistsFor(name) + try + call s:Bookmark.BookmarkFor(a:name) + return 1 + catch /^NERDTree.BookmarkNotFoundError/ + return 0 + endtry +endfunction + +" FUNCTION: Bookmark.BookmarkFor(name) {{{1 +" Class method to get the bookmark that has the given name. {} is return if no +" bookmark is found +function! s:Bookmark.BookmarkFor(name) + for i in s:Bookmark.Bookmarks() + if i.name ==# a:name + return i + endif + endfor + throw "NERDTree.BookmarkNotFoundError: no bookmark found for name: \"". a:name .'"' +endfunction + +" FUNCTION: Bookmark.BookmarkNames() {{{1 +" Class method to return an array of all bookmark names +function! s:Bookmark.BookmarkNames() + let names = [] + for i in s:Bookmark.Bookmarks() + call add(names, i.name) + endfor + return names +endfunction + +" FUNCTION: Bookmark.CacheBookmarks(silent) {{{1 +" Class method to read all bookmarks from the bookmarks file initialize +" bookmark objects for each one. +" +" Args: +" silent - dont echo an error msg if invalid bookmarks are found +function! s:Bookmark.CacheBookmarks(silent) + if filereadable(g:NERDTreeBookmarksFile) + let g:NERDTreeBookmarks = [] + let g:NERDTreeInvalidBookmarks = [] + let bookmarkStrings = readfile(g:NERDTreeBookmarksFile) + let invalidBookmarksFound = 0 + for i in bookmarkStrings + + "ignore blank lines + if i != '' + + let name = substitute(i, '^\(.\{-}\) .*$', '\1', '') + let path = substitute(i, '^.\{-} \(.*\)$', '\1', '') + + try + let bookmark = s:Bookmark.New(name, g:NERDTreePath.New(path)) + call add(g:NERDTreeBookmarks, bookmark) + catch /^NERDTree.InvalidArgumentsError/ + call add(g:NERDTreeInvalidBookmarks, i) + let invalidBookmarksFound += 1 + endtry + endif + endfor + if invalidBookmarksFound + call s:Bookmark.Write() + if !a:silent + call nerdtree#echo(invalidBookmarksFound . " invalid bookmarks were read. See :help NERDTreeInvalidBookmarks for info.") + endif + endif + if g:NERDTreeBookmarksSort ==# 1 + call s:Bookmark.Sort() + endif + endif +endfunction + +" FUNCTION: Bookmark.compareTo(otherbookmark) {{{1 +" Compare these two bookmarks for sorting purposes +function! s:Bookmark.compareTo(otherbookmark) + return a:otherbookmark.name < self.name +endfunction +" FUNCTION: Bookmark.ClearAll() {{{1 +" Class method to delete all bookmarks. +function! s:Bookmark.ClearAll() + for i in s:Bookmark.Bookmarks() + call i.delete() + endfor + call s:Bookmark.Write() +endfunction + +" FUNCTION: Bookmark.delete() {{{1 +" Delete this bookmark. If the node for this bookmark is under the current +" root, then recache bookmarks for its Path object +function! s:Bookmark.delete() + let node = {} + try + let node = self.getNode(1) + catch /^NERDTree.BookmarkedNodeNotFoundError/ + endtry + call remove(s:Bookmark.Bookmarks(), index(s:Bookmark.Bookmarks(), self)) + if !empty(node) + call node.path.cacheDisplayString() + endif + call s:Bookmark.Write() +endfunction + +" FUNCTION: Bookmark.getNode(searchFromAbsoluteRoot) {{{1 +" Gets the treenode for this bookmark +" +" Args: +" searchFromAbsoluteRoot: specifies whether we should search from the current +" tree root, or the highest cached node +function! s:Bookmark.getNode(searchFromAbsoluteRoot) + let searchRoot = a:searchFromAbsoluteRoot ? g:NERDTreeDirNode.AbsoluteTreeRoot() : b:NERDTreeRoot + let targetNode = searchRoot.findNode(self.path) + if empty(targetNode) + throw "NERDTree.BookmarkedNodeNotFoundError: no node was found for bookmark: " . self.name + endif + return targetNode +endfunction + +" FUNCTION: Bookmark.GetNodeForName(name, searchFromAbsoluteRoot) {{{1 +" Class method that finds the bookmark with the given name and returns the +" treenode for it. +function! s:Bookmark.GetNodeForName(name, searchFromAbsoluteRoot) + let bookmark = s:Bookmark.BookmarkFor(a:name) + return bookmark.getNode(a:searchFromAbsoluteRoot) +endfunction + +" FUNCTION: Bookmark.GetSelected() {{{1 +" returns the Bookmark the cursor is over, or {} +function! s:Bookmark.GetSelected() + let line = getline(".") + let name = substitute(line, '^>\(.\{-}\) .\+$', '\1', '') + if name != line + try + return s:Bookmark.BookmarkFor(name) + catch /^NERDTree.BookmarkNotFoundError/ + return {} + endtry + endif + return {} +endfunction + +" FUNCTION: Bookmark.InvalidBookmarks() {{{1 +" Class method to get all invalid bookmark strings read from the bookmarks +" file +function! s:Bookmark.InvalidBookmarks() + if !exists("g:NERDTreeInvalidBookmarks") + let g:NERDTreeInvalidBookmarks = [] + endif + return g:NERDTreeInvalidBookmarks +endfunction + +" FUNCTION: Bookmark.mustExist() {{{1 +function! s:Bookmark.mustExist() + if !self.path.exists() + call s:Bookmark.CacheBookmarks(1) + throw "NERDTree.BookmarkPointsToInvalidLocationError: the bookmark \"". + \ self.name ."\" points to a non existing location: \"". self.path.str() + endif +endfunction + +" FUNCTION: Bookmark.New(name, path) {{{1 +" Create a new bookmark object with the given name and path object +function! s:Bookmark.New(name, path) + if a:name =~# ' ' + throw "NERDTree.IllegalBookmarkNameError: illegal name:" . a:name + endif + + let newBookmark = copy(self) + let newBookmark.name = a:name + let newBookmark.path = a:path + return newBookmark +endfunction + +" FUNCTION: Bookmark.open([options]) {{{1 +"Args: +"A dictionary containing the following keys (all optional): +" 'where': Specifies whether the node should be opened in new split/tab or in +" the previous window. Can be either 'v' (vertical split), 'h' +" (horizontal split), 't' (new tab) or 'p' (previous window). +" 'reuse': if a window is displaying the file then jump the cursor there +" 'keepopen': dont close the tree window +" 'stay': open the file, but keep the cursor in the tree win +" +function! s:Bookmark.open(...) + let opts = a:0 ? a:1 : {} + + if self.path.isDirectory && !has_key(opts, 'where') + call self.toRoot() + else + let opener = g:NERDTreeOpener.New(self.path, opts) + call opener.open(self) + endif +endfunction + +" FUNCTION: Bookmark.openInNewTab(options) {{{1 +" Create a new bookmark object with the given name and path object +function! s:Bookmark.openInNewTab(options) + call nerdtree#deprecated('Bookmark.openInNewTab', 'is deprecated, use open() instead') + call self.open(a:options) +endfunction + +" FUNCTION: Bookmark.setPath(path) {{{1 +" makes this bookmark point to the given path +function! s:Bookmark.setPath(path) + let self.path = a:path +endfunction + +" FUNCTION: Bookmark.Sort() {{{1 +" Class method that sorts all bookmarks +function! s:Bookmark.Sort() + let CompareFunc = function("nerdtree#compareBookmarks") + call sort(s:Bookmark.Bookmarks(), CompareFunc) +endfunction + +" FUNCTION: Bookmark.str() {{{1 +" Get the string that should be rendered in the view for this bookmark +function! s:Bookmark.str() + let pathStrMaxLen = winwidth(nerdtree#getTreeWinNum()) - 4 - len(self.name) + if &nu + let pathStrMaxLen = pathStrMaxLen - &numberwidth + endif + + let pathStr = self.path.str({'format': 'UI'}) + if len(pathStr) > pathStrMaxLen + let pathStr = '<' . strpart(pathStr, len(pathStr) - pathStrMaxLen) + endif + return '>' . self.name . ' ' . pathStr +endfunction + +" FUNCTION: Bookmark.toRoot() {{{1 +" Make the node for this bookmark the new tree root +function! s:Bookmark.toRoot() + if self.validate() + try + let targetNode = self.getNode(1) + catch /^NERDTree.BookmarkedNodeNotFoundError/ + let targetNode = g:NERDTreeFileNode.New(s:Bookmark.BookmarkFor(self.name).path) + endtry + call targetNode.makeRoot() + call b:NERDTree.render() + call targetNode.putCursorHere(0, 0) + endif +endfunction + +" FUNCTION: Bookmark.ToRoot(name) {{{1 +" Make the node for this bookmark the new tree root +function! s:Bookmark.ToRoot(name) + let bookmark = s:Bookmark.BookmarkFor(a:name) + call bookmark.toRoot() +endfunction + +" FUNCTION: Bookmark.validate() {{{1 +function! s:Bookmark.validate() + if self.path.exists() + return 1 + else + call s:Bookmark.CacheBookmarks(1) + call b:NERDTree.render() + call nerdtree#echo(self.name . "now points to an invalid location. See :help NERDTreeInvalidBookmarks for info.") + return 0 + endif +endfunction + +" FUNCTION: Bookmark.Write() {{{1 +" Class method to write all bookmarks to the bookmarks file +function! s:Bookmark.Write() + let bookmarkStrings = [] + for i in s:Bookmark.Bookmarks() + call add(bookmarkStrings, i.name . ' ' . i.path.str()) + endfor + + "add a blank line before the invalid ones + call add(bookmarkStrings, "") + + for j in s:Bookmark.InvalidBookmarks() + call add(bookmarkStrings, j) + endfor + call writefile(bookmarkStrings, g:NERDTreeBookmarksFile) +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/nerdtree/lib/nerdtree/creator.vim b/vim/bundle/nerdtree/lib/nerdtree/creator.vim new file mode 100644 index 0000000..86f951a --- /dev/null +++ b/vim/bundle/nerdtree/lib/nerdtree/creator.vim @@ -0,0 +1,357 @@ +"CLASS: Creator +"Creates primary/secondary/mirror nerdtree windows. Sets up all the window and +"buffer options and key mappings etc. +"============================================================ +let s:Creator = {} +let g:NERDTreeCreator = s:Creator + +"FUNCTION: s:Creator._bindMappings() {{{1 +function! s:Creator._bindMappings() + "make do the same as the activate node mapping + nnoremap :call nerdtree#ui_glue#invokeKeyMap(g:NERDTreeMapActivateNode) + + call g:NERDTreeKeyMap.BindAll() + + command! -buffer -nargs=? Bookmark :call nerdtree#ui_glue#bookmarkNode('') + command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=1 RevealBookmark :call nerdtree#ui_glue#revealBookmark('') + command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=1 OpenBookmark :call nerdtree#ui_glue#openBookmark('') + command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=* ClearBookmarks call nerdtree#ui_glue#clearBookmarks('') + command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=+ BookmarkToRoot call g:NERDTreeBookmark.ToRoot('') + command! -buffer -nargs=0 ClearAllBookmarks call g:NERDTreeBookmark.ClearAll() call b:NERDTree.render() + command! -buffer -nargs=0 ReadBookmarks call g:NERDTreeBookmark.CacheBookmarks(0) call b:NERDTree.render() + command! -buffer -nargs=0 WriteBookmarks call g:NERDTreeBookmark.Write() +endfunction + +"FUNCTION: s:Creator._broadcastInitEvent() {{{1 +function! s:Creator._broadcastInitEvent() + silent doautocmd User NERDTreeInit +endfunction + +" FUNCTION: s:Creator.BufNamePrefix() {{{2 +function! s:Creator.BufNamePrefix() + return 'NERD_tree_' +endfunction + +"FUNCTION: s:Creator.CreatePrimary(a:name) {{{1 +function! s:Creator.CreatePrimary(name) + let creator = s:Creator.New() + call creator.createPrimary(a:name) +endfunction + +"FUNCTION: s:Creator.createPrimary(a:name) {{{1 +"name: the name of a bookmark or a directory +function! s:Creator.createPrimary(name) + let path = self._pathForString(a:name) + + "if instructed to, then change the vim CWD to the dir the NERDTree is + "inited in + if g:NERDTreeChDirMode != 0 + call path.changeToDir() + endif + + if g:NERDTree.ExistsForTab() + if nerdtree#isTreeOpen() + call nerdtree#closeTree() + endif + unlet t:NERDTreeBufName + endif + + call self._createTreeWin() + call self._createNERDTree(path) + let b:NERDTreeType = "primary" + let b:treeShowHelp = 0 + let b:NERDTreeIgnoreEnabled = 1 + let b:NERDTreeShowFiles = g:NERDTreeShowFiles + let b:NERDTreeShowHidden = g:NERDTreeShowHidden + let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks + + call b:NERDTree.render() + call b:NERDTreeRoot.putCursorHere(0, 0) + + call self._broadcastInitEvent() +endfunction + +"FUNCTION: s:Creator.CreateSecondary(dir) {{{1 +function! s:Creator.CreateSecondary(dir) + let creator = s:Creator.New() + call creator.createSecondary(a:dir) +endfunction + +"FUNCTION: s:Creator.createSecondary(dir) {{{1 +function! s:Creator.createSecondary(dir) + try + let path = g:NERDTreePath.New(a:dir) + catch /^NERDTree.InvalidArgumentsError/ + call nerdtree#echo("Invalid directory name:" . a:name) + return + endtry + + "we want the directory buffer to disappear when we do the :edit below + setlocal bufhidden=wipe + + let previousBuf = expand("#") + + "we need a unique name for each secondary tree buffer to ensure they are + "all independent + exec "silent edit " . self._nextBufferName() + + let b:NERDTreePreviousBuf = bufnr(previousBuf) + call self._createNERDTree(path) + call self._setCommonBufOptions() + let b:NERDTreeType = "secondary" + + call b:NERDTree.render() + + call self._broadcastInitEvent() +endfunction + +" FUNCTION: s:Creator._createNERDTree(path) {{{1 +function! s:Creator._createNERDTree(path) + let b:NERDTree = g:NERDTree.New(a:path) + "TODO: This is kept for compatability only since many things use + "b:NERDTreeRoot instead of the new NERDTree.root + "Remove this one day + let b:NERDTreeRoot = b:NERDTree.root + + call b:NERDTree.root.open() +endfunction + +" FUNCTION: s:Creator.CreateMirror() {{{1 +function! s:Creator.CreateMirror() + let creator = s:Creator.New() + call creator.createMirror() +endfunction + +" FUNCTION: s:Creator.createMirror() {{{1 +function! s:Creator.createMirror() + "get the names off all the nerd tree buffers + let treeBufNames = [] + for i in range(1, tabpagenr("$")) + let nextName = self._tabpagevar(i, 'NERDTreeBufName') + if nextName != -1 && (!exists("t:NERDTreeBufName") || nextName != t:NERDTreeBufName) + call add(treeBufNames, nextName) + endif + endfor + let treeBufNames = self._uniq(treeBufNames) + + "map the option names (that the user will be prompted with) to the nerd + "tree buffer names + let options = {} + let i = 0 + while i < len(treeBufNames) + let bufName = treeBufNames[i] + let treeRoot = getbufvar(bufName, "NERDTreeRoot") + let options[i+1 . '. ' . treeRoot.path.str() . ' (buf name: ' . bufName . ')'] = bufName + let i = i + 1 + endwhile + + "work out which tree to mirror, if there is more than 1 then ask the user + let bufferName = '' + if len(keys(options)) > 1 + let choices = ["Choose a tree to mirror"] + let choices = extend(choices, sort(keys(options))) + let choice = inputlist(choices) + if choice < 1 || choice > len(options) || choice ==# '' + return + endif + + let bufferName = options[sort(keys(options))[choice-1]] + elseif len(keys(options)) ==# 1 + let bufferName = values(options)[0] + else + call nerdtree#echo("No trees to mirror") + return + endif + + if g:NERDTree.ExistsForTab() && nerdtree#isTreeOpen() + call nerdtree#closeTree() + endif + + let t:NERDTreeBufName = bufferName + call self._createTreeWin() + exec 'buffer ' . bufferName + if !&hidden + call b:NERDTree.render() + endif +endfunction + +"FUNCTION: s:Creator._createTreeWin() {{{1 +"Inits the NERD tree window. ie. opens it, sizes it, sets all the local +"options etc +function! s:Creator._createTreeWin() + "create the nerd tree window + let splitLocation = g:NERDTreeWinPos ==# "left" ? "topleft " : "botright " + let splitSize = g:NERDTreeWinSize + + if !exists('t:NERDTreeBufName') + let t:NERDTreeBufName = self._nextBufferName() + silent! exec splitLocation . 'vertical ' . splitSize . ' new' + silent! exec "edit " . t:NERDTreeBufName + else + silent! exec splitLocation . 'vertical ' . splitSize . ' split' + silent! exec "buffer " . t:NERDTreeBufName + endif + + setlocal winfixwidth + call self._setCommonBufOptions() +endfunction + +"FUNCTION: s:Creator.New() {{{1 +function! s:Creator.New() + let newCreator = copy(self) + return newCreator +endfunction + +" FUNCTION: s:Creator._nextBufferName() {{{2 +" returns the buffer name for the next nerd tree +function! s:Creator._nextBufferName() + let name = s:Creator.BufNamePrefix() . self._nextBufferNumber() + return name +endfunction + +" FUNCTION: s:Creator._nextBufferNumber() {{{2 +" the number to add to the nerd tree buffer name to make the buf name unique +function! s:Creator._nextBufferNumber() + if !exists("s:Creator._NextBufNum") + let s:Creator._NextBufNum = 1 + else + let s:Creator._NextBufNum += 1 + endif + + return s:Creator._NextBufNum +endfunction + +"FUNCTION: s:Creator._pathForString(str) {{{1 +"find a bookmark or adirectory for the given string +function! s:Creator._pathForString(str) + let path = {} + if g:NERDTreeBookmark.BookmarkExistsFor(a:str) + let path = g:NERDTreeBookmark.BookmarkFor(a:str).path + else + let dir = a:str ==# '' ? getcwd() : a:str + + "hack to get an absolute path if a relative path is given + if dir =~# '^\.' + let dir = getcwd() . g:NERDTreePath.Slash() . dir + endif + let dir = g:NERDTreePath.Resolve(dir) + + try + let path = g:NERDTreePath.New(dir) + catch /^NERDTree.InvalidArgumentsError/ + call nerdtree#echo("No bookmark or directory found for: " . a:str) + return + endtry + endif + if !path.isDirectory + let path = path.getParent() + endif + + return path +endfunction + +"FUNCTION: s:Creator._setCommonBufOptions() {{{1 +function! s:Creator._setCommonBufOptions() + "throwaway buffer options + setlocal noswapfile + setlocal buftype=nofile + setlocal bufhidden=hide + setlocal nowrap + setlocal foldcolumn=0 + setlocal foldmethod=manual + setlocal nofoldenable + setlocal nobuflisted + setlocal nospell + if g:NERDTreeShowLineNumbers + setlocal nu + else + setlocal nonu + if v:version >= 703 + setlocal nornu + endif + endif + + iabc + + if g:NERDTreeHighlightCursorline + setlocal cursorline + endif + + call self._setupStatusline() + + let b:treeShowHelp = 0 + let b:NERDTreeIgnoreEnabled = 1 + let b:NERDTreeShowFiles = g:NERDTreeShowFiles + let b:NERDTreeShowHidden = g:NERDTreeShowHidden + let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks + call self._bindMappings() + setlocal filetype=nerdtree +endfunction + +"FUNCTION: s:Creator._setupStatusline() {{{1 +function! s:Creator._setupStatusline() + if g:NERDTreeStatusline != -1 + let &l:statusline = g:NERDTreeStatusline + endif +endfunction + +" FUNCTION: s:Creator._tabpagevar(tabnr, var) {{{1 +function! s:Creator._tabpagevar(tabnr, var) + let currentTab = tabpagenr() + let old_ei = &ei + set ei=all + + exec "tabnext " . a:tabnr + let v = -1 + if exists('t:' . a:var) + exec 'let v = t:' . a:var + endif + exec "tabnext " . currentTab + + let &ei = old_ei + + return v +endfunction + +"FUNCTION: s:Creator.TogglePrimary(dir) {{{1 +function! s:Creator.TogglePrimary(dir) + let creator = s:Creator.New() + call creator.togglePrimary(a:dir) +endfunction + +"FUNCTION: s:Creator.togglePrimary(dir) {{{1 +"Toggles the NERD tree. I.e the NERD tree is open, it is closed, if it is +"closed it is restored or initialized (if it doesnt exist) +" +"Args: +"dir: the full path for the root node (is only used if the NERD tree is being +"initialized. +function! s:Creator.togglePrimary(dir) + if g:NERDTree.ExistsForTab() + if !nerdtree#isTreeOpen() + call self._createTreeWin() + if !&hidden + call b:NERDTree.render() + endif + call b:NERDTree.ui.restoreScreenState() + else + call nerdtree#closeTree() + endif + else + call self.createPrimary(a:dir) + endif +endfunction + +" Function: s:Creator._uniq(list) {{{1 +" returns a:list without duplicates +function! s:Creator._uniq(list) + let uniqlist = [] + for elem in a:list + if index(uniqlist, elem) ==# -1 + let uniqlist += [elem] + endif + endfor + return uniqlist +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/nerdtree/lib/nerdtree/event.vim b/vim/bundle/nerdtree/lib/nerdtree/event.vim new file mode 100644 index 0000000..964e8ff --- /dev/null +++ b/vim/bundle/nerdtree/lib/nerdtree/event.vim @@ -0,0 +1,13 @@ +"CLASS: Event +"============================================================ +let s:Event = {} +let g:NERDTreeEvent = s:Event + +function! s:Event.New(nerdtree, subject, action, params) abort + let newObj = copy(self) + let newObj.nerdtree = a:nerdtree + let newObj.subject = a:subject + let newObj.action = a:action + let newObj.params = a:params + return newObj +endfunction diff --git a/vim/bundle/nerdtree/lib/nerdtree/flag_set.vim b/vim/bundle/nerdtree/lib/nerdtree/flag_set.vim new file mode 100644 index 0000000..9d8d335 --- /dev/null +++ b/vim/bundle/nerdtree/lib/nerdtree/flag_set.vim @@ -0,0 +1,56 @@ +"CLASS: FlagSet +"============================================================ +let s:FlagSet = {} +let g:NERDTreeFlagSet = s:FlagSet + +"FUNCTION: FlagSet.addFlag(scope, flag) {{{1 +function! s:FlagSet.addFlag(scope, flag) + let flags = self._flagsForScope(a:scope) + if index(flags, a:flag) == -1 + call add(flags, a:flag) + end +endfunction + +"FUNCTION: FlagSet.clearFlags(scope) {{{1 +function! s:FlagSet.clearFlags(scope) + let self._flags[a:scope] = [] +endfunction + +"FUNCTION: FlagSet._flagsForScope(scope) {{{1 +function! s:FlagSet._flagsForScope(scope) + if !has_key(self._flags, a:scope) + let self._flags[a:scope] = [] + endif + return self._flags[a:scope] +endfunction + +"FUNCTION: FlagSet.New() {{{1 +function! s:FlagSet.New() + let newObj = copy(self) + let newObj._flags = {} + return newObj +endfunction + +"FUNCTION: FlagSet.removeFlag(scope, flag) {{{1 +function! s:FlagSet.removeFlag(scope, flag) + let flags = self._flagsForScope(a:scope) + + let i = index(flags, a:flag) + if i >= 0 + call remove(flags, i) + endif +endfunction + +"FUNCTION: FlagSet.renderToString() {{{1 +function! s:FlagSet.renderToString() + let flagstring = "" + for i in values(self._flags) + let flagstring .= join(i) + endfor + + if len(flagstring) == 0 + return "" + endif + + return '[' . flagstring . ']' +endfunction diff --git a/vim/bundle/nerdtree/lib/nerdtree/key_map.vim b/vim/bundle/nerdtree/lib/nerdtree/key_map.vim new file mode 100644 index 0000000..2411406 --- /dev/null +++ b/vim/bundle/nerdtree/lib/nerdtree/key_map.vim @@ -0,0 +1,159 @@ +"CLASS: KeyMap +"============================================================ +let s:KeyMap = {} +let g:NERDTreeKeyMap = s:KeyMap + +"FUNCTION: KeyMap.All() {{{1 +function! s:KeyMap.All() + if !exists("s:keyMaps") + let s:keyMaps = [] + endif + return s:keyMaps +endfunction + +"FUNCTION: KeyMap.FindFor(key, scope) {{{1 +function! s:KeyMap.FindFor(key, scope) + for i in s:KeyMap.All() + if i.key ==# a:key && i.scope ==# a:scope + return i + endif + endfor + return {} +endfunction + +"FUNCTION: KeyMap.BindAll() {{{1 +function! s:KeyMap.BindAll() + for i in s:KeyMap.All() + call i.bind() + endfor +endfunction + +"FUNCTION: KeyMap.bind() {{{1 +function! s:KeyMap.bind() + " If the key sequence we're trying to map contains any '<>' notation, we + " must replace each of the '<' characters with '' to ensure the string + " is not translated into its corresponding keycode during the later part + " of the map command below + " :he <> + let specialNotationRegex = '\m<\([[:alnum:]_-]\+>\)' + if self.key =~# specialNotationRegex + let keymapInvokeString = substitute(self.key, specialNotationRegex, '\1', 'g') + else + let keymapInvokeString = self.key + endif + + let premap = self.key == "" ? " " : " " + + exec 'nnoremap '. self.key . premap . ':call nerdtree#ui_glue#invokeKeyMap("'. keymapInvokeString .'")' +endfunction + +"FUNCTION: KeyMap.Remove(key, scope) {{{1 +function! s:KeyMap.Remove(key, scope) + let maps = s:KeyMap.All() + for i in range(len(maps)) + if maps[i].key ==# a:key && maps[i].scope ==# a:scope + return remove(maps, i) + endif + endfor +endfunction + +"FUNCTION: KeyMap.invoke() {{{1 +"Call the KeyMaps callback function +function! s:KeyMap.invoke(...) + let Callback = function(self.callback) + if a:0 + call Callback(a:1) + else + call Callback() + endif +endfunction + +"FUNCTION: KeyMap.Invoke() {{{1 +"Find a keymapping for a:key and the current scope invoke it. +" +"Scope is determined as follows: +" * if the cursor is on a dir node then "DirNode" +" * if the cursor is on a file node then "FileNode" +" * if the cursor is on a bookmark then "Bookmark" +" +"If a keymap has the scope of "all" then it will be called if no other keymap +"is found for a:key and the scope. +function! s:KeyMap.Invoke(key) + + "required because clicking the command window below another window still + "invokes the mapping - but changes the window cursor + "is in first + " + "TODO: remove this check when the vim bug is fixed + if !g:NERDTree.ExistsForBuf() + return {} + endif + + let node = g:NERDTreeFileNode.GetSelected() + if !empty(node) + + "try file node + if !node.path.isDirectory + let km = s:KeyMap.FindFor(a:key, "FileNode") + if !empty(km) + return km.invoke(node) + endif + endif + + "try dir node + if node.path.isDirectory + let km = s:KeyMap.FindFor(a:key, "DirNode") + if !empty(km) + return km.invoke(node) + endif + endif + + "try generic node + let km = s:KeyMap.FindFor(a:key, "Node") + if !empty(km) + return km.invoke(node) + endif + + endif + + "try bookmark + let bm = g:NERDTreeBookmark.GetSelected() + if !empty(bm) + let km = s:KeyMap.FindFor(a:key, "Bookmark") + if !empty(km) + return km.invoke(bm) + endif + endif + + "try all + let km = s:KeyMap.FindFor(a:key, "all") + if !empty(km) + return km.invoke() + endif +endfunction + +"FUNCTION: KeyMap.Create(options) {{{1 +function! s:KeyMap.Create(options) + let opts = extend({'scope': 'all', 'quickhelpText': ''}, copy(a:options)) + + "dont override other mappings unless the 'override' option is given + if get(opts, 'override', 0) == 0 && !empty(s:KeyMap.FindFor(opts['key'], opts['scope'])) + return + end + + let newKeyMap = copy(self) + let newKeyMap.key = opts['key'] + let newKeyMap.quickhelpText = opts['quickhelpText'] + let newKeyMap.callback = opts['callback'] + let newKeyMap.scope = opts['scope'] + + call s:KeyMap.Add(newKeyMap) +endfunction + +"FUNCTION: KeyMap.Add(keymap) {{{1 +function! s:KeyMap.Add(keymap) + call s:KeyMap.Remove(a:keymap.key, a:keymap.scope) + call add(s:KeyMap.All(), a:keymap) +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/nerdtree/lib/nerdtree/menu_controller.vim b/vim/bundle/nerdtree/lib/nerdtree/menu_controller.vim new file mode 100644 index 0000000..ae0ee84 --- /dev/null +++ b/vim/bundle/nerdtree/lib/nerdtree/menu_controller.vim @@ -0,0 +1,180 @@ +"CLASS: MenuController +"============================================================ +let s:MenuController = {} +let g:NERDTreeMenuController = s:MenuController + +"FUNCTION: MenuController.New(menuItems) {{{1 +"create a new menu controller that operates on the given menu items +function! s:MenuController.New(menuItems) + let newMenuController = copy(self) + if a:menuItems[0].isSeparator() + let newMenuController.menuItems = a:menuItems[1:-1] + else + let newMenuController.menuItems = a:menuItems + endif + return newMenuController +endfunction + +"FUNCTION: MenuController.showMenu() {{{1 +"start the main loop of the menu and get the user to choose/execute a menu +"item +function! s:MenuController.showMenu() + call self._saveOptions() + + try + let self.selection = 0 + + let done = 0 + while !done + redraw! + call self._echoPrompt() + let key = nr2char(getchar()) + let done = self._handleKeypress(key) + endwhile + finally + call self._restoreOptions() + endtry + + if self.selection != -1 + let m = self._current() + call m.execute() + endif +endfunction + +"FUNCTION: MenuController._echoPrompt() {{{1 +function! s:MenuController._echoPrompt() + echo "NERDTree Menu. Use j/k/enter and the shortcuts indicated" + echo "==========================================================" + + for i in range(0, len(self.menuItems)-1) + if self.selection == i + echo "> " . self.menuItems[i].text + else + echo " " . self.menuItems[i].text + endif + endfor +endfunction + +"FUNCTION: MenuController._current(key) {{{1 +"get the MenuItem that is currently selected +function! s:MenuController._current() + return self.menuItems[self.selection] +endfunction + +"FUNCTION: MenuController._handleKeypress(key) {{{1 +"change the selection (if appropriate) and return 1 if the user has made +"their choice, 0 otherwise +function! s:MenuController._handleKeypress(key) + if a:key == 'j' + call self._cursorDown() + elseif a:key == 'k' + call self._cursorUp() + elseif a:key == nr2char(27) "escape + let self.selection = -1 + return 1 + elseif a:key == "\r" || a:key == "\n" "enter and ctrl-j + return 1 + else + let index = self._nextIndexFor(a:key) + if index != -1 + let self.selection = index + if len(self._allIndexesFor(a:key)) == 1 + return 1 + endif + endif + endif + + return 0 +endfunction + +"FUNCTION: MenuController._allIndexesFor(shortcut) {{{1 +"get indexes to all menu items with the given shortcut +function! s:MenuController._allIndexesFor(shortcut) + let toReturn = [] + + for i in range(0, len(self.menuItems)-1) + if self.menuItems[i].shortcut == a:shortcut + call add(toReturn, i) + endif + endfor + + return toReturn +endfunction + +"FUNCTION: MenuController._nextIndexFor(shortcut) {{{1 +"get the index to the next menu item with the given shortcut, starts from the +"current cursor location and wraps around to the top again if need be +function! s:MenuController._nextIndexFor(shortcut) + for i in range(self.selection+1, len(self.menuItems)-1) + if self.menuItems[i].shortcut == a:shortcut + return i + endif + endfor + + for i in range(0, self.selection) + if self.menuItems[i].shortcut == a:shortcut + return i + endif + endfor + + return -1 +endfunction + +"FUNCTION: MenuController._setCmdheight() {{{1 +"sets &cmdheight to whatever is needed to display the menu +function! s:MenuController._setCmdheight() + let &cmdheight = len(self.menuItems) + 3 +endfunction + +"FUNCTION: MenuController._saveOptions() {{{1 +"set any vim options that are required to make the menu work (saving their old +"values) +function! s:MenuController._saveOptions() + let self._oldLazyredraw = &lazyredraw + let self._oldCmdheight = &cmdheight + set nolazyredraw + call self._setCmdheight() +endfunction + +"FUNCTION: MenuController._restoreOptions() {{{1 +"restore the options we saved in _saveOptions() +function! s:MenuController._restoreOptions() + let &cmdheight = self._oldCmdheight + let &lazyredraw = self._oldLazyredraw +endfunction + +"FUNCTION: MenuController._cursorDown() {{{1 +"move the cursor to the next menu item, skipping separators +function! s:MenuController._cursorDown() + let done = 0 + while !done + if self.selection < len(self.menuItems)-1 + let self.selection += 1 + else + let self.selection = 0 + endif + + if !self._current().isSeparator() + let done = 1 + endif + endwhile +endfunction + +"FUNCTION: MenuController._cursorUp() {{{1 +"move the cursor to the previous menu item, skipping separators +function! s:MenuController._cursorUp() + let done = 0 + while !done + if self.selection > 0 + let self.selection -= 1 + else + let self.selection = len(self.menuItems)-1 + endif + + if !self._current().isSeparator() + let done = 1 + endif + endwhile +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/nerdtree/lib/nerdtree/menu_item.vim b/vim/bundle/nerdtree/lib/nerdtree/menu_item.vim new file mode 100644 index 0000000..92c1bbb --- /dev/null +++ b/vim/bundle/nerdtree/lib/nerdtree/menu_item.vim @@ -0,0 +1,114 @@ +"CLASS: MenuItem +"============================================================ +let s:MenuItem = {} +let g:NERDTreeMenuItem = s:MenuItem + +"FUNCTION: MenuItem.All() {{{1 +"get all top level menu items +function! s:MenuItem.All() + if !exists("s:menuItems") + let s:menuItems = [] + endif + return s:menuItems +endfunction + +"FUNCTION: MenuItem.AllEnabled() {{{1 +"get all top level menu items that are currently enabled +function! s:MenuItem.AllEnabled() + let toReturn = [] + for i in s:MenuItem.All() + if i.enabled() + call add(toReturn, i) + endif + endfor + return toReturn +endfunction + +"FUNCTION: MenuItem.Create(options) {{{1 +"make a new menu item and add it to the global list +function! s:MenuItem.Create(options) + let newMenuItem = copy(self) + + let newMenuItem.text = a:options['text'] + let newMenuItem.shortcut = a:options['shortcut'] + let newMenuItem.children = [] + + let newMenuItem.isActiveCallback = -1 + if has_key(a:options, 'isActiveCallback') + let newMenuItem.isActiveCallback = a:options['isActiveCallback'] + endif + + let newMenuItem.callback = -1 + if has_key(a:options, 'callback') + let newMenuItem.callback = a:options['callback'] + endif + + if has_key(a:options, 'parent') + call add(a:options['parent'].children, newMenuItem) + else + call add(s:MenuItem.All(), newMenuItem) + endif + + return newMenuItem +endfunction + +"FUNCTION: MenuItem.CreateSeparator(options) {{{1 +"make a new separator menu item and add it to the global list +function! s:MenuItem.CreateSeparator(options) + let standard_options = { 'text': '--------------------', + \ 'shortcut': -1, + \ 'callback': -1 } + let options = extend(a:options, standard_options, "force") + + return s:MenuItem.Create(options) +endfunction + +"FUNCTION: MenuItem.CreateSubmenu(options) {{{1 +"make a new submenu and add it to global list +function! s:MenuItem.CreateSubmenu(options) + let standard_options = { 'callback': -1 } + let options = extend(a:options, standard_options, "force") + + return s:MenuItem.Create(options) +endfunction + +"FUNCTION: MenuItem.enabled() {{{1 +"return 1 if this menu item should be displayed +" +"delegates off to the isActiveCallback, and defaults to 1 if no callback was +"specified +function! s:MenuItem.enabled() + if self.isActiveCallback != -1 + return {self.isActiveCallback}() + endif + return 1 +endfunction + +"FUNCTION: MenuItem.execute() {{{1 +"perform the action behind this menu item, if this menuitem has children then +"display a new menu for them, otherwise deletegate off to the menuitem's +"callback +function! s:MenuItem.execute() + if len(self.children) + let mc = g:NERDTreeMenuController.New(self.children) + call mc.showMenu() + else + if self.callback != -1 + call {self.callback}() + endif + endif +endfunction + +"FUNCTION: MenuItem.isSeparator() {{{1 +"return 1 if this menuitem is a separator +function! s:MenuItem.isSeparator() + return self.callback == -1 && self.children == [] +endfunction + +"FUNCTION: MenuItem.isSubmenu() {{{1 +"return 1 if this menuitem is a submenu +function! s:MenuItem.isSubmenu() + return self.callback == -1 && !empty(self.children) +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/nerdtree/lib/nerdtree/nerdtree.vim b/vim/bundle/nerdtree/lib/nerdtree/nerdtree.vim new file mode 100644 index 0000000..a41490b --- /dev/null +++ b/vim/bundle/nerdtree/lib/nerdtree/nerdtree.vim @@ -0,0 +1,39 @@ +"CLASS: NERDTree +"============================================================ +let s:NERDTree = {} +let g:NERDTree = s:NERDTree + +" Function: s:NERDTree.ExistsForBuffer() {{{1 +" Returns 1 if a nerd tree root exists in the current buffer +function! s:NERDTree.ExistsForBuf() + return exists("b:NERDTreeRoot") +endfunction + +" Function: s:NERDTree.ExistsForTab() {{{1 +" Returns 1 if a nerd tree root exists in the current tab +function! s:NERDTree.ExistsForTab() + return exists("t:NERDTreeBufName") +endfunction + +function! s:NERDTree.ForCurrentBuf() + if s:NERDTree.ExistsForBuf() + return b:NERDTree + else + return {} + endif +endfunction + +function! s:NERDTree.New(path) + let newObj = copy(self) + let newObj.ui = g:NERDTreeUI.New(newObj) + let newObj.root = g:NERDTreeDirNode.New(a:path) + + return newObj +endfunction + +"FUNCTION: s:NERDTree.render() {{{1 +"A convenience function - since this is called often +function! s:NERDTree.render() + call self.ui.render() +endfunction + diff --git a/vim/bundle/nerdtree/lib/nerdtree/notifier.vim b/vim/bundle/nerdtree/lib/nerdtree/notifier.vim new file mode 100644 index 0000000..b445f8a --- /dev/null +++ b/vim/bundle/nerdtree/lib/nerdtree/notifier.vim @@ -0,0 +1,35 @@ +"CLASS: Notifier +"============================================================ +let s:Notifier = {} + +function! s:Notifier.AddListener(event, funcname) + let listeners = s:Notifier.GetListenersForEvent(a:event) + if listeners == [] + let listenersMap = s:Notifier.GetListenersMap() + let listenersMap[a:event] = listeners + endif + call add(listeners, a:funcname) +endfunction + +function! s:Notifier.NotifyListeners(event, path, params) + let event = g:NERDTreeEvent.New(b:NERDTree, a:path, a:event, a:params) + + for listener in s:Notifier.GetListenersForEvent(a:event) + call {listener}(event) + endfor +endfunction + +function! s:Notifier.GetListenersMap() + if !exists("s:refreshListenersMap") + let s:refreshListenersMap = {} + endif + return s:refreshListenersMap +endfunction + +function! s:Notifier.GetListenersForEvent(name) + let listenersMap = s:Notifier.GetListenersMap() + return get(listenersMap, a:name, []) +endfunction + +let g:NERDTreePathNotifier = deepcopy(s:Notifier) + diff --git a/vim/bundle/nerdtree/lib/nerdtree/opener.vim b/vim/bundle/nerdtree/lib/nerdtree/opener.vim new file mode 100644 index 0000000..845e55c --- /dev/null +++ b/vim/bundle/nerdtree/lib/nerdtree/opener.vim @@ -0,0 +1,336 @@ +"CLASS: Opener +"============================================================ +let s:Opener = {} +let g:NERDTreeOpener = s:Opener + +"FUNCTION: s:Opener._bufInWindows(bnum){{{1 +"[[STOLEN FROM VTREEEXPLORER.VIM]] +"Determine the number of windows open to this buffer number. +"Care of Yegappan Lakshman. Thanks! +" +"Args: +"bnum: the subject buffers buffer number +function! s:Opener._bufInWindows(bnum) + let cnt = 0 + let winnum = 1 + while 1 + let bufnum = winbufnr(winnum) + if bufnum < 0 + break + endif + if bufnum ==# a:bnum + let cnt = cnt + 1 + endif + let winnum = winnum + 1 + endwhile + + return cnt +endfunction +"FUNCTION: Opener._checkToCloseTree(newtab) {{{1 +"Check the class options and global options (i.e. NERDTreeQuitOnOpen) to see +"if the tree should be closed now. +" +"Args: +"a:newtab - boolean. If set, only close the tree now if we are opening the +"target in a new tab. This is needed because we have to close tree before we +"leave the tab +function! s:Opener._checkToCloseTree(newtab) + if self._keepopen + return + endif + + if (a:newtab && self._where == 't') || !a:newtab + call nerdtree#closeTreeIfQuitOnOpen() + endif +endfunction + + +"FUNCTION: s:Opener._firstUsableWindow(){{{1 +"find the window number of the first normal window +function! s:Opener._firstUsableWindow() + let i = 1 + while i <= winnr("$") + let bnum = winbufnr(i) + if bnum != -1 && getbufvar(bnum, '&buftype') ==# '' + \ && !getwinvar(i, '&previewwindow') + \ && (!getbufvar(bnum, '&modified') || &hidden) + return i + endif + + let i += 1 + endwhile + return -1 +endfunction + +"FUNCTION: Opener._gotoTargetWin() {{{1 +function! s:Opener._gotoTargetWin() + if b:NERDTreeType ==# "secondary" + if self._where == 'v' + vsplit + elseif self._where == 'h' + split + elseif self._where == 't' + tabnew + endif + else + call self._checkToCloseTree(1) + + if self._where == 'v' + call self._newVSplit() + elseif self._where == 'h' + call self._newSplit() + elseif self._where == 't' + tabnew + elseif self._where == 'p' + call self._previousWindow() + endif + + call self._checkToCloseTree(0) + endif +endfunction + +"FUNCTION: s:Opener._isWindowUsable(winnumber) {{{1 +"Returns 0 if opening a file from the tree in the given window requires it to +"be split, 1 otherwise +" +"Args: +"winnumber: the number of the window in question +function! s:Opener._isWindowUsable(winnumber) + "gotta split if theres only one window (i.e. the NERD tree) + if winnr("$") ==# 1 + return 0 + endif + + let oldwinnr = winnr() + call nerdtree#exec(a:winnumber . "wincmd p") + let specialWindow = getbufvar("%", '&buftype') != '' || getwinvar('%', '&previewwindow') + let modified = &modified + call nerdtree#exec(oldwinnr . "wincmd p") + + "if its a special window e.g. quickfix or another explorer plugin then we + "have to split + if specialWindow + return 0 + endif + + if &hidden + return 1 + endif + + return !modified || self._bufInWindows(winbufnr(a:winnumber)) >= 2 +endfunction + +"FUNCTION: Opener.New(path, opts) {{{1 +"Args: +" +"a:path: The path object that is to be opened. +" +"a:opts: +" +"A dictionary containing the following keys (all optional): +" 'where': Specifies whether the node should be opened in new split/tab or in +" the previous window. Can be either 'v' or 'h' or 't' (for open in +" new tab) +" 'reuse': if a window is displaying the file then jump the cursor there +" 'keepopen': dont close the tree window +" 'stay': open the file, but keep the cursor in the tree win +function! s:Opener.New(path, opts) + let newObj = copy(self) + + let newObj._path = a:path + let newObj._stay = nerdtree#has_opt(a:opts, 'stay') + let newObj._reuse = nerdtree#has_opt(a:opts, 'reuse') + let newObj._keepopen = nerdtree#has_opt(a:opts, 'keepopen') + let newObj._where = has_key(a:opts, 'where') ? a:opts['where'] : '' + let newObj._treetype = b:NERDTreeType + call newObj._saveCursorPos() + + return newObj +endfunction + +"FUNCTION: Opener._newSplit() {{{1 +function! s:Opener._newSplit() + " Save the user's settings for splitbelow and splitright + let savesplitbelow=&splitbelow + let savesplitright=&splitright + + " 'there' will be set to a command to move from the split window + " back to the explorer window + " + " 'back' will be set to a command to move from the explorer window + " back to the newly split window + " + " 'right' and 'below' will be set to the settings needed for + " splitbelow and splitright IF the explorer is the only window. + " + let there= g:NERDTreeWinPos ==# "left" ? "wincmd h" : "wincmd l" + let back = g:NERDTreeWinPos ==# "left" ? "wincmd l" : "wincmd h" + let right= g:NERDTreeWinPos ==# "left" + let below=0 + + " Attempt to go to adjacent window + call nerdtree#exec(back) + + let onlyOneWin = (winnr("$") ==# 1) + + " If no adjacent window, set splitright and splitbelow appropriately + if onlyOneWin + let &splitright=right + let &splitbelow=below + else + " found adjacent window - invert split direction + let &splitright=!right + let &splitbelow=!below + endif + + let splitMode = onlyOneWin ? "vertical" : "" + + " Open the new window + try + exec(splitMode." sp ") + catch /^Vim\%((\a\+)\)\=:E37/ + call nerdtree#putCursorInTreeWin() + throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self._path.str() ." is already open and modified." + catch /^Vim\%((\a\+)\)\=:/ + "do nothing + endtry + + "resize the tree window if no other window was open before + if onlyOneWin + let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize + call nerdtree#exec(there) + exec("silent ". splitMode ." resize ". size) + call nerdtree#exec('wincmd p') + endif + + " Restore splitmode settings + let &splitbelow=savesplitbelow + let &splitright=savesplitright +endfunction + +"FUNCTION: Opener._newVSplit() {{{1 +function! s:Opener._newVSplit() + let winwidth = winwidth(".") + if winnr("$")==#1 + let winwidth = g:NERDTreeWinSize + endif + + call nerdtree#exec("wincmd p") + vnew + + "resize the nerd tree back to the original size + call nerdtree#putCursorInTreeWin() + exec("silent vertical resize ". winwidth) + call nerdtree#exec('wincmd p') +endfunction + +"FUNCTION: Opener.open(target) {{{1 +function! s:Opener.open(target) + if self._path.isDirectory + call self._openDirectory(a:target) + else + call self._openFile() + endif +endfunction + +"FUNCTION: Opener._openFile() {{{1 +function! s:Opener._openFile() + if self._reuse && self._reuseWindow() + return + endif + + call self._gotoTargetWin() + + if self._treetype ==# "secondary" + call self._path.edit() + else + call self._path.edit() + + + if self._stay + call self._restoreCursorPos() + endif + endif +endfunction + +"FUNCTION: Opener._openDirectory(node) {{{1 +function! s:Opener._openDirectory(node) + if self._treetype ==# "secondary" + call self._gotoTargetWin() + call g:NERDTreeCreator.CreateSecondary(a:node.path.str()) + else + call self._gotoTargetWin() + if empty(self._where) + call a:node.makeRoot() + call b:NERDTree.render() + call a:node.putCursorHere(0, 0) + elseif self._where == 't' + call g:NERDTreeCreator.CreatePrimary(a:node.path.str()) + else + call g:NERDTreeCreator.CreateSecondary(a:node.path.str()) + endif + endif + + if self._stay + call self._restoreCursorPos() + endif +endfunction + +"FUNCTION: Opener._previousWindow() {{{1 +function! s:Opener._previousWindow() + if !self._isWindowUsable(winnr("#")) && self._firstUsableWindow() ==# -1 + call self._newSplit() + else + try + if !self._isWindowUsable(winnr("#")) + call nerdtree#exec(self._firstUsableWindow() . "wincmd w") + else + call nerdtree#exec('wincmd p') + endif + catch /^Vim\%((\a\+)\)\=:E37/ + call nerdtree#putCursorInTreeWin() + throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self._path.str() ." is already open and modified." + catch /^Vim\%((\a\+)\)\=:/ + echo v:exception + endtry + endif +endfunction + +"FUNCTION: Opener._restoreCursorPos(){{{1 +function! s:Opener._restoreCursorPos() + call nerdtree#exec('normal ' . self._tabnr . 'gt') + call nerdtree#exec(bufwinnr(self._bufnr) . 'wincmd w') +endfunction + +"FUNCTION: Opener._reuseWindow(){{{1 +"put the cursor in the first window we find for this file +" +"return 1 if we were successful +function! s:Opener._reuseWindow() + "check the current tab for the window + let winnr = bufwinnr('^' . self._path.str() . '$') + if winnr != -1 + call nerdtree#exec(winnr . "wincmd w") + call self._checkToCloseTree(0) + return 1 + else + "check other tabs + let tabnr = self._path.tabnr() + if tabnr + call self._checkToCloseTree(1) + call nerdtree#exec('normal! ' . tabnr . 'gt') + let winnr = bufwinnr('^' . self._path.str() . '$') + call nerdtree#exec(winnr . "wincmd w") + return 1 + endif + endif + return 0 +endfunction + +"FUNCTION: Opener._saveCursorPos(){{{1 +function! s:Opener._saveCursorPos() + let self._bufnr = bufnr("") + let self._tabnr = tabpagenr() +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/nerdtree/lib/nerdtree/path.vim b/vim/bundle/nerdtree/lib/nerdtree/path.vim new file mode 100644 index 0000000..ea6aa03 --- /dev/null +++ b/vim/bundle/nerdtree/lib/nerdtree/path.vim @@ -0,0 +1,754 @@ +"we need to use this number many times for sorting... so we calculate it only +"once here +let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*') + +"CLASS: Path +"============================================================ +let s:Path = {} +let g:NERDTreePath = s:Path + +"FUNCTION: Path.AbsolutePathFor(str) {{{1 +function! s:Path.AbsolutePathFor(str) + let prependCWD = 0 + if nerdtree#runningWindows() + let prependCWD = a:str !~# '^.:\(\\\|\/\)' && a:str !~# '^\(\\\\\|\/\/\)' + else + let prependCWD = a:str !~# '^/' + endif + + let toReturn = a:str + if prependCWD + let toReturn = getcwd() . s:Path.Slash() . a:str + endif + + return toReturn +endfunction + +"FUNCTION: Path.bookmarkNames() {{{1 +function! s:Path.bookmarkNames() + if !exists("self._bookmarkNames") + call self.cacheDisplayString() + endif + return self._bookmarkNames +endfunction + +"FUNCTION: Path.cacheDisplayString() {{{1 +function! s:Path.cacheDisplayString() abort + let self.cachedDisplayString = self.flagSet.renderToString() + + let self.cachedDisplayString .= self.getLastPathComponent(1) + + if self.isExecutable + let self.cachedDisplayString = self.cachedDisplayString . '*' + endif + + let self._bookmarkNames = [] + for i in g:NERDTreeBookmark.Bookmarks() + if i.path.equals(self) + call add(self._bookmarkNames, i.name) + endif + endfor + if !empty(self._bookmarkNames) + let self.cachedDisplayString .= ' {' . join(self._bookmarkNames) . '}' + endif + + if self.isSymLink + let self.cachedDisplayString .= ' -> ' . self.symLinkDest + endif + + if self.isReadOnly + let self.cachedDisplayString .= ' [RO]' + endif +endfunction + +"FUNCTION: Path.changeToDir() {{{1 +function! s:Path.changeToDir() + let dir = self.str({'format': 'Cd'}) + if self.isDirectory ==# 0 + let dir = self.getParent().str({'format': 'Cd'}) + endif + + try + execute "cd " . dir + call nerdtree#echo("CWD is now: " . getcwd()) + catch + throw "NERDTree.PathChangeError: cannot change CWD to " . dir + endtry +endfunction + +"FUNCTION: Path.compareTo() {{{1 +" +"Compares this Path to the given path and returns 0 if they are equal, -1 if +"this Path is "less than" the given path, or 1 if it is "greater". +" +"Args: +"path: the path object to compare this to +" +"Return: +"1, -1 or 0 +function! s:Path.compareTo(path) + let thisPath = self.getLastPathComponent(1) + let thatPath = a:path.getLastPathComponent(1) + + "if the paths are the same then clearly we return 0 + if thisPath ==# thatPath + return 0 + endif + + let thisSS = self.getSortOrderIndex() + let thatSS = a:path.getSortOrderIndex() + + "compare the sort sequences, if they are different then the return + "value is easy + if thisSS < thatSS + return -1 + elseif thisSS > thatSS + return 1 + else + if !g:NERDTreeSortHiddenFirst + let thisPath = substitute(thisPath, '^[._]', '', '') + let thatPath = substitute(thatPath, '^[._]', '', '') + endif + "if the sort sequences are the same then compare the paths + "alphabetically + let pathCompare = g:NERDTreeCaseSensitiveSort ? thisPath <# thatPath : thisPath " + endif + + return " \\`\|\"#%&,?()\*^<>[]" +endfunction + +"FUNCTION: Path.getDir() {{{1 +" +"Returns this path if it is a directory, else this paths parent. +" +"Return: +"a Path object +function! s:Path.getDir() + if self.isDirectory + return self + else + return self.getParent() + endif +endfunction + +"FUNCTION: Path.getParent() {{{1 +" +"Returns a new path object for this paths parent +" +"Return: +"a new Path object +function! s:Path.getParent() + if nerdtree#runningWindows() + let path = self.drive . '\' . join(self.pathSegments[0:-2], '\') + else + let path = '/'. join(self.pathSegments[0:-2], '/') + endif + + return s:Path.New(path) +endfunction + +"FUNCTION: Path.getLastPathComponent(dirSlash) {{{1 +" +"Gets the last part of this path. +" +"Args: +"dirSlash: if 1 then a trailing slash will be added to the returned value for +"directory nodes. +function! s:Path.getLastPathComponent(dirSlash) + if empty(self.pathSegments) + return '' + endif + let toReturn = self.pathSegments[-1] + if a:dirSlash && self.isDirectory + let toReturn = toReturn . '/' + endif + return toReturn +endfunction + +"FUNCTION: Path.getSortOrderIndex() {{{1 +"returns the index of the pattern in g:NERDTreeSortOrder that this path matches +function! s:Path.getSortOrderIndex() + let i = 0 + while i < len(g:NERDTreeSortOrder) + if self.getLastPathComponent(1) =~# g:NERDTreeSortOrder[i] + return i + endif + let i = i + 1 + endwhile + return s:NERDTreeSortStarIndex +endfunction + +"FUNCTION: Path.isUnixHiddenFile() {{{1 +"check for unix hidden files +function! s:Path.isUnixHiddenFile() + return self.getLastPathComponent(0) =~# '^\.' +endfunction + +"FUNCTION: Path.isUnixHiddenPath() {{{1 +"check for unix path with hidden components +function! s:Path.isUnixHiddenPath() + if self.getLastPathComponent(0) =~# '^\.' + return 1 + else + for segment in self.pathSegments + if segment =~# '^\.' + return 1 + endif + endfor + return 0 + endif +endfunction + +"FUNCTION: Path.ignore() {{{1 +"returns true if this path should be ignored +function! s:Path.ignore() + "filter out the user specified paths to ignore + if b:NERDTreeIgnoreEnabled + for i in g:NERDTreeIgnore + if self._ignorePatternMatches(i) + return 1 + endif + endfor + endif + + "dont show hidden files unless instructed to + if b:NERDTreeShowHidden ==# 0 && self.isUnixHiddenFile() + return 1 + endif + + if b:NERDTreeShowFiles ==# 0 && self.isDirectory ==# 0 + return 1 + endif + + if exists("*NERDTreeCustomIgnoreFilter") && NERDTreeCustomIgnoreFilter(self) + return 1 + endif + + return 0 +endfunction + +"FUNCTION: Path._ignorePatternMatches(pattern) {{{1 +"returns true if this path matches the given ignore pattern +function! s:Path._ignorePatternMatches(pattern) + let pat = a:pattern + if strpart(pat,len(pat)-7) == '[[dir]]' + if !self.isDirectory + return 0 + endif + let pat = strpart(pat,0, len(pat)-7) + elseif strpart(pat,len(pat)-8) == '[[file]]' + if self.isDirectory + return 0 + endif + let pat = strpart(pat,0, len(pat)-8) + endif + + return self.getLastPathComponent(0) =~# pat +endfunction + +"FUNCTION: Path.isUnder(path) {{{1 +"return 1 if this path is somewhere under the given path in the filesystem. +" +"a:path should be a dir +function! s:Path.isUnder(path) + if a:path.isDirectory == 0 + return 0 + endif + + let this = self.str() + let that = a:path.str() + return stridx(this, that . s:Path.Slash()) == 0 +endfunction + +"FUNCTION: Path.JoinPathStrings(...) {{{1 +function! s:Path.JoinPathStrings(...) + let components = [] + for i in a:000 + let components = extend(components, split(i, '/')) + endfor + return '/' . join(components, '/') +endfunction + +"FUNCTION: Path.equals() {{{1 +" +"Determines whether 2 path objects are "equal". +"They are equal if the paths they represent are the same +" +"Args: +"path: the other path obj to compare this with +function! s:Path.equals(path) + return self.str() ==# a:path.str() +endfunction + +"FUNCTION: Path.New() {{{1 +"The Constructor for the Path object +function! s:Path.New(path) + let newPath = copy(self) + + call newPath.readInfoFromDisk(s:Path.AbsolutePathFor(a:path)) + + let newPath.cachedDisplayString = "" + let newPath.flagSet = g:NERDTreeFlagSet.New() + + return newPath +endfunction + +"FUNCTION: Path.Slash() {{{1 +"return the slash to use for the current OS +function! s:Path.Slash() + return nerdtree#runningWindows() ? '\' : '/' +endfunction + +"FUNCTION: Path.Resolve() {{{1 +"Invoke the vim resolve() function and return the result +"This is necessary because in some versions of vim resolve() removes trailing +"slashes while in other versions it doesn't. This always removes the trailing +"slash +function! s:Path.Resolve(path) + let tmp = resolve(a:path) + return tmp =~# '.\+/$' ? substitute(tmp, '/$', '', '') : tmp +endfunction + +"FUNCTION: Path.readInfoFromDisk(fullpath) {{{1 +" +" +"Throws NERDTree.Path.InvalidArguments exception. +function! s:Path.readInfoFromDisk(fullpath) + call self.extractDriveLetter(a:fullpath) + + let fullpath = s:Path.WinToUnixPath(a:fullpath) + + if getftype(fullpath) ==# "fifo" + throw "NERDTree.InvalidFiletypeError: Cant handle FIFO files: " . a:fullpath + endif + + let self.pathSegments = split(fullpath, '/') + + let self.isReadOnly = 0 + if isdirectory(a:fullpath) + let self.isDirectory = 1 + elseif filereadable(a:fullpath) + let self.isDirectory = 0 + let self.isReadOnly = filewritable(a:fullpath) ==# 0 + else + throw "NERDTree.InvalidArgumentsError: Invalid path = " . a:fullpath + endif + + let self.isExecutable = 0 + if !self.isDirectory + let self.isExecutable = getfperm(a:fullpath) =~# 'x' + endif + + "grab the last part of the path (minus the trailing slash) + let lastPathComponent = self.getLastPathComponent(0) + + "get the path to the new node with the parent dir fully resolved + let hardPath = s:Path.Resolve(self.strTrunk()) . '/' . lastPathComponent + + "if the last part of the path is a symlink then flag it as such + let self.isSymLink = (s:Path.Resolve(hardPath) != hardPath) + if self.isSymLink + let self.symLinkDest = s:Path.Resolve(fullpath) + + "if the link is a dir then slap a / on the end of its dest + if isdirectory(self.symLinkDest) + + "we always wanna treat MS windows shortcuts as files for + "simplicity + if hardPath !~# '\.lnk$' + + let self.symLinkDest = self.symLinkDest . '/' + endif + endif + endif +endfunction + +"FUNCTION: Path.refresh() {{{1 +function! s:Path.refresh() + call self.readInfoFromDisk(self.str()) + call g:NERDTreePathNotifier.NotifyListeners('refresh', self, {}) + call self.cacheDisplayString() +endfunction + +"FUNCTION: Path.refreshFlags() {{{1 +function! s:Path.refreshFlags() + call g:NERDTreePathNotifier.NotifyListeners('refreshFlags', self, {}) + call self.cacheDisplayString() +endfunction + +"FUNCTION: Path.rename() {{{1 +" +"Renames this node on the filesystem +function! s:Path.rename(newPath) + if a:newPath ==# '' + throw "NERDTree.InvalidArgumentsError: Invalid newPath for renaming = ". a:newPath + endif + + let success = rename(self.str(), a:newPath) + if success != 0 + throw "NERDTree.PathRenameError: Could not rename: '" . self.str() . "'" . 'to:' . a:newPath + endif + call self.readInfoFromDisk(a:newPath) + + for i in self.bookmarkNames() + let b = g:NERDTreeBookmark.BookmarkFor(i) + call b.setPath(copy(self)) + endfor + call g:NERDTreeBookmark.Write() +endfunction + +"FUNCTION: Path.str() {{{1 +" +"Returns a string representation of this Path +" +"Takes an optional dictionary param to specify how the output should be +"formatted. +" +"The dict may have the following keys: +" 'format' +" 'escape' +" 'truncateTo' +" +"The 'format' key may have a value of: +" 'Cd' - a string to be used with the :cd command +" 'Edit' - a string to be used with :e :sp :new :tabedit etc +" 'UI' - a string used in the NERD tree UI +" +"The 'escape' key, if specified will cause the output to be escaped with +"shellescape() +" +"The 'truncateTo' key causes the resulting string to be truncated to the value +"'truncateTo' maps to. A '<' char will be prepended. +function! s:Path.str(...) + let options = a:0 ? a:1 : {} + let toReturn = "" + + if has_key(options, 'format') + let format = options['format'] + if has_key(self, '_strFor' . format) + exec 'let toReturn = self._strFor' . format . '()' + else + raise 'NERDTree.UnknownFormatError: unknown format "'. format .'"' + endif + else + let toReturn = self._str() + endif + + if nerdtree#has_opt(options, 'escape') + let toReturn = shellescape(toReturn) + endif + + if has_key(options, 'truncateTo') + let limit = options['truncateTo'] + if len(toReturn) > limit + let toReturn = "<" . strpart(toReturn, len(toReturn) - limit + 1) + endif + endif + + return toReturn +endfunction + +"FUNCTION: Path._strForUI() {{{1 +function! s:Path._strForUI() + let toReturn = '/' . join(self.pathSegments, '/') + if self.isDirectory && toReturn != '/' + let toReturn = toReturn . '/' + endif + return toReturn +endfunction + +"FUNCTION: Path._strForCd() {{{1 +" +" returns a string that can be used with :cd +function! s:Path._strForCd() + return escape(self.str(), self._escChars()) +endfunction + +"FUNCTION: Path._strForEdit() {{{1 +" +"Return: the string for this path that is suitable to be used with the :edit +"command +function! s:Path._strForEdit() + let p = escape(self.str(), self._escChars()) + + "make it relative + let p = fnamemodify(p, ':.') + + "handle the edge case where the file begins with a + (vim interprets + "the +foo in `:e +foo` as an option to :edit) + if p[0] == "+" + let p = '\' . p + endif + + if p ==# '' + let p = '.' + endif + + return p +endfunction + +"FUNCTION: Path._strForGlob() {{{1 +function! s:Path._strForGlob() + let lead = s:Path.Slash() + + "if we are running windows then slap a drive letter on the front + if nerdtree#runningWindows() + let lead = self.drive . '\' + endif + + let toReturn = lead . join(self.pathSegments, s:Path.Slash()) + + if !nerdtree#runningWindows() + let toReturn = escape(toReturn, self._escChars()) + endif + return toReturn +endfunction + +"FUNCTION: Path._str() {{{1 +" +"Gets the string path for this path object that is appropriate for the OS. +"EG, in windows c:\foo\bar +" in *nix /foo/bar +function! s:Path._str() + let lead = s:Path.Slash() + + "if we are running windows then slap a drive letter on the front + if nerdtree#runningWindows() + let lead = self.drive . '\' + endif + + return lead . join(self.pathSegments, s:Path.Slash()) +endfunction + +"FUNCTION: Path.strTrunk() {{{1 +"Gets the path without the last segment on the end. +function! s:Path.strTrunk() + return self.drive . '/' . join(self.pathSegments[0:-2], '/') +endfunction + +" FUNCTION: Path.tabnr() {{{1 +" return the number of the first tab that is displaying this file +" +" return 0 if no tab was found +function! s:Path.tabnr() + let str = self.str() + for t in range(tabpagenr('$')) + for b in tabpagebuflist(t+1) + if str == expand('#' . b . ':p') + return t+1 + endif + endfor + endfor + return 0 +endfunction + +"FUNCTION: Path.WinToUnixPath(pathstr){{{1 +"Takes in a windows path and returns the unix equiv +" +"A class level method +" +"Args: +"pathstr: the windows path to convert +function! s:Path.WinToUnixPath(pathstr) + if !nerdtree#runningWindows() + return a:pathstr + endif + + let toReturn = a:pathstr + + "remove the x:\ of the front + let toReturn = substitute(toReturn, '^.*:\(\\\|/\)\?', '/', "") + + "remove the \\ network share from the front + let toReturn = substitute(toReturn, '^\(\\\\\|\/\/\)[^\\\/]*\(\\\|\/\)[^\\\/]*\(\\\|\/\)\?', '/', "") + + "convert all \ chars to / + let toReturn = substitute(toReturn, '\', '/', "g") + + return toReturn +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/nerdtree/lib/nerdtree/tree_dir_node.vim b/vim/bundle/nerdtree/lib/nerdtree/tree_dir_node.vim new file mode 100644 index 0000000..a24c270 --- /dev/null +++ b/vim/bundle/nerdtree/lib/nerdtree/tree_dir_node.vim @@ -0,0 +1,543 @@ +"CLASS: TreeDirNode +"A subclass of NERDTreeFileNode. +" +"The 'composite' part of the file/dir composite. +"============================================================ +let s:TreeDirNode = copy(g:NERDTreeFileNode) +let g:NERDTreeDirNode = s:TreeDirNode + +"FUNCTION: TreeDirNode.AbsoluteTreeRoot(){{{1 +"class method that returns the highest cached ancestor of the current root +function! s:TreeDirNode.AbsoluteTreeRoot() + let currentNode = b:NERDTreeRoot + while currentNode.parent != {} + let currentNode = currentNode.parent + endwhile + return currentNode +endfunction + +"FUNCTION: TreeDirNode.activate([options]) {{{1 +unlet s:TreeDirNode.activate +function! s:TreeDirNode.activate(...) + let opts = a:0 ? a:1 : {} + call self.toggleOpen(opts) + call b:NERDTree.render() + call self.putCursorHere(0, 0) +endfunction + +"FUNCTION: TreeDirNode.addChild(treenode, inOrder) {{{1 +"Adds the given treenode to the list of children for this node +" +"Args: +"-treenode: the node to add +"-inOrder: 1 if the new node should be inserted in sorted order +function! s:TreeDirNode.addChild(treenode, inOrder) + call add(self.children, a:treenode) + let a:treenode.parent = self + + if a:inOrder + call self.sortChildren() + endif +endfunction + +"FUNCTION: TreeDirNode.close() {{{1 +"Closes this directory +function! s:TreeDirNode.close() + let self.isOpen = 0 +endfunction + +"FUNCTION: TreeDirNode.closeChildren() {{{1 +"Closes all the child dir nodes of this node +function! s:TreeDirNode.closeChildren() + for i in self.children + if i.path.isDirectory + call i.close() + call i.closeChildren() + endif + endfor +endfunction + +"FUNCTION: TreeDirNode.createChild(path, inOrder) {{{1 +"Instantiates a new child node for this node with the given path. The new +"nodes parent is set to this node. +" +"Args: +"path: a Path object that this node will represent/contain +"inOrder: 1 if the new node should be inserted in sorted order +" +"Returns: +"the newly created node +function! s:TreeDirNode.createChild(path, inOrder) + let newTreeNode = g:NERDTreeFileNode.New(a:path) + call self.addChild(newTreeNode, a:inOrder) + return newTreeNode +endfunction + +"FUNCTION: TreeDirNode.findNode(path) {{{1 +"Will find one of the children (recursively) that has the given path +" +"Args: +"path: a path object +unlet s:TreeDirNode.findNode +function! s:TreeDirNode.findNode(path) + if a:path.equals(self.path) + return self + endif + if stridx(a:path.str(), self.path.str(), 0) ==# -1 + return {} + endif + + if self.path.isDirectory + for i in self.children + let retVal = i.findNode(a:path) + if retVal != {} + return retVal + endif + endfor + endif + return {} +endfunction + +"FUNCTION: TreeDirNode.getChildCount() {{{1 +"Returns the number of children this node has +function! s:TreeDirNode.getChildCount() + return len(self.children) +endfunction + +"FUNCTION: TreeDirNode.getChild(path) {{{1 +"Returns child node of this node that has the given path or {} if no such node +"exists. +" +"This function doesnt not recurse into child dir nodes +" +"Args: +"path: a path object +function! s:TreeDirNode.getChild(path) + if stridx(a:path.str(), self.path.str(), 0) ==# -1 + return {} + endif + + let index = self.getChildIndex(a:path) + if index ==# -1 + return {} + else + return self.children[index] + endif + +endfunction + +"FUNCTION: TreeDirNode.getChildByIndex(indx, visible) {{{1 +"returns the child at the given index +"Args: +"indx: the index to get the child from +"visible: 1 if only the visible children array should be used, 0 if all the +"children should be searched. +function! s:TreeDirNode.getChildByIndex(indx, visible) + let array_to_search = a:visible? self.getVisibleChildren() : self.children + if a:indx > len(array_to_search) + throw "NERDTree.InvalidArgumentsError: Index is out of bounds." + endif + return array_to_search[a:indx] +endfunction + +"FUNCTION: TreeDirNode.getChildIndex(path) {{{1 +"Returns the index of the child node of this node that has the given path or +"-1 if no such node exists. +" +"This function doesnt not recurse into child dir nodes +" +"Args: +"path: a path object +function! s:TreeDirNode.getChildIndex(path) + if stridx(a:path.str(), self.path.str(), 0) ==# -1 + return -1 + endif + + "do a binary search for the child + let a = 0 + let z = self.getChildCount() + while a < z + let mid = (a+z)/2 + let diff = a:path.compareTo(self.children[mid].path) + + if diff ==# -1 + let z = mid + elseif diff ==# 1 + let a = mid+1 + else + return mid + endif + endwhile + return -1 +endfunction + +"FUNCTION: TreeDirNode.GetSelected() {{{1 +"Returns the current node if it is a dir node, or else returns the current +"nodes parent +unlet s:TreeDirNode.GetSelected +function! s:TreeDirNode.GetSelected() + let currentDir = g:NERDTreeFileNode.GetSelected() + if currentDir != {} && !currentDir.isRoot() + if currentDir.path.isDirectory ==# 0 + let currentDir = currentDir.parent + endif + endif + return currentDir +endfunction + +"FUNCTION: TreeDirNode.getVisibleChildCount() {{{1 +"Returns the number of visible children this node has +function! s:TreeDirNode.getVisibleChildCount() + return len(self.getVisibleChildren()) +endfunction + +"FUNCTION: TreeDirNode.getVisibleChildren() {{{1 +"Returns a list of children to display for this node, in the correct order +" +"Return: +"an array of treenodes +function! s:TreeDirNode.getVisibleChildren() + let toReturn = [] + for i in self.children + if i.path.ignore() ==# 0 + call add(toReturn, i) + endif + endfor + return toReturn +endfunction + +"FUNCTION: TreeDirNode.hasVisibleChildren() {{{1 +"returns 1 if this node has any childre, 0 otherwise.. +function! s:TreeDirNode.hasVisibleChildren() + return self.getVisibleChildCount() != 0 +endfunction + +"FUNCTION: TreeDirNode._initChildren() {{{1 +"Removes all childen from this node and re-reads them +" +"Args: +"silent: 1 if the function should not echo any "please wait" messages for +"large directories +" +"Return: the number of child nodes read +function! s:TreeDirNode._initChildren(silent) + "remove all the current child nodes + let self.children = [] + + "get an array of all the files in the nodes dir + let dir = self.path + let globDir = dir.str({'format': 'Glob'}) + + if version >= 703 + let filesStr = globpath(globDir, '*', !g:NERDTreeRespectWildIgnore) . "\n" . globpath(globDir, '.*', !g:NERDTreeRespectWildIgnore) + else + let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*') + endif + + let files = split(filesStr, "\n") + + if !a:silent && len(files) > g:NERDTreeNotificationThreshold + call nerdtree#echo("Please wait, caching a large dir ...") + endif + + let invalidFilesFound = 0 + for i in files + + "filter out the .. and . directories + "Note: we must match .. AND ../ cos sometimes the globpath returns + "../ for path with strange chars (eg $) + if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' + + "put the next file in a new node and attach it + try + let path = g:NERDTreePath.New(i) + call self.createChild(path, 0) + call g:NERDTreePathNotifier.NotifyListeners('init', path, {}) + catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/ + let invalidFilesFound += 1 + endtry + endif + endfor + + call self.sortChildren() + + if !a:silent && len(files) > g:NERDTreeNotificationThreshold + call nerdtree#echo("Please wait, caching a large dir ... DONE (". self.getChildCount() ." nodes cached).") + endif + + if invalidFilesFound + call nerdtree#echoWarning(invalidFilesFound . " file(s) could not be loaded into the NERD tree") + endif + return self.getChildCount() +endfunction + +"FUNCTION: TreeDirNode.New(path) {{{1 +"Returns a new TreeNode object with the given path and parent +" +"Args: +"path: a path object representing the full filesystem path to the file/dir that the node represents +unlet s:TreeDirNode.New +function! s:TreeDirNode.New(path) + if a:path.isDirectory != 1 + throw "NERDTree.InvalidArgumentsError: A TreeDirNode object must be instantiated with a directory Path object." + endif + + let newTreeNode = copy(self) + let newTreeNode.path = a:path + + let newTreeNode.isOpen = 0 + let newTreeNode.children = [] + + let newTreeNode.parent = {} + + return newTreeNode +endfunction + +"FUNCTION: TreeDirNode.open([opts]) {{{1 +"Open the dir in the current tree or in a new tree elsewhere. +" +"If opening in the current tree, return the number of cached nodes. +unlet s:TreeDirNode.open +function! s:TreeDirNode.open(...) + let opts = a:0 ? a:1 : {} + + if has_key(opts, 'where') && !empty(opts['where']) + let opener = g:NERDTreeOpener.New(self.path, opts) + call opener.open(self) + else + let self.isOpen = 1 + if self.children ==# [] + return self._initChildren(0) + else + return 0 + endif + endif +endfunction + +"FUNCTION: TreeDirNode.openAlong([opts]) {{{1 +"recursive open the dir if it has only one directory child. +" +"return the level of opened directories. +function! s:TreeDirNode.openAlong(...) + let opts = a:0 ? a:1 : {} + let level = 0 + + let node = self + while node.path.isDirectory + call node.open(opts) + let level += 1 + if node.getVisibleChildCount() == 1 + let node = node.getChildByIndex(0, 1) + else + break + endif + endwhile + return level +endfunction + +" FUNCTION: TreeDirNode.openExplorer() {{{1 +" opens an explorer window for this node in the previous window (could be a +" nerd tree or a netrw) +function! s:TreeDirNode.openExplorer() + call self.open({'where': 'p'}) +endfunction + +"FUNCTION: TreeDirNode.openInNewTab(options) {{{1 +unlet s:TreeDirNode.openInNewTab +function! s:TreeDirNode.openInNewTab(options) + call nerdtree#deprecated('TreeDirNode.openInNewTab', 'is deprecated, use open() instead') + call self.open({'where': 't'}) +endfunction + +"FUNCTION: TreeDirNode._openInNewTab() {{{1 +function! s:TreeDirNode._openInNewTab() + tabnew + call g:NERDTreeCreator.CreatePrimary(self.path.str()) +endfunction + +"FUNCTION: TreeDirNode.openRecursively() {{{1 +"Opens this treenode and all of its children whose paths arent 'ignored' +"because of the file filters. +" +"This method is actually a wrapper for the OpenRecursively2 method which does +"the work. +function! s:TreeDirNode.openRecursively() + call self._openRecursively2(1) +endfunction + +"FUNCTION: TreeDirNode._openRecursively2() {{{1 +"Opens this all children of this treenode recursively if either: +" *they arent filtered by file filters +" *a:forceOpen is 1 +" +"Args: +"forceOpen: 1 if this node should be opened regardless of file filters +function! s:TreeDirNode._openRecursively2(forceOpen) + if self.path.ignore() ==# 0 || a:forceOpen + let self.isOpen = 1 + if self.children ==# [] + call self._initChildren(1) + endif + + for i in self.children + if i.path.isDirectory ==# 1 + call i._openRecursively2(0) + endif + endfor + endif +endfunction + +"FUNCTION: TreeDirNode.refresh() {{{1 +unlet s:TreeDirNode.refresh +function! s:TreeDirNode.refresh() + call self.path.refresh() + + "if this node was ever opened, refresh its children + if self.isOpen || !empty(self.children) + "go thru all the files/dirs under this node + let newChildNodes = [] + let invalidFilesFound = 0 + let dir = self.path + let globDir = dir.str({'format': 'Glob'}) + let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*') + let files = split(filesStr, "\n") + for i in files + "filter out the .. and . directories + "Note: we must match .. AND ../ cos sometimes the globpath returns + "../ for path with strange chars (eg $) + if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' + + try + "create a new path and see if it exists in this nodes children + let path = g:NERDTreePath.New(i) + let newNode = self.getChild(path) + if newNode != {} + call newNode.refresh() + call add(newChildNodes, newNode) + + "the node doesnt exist so create it + else + let newNode = g:NERDTreeFileNode.New(path) + let newNode.parent = self + call add(newChildNodes, newNode) + endif + + + catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/ + let invalidFilesFound = 1 + endtry + endif + endfor + + "swap this nodes children out for the children we just read/refreshed + let self.children = newChildNodes + call self.sortChildren() + + if invalidFilesFound + call nerdtree#echoWarning("some files could not be loaded into the NERD tree") + endif + endif +endfunction + +"FUNCTION: TreeDirNode.refreshFlags() {{{1 +unlet s:TreeDirNode.refreshFlags +function! s:TreeDirNode.refreshFlags() + call self.path.refreshFlags() + for i in self.children + call i.refreshFlags() + endfor +endfunction + +"FUNCTION: TreeDirNode.refreshDirFlags() {{{1 +function! s:TreeDirNode.refreshDirFlags() + call self.path.refreshFlags() +endfunction + +"FUNCTION: TreeDirNode.reveal(path) {{{1 +"reveal the given path, i.e. cache and open all treenodes needed to display it +"in the UI +function! s:TreeDirNode.reveal(path) + if !a:path.isUnder(self.path) + throw "NERDTree.InvalidArgumentsError: " . a:path.str() . " should be under " . self.path.str() + endif + + call self.open() + + if self.path.equals(a:path.getParent()) + let n = self.findNode(a:path) + call b:NERDTree.render() + call n.putCursorHere(1,0) + return + endif + + let p = a:path + while !p.getParent().equals(self.path) + let p = p.getParent() + endwhile + + let n = self.findNode(p) + call n.reveal(a:path) +endfunction + +"FUNCTION: TreeDirNode.removeChild(treenode) {{{1 +" +"Removes the given treenode from this nodes set of children +" +"Args: +"treenode: the node to remove +" +"Throws a NERDTree.ChildNotFoundError if the given treenode is not found +function! s:TreeDirNode.removeChild(treenode) + for i in range(0, self.getChildCount()-1) + if self.children[i].equals(a:treenode) + call remove(self.children, i) + return + endif + endfor + + throw "NERDTree.ChildNotFoundError: child node was not found" +endfunction + +"FUNCTION: TreeDirNode.sortChildren() {{{1 +" +"Sorts the children of this node according to alphabetical order and the +"directory priority. +" +function! s:TreeDirNode.sortChildren() + let CompareFunc = function("nerdtree#compareNodes") + call sort(self.children, CompareFunc) +endfunction + +"FUNCTION: TreeDirNode.toggleOpen([options]) {{{1 +"Opens this directory if it is closed and vice versa +function! s:TreeDirNode.toggleOpen(...) + let opts = a:0 ? a:1 : {} + if self.isOpen ==# 1 + call self.close() + else + if g:NERDTreeCascadeOpenSingleChildDir == 0 + call self.open(opts) + else + call self.openAlong(opts) + endif + endif +endfunction + +"FUNCTION: TreeDirNode.transplantChild(newNode) {{{1 +"Replaces the child of this with the given node (where the child node's full +"path matches a:newNode's fullpath). The search for the matching node is +"non-recursive +" +"Arg: +"newNode: the node to graft into the tree +function! s:TreeDirNode.transplantChild(newNode) + for i in range(0, self.getChildCount()-1) + if self.children[i].equals(a:newNode) + let self.children[i] = a:newNode + let a:newNode.parent = self + break + endif + endfor +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/nerdtree/lib/nerdtree/tree_file_node.vim b/vim/bundle/nerdtree/lib/nerdtree/tree_file_node.vim new file mode 100644 index 0000000..b4924d7 --- /dev/null +++ b/vim/bundle/nerdtree/lib/nerdtree/tree_file_node.vim @@ -0,0 +1,431 @@ +"CLASS: TreeFileNode +"This class is the parent of the TreeDirNode class and is the +"'Component' part of the composite design pattern between the treenode +"classes. +"============================================================ +let s:TreeFileNode = {} +let g:NERDTreeFileNode = s:TreeFileNode + +"FUNCTION: TreeFileNode.activate(...) {{{1 +function! s:TreeFileNode.activate(...) + call self.open(a:0 ? a:1 : {}) +endfunction + +"FUNCTION: TreeFileNode.bookmark(name) {{{1 +"bookmark this node with a:name +function! s:TreeFileNode.bookmark(name) + + "if a bookmark exists with the same name and the node is cached then save + "it so we can update its display string + let oldMarkedNode = {} + try + let oldMarkedNode = g:NERDTreeBookmark.GetNodeForName(a:name, 1) + catch /^NERDTree.BookmarkNotFoundError/ + catch /^NERDTree.BookmarkedNodeNotFoundError/ + endtry + + call g:NERDTreeBookmark.AddBookmark(a:name, self.path) + call self.path.cacheDisplayString() + call g:NERDTreeBookmark.Write() + + if !empty(oldMarkedNode) + call oldMarkedNode.path.cacheDisplayString() + endif +endfunction + +"FUNCTION: TreeFileNode.cacheParent() {{{1 +"initializes self.parent if it isnt already +function! s:TreeFileNode.cacheParent() + if empty(self.parent) + let parentPath = self.path.getParent() + if parentPath.equals(self.path) + throw "NERDTree.CannotCacheParentError: already at root" + endif + let self.parent = s:TreeFileNode.New(parentPath) + endif +endfunction + +"FUNCTION: TreeFileNode.clearBookmarks() {{{1 +function! s:TreeFileNode.clearBookmarks() + for i in g:NERDTreeBookmark.Bookmarks() + if i.path.equals(self.path) + call i.delete() + end + endfor + call self.path.cacheDisplayString() +endfunction + +"FUNCTION: TreeFileNode.copy(dest) {{{1 +function! s:TreeFileNode.copy(dest) + call self.path.copy(a:dest) + let newPath = g:NERDTreePath.New(a:dest) + let parent = b:NERDTreeRoot.findNode(newPath.getParent()) + if !empty(parent) + call parent.refresh() + return parent.findNode(newPath) + else + return {} + endif +endfunction + +"FUNCTION: TreeFileNode.delete {{{1 +"Removes this node from the tree and calls the Delete method for its path obj +function! s:TreeFileNode.delete() + call self.path.delete() + call self.parent.removeChild(self) +endfunction + +"FUNCTION: TreeFileNode.displayString() {{{1 +" +"Returns a string that specifies how the node should be represented as a +"string +" +"Return: +"a string that can be used in the view to represent this node +function! s:TreeFileNode.displayString() + return self.path.displayString() +endfunction + +"FUNCTION: TreeFileNode.equals(treenode) {{{1 +" +"Compares this treenode to the input treenode and returns 1 if they are the +"same node. +" +"Use this method instead of == because sometimes when the treenodes contain +"many children, vim seg faults when doing == +" +"Args: +"treenode: the other treenode to compare to +function! s:TreeFileNode.equals(treenode) + return self.path.str() ==# a:treenode.path.str() +endfunction + +"FUNCTION: TreeFileNode.findNode(path) {{{1 +"Returns self if this node.path.Equals the given path. +"Returns {} if not equal. +" +"Args: +"path: the path object to compare against +function! s:TreeFileNode.findNode(path) + if a:path.equals(self.path) + return self + endif + return {} +endfunction + +"FUNCTION: TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) {{{1 +" +"Finds the next sibling for this node in the indicated direction. This sibling +"must be a directory and may/may not have children as specified. +" +"Args: +"direction: 0 if you want to find the previous sibling, 1 for the next sibling +" +"Return: +"a treenode object or {} if no appropriate sibling could be found +function! s:TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) + "if we have no parent then we can have no siblings + if self.parent != {} + let nextSibling = self.findSibling(a:direction) + + while nextSibling != {} + if nextSibling.path.isDirectory && nextSibling.hasVisibleChildren() && nextSibling.isOpen + return nextSibling + endif + let nextSibling = nextSibling.findSibling(a:direction) + endwhile + endif + + return {} +endfunction + +"FUNCTION: TreeFileNode.findSibling(direction) {{{1 +" +"Finds the next sibling for this node in the indicated direction +" +"Args: +"direction: 0 if you want to find the previous sibling, 1 for the next sibling +" +"Return: +"a treenode object or {} if no sibling could be found +function! s:TreeFileNode.findSibling(direction) + "if we have no parent then we can have no siblings + if self.parent != {} + + "get the index of this node in its parents children + let siblingIndx = self.parent.getChildIndex(self.path) + + if siblingIndx != -1 + "move a long to the next potential sibling node + let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1 + + "keep moving along to the next sibling till we find one that is valid + let numSiblings = self.parent.getChildCount() + while siblingIndx >= 0 && siblingIndx < numSiblings + + "if the next node is not an ignored node (i.e. wont show up in the + "view) then return it + if self.parent.children[siblingIndx].path.ignore() ==# 0 + return self.parent.children[siblingIndx] + endif + + "go to next node + let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1 + endwhile + endif + endif + + return {} +endfunction + +"FUNCTION: TreeFileNode.GetRootForTab(){{{1 +"get the root node for this tab +function! s:TreeFileNode.GetRootForTab() + if g:NERDTree.ExistsForTab() + return getbufvar(t:NERDTreeBufName, 'NERDTreeRoot') + end + return {} +endfunction + +"FUNCTION: TreeFileNode.GetSelected() {{{1 +"gets the treenode that the cursor is currently over +function! s:TreeFileNode.GetSelected() + try + let path = b:NERDTree.ui.getPath(line(".")) + if path ==# {} + return {} + endif + return b:NERDTreeRoot.findNode(path) + catch /^NERDTree/ + return {} + endtry +endfunction + +"FUNCTION: TreeFileNode.isVisible() {{{1 +"returns 1 if this node should be visible according to the tree filters and +"hidden file filters (and their on/off status) +function! s:TreeFileNode.isVisible() + return !self.path.ignore() +endfunction + +"FUNCTION: TreeFileNode.isRoot() {{{1 +"returns 1 if this node is b:NERDTreeRoot +function! s:TreeFileNode.isRoot() + if !g:NERDTree.ExistsForBuf() + throw "NERDTree.NoTreeError: No tree exists for the current buffer" + endif + + return self.equals(b:NERDTreeRoot) +endfunction + +"FUNCTION: TreeFileNode.makeRoot() {{{1 +"Make this node the root of the tree +function! s:TreeFileNode.makeRoot() + if self.path.isDirectory + let b:NERDTreeRoot = self + else + call self.cacheParent() + let b:NERDTreeRoot = self.parent + endif + + call b:NERDTreeRoot.open() + + "change dir to the dir of the new root if instructed to + if g:NERDTreeChDirMode ==# 2 + exec "cd " . b:NERDTreeRoot.path.str({'format': 'Edit'}) + endif + + silent doautocmd User NERDTreeNewRoot +endfunction + +"FUNCTION: TreeFileNode.New(path) {{{1 +"Returns a new TreeNode object with the given path and parent +" +"Args: +"path: a path object representing the full filesystem path to the file/dir that the node represents +function! s:TreeFileNode.New(path) + if a:path.isDirectory + return g:NERDTreeDirNode.New(a:path) + else + let newTreeNode = copy(self) + let newTreeNode.path = a:path + let newTreeNode.parent = {} + return newTreeNode + endif +endfunction + +"FUNCTION: TreeFileNode.open() {{{1 +function! s:TreeFileNode.open(...) + let opts = a:0 ? a:1 : {} + let opener = g:NERDTreeOpener.New(self.path, opts) + call opener.open(self) +endfunction + +"FUNCTION: TreeFileNode.openSplit() {{{1 +"Open this node in a new window +function! s:TreeFileNode.openSplit() + call nerdtree#deprecated('TreeFileNode.openSplit', 'is deprecated, use .open() instead.') + call self.open({'where': 'h'}) +endfunction + +"FUNCTION: TreeFileNode.openVSplit() {{{1 +"Open this node in a new vertical window +function! s:TreeFileNode.openVSplit() + call nerdtree#deprecated('TreeFileNode.openVSplit', 'is deprecated, use .open() instead.') + call self.open({'where': 'v'}) +endfunction + +"FUNCTION: TreeFileNode.openInNewTab(options) {{{1 +function! s:TreeFileNode.openInNewTab(options) + echomsg 'TreeFileNode.openInNewTab is deprecated' + call self.open(extend({'where': 't'}, a:options)) +endfunction + +"FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{1 +"Places the cursor on the line number this node is rendered on +" +"Args: +"isJump: 1 if this cursor movement should be counted as a jump by vim +"recurseUpward: try to put the cursor on the parent if the this node isnt +"visible +function! s:TreeFileNode.putCursorHere(isJump, recurseUpward) + let ln = b:NERDTree.ui.getLineNum(self) + if ln != -1 + if a:isJump + mark ' + endif + call cursor(ln, col(".")) + else + if a:recurseUpward + let node = self + while node != {} && b:NERDTree.ui.getLineNum(node) ==# -1 + let node = node.parent + call node.open() + endwhile + call b:NERDTree.render() + call node.putCursorHere(a:isJump, 0) + endif + endif +endfunction + +"FUNCTION: TreeFileNode.refresh() {{{1 +function! s:TreeFileNode.refresh() + call self.path.refresh() +endfunction + +"FUNCTION: TreeFileNode.refreshFlags() {{{1 +function! s:TreeFileNode.refreshFlags() + call self.path.refreshFlags() +endfunction + +"FUNCTION: TreeFileNode.rename() {{{1 +"Calls the rename method for this nodes path obj +function! s:TreeFileNode.rename(newName) + let newName = substitute(a:newName, '\(\\\|\/\)$', '', '') + call self.path.rename(newName) + call self.parent.removeChild(self) + + let parentPath = self.path.getParent() + let newParent = b:NERDTreeRoot.findNode(parentPath) + + if newParent != {} + call newParent.createChild(self.path, 1) + call newParent.refresh() + endif +endfunction + +"FUNCTION: TreeFileNode.renderToString {{{1 +"returns a string representation for this tree to be rendered in the view +function! s:TreeFileNode.renderToString() + return self._renderToString(0, 0, [], self.getChildCount() ==# 1) +endfunction + +"Args: +"depth: the current depth in the tree for this call +"drawText: 1 if we should actually draw the line for this node (if 0 then the +"child nodes are rendered only) +"vertMap: a binary array that indicates whether a vertical bar should be draw +"for each depth in the tree +"isLastChild:true if this curNode is the last child of its parent +function! s:TreeFileNode._renderToString(depth, drawText, vertMap, isLastChild) + let output = "" + if a:drawText ==# 1 + + let treeParts = '' + + "get all the leading spaces and vertical tree parts for this line + if a:depth > 1 + for j in a:vertMap[0:-2] + if g:NERDTreeDirArrows + let treeParts = treeParts . ' ' + else + if j ==# 1 + let treeParts = treeParts . '| ' + else + let treeParts = treeParts . ' ' + endif + endif + endfor + endif + + "get the last vertical tree part for this line which will be different + "if this node is the last child of its parent + if !g:NERDTreeDirArrows + if a:isLastChild + let treeParts = treeParts . '`' + else + let treeParts = treeParts . '|' + endif + endif + + "smack the appropriate dir/file symbol on the line before the file/dir + "name itself + if self.path.isDirectory + if self.isOpen + if g:NERDTreeDirArrows + let treeParts = treeParts . '▾ ' + else + let treeParts = treeParts . '~' + endif + else + if g:NERDTreeDirArrows + let treeParts = treeParts . '▸ ' + else + let treeParts = treeParts . '+' + endif + endif + else + if g:NERDTreeDirArrows + let treeParts = treeParts . ' ' + else + let treeParts = treeParts . '-' + endif + endif + let line = treeParts . self.displayString() + + let output = output . line . "\n" + endif + + "if the node is an open dir, draw its children + if self.path.isDirectory ==# 1 && self.isOpen ==# 1 + + let childNodesToDraw = self.getVisibleChildren() + if len(childNodesToDraw) > 0 + + "draw all the nodes children except the last + let lastIndx = len(childNodesToDraw)-1 + if lastIndx > 0 + for i in childNodesToDraw[0:lastIndx-1] + let output = output . i._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 1), 0) + endfor + endif + + "draw the last child, indicating that it IS the last + let output = output . childNodesToDraw[lastIndx]._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 0), 1) + endif + endif + + return output +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/nerdtree/lib/nerdtree/ui.vim b/vim/bundle/nerdtree/lib/nerdtree/ui.vim new file mode 100644 index 0000000..ed93d80 --- /dev/null +++ b/vim/bundle/nerdtree/lib/nerdtree/ui.vim @@ -0,0 +1,332 @@ +"CLASS: UI +"============================================================ +let s:UI = {} +let g:NERDTreeUI = s:UI + + +function! s:UI.lolcats() + echomsg "lolcats" +endfunction + +"FUNCTION: s:UI.centerView() {{{2 +"centers the nerd tree window around the cursor (provided the nerd tree +"options permit) +function! s:UI.centerView() + if g:NERDTreeAutoCenter + let current_line = winline() + let lines_to_top = current_line + let lines_to_bottom = winheight(nerdtree#getTreeWinNum()) - current_line + if lines_to_top < g:NERDTreeAutoCenterThreshold || lines_to_bottom < g:NERDTreeAutoCenterThreshold + normal! zz + endif + endif +endfunction + +"FUNCTION: s:UI.new(nerdtree) {{{1 +function! s:UI.New(nerdtree) + let newObj = copy(self) + let newObj.nerdtree = a:nerdtree + return newObj +endfunction + +"FUNCTION: s:UI.getPath(ln) {{{1 +"Gets the full path to the node that is rendered on the given line number +" +"Args: +"ln: the line number to get the path for +" +"Return: +"A path if a node was selected, {} if nothing is selected. +"If the 'up a dir' line was selected then the path to the parent of the +"current root is returned +function! s:UI.getPath(ln) + let line = getline(a:ln) + + let rootLine = self.getRootLineNum() + + "check to see if we have the root node + if a:ln == rootLine + return b:NERDTreeRoot.path + endif + + if !g:NERDTreeDirArrows + " in case called from outside the tree + if line !~# '^ *[|`▸▾ ]' || line =~# '^$' + return {} + endif + endif + + if line ==# nerdtree#treeUpDirLine() + return b:NERDTreeRoot.path.getParent() + endif + + let indent = self._indentLevelFor(line) + + "remove the tree parts and the leading space + let curFile = nerdtree#stripMarkupFromLine(line, 0) + + let wasdir = 0 + if curFile =~# '/$' + let wasdir = 1 + let curFile = substitute(curFile, '/\?$', '/', "") + endif + + let dir = "" + let lnum = a:ln + while lnum > 0 + let lnum = lnum - 1 + let curLine = getline(lnum) + let curLineStripped = nerdtree#stripMarkupFromLine(curLine, 1) + + "have we reached the top of the tree? + if lnum == rootLine + let dir = b:NERDTreeRoot.path.str({'format': 'UI'}) . dir + break + endif + if curLineStripped =~# '/$' + let lpindent = self._indentLevelFor(curLine) + if lpindent < indent + let indent = indent - 1 + + let dir = substitute (curLineStripped,'^\\', "", "") . dir + continue + endif + endif + endwhile + let curFile = b:NERDTreeRoot.path.drive . dir . curFile + let toReturn = g:NERDTreePath.New(curFile) + return toReturn +endfunction + +"FUNCTION: s:UI.getLineNum(file_node){{{1 +"returns the line number this node is rendered on, or -1 if it isnt rendered +function! s:UI.getLineNum(file_node) + "if the node is the root then return the root line no. + if a:file_node.isRoot() + return b:NERDTree.ui.getRootLineNum() + endif + + let totalLines = line("$") + + "the path components we have matched so far + let pathcomponents = [substitute(b:NERDTreeRoot.path.str({'format': 'UI'}), '/ *$', '', '')] + "the index of the component we are searching for + let curPathComponent = 1 + + let fullpath = a:file_node.path.str({'format': 'UI'}) + + let lnum = b:NERDTree.ui.getRootLineNum() + while lnum > 0 + let lnum = lnum + 1 + "have we reached the bottom of the tree? + if lnum ==# totalLines+1 + return -1 + endif + + let curLine = getline(lnum) + + let indent = self._indentLevelFor(curLine) + if indent ==# curPathComponent + let curLine = nerdtree#stripMarkupFromLine(curLine, 1) + + let curPath = join(pathcomponents, '/') . '/' . curLine + if stridx(fullpath, curPath, 0) ==# 0 + if fullpath ==# curPath || strpart(fullpath, len(curPath)-1,1) ==# '/' + let curLine = substitute(curLine, '/ *$', '', '') + call add(pathcomponents, curLine) + let curPathComponent = curPathComponent + 1 + + if fullpath ==# curPath + return lnum + endif + endif + endif + endif + endwhile + return -1 +endfunction + + +"FUNCTION: s:UI.getRootLineNum(){{{1 +"gets the line number of the root node +function! s:UI.getRootLineNum() + let rootLine = 1 + while getline(rootLine) !~# '^\(/\|<\)' + let rootLine = rootLine + 1 + endwhile + return rootLine +endfunction + +"FUNCTION: s:UI._indentLevelFor(line) {{{2 +function! s:UI._indentLevelFor(line) + let level = match(a:line, '[^ \-+~▸▾`|]') / nerdtree#treeWid() + " check if line includes arrows + if match(a:line, '[▸▾]') > -1 + " decrement level as arrow uses 3 ascii chars + let level = level - 1 + endif + return level +endfunction + + +"FUNCTION: s:UI.restoreScreenState() {{{2 +" +"Sets the screen state back to what it was when nerdtree#saveScreenState was last +"called. +" +"Assumes the cursor is in the NERDTree window +function! s:UI.restoreScreenState() + if !has_key(self, '_screenState') + return + endif + exec("silent vertical resize " . self._screenState['oldWindowSize']) + + let old_scrolloff=&scrolloff + let &scrolloff=0 + call cursor(self._screenState['oldTopLine'], 0) + normal! zt + call setpos(".", self._screenState['oldPos']) + let &scrolloff=old_scrolloff +endfunction + +"FUNCTION: s:UI.saveScreenState() {{{2 +"Saves the current cursor position in the current buffer and the window +"scroll position +function! s:UI.saveScreenState() + let win = winnr() + try + call nerdtree#putCursorInTreeWin() + let self._screenState = {} + let self._screenState['oldPos'] = getpos(".") + let self._screenState['oldTopLine'] = line("w0") + let self._screenState['oldWindowSize']= winwidth("") + call nerdtree#exec(win . "wincmd w") + catch /^NERDTree.InvalidOperationError/ + endtry +endfunction + +"FUNCTION: s:UI.render() {{{2 +function! s:UI.render() + setlocal modifiable + + "remember the top line of the buffer and the current line so we can + "restore the view exactly how it was + let curLine = line(".") + let curCol = col(".") + let topLine = line("w0") + + "delete all lines in the buffer (being careful not to clobber a register) + silent 1,$delete _ + + call nerdtree#dumpHelp() + + "delete the blank line before the help and add one after it + if g:NERDTreeMinimalUI == 0 + call setline(line(".")+1, "") + call cursor(line(".")+1, col(".")) + endif + + if b:NERDTreeShowBookmarks + call nerdtree#renderBookmarks() + endif + + "add the 'up a dir' line + if !g:NERDTreeMinimalUI + call setline(line(".")+1, nerdtree#treeUpDirLine()) + call cursor(line(".")+1, col(".")) + endif + + "draw the header line + let header = b:NERDTreeRoot.path.str({'format': 'UI', 'truncateTo': winwidth(0)}) + call setline(line(".")+1, header) + call cursor(line(".")+1, col(".")) + + "draw the tree + let old_o = @o + let @o = b:NERDTreeRoot.renderToString() + silent put o + let @o = old_o + + "delete the blank line at the top of the buffer + silent 1,1delete _ + + "restore the view + let old_scrolloff=&scrolloff + let &scrolloff=0 + call cursor(topLine, 1) + normal! zt + call cursor(curLine, curCol) + let &scrolloff = old_scrolloff + + setlocal nomodifiable +endfunction + + +"FUNCTION: UI.renderViewSavingPosition {{{1 +"Renders the tree and ensures the cursor stays on the current node or the +"current nodes parent if it is no longer available upon re-rendering +function! s:UI.renderViewSavingPosition() + let currentNode = g:NERDTreeFileNode.GetSelected() + + "go up the tree till we find a node that will be visible or till we run + "out of nodes + while currentNode != {} && !currentNode.isVisible() && !currentNode.isRoot() + let currentNode = currentNode.parent + endwhile + + call b:NERDTree.render() + + if currentNode != {} + call currentNode.putCursorHere(0, 0) + endif +endfunction + +" FUNCTION: s:UI.toggleIgnoreFilter() {{{1 +" toggles the use of the NERDTreeIgnore option +function! s:UI.toggleIgnoreFilter() + let b:NERDTreeIgnoreEnabled = !b:NERDTreeIgnoreEnabled + call b:NERDTree.ui.renderViewSavingPosition() + call b:NERDTree.ui.centerView() +endfunction + +" FUNCTION: s:UI.toggleShowBookmarks() {{{1 +" toggles the display of bookmarks +function! s:UI.toggleShowBookmarks() + let b:NERDTreeShowBookmarks = !b:NERDTreeShowBookmarks + if b:NERDTreeShowBookmarks + call b:NERDTree.render() + call nerdtree#putCursorOnBookmarkTable() + else + call b:NERDTree.ui.renderViewSavingPosition() + endif + call b:NERDTree.ui.centerView() +endfunction + +" FUNCTION: s:UI.toggleShowFiles() {{{1 +" toggles the display of hidden files +function! s:UI.toggleShowFiles() + let b:NERDTreeShowFiles = !b:NERDTreeShowFiles + call b:NERDTree.ui.renderViewSavingPosition() + call b:NERDTree.ui.centerView() +endfunction + +" FUNCTION: s:UI.toggleShowHidden() {{{1 +" toggles the display of hidden files +function! s:UI.toggleShowHidden() + let b:NERDTreeShowHidden = !b:NERDTreeShowHidden + call b:NERDTree.ui.renderViewSavingPosition() + call self.centerView() +endfunction + +" FUNCTION: s:UI.toggleZoom() {{{1 +" zoom (maximize/minimize) the NERDTree window +function! s:UI.toggleZoom() + if exists("b:NERDTreeZoomed") && b:NERDTreeZoomed + let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize + exec "silent vertical resize ". size + let b:NERDTreeZoomed = 0 + else + exec "vertical resize" + let b:NERDTreeZoomed = 1 + endif +endfunction diff --git a/vim/bundle/nerdtree/nerdtree_plugin/exec_menuitem.vim b/vim/bundle/nerdtree/nerdtree_plugin/exec_menuitem.vim new file mode 100644 index 0000000..e7a7c53 --- /dev/null +++ b/vim/bundle/nerdtree/nerdtree_plugin/exec_menuitem.vim @@ -0,0 +1,41 @@ +" ============================================================================ +" File: exec_menuitem.vim +" Description: plugin for NERD Tree that provides an execute file menu item +" Maintainer: Martin Grenfell +" Last Change: 22 July, 2009 +" License: This program is free software. It comes without any warranty, +" to the extent permitted by applicable law. You can redistribute +" it and/or modify it under the terms of the Do What The Fuck You +" Want To Public License, Version 2, as published by Sam Hocevar. +" See http://sam.zoy.org/wtfpl/COPYING for more details. +" +" ============================================================================ +if exists("g:loaded_nerdtree_exec_menuitem") + finish +endif +let g:loaded_nerdtree_exec_menuitem = 1 + +call NERDTreeAddMenuItem({ + \ 'text': '(!)Execute file', + \ 'shortcut': '!', + \ 'callback': 'NERDTreeExecFile', + \ 'isActiveCallback': 'NERDTreeExecFileActive' }) + +function! NERDTreeExecFileActive() + let node = g:NERDTreeFileNode.GetSelected() + return !node.path.isDirectory && node.path.isExecutable +endfunction + +function! NERDTreeExecFile() + let treenode = g:NERDTreeFileNode.GetSelected() + echo "==========================================================\n" + echo "Complete the command to execute (add arguments etc):\n" + let cmd = treenode.path.str({'escape': 1}) + let cmd = input(':!', cmd . ' ') + + if cmd != '' + exec ':!' . cmd + else + echo "Aborted" + endif +endfunction diff --git a/vim/bundle/nerdtree/nerdtree_plugin/fs_menu.vim b/vim/bundle/nerdtree/nerdtree_plugin/fs_menu.vim new file mode 100644 index 0000000..e99a85b --- /dev/null +++ b/vim/bundle/nerdtree/nerdtree_plugin/fs_menu.vim @@ -0,0 +1,270 @@ +" ============================================================================ +" File: fs_menu.vim +" Description: plugin for the NERD Tree that provides a file system menu +" Maintainer: Martin Grenfell +" Last Change: 17 July, 2009 +" License: This program is free software. It comes without any warranty, +" to the extent permitted by applicable law. You can redistribute +" it and/or modify it under the terms of the Do What The Fuck You +" Want To Public License, Version 2, as published by Sam Hocevar. +" See http://sam.zoy.org/wtfpl/COPYING for more details. +" +" ============================================================================ +if exists("g:loaded_nerdtree_fs_menu") + finish +endif +let g:loaded_nerdtree_fs_menu = 1 + +"Automatically delete the buffer after deleting or renaming a file +if !exists("g:NERDTreeAutoDeleteBuffer") + let g:NERDTreeAutoDeleteBuffer = 0 +endif + +call NERDTreeAddMenuItem({'text': '(a)dd a childnode', 'shortcut': 'a', 'callback': 'NERDTreeAddNode'}) +call NERDTreeAddMenuItem({'text': '(m)ove the current node', 'shortcut': 'm', 'callback': 'NERDTreeMoveNode'}) +call NERDTreeAddMenuItem({'text': '(d)elete the current node', 'shortcut': 'd', 'callback': 'NERDTreeDeleteNode'}) + +if has("gui_mac") || has("gui_macvim") + call NERDTreeAddMenuItem({'text': '(r)eveal in Finder the current node', 'shortcut': 'r', 'callback': 'NERDTreeRevealInFinder'}) + call NERDTreeAddMenuItem({'text': '(o)pen the current node with system editor', 'shortcut': 'o', 'callback': 'NERDTreeExecuteFile'}) + call NERDTreeAddMenuItem({'text': '(q)uicklook the current node', 'shortcut': 'q', 'callback': 'NERDTreeQuickLook'}) +endif + +if g:NERDTreePath.CopyingSupported() + call NERDTreeAddMenuItem({'text': '(c)opy the current node', 'shortcut': 'c', 'callback': 'NERDTreeCopyNode'}) +endif + +"FUNCTION: s:echo(msg){{{1 +function! s:echo(msg) + redraw + echomsg "NERDTree: " . a:msg +endfunction + +"FUNCTION: s:echoWarning(msg){{{1 +function! s:echoWarning(msg) + echohl warningmsg + call s:echo(a:msg) + echohl normal +endfunction + +"FUNCTION: s:promptToDelBuffer(bufnum, msg){{{1 +"prints out the given msg and, if the user responds by pushing 'y' then the +"buffer with the given bufnum is deleted +" +"Args: +"bufnum: the buffer that may be deleted +"msg: a message that will be echoed to the user asking them if they wish to +" del the buffer +function! s:promptToDelBuffer(bufnum, msg) + echo a:msg + if g:NERDTreeAutoDeleteBuffer || nr2char(getchar()) ==# 'y' + " 1. ensure that all windows which display the just deleted filename + " now display an empty buffer (so a layout is preserved). + " Is not it better to close single tabs with this file only ? + let s:originalTabNumber = tabpagenr() + let s:originalWindowNumber = winnr() + exec "tabdo windo if winbufnr(0) == " . a:bufnum . " | exec ':enew! ' | endif" + exec "tabnext " . s:originalTabNumber + exec s:originalWindowNumber . "wincmd w" + " 3. We don't need a previous buffer anymore + exec "bwipeout! " . a:bufnum + endif +endfunction + +"FUNCTION: s:promptToRenameBuffer(bufnum, msg){{{1 +"prints out the given msg and, if the user responds by pushing 'y' then the +"buffer with the given bufnum is replaced with a new one +" +"Args: +"bufnum: the buffer that may be deleted +"msg: a message that will be echoed to the user asking them if they wish to +" del the buffer +function! s:promptToRenameBuffer(bufnum, msg, newFileName) + echo a:msg + if g:NERDTreeAutoDeleteBuffer || nr2char(getchar()) ==# 'y' + let quotedFileName = "'" . a:newFileName . "'" + " 1. ensure that a new buffer is loaded + exec "badd " . quotedFileName + " 2. ensure that all windows which display the just deleted filename + " display a buffer for a new filename. + let s:originalTabNumber = tabpagenr() + let s:originalWindowNumber = winnr() + let editStr = g:NERDTreePath.New(a:newFileName).str({'format': 'Edit'}) + exec "tabdo windo if winbufnr(0) == " . a:bufnum . " | exec ':e! " . editStr . "' | endif" + exec "tabnext " . s:originalTabNumber + exec s:originalWindowNumber . "wincmd w" + " 3. We don't need a previous buffer anymore + exec "bwipeout! " . a:bufnum + endif +endfunction +"FUNCTION: NERDTreeAddNode(){{{1 +function! NERDTreeAddNode() + let curDirNode = g:NERDTreeDirNode.GetSelected() + + let newNodeName = input("Add a childnode\n". + \ "==========================================================\n". + \ "Enter the dir/file name to be created. Dirs end with a '/'\n" . + \ "", curDirNode.path.str() . g:NERDTreePath.Slash(), "file") + + if newNodeName ==# '' + call s:echo("Node Creation Aborted.") + return + endif + + try + let newPath = g:NERDTreePath.Create(newNodeName) + let parentNode = b:NERDTreeRoot.findNode(newPath.getParent()) + + let newTreeNode = g:NERDTreeFileNode.New(newPath) + if empty(parentNode) + call b:NERDTreeRoot.refresh() + call b:NERDTree.render() + elseif parentNode.isOpen || !empty(parentNode.children) + call parentNode.addChild(newTreeNode, 1) + call NERDTreeRender() + call newTreeNode.putCursorHere(1, 0) + endif + catch /^NERDTree/ + call s:echoWarning("Node Not Created.") + endtry +endfunction + +"FUNCTION: NERDTreeMoveNode(){{{1 +function! NERDTreeMoveNode() + let curNode = g:NERDTreeFileNode.GetSelected() + let newNodePath = input("Rename the current node\n" . + \ "==========================================================\n" . + \ "Enter the new path for the node: \n" . + \ "", curNode.path.str(), "file") + + if newNodePath ==# '' + call s:echo("Node Renaming Aborted.") + return + endif + + try + let bufnum = bufnr("^".curNode.path.str()."$") + + call curNode.rename(newNodePath) + call NERDTreeRender() + + "if the node is open in a buffer, ask the user if they want to + "close that buffer + if bufnum != -1 + let prompt = "\nNode renamed.\n\nThe old file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? " (hidden)" : "") .". Replace this buffer with a new file? (yN)" + call s:promptToRenameBuffer(bufnum, prompt, newNodePath) + endif + + call curNode.putCursorHere(1, 0) + + redraw + catch /^NERDTree/ + call s:echoWarning("Node Not Renamed.") + endtry +endfunction + +" FUNCTION: NERDTreeDeleteNode() {{{1 +function! NERDTreeDeleteNode() + let currentNode = g:NERDTreeFileNode.GetSelected() + let confirmed = 0 + + if currentNode.path.isDirectory + let choice =input("Delete the current node\n" . + \ "==========================================================\n" . + \ "STOP! To delete this entire directory, type 'yes'\n" . + \ "" . currentNode.path.str() . ": ") + let confirmed = choice ==# 'yes' + else + echo "Delete the current node\n" . + \ "==========================================================\n". + \ "Are you sure you wish to delete the node:\n" . + \ "" . currentNode.path.str() . " (yN):" + let choice = nr2char(getchar()) + let confirmed = choice ==# 'y' + endif + + + if confirmed + try + call currentNode.delete() + call NERDTreeRender() + + "if the node is open in a buffer, ask the user if they want to + "close that buffer + let bufnum = bufnr("^".currentNode.path.str()."$") + if buflisted(bufnum) + let prompt = "\nNode deleted.\n\nThe file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? " (hidden)" : "") .". Delete this buffer? (yN)" + call s:promptToDelBuffer(bufnum, prompt) + endif + + redraw + catch /^NERDTree/ + call s:echoWarning("Could not remove node") + endtry + else + call s:echo("delete aborted") + endif + +endfunction + +" FUNCTION: NERDTreeCopyNode() {{{1 +function! NERDTreeCopyNode() + let currentNode = g:NERDTreeFileNode.GetSelected() + let newNodePath = input("Copy the current node\n" . + \ "==========================================================\n" . + \ "Enter the new path to copy the node to: \n" . + \ "", currentNode.path.str(), "file") + + if newNodePath != "" + "strip trailing slash + let newNodePath = substitute(newNodePath, '\/$', '', '') + + let confirmed = 1 + if currentNode.path.copyingWillOverwrite(newNodePath) + call s:echo("Warning: copying may overwrite files! Continue? (yN)") + let choice = nr2char(getchar()) + let confirmed = choice ==# 'y' + endif + + if confirmed + try + let newNode = currentNode.copy(newNodePath) + if empty(newNode) + call b:NERDTreeRoot.refresh() + call b:NERDTree.render() + else + call NERDTreeRender() + call newNode.putCursorHere(0, 0) + endif + catch /^NERDTree/ + call s:echoWarning("Could not copy node") + endtry + endif + else + call s:echo("Copy aborted.") + endif + redraw +endfunction + +function! NERDTreeQuickLook() + let treenode = g:NERDTreeFileNode.GetSelected() + if treenode != {} + call system("qlmanage -p 2>/dev/null '" . treenode.path.str() . "'") + endif +endfunction + +function! NERDTreeRevealInFinder() + let treenode = g:NERDTreeFileNode.GetSelected() + if treenode != {} + let x = system("open -R '" . treenode.path.str() . "'") + endif +endfunction + +function! NERDTreeExecuteFile() + let treenode = g:NERDTreeFileNode.GetSelected() + if treenode != {} + let x = system("open '" . treenode.path.str() . "'") + endif +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/nerdtree/plugin/NERD_tree.vim b/vim/bundle/nerdtree/plugin/NERD_tree.vim new file mode 100644 index 0000000..28fd3ad --- /dev/null +++ b/vim/bundle/nerdtree/plugin/NERD_tree.vim @@ -0,0 +1,205 @@ +" ============================================================================ +" File: NERD_tree.vim +" Description: vim global plugin that provides a nice tree explorer +" Maintainer: Martin Grenfell +" Last Change: 28 December, 2011 +" License: This program is free software. It comes without any warranty, +" to the extent permitted by applicable law. You can redistribute +" it and/or modify it under the terms of the Do What The Fuck You +" Want To Public License, Version 2, as published by Sam Hocevar. +" See http://sam.zoy.org/wtfpl/COPYING for more details. +" +" ============================================================================ +" +" SECTION: Script init stuff {{{1 +"============================================================ +if exists("loaded_nerd_tree") + finish +endif +if v:version < 700 + echoerr "NERDTree: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!" + finish +endif +let loaded_nerd_tree = 1 + +"for line continuation - i.e dont want C in &cpo +let s:old_cpo = &cpo +set cpo&vim + +"Function: s:initVariable() function {{{2 +"This function is used to initialise a given variable to a given value. The +"variable is only initialised if it does not exist prior +" +"Args: +"var: the name of the var to be initialised +"value: the value to initialise var to +" +"Returns: +"1 if the var is set, 0 otherwise +function! s:initVariable(var, value) + if !exists(a:var) + exec 'let ' . a:var . ' = ' . "'" . substitute(a:value, "'", "''", "g") . "'" + return 1 + endif + return 0 +endfunction + +"SECTION: Init variable calls and other random constants {{{2 +call s:initVariable("g:NERDTreeAutoCenter", 1) +call s:initVariable("g:NERDTreeAutoCenterThreshold", 3) +call s:initVariable("g:NERDTreeCaseSensitiveSort", 0) +call s:initVariable("g:NERDTreeSortHiddenFirst", 1) +call s:initVariable("g:NERDTreeChDirMode", 0) +call s:initVariable("g:NERDTreeMinimalUI", 0) +if !exists("g:NERDTreeIgnore") + let g:NERDTreeIgnore = ['\~$'] +endif +call s:initVariable("g:NERDTreeBookmarksFile", expand('$HOME') . '/.NERDTreeBookmarks') +call s:initVariable("g:NERDTreeBookmarksSort", 1) +call s:initVariable("g:NERDTreeHighlightCursorline", 1) +call s:initVariable("g:NERDTreeHijackNetrw", 1) +call s:initVariable("g:NERDTreeMouseMode", 1) +call s:initVariable("g:NERDTreeNotificationThreshold", 100) +call s:initVariable("g:NERDTreeQuitOnOpen", 0) +call s:initVariable("g:NERDTreeRespectWildIgnore", 0) +call s:initVariable("g:NERDTreeShowBookmarks", 0) +call s:initVariable("g:NERDTreeShowFiles", 1) +call s:initVariable("g:NERDTreeShowHidden", 0) +call s:initVariable("g:NERDTreeShowLineNumbers", 0) +call s:initVariable("g:NERDTreeSortDirs", 1) +call s:initVariable("g:NERDTreeDirArrows", !nerdtree#runningWindows()) +call s:initVariable("g:NERDTreeCascadeOpenSingleChildDir", 1) + +if !exists("g:NERDTreeSortOrder") + let g:NERDTreeSortOrder = ['\/$', '*', '\.swp$', '\.bak$', '\~$'] +else + "if there isnt a * in the sort sequence then add one + if count(g:NERDTreeSortOrder, '*') < 1 + call add(g:NERDTreeSortOrder, '*') + endif +endif + +if !exists('g:NERDTreeStatusline') + + "the exists() crap here is a hack to stop vim spazzing out when + "loading a session that was created with an open nerd tree. It spazzes + "because it doesnt store b:NERDTreeRoot (its a b: var, and its a hash) + let g:NERDTreeStatusline = "%{exists('b:NERDTreeRoot')?b:NERDTreeRoot.path.str():''}" + +endif +call s:initVariable("g:NERDTreeWinPos", "left") +call s:initVariable("g:NERDTreeWinSize", 31) + +"init the shell commands that will be used to copy nodes, and remove dir trees +" +"Note: the space after the command is important +if nerdtree#runningWindows() + call s:initVariable("g:NERDTreeRemoveDirCmd", 'rmdir /s /q ') +else + call s:initVariable("g:NERDTreeRemoveDirCmd", 'rm -rf ') + call s:initVariable("g:NERDTreeCopyCmd", 'cp -r ') +endif + + +"SECTION: Init variable calls for key mappings {{{2 +call s:initVariable("g:NERDTreeMapActivateNode", "o") +call s:initVariable("g:NERDTreeMapChangeRoot", "C") +call s:initVariable("g:NERDTreeMapChdir", "cd") +call s:initVariable("g:NERDTreeMapCloseChildren", "X") +call s:initVariable("g:NERDTreeMapCloseDir", "x") +call s:initVariable("g:NERDTreeMapDeleteBookmark", "D") +call s:initVariable("g:NERDTreeMapMenu", "m") +call s:initVariable("g:NERDTreeMapHelp", "?") +call s:initVariable("g:NERDTreeMapJumpFirstChild", "K") +call s:initVariable("g:NERDTreeMapJumpLastChild", "J") +call s:initVariable("g:NERDTreeMapJumpNextSibling", "") +call s:initVariable("g:NERDTreeMapJumpParent", "p") +call s:initVariable("g:NERDTreeMapJumpPrevSibling", "") +call s:initVariable("g:NERDTreeMapJumpRoot", "P") +call s:initVariable("g:NERDTreeMapOpenExpl", "e") +call s:initVariable("g:NERDTreeMapOpenInTab", "t") +call s:initVariable("g:NERDTreeMapOpenInTabSilent", "T") +call s:initVariable("g:NERDTreeMapOpenRecursively", "O") +call s:initVariable("g:NERDTreeMapOpenSplit", "i") +call s:initVariable("g:NERDTreeMapOpenVSplit", "s") +call s:initVariable("g:NERDTreeMapPreview", "g" . NERDTreeMapActivateNode) +call s:initVariable("g:NERDTreeMapPreviewSplit", "g" . NERDTreeMapOpenSplit) +call s:initVariable("g:NERDTreeMapPreviewVSplit", "g" . NERDTreeMapOpenVSplit) +call s:initVariable("g:NERDTreeMapQuit", "q") +call s:initVariable("g:NERDTreeMapRefresh", "r") +call s:initVariable("g:NERDTreeMapRefreshRoot", "R") +call s:initVariable("g:NERDTreeMapToggleBookmarks", "B") +call s:initVariable("g:NERDTreeMapToggleFiles", "F") +call s:initVariable("g:NERDTreeMapToggleFilters", "f") +call s:initVariable("g:NERDTreeMapToggleHidden", "I") +call s:initVariable("g:NERDTreeMapToggleZoom", "A") +call s:initVariable("g:NERDTreeMapUpdir", "u") +call s:initVariable("g:NERDTreeMapUpdirKeepOpen", "U") +call s:initVariable("g:NERDTreeMapCWD", "CD") + +"SECTION: Load class files{{{2 +call nerdtree#loadClassFiles() + +" SECTION: Commands {{{1 +"============================================================ +call nerdtree#ui_glue#setupCommands() + +" SECTION: Auto commands {{{1 +"============================================================ +augroup NERDTree + "Save the cursor position whenever we close the nerd tree + exec "autocmd BufLeave ". g:NERDTreeCreator.BufNamePrefix() ."* call b:NERDTree.ui.saveScreenState()" + + "disallow insert mode in the NERDTree + exec "autocmd BufEnter ". g:NERDTreeCreator.BufNamePrefix() ."* stopinsert" +augroup END + +if g:NERDTreeHijackNetrw + augroup NERDTreeHijackNetrw + autocmd VimEnter * silent! autocmd! FileExplorer + au BufEnter,VimEnter * call nerdtree#checkForBrowse(expand("")) + augroup END +endif + +" SECTION: Public API {{{1 +"============================================================ +function! NERDTreeAddMenuItem(options) + call g:NERDTreeMenuItem.Create(a:options) +endfunction + +function! NERDTreeAddMenuSeparator(...) + let opts = a:0 ? a:1 : {} + call g:NERDTreeMenuItem.CreateSeparator(opts) +endfunction + +function! NERDTreeAddSubmenu(options) + return g:NERDTreeMenuItem.Create(a:options) +endfunction + +function! NERDTreeAddKeyMap(options) + call g:NERDTreeKeyMap.Create(a:options) +endfunction + +function! NERDTreeRender() + call nerdtree#renderView() +endfunction + +function! NERDTreeFocus() + if nerdtree#isTreeOpen() + call nerdtree#putCursorInTreeWin() + else + call g:NERDTreeCreator.TogglePrimary("") + endif +endfunction + +function! NERDTreeCWD() + call NERDTreeFocus() + call nerdtree#ui_glue#chRootCwd() +endfunction +" SECTION: Post Source Actions {{{1 +call nerdtree#postSourceActions() + +"reset &cpo back to users setting +let &cpo = s:old_cpo + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/bundle/nerdtree/syntax/nerdtree.vim b/vim/bundle/nerdtree/syntax/nerdtree.vim new file mode 100644 index 0000000..5f7b49c --- /dev/null +++ b/vim/bundle/nerdtree/syntax/nerdtree.vim @@ -0,0 +1,105 @@ +let s:tree_up_dir_line = '.. (up a dir)' +syn match NERDTreeIgnore #\~# +syn match NERDTreeIgnore #\[RO\]# + +"highlighting for the .. (up dir) line at the top of the tree +execute "syn match NERDTreeUp #\\V". s:tree_up_dir_line ."#" + +"quickhelp syntax elements +syn match NERDTreeHelpKey #" \{1,2\}[^ ]*:#ms=s+2,me=e-1 +syn match NERDTreeHelpKey #" \{1,2\}[^ ]*,#ms=s+2,me=e-1 +syn match NERDTreeHelpTitle #" .*\~#ms=s+2,me=e-1 +syn match NERDTreeToggleOn #(on)#ms=s+1,he=e-1 +syn match NERDTreeToggleOff #(off)#ms=e-3,me=e-1 +syn match NERDTreeHelpCommand #" :.\{-}\>#hs=s+3 +syn match NERDTreeHelp #^".*# contains=NERDTreeHelpKey,NERDTreeHelpTitle,NERDTreeIgnore,NERDTreeToggleOff,NERDTreeToggleOn,NERDTreeHelpCommand + +"highlighting for sym links +syn match NERDTreeLinkTarget #->.*# containedin=NERDTreeDir,NERDTreeFile +syn match NERDTreeLinkFile #.* ->#me=e-3 containedin=NERDTreeFile +syn match NERDTreeLinkDir #.*/ ->#me=e-3 containedin=NERDTreeDir + +"highlighing for directory nodes and file nodes +syn match NERDTreeDirSlash #/# containedin=NERDTreeDir + +if g:NERDTreeDirArrows + syn match NERDTreeClosable #▾# containedin=NERDTreeDir,NERDTreeFile + syn match NERDTreeOpenable #▸# containedin=NERDTreeDir,NERDTreeFile + + syn match NERDTreeDir #[^▾▸ ].*/# + syn match NERDTreeExecFile #^ .*\*\($\| \)# contains=NERDTreeRO,NERDTreeBookmark + syn match NERDTreeFile #^[^"\.▾▸] *[^▾▸]*# contains=NERDTreeLink,NERDTreeRO,NERDTreeBookmark,NERDTreeExecFile + + "highlighting for readonly files + syn match NERDTreeRO # *\zs.*\ze \[RO\]# contains=NERDTreeIgnore,NERDTreeBookmark,NERDTreeFile + + syn match NERDTreeFlags #^ *\zs\[.\]# containedin=NERDTreeFile + syn match NERDTreeFlags #\[.\]# containedin=NERDTreeDir +else + "highlighting for the ~/+ symbols for the directory nodes + syn match NERDTreeClosable #\~\<# + syn match NERDTreeClosable #\~\.# + syn match NERDTreeOpenable #+\<# + syn match NERDTreeOpenable #+\.#he=e-1 + + "highlighting for the tree structural parts + syn match NERDTreePart #|# + syn match NERDTreePart #`# + syn match NERDTreePartFile #[|`]-#hs=s+1 contains=NERDTreePart + + syn match NERDTreeDir #[^-| `].*/# contains=NERDTreeLink,NERDTreeOpenable,NERDTreeClosable + syn match NERDTreeExecFile #[|` ].*\*\($\| \)# contains=NERDTreeLink,NERDTreePart,NERDTreePartFile,NERDTreeBookmark + syn match NERDTreeFile #|-.*# contains=NERDTreeLink,NERDTreePart,NERDTreePartFile,NERDTreeBookmark,NERDTreeExecFile + syn match NERDTreeFile #`-.*# contains=NERDTreeLink,NERDTreePart,NERDTreePartFile,NERDTreeBookmark,NERDTreeExecFile + + "highlighting for readonly files + syn match NERDTreeRO #|-.*\[RO\]#he=e-5 contains=NERDTreeIgnore,NERDTreeBookmark,NERDTreePart,NERDTreePartFile + + syn match NERDTreeFlags #-\[.\]# containedin=NERDTreeFile,NERDTreePartFile + syn match NERDTreeFlags #[+~]\zs\[.\]# containedin=NERDTreeDir +endif + +syn match NERDTreeCWD #^[# +syn match NERDTreeBookmarksHeader #^>-\+Bookmarks-\+$# contains=NERDTreeBookmarksLeader +syn match NERDTreeBookmarkName #^>.\{-} #he=e-1 contains=NERDTreeBookmarksLeader +syn match NERDTreeBookmark #^>.*$# contains=NERDTreeBookmarksLeader,NERDTreeBookmarkName,NERDTreeBookmarksHeader + +hi def link NERDTreePart Special +hi def link NERDTreePartFile Type +hi def link NERDTreeExecFile Title +hi def link NERDTreeDirSlash Identifier + +hi def link NERDTreeBookmarksHeader statement +hi def link NERDTreeBookmarksLeader ignore +hi def link NERDTreeBookmarkName Identifier +hi def link NERDTreeBookmark normal + +hi def link NERDTreeHelp String +hi def link NERDTreeHelpKey Identifier +hi def link NERDTreeHelpCommand Identifier +hi def link NERDTreeHelpTitle Macro +hi def link NERDTreeToggleOn Question +hi def link NERDTreeToggleOff WarningMsg + +hi def link NERDTreeLinkTarget Type +hi def link NERDTreeLinkFile Macro +hi def link NERDTreeLinkDir Macro + +hi def link NERDTreeDir Directory +hi def link NERDTreeUp Directory +hi def link NERDTreeFile Normal +hi def link NERDTreeCWD Statement +hi def link NERDTreeOpenable Title +hi def link NERDTreeClosable Title +hi def link NERDTreeIgnore ignore +hi def link NERDTreeRO WarningMsg +hi def link NERDTreeBookmark Statement +hi def link NERDTreeFlags Number + +hi def link NERDTreeCurrentNode Search diff --git a/vim/bundle/vim-coffee-script/.gitignore b/vim/bundle/vim-coffee-script/.gitignore new file mode 100644 index 0000000..1ff7b05 --- /dev/null +++ b/vim/bundle/vim-coffee-script/.gitignore @@ -0,0 +1,4 @@ +.*.sw[a-z] +.*.un~ +doc/tags + diff --git a/vim/bundle/vim-coffee-script/Copying.md b/vim/bundle/vim-coffee-script/Copying.md new file mode 100644 index 0000000..a31ad2f --- /dev/null +++ b/vim/bundle/vim-coffee-script/Copying.md @@ -0,0 +1,15 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2010 to 2014 Mick Koch + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. + + diff --git a/vim/bundle/vim-coffee-script/Makefile b/vim/bundle/vim-coffee-script/Makefile new file mode 100644 index 0000000..e6ef409 --- /dev/null +++ b/vim/bundle/vim-coffee-script/Makefile @@ -0,0 +1,25 @@ +REF = HEAD +VERSION = $(shell git describe --always $(REF)) + +ARCHIVE = vim-coffee-script-$(VERSION).zip +ARCHIVE_DIRS = after autoload compiler doc ftdetect ftplugin indent syntax + +# Don't do anything by default. +all: + +# Make vim.org zipball. +archive: + git archive $(REF) -o $(ARCHIVE) -- $(ARCHIVE_DIRS) + +# Remove zipball. +clean: + -rm -f $(ARCHIVE) + +# Build the list of syntaxes for @coffeeAll. +coffeeAll: + @grep -E 'syn (match|region)' syntax/coffee.vim |\ + grep -v 'contained' |\ + awk '{print $$3}' |\ + uniq + +.PHONY: all archive clean hash coffeeAll diff --git a/vim/bundle/vim-coffee-script/News.md b/vim/bundle/vim-coffee-script/News.md new file mode 100644 index 0000000..9f3f139 --- /dev/null +++ b/vim/bundle/vim-coffee-script/News.md @@ -0,0 +1,22 @@ +### Version 003 (October 10, 2014) + +Almost 3 years' worth of fixes and (hopefully) improvements. + +### Version 002 (December 5, 2011) + +Added binary numbers (0b0101) and fixed some bugs (#9, #62, #63, #65). + +### Version 001 (October 18, 2011) + +Removed deprecated `coffee_folding` option, added `coffee_compile_vert` option, +split out compiler, fixed indentation and syntax bugs, and added Haml support +and omnicompletion. + + - The coffee compiler is now a proper vim compiler that can be loaded with + `:compiler coffee`. + - The `coffee_compile_vert` option can now be set to split the CoffeeCompile + buffer vertically by default. + - CoffeeScript is now highlighted inside the `:coffeescript` filter in Haml. + - Omnicompletion (`:help compl-omni`) now uses JavaScript's dictionary to + complete words. + - We now have a fancy version number. diff --git a/vim/bundle/vim-coffee-script/Readme.md b/vim/bundle/vim-coffee-script/Readme.md new file mode 100644 index 0000000..08d61f1 --- /dev/null +++ b/vim/bundle/vim-coffee-script/Readme.md @@ -0,0 +1,599 @@ +This project adds [CoffeeScript] support to vim. It covers syntax, indenting, +compiling, and more. + +![Screenshot](http://i.imgur.com/j1BhpZQ.png) + +[CoffeeScript]: http://coffeescript.org/ + +## Table of Contents + +- Installation + - [Requirements](#requirements) + - [Install using Pathogen](#install-using-pathogen) + - [Install using Vundle](#install-using-vundle) + - [Install from a Zip File](#install-from-a-zip-file) +- Coffee Commands + - [Compile to JavaScript](#compile-to-javascript) + - [Compile CoffeeScript Snippets](#coffeecompile-compile-coffeescript-snippets) + - [Live Preview Compiling](#coffeewatch-live-preview-compiling) + - [Run CoffeeScript Snippets](#coffeerun-run-coffeescript-snippets) + - [Lint your CoffeeScript](#coffeelint-lint-your-coffeescript) +- Extras + - [Literate CoffeeScript](#literate-coffeescript) + - [CoffeeScript in HTML](#coffeescript-in-html) + - [CoffeeScript in Haml](#coffeescript-in-haml) +- Configuration + - [Custom Autocmds](#custom-autocmds) + - [Configuration Variables](#configuration-variables) + - [Configure Syntax Highlighting](#configure-syntax-highlighting) + - [Tune Vim for CoffeeScript](#tune-vim-for-coffeescript) + +## Requirements + + - vim 7.4 or later + - coffee 1.2.0 or later + +## Install using Pathogen + +This project uses rolling releases based on git commits, so pathogen is a +natural fit for it. If you're already using pathogen, you can skip to step 4. + +1. Install [pathogen.vim] into `~/.vim/autoload/` (see [pathogen's + readme][install-pathogen] for more information.) + +[pathogen.vim]: http://www.vim.org/scripts/script.php?script_id=2332 +[install-pathogen]: https://github.com/tpope/vim-pathogen#installation + +2. Enable pathogen in your vimrc. Here's a bare-minimum vimrc that enables + all the features of `vim-coffee-script`: + + ```vim + call pathogen#infect() + syntax enable + filetype plugin indent on + ``` + + If you already have a vimrc built up, just make sure it contains these calls, + in this order. + +3. Create the directory `~/.vim/bundle/`: + + mkdir ~/.vim/bundle + +4. Clone the `vim-coffee-script` repo into `~/.vim/bundle/`: + + git clone https://github.com/kchmck/vim-coffee-script.git ~/.vim/bundle/vim-coffee-script/ + +Updating takes two steps: + +1. Change into `~/.vim/bundle/vim-coffee-script/`: + + cd ~/.vim/bundle/vim-coffee-script + +2. Pull in the latest changes: + + git pull + +## Install using Vundle + +1. [Install Vundle] into `~/.vim/bundle/`. + +[Install Vundle]: https://github.com/gmarik/vundle#quick-start + +2. Configure your vimrc for Vundle. Here's a bare-minimum vimrc that enables all + the features of `vim-coffee-script`: + + + ```vim + set nocompatible + filetype off + + set rtp+=~/.vim/bundle/vundle/ + call vundle#rc() + + Plugin 'kchmck/vim-coffee-script' + + syntax enable + filetype plugin indent on + ``` + + If you're adding Vundle to a built-up vimrc, just make sure all these calls + are in there and that they occur in this order. + +3. Open vim and run `:PluginInstall`. + +To update, open vim and run `:PluginInstall!` (notice the bang!) + +## Install from a Zip File + +1. Download the latest zip file from [vim.org][zip]. + +2. Extract the archive into `~/.vim/`: + + unzip -od ~/.vim/ ARCHIVE.zip + + This should create the files `~/.vim/autoload/coffee.vim`, + `~/.vim/compiler/coffee.vim`, etc. + +You can update the plugin using the same steps. + +[zip]: http://www.vim.org/scripts/script.php?script_id=3590 + +## Compile to JavaScript + +A `coffee` wrapper for use with `:make` is enabled automatically for coffee +files if no other compiler is loaded. To enable it manually, run + + :compiler coffee + +The `:make` command is then configured to use the `coffee` compiler and +recognize its errors. I've included a quick reference here but be sure to check +out [`:help :make`][make] for a full reference of the command. + + ![make](http://i.imgur.com/scUXmxR.png) + + ![make Result](http://i.imgur.com/eGIjEdn.png) + +[make]: http://vimdoc.sourceforge.net/htmldoc/quickfix.html#:make_makeprg + +Consider the full signature of a `:make` call as + + :[silent] make[!] [COFFEE-OPTIONS]... + +By default `:make` shows all compiler output and jumps to the first line +reported as an error. Compiler output can be hidden with a leading `:silent`: + + :silent make + +Line-jumping can be turned off by adding a bang: + + :make! + +`COFFEE-OPTIONS` given to `:make` are passed along to `coffee` (see also +[`coffee_make_options`](#coffee_make_options)): + + :make --bare --output /some/dir + +See the [full table of options](http://coffeescript.org/#usage) for a +list of all the options that `coffee` recognizes. + +*Configuration*: [`coffee_compiler`](#coffee_compiler), +[`coffee_make_options`](#coffee_make_options) + +#### The quickfix window + +Compiler errors are added to the [quickfix] list by `:make`, but the quickfix +window isn't automatically shown. The [`:cwindow`][cwindow] command will pop up +the quickfix window if there are any errors: + + :make + :cwindow + +This is usually the desired behavior, so you may want to add an autocmd to your +vimrc to do this automatically: + + autocmd QuickFixCmdPost * nested cwindow | redraw! + +The `redraw!` command is needed to fix a redrawing quirk in terminal vim, but +can removed for gVim. + +[quickfix]: http://vimdoc.sourceforge.net/htmldoc/quickfix.html#quickfix +[cwindow]: http://vimdoc.sourceforge.net/htmldoc/quickfix.html#:cwindow + +#### Recompile on write + +To recompile a file when it's written, add a `BufWritePost` autocmd to your +vimrc: + + autocmd BufWritePost *.coffee silent make! + +#### Cake and Cakefiles + +A `cake` compiler is also available with the call + + :compiler cake + +You can then use `:make` as above to run your Cakefile and capture any `coffee` +errors: + + :silent make build + +It runs within the current directory, so make sure you're in the directory of +your Cakefile before calling it. + +*Configuration*: [`coffee_cake`](#coffee_cake), +[`coffee_cake_options`](#coffee_cake_options) + +## CoffeeCompile: Compile CoffeeScript Snippets + +CoffeeCompile shows how the current file or a snippet of CoffeeScript is +compiled to JavaScript. + + :[RANGE] CoffeeCompile [vert[ical]] [WINDOW-SIZE] + +Calling `:CoffeeCompile` without a range compiles the whole file: + + ![CoffeeCompile](http://i.imgur.com/0zFG0l0.png) + + ![CoffeeCompile Result](http://i.imgur.com/bpiAxaa.png) + +Calling it with a range, like in visual mode, compiles only the selected snippet +of CoffeeScript: + + ![CoffeeCompile Snippet](http://i.imgur.com/x3OT3Ay.png) + + ![Compiled Snippet](http://i.imgur.com/J02j4T8.png) + +Each file gets its own CoffeeCompile buffer, and the same buffer is used for all +future calls of `:CoffeeCompile` on that file. It can be quickly closed by +hitting `q` in normal mode. + +Using `vert` opens the CoffeeCompile buffer vertically instead of horizontally +(see also [`coffee_compile_vert`](#coffee_compile_vert)): + + :CoffeeCompile vert + +By default the CoffeeCompile buffer splits the source buffer in half, but this +can be overridden by passing in a `WINDOW-SIZE`: + + :CoffeeCompile 4 + +*Configuration*: [`coffee_compiler`](#coffee_compiler`), +[`coffee_compile_vert`](#coffee_compile_vert) + +#### Quick syntax checking + +If compiling a snippet results in a compiler error, CoffeeCompile adds that +error to the [quickfix] list. + +[quickfix]: http://vimdoc.sourceforge.net/htmldoc/quickfix.html#quickfix + + ![Syntax Checking](http://i.imgur.com/RC8accF.png) + + ![Syntax Checking Result](http://i.imgur.com/gi1ON75.png) + +You can use this to quickly check the syntax of a snippet. + +## CoffeeWatch: Live Preview Compiling + +CoffeeWatch emulates using the Try CoffeeScript preview box on the [CoffeeScript +homepage][CoffeeScript]. + + ![CoffeeWatch](http://i.imgur.com/TRHdIMG.png) + + ![CoffeeWatch Result](http://i.imgur.com/rJbOeeS.png) + +CoffeeWatch takes the same options as CoffeeCompile: + + :CoffeeWatch [vert[ical]] [WINDOW-SIZE] + +After a source buffer is watched, leaving insert mode or saving the file fires +off a recompile of the CoffeeScript: + + ![Insert Mode](http://i.imgur.com/SBVcf4k.png) + + ![Recompile](http://i.imgur.com/pbPMog7.png) + +You can force recompilation by calling `:CoffeeWatch`. + +To get synchronized scrolling of the source buffer and CoffeeWatch buffer, set +[`'scrollbind'`](http://vimdoc.sourceforge.net/htmldoc/options.html#'scrollbind') +on each: + + :setl scrollbind + +*Configuration*: [`coffee_compiler`](#coffee_compiler), +[`coffee_watch_vert`](#coffee_watch_vert) + +## CoffeeRun: Run CoffeeScript Snippets + +CoffeeRun compiles the current file or selected snippet and runs the resulting +JavaScript. + + ![CoffeeRun](http://i.imgur.com/YSkHUuQ.png) + + ![CoffeeRun Output](http://i.imgur.com/wZQbggN.png) + +The command has two forms: + + :CoffeeRun [PROGRAM-OPTIONS]... + +This form applies when no `RANGE` is given or when the given range is `1,$` +(first line to last line). It allows passing `PROGRAM-OPTIONS` to your compiled +program. The filename is passed directly to `coffee` so you must save the file +for your changes to take effect. + + :RANGE CoffeeRun [COFFEE-OPTIONS]... + +This form applies with all other ranges. It compiles and runs the lines within +the given `RANGE` and any extra `COFFEE-OPTIONS` are passed to `coffee`. + +*Configuration*: [`coffee_compiler`](#coffee_compiler), +[`coffee_run_vert`](#coffee_run_vert) + +## CoffeeLint: Lint your CoffeeScript + +CoffeeLint runs [coffeelint](http://www.coffeelint.org/) (version 1.4.0 or later +required) on the current file and adds any issues to the [quickfix] list. + + ![CoffeeLint](http://i.imgur.com/UN8Nr5N.png) + + ![CoffeeLint Result](http://i.imgur.com/9hSIj3W.png) + + :[RANGE] CoffeeLint[!] [COFFEELINT-OPTIONS]... [ | cwindow] + +If a `RANGE` is given, only those lines are piped to `coffeelint`. Options given +in `COFFEELINT-OPTIONS` are passed to `coffeelint` (see also +[`coffee_lint_options`](#coffee_lint_options)): + + :CoffeeLint -f lint.json + +It behaves very similar to `:make`, described [above](#compile-to-javascript). + + :CoffeeLint! | cwindow + +*Configuration*: [`coffee_linter`](#coffee_linter), +[`coffee_lint_options`](#coffee_lint_options) + +## Literate CoffeeScript + +Literate CoffeeScript syntax and indent support is provided by +[vim-literate-coffeescript]. The `Coffee` commands detect when they're running +on a litcoffee file and pass the `--literate` flag to their respective tools, +but at this time the commands are not automatically loaded when a litcoffee file +is opened. + +[vim-literate-coffeescript]: https://github.com/mintplant/vim-literate-coffeescript + +To load them, run + + runtime ftplugin/coffee.vim + +while inside a litcoffee buffer. To do this automatically, add + + autocmd FileType litcoffee runtime ftplugin/coffee.vim + +to your vimrc. + +## CoffeeScript in HTML + +CoffeeScript is highlighted and indented within + +```html + +``` + +blocks in html files. + +## CoffeeScript in Haml + +CoffeeScript is highlighted within the `:coffeescript` filter in haml files: + +```haml +:coffeescript + console.log "hullo" +``` + +At this time, coffee indenting doesn't work in these blocks. + +## Custom Autocmds + +You can [define commands][autocmd-explain] to be ran automatically on these +custom events. + +In all cases, the name of the command running the event (`CoffeeCompile`, +`CoffeeWatch`, or `CoffeeRun`) is matched by the [`{pat}`][autocmd] argument. +You can match all commands with a `*` or only specific commands by separating +them with a comma: `CoffeeCompile,CoffeeWatch`. + +[autocmd-explain]: http://vimdoc.sourceforge.net/htmldoc/usr_40.html#40.3 +[autocmd]: http://vimdoc.sourceforge.net/htmldoc/autocmd.html#:autocmd + +#### CoffeeBufNew + +CoffeeBufNew is ran when a new scratch buffer is created. It's called from the +new buffer, so it can be used to do additional set up. + +```vim +augroup CoffeeBufNew + autocmd User * set wrap +augroup END +``` + +*Used By*: CoffeeCompile, CoffeeWatch, CoffeeRun + +#### CoffeeBufUpdate + +CoffeeBufUpdate is ran when a scratch buffer is updated with output from +`coffee`. It's called from the scratch buffer, so it can be used to alter the +compiled output. + +```vim +" Switch back to the source buffer after updating. +augroup CoffeeBufUpdate + autocmd User CoffeeCompile,CoffeeRun exec bufwinnr(b:coffee_src_buf) 'wincmd w' +augroup END +``` + +For example, to strip off the "Generated by" comment on the first line, put this +in your vimrc: + +```vim +function! s:RemoveGeneratedBy() + " If there was an error compiling, there's no comment to remove. + if v:shell_error + return + endif + + " Save cursor position. + let pos = getpos('.') + + " Remove first line. + set modifiable + 1 delete _ + set nomodifiable + + " Restore cursor position. + call setpos('.', pos) +endfunction + +augroup CoffeeBufUpdate + autocmd User CoffeeCompile,CoffeeWatch call s:RemoveGeneratedBy() +augroup END +``` + +*Used By*: CoffeeCompile, CoffeeWatch, CoffeeRun + +## Configuration Variables + +This is the full list of configuration variables available, with example +settings and default values. Use these in your vimrc to control the default +behavior. + +#### coffee\_indent\_keep\_current + +By default, the indent function matches the indent of the previous line if it +doesn't find a reason to indent or outdent. To change this behavior so it +instead keeps the [current indent of the cursor][98], use + + let coffee_indent_keep_current = 1 + +[98]: https://github.com/kchmck/vim-coffee-script/pull/98 + +*Default*: `unlet coffee_indent_keep_current` + +Note that if you change this after a coffee file has been loaded, you'll have to +reload the indent script for the change to take effect: + + unlet b:did_indent | runtime indent/coffee.vim + +#### coffee\_compiler + +Path to the `coffee` executable used by the `Coffee` commands: + + let coffee_compiler = '/usr/bin/coffee' + +*Default*: `'coffee'` (search `$PATH` for executable) + +#### coffee\_make\_options + +Options to pass to `coffee` with `:make`: + + let coffee_make_options = '--bare' + +*Default*: `''` (nothing) + +Note that `coffee_make_options` is embedded into `'makeprg'`, so `:compiler +coffee` must be ran after changing `coffee_make_options` for the changes to take +effect. + +#### coffee\_cake + +Path to the `cake` executable: + + let coffee_cake = '/opt/bin/cake' + +*Default*: `'cake'` (search `$PATH` for executable) + +#### coffee\_cake\_options + +Options to pass to `cake` with `:make`: + + let coffee_cake_options = 'build' + +*Default*: `''` (nothing) + +#### coffee\_linter + +Path to the `coffeelint` executable: + + let coffee_linter = '/opt/bin/coffeelint' + +*Default*: `'coffeelint'` (search `$PATH` for executable) + +#### coffee\_lint\_options + +Options to pass to `coffeelint`: + + let coffee_lint_options = '-f lint.json' + +*Default*: `''` (nothing) + +#### coffee\_compile\_vert + +Open the CoffeeCompile buffer with a vertical split instead of a horizontal +one: + + let coffee_compile_vert = 1 + +*Default*: `unlet coffee_compile_vert` + +#### coffee\_watch\_vert + +Open the CoffeeWatch buffer with a vertical split instead of a horizontal +one: + + let coffee_watch_vert = 1 + +*Default*: `unlet coffee_watch_vert` + +#### coffee\_run\_vert + +Open the CoffeeRun buffer with a vertical split instead of a horizontal +one: + + let coffee_run_vert = 1 + +*Default*: `unlet coffee_run_vert` + +## Configure Syntax Highlighting + +Add these lines to your vimrc to disable the relevant syntax group. + +#### Disable trailing whitespace error + +Trailing whitespace is highlighted as an error by default. This can be disabled +with: + + hi link coffeeSpaceError NONE + +#### Disable trailing semicolon error + +Trailing semicolons are considered an error (for help transitioning from +JavaScript.) This can be disabled with: + + hi link coffeeSemicolonError NONE + +#### Disable reserved words error + +Reserved words like `function` and `var` are highlighted as an error where +they're not allowed in CoffeeScript. This can be disabled with: + + hi link coffeeReservedError NONE + +## Tune Vim for CoffeeScript + +Changing these core settings can make vim more CoffeeScript friendly. + +#### Fold by indentation + +Folding by indentation works well for CoffeeScript functions and classes: + + ![Folding](http://i.imgur.com/gDgUBdO.png) + +To fold by indentation in CoffeeScript files, add this line to your vimrc: + + autocmd BufNewFile,BufReadPost *.coffee setl foldmethod=indent nofoldenable + +With this, folding is disabled by default but can be quickly toggled per-file +by hitting `zi`. To enable folding by default, remove `nofoldenable`: + + autocmd BufNewFile,BufReadPost *.coffee setl foldmethod=indent + +#### Two-space indentation + +To get standard two-space indentation in CoffeeScript files, add this line to +your vimrc: + + autocmd BufNewFile,BufReadPost *.coffee setl shiftwidth=2 expandtab diff --git a/vim/bundle/vim-coffee-script/Thanks.md b/vim/bundle/vim-coffee-script/Thanks.md new file mode 100644 index 0000000..8ddcf23 --- /dev/null +++ b/vim/bundle/vim-coffee-script/Thanks.md @@ -0,0 +1,44 @@ +Thanks to all bug reporters, and special thanks to those who have contributed +code: + + Brian Egan (brianegan): + Initial compiling support + + Ches Martin (ches): + Initial vim docs + + Chris Hoffman (cehoffman): + Add new keywoards from, to, and do + Highlight the - in negative integers + Add here regex highlighting, increase fold level for here docs + + David Wilhelm (bigfish): + CoffeeRun command + + Jay Adkisson (jayferd): + Support for eco templates + + Karl Guertin (grayrest) + Cakefiles are coffeescript + + Maciej Konieczny (narfdotpl): + Fix funny typo + + Matt Sacks (mattsa): + Javascript omni-completion + coffee_compile_vert option + + Nick Stenning (nickstenning): + Fold by indentation for coffeescript + + Simon Lipp (sloonz): + Trailing spaces are not error on lines containing only spaces + + Stéphan Kochen (stephank): + Initial HTML CoffeeScript highlighting + + Sven Felix Oberquelle (Svelix): + Haml CoffeeScript highlighting + + Wei Dai (clvv): + Fix the use of Vim built-in make command. diff --git a/vim/bundle/vim-coffee-script/Todo.md b/vim/bundle/vim-coffee-script/Todo.md new file mode 100644 index 0000000..3d4ffaa --- /dev/null +++ b/vim/bundle/vim-coffee-script/Todo.md @@ -0,0 +1 @@ +- Don't highlight bad operator combinations diff --git a/vim/bundle/vim-coffee-script/after/indent/html.vim b/vim/bundle/vim-coffee-script/after/indent/html.vim new file mode 100644 index 0000000..2fa8637 --- /dev/null +++ b/vim/bundle/vim-coffee-script/after/indent/html.vim @@ -0,0 +1,33 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +" Load the coffee and html indent functions. +silent! unlet b:did_indent +runtime indent/coffee.vim +let s:coffeeIndentExpr = &l:indentexpr + +" Load html last so it can overwrite coffee settings. +silent! unlet b:did_indent +runtime indent/html.vim +let s:htmlIndentExpr = &l:indentexpr + +" Inject our wrapper indent function. +setlocal indentexpr=GetCoffeeHtmlIndent(v:lnum) + +function! GetCoffeeHtmlIndent(curlinenum) + " See if we're inside a coffeescript block. + let scriptlnum = searchpair('', 'bWn') + let prevlnum = prevnonblank(a:curlinenum) + + " If we're in the script block and the previous line isn't the script tag + " itself, use coffee indenting. + if scriptlnum && scriptlnum != prevlnum + exec 'return ' s:coffeeIndentExpr + endif + + " Otherwise use html indenting. + exec 'return ' s:htmlIndentExpr +endfunction diff --git a/vim/bundle/vim-coffee-script/after/syntax/haml.vim b/vim/bundle/vim-coffee-script/after/syntax/haml.vim new file mode 100644 index 0000000..4c517eb --- /dev/null +++ b/vim/bundle/vim-coffee-script/after/syntax/haml.vim @@ -0,0 +1,13 @@ +" Language: CoffeeScript +" Maintainer: Sven Felix Oberquelle +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +" Inherit coffee from html so coffeeComment isn't redefined and given higher +" priority than hamlInterpolation. +syn cluster hamlCoffeescript contains=@htmlCoffeeScript +syn region hamlCoffeescriptFilter matchgroup=hamlFilter +\ start="^\z(\s*\):coffee\z(script\)\?\s*$" +\ end="^\%(\z1 \| *$\)\@!" +\ contains=@hamlCoffeeScript,hamlInterpolation +\ keepend diff --git a/vim/bundle/vim-coffee-script/after/syntax/html.vim b/vim/bundle/vim-coffee-script/after/syntax/html.vim new file mode 100644 index 0000000..82b44f1 --- /dev/null +++ b/vim/bundle/vim-coffee-script/after/syntax/html.vim @@ -0,0 +1,11 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +" Syntax highlighting for text/coffeescript script tags +syn include @htmlCoffeeScript syntax/coffee.vim +syn region coffeeScript start=##me=s-1 keepend +\ contains=@htmlCoffeeScript,htmlScriptTag,@htmlPreproc +\ containedin=htmlHead diff --git a/vim/bundle/vim-coffee-script/autoload/coffee.vim b/vim/bundle/vim-coffee-script/autoload/coffee.vim new file mode 100644 index 0000000..8d72795 --- /dev/null +++ b/vim/bundle/vim-coffee-script/autoload/coffee.vim @@ -0,0 +1,54 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +" Set up some common global/buffer variables. +function! coffee#CoffeeSetUpVariables() + " Path to coffee executable + if !exists('g:coffee_compiler') + let g:coffee_compiler = 'coffee' + endif + + " Options passed to coffee with make + if !exists('g:coffee_make_options') + let g:coffee_make_options = '' + endif + + " Path to cake executable + if !exists('g:coffee_cake') + let g:coffee_cake = 'cake' + endif + + " Extra options passed to cake + if !exists('g:coffee_cake_options') + let g:coffee_cake_options = '' + endif + + " Path to coffeelint executable + if !exists('g:coffee_linter') + let g:coffee_linter = 'coffeelint' + endif + + " Options passed to CoffeeLint + if !exists('g:coffee_lint_options') + let g:coffee_lint_options = '' + endif + + " Pass the litcoffee flag to tools in this buffer if a litcoffee file is open. + " Let the variable be overwritten so it can be updated if a different filetype + " is set. + if &filetype == 'litcoffee' + let b:coffee_litcoffee = '--literate' + else + let b:coffee_litcoffee = '' + endif +endfunction + +function! coffee#CoffeeSetUpErrorFormat() + CompilerSet errorformat=Error:\ In\ %f\\,\ %m\ on\ line\ %l, + \Error:\ In\ %f\\,\ Parse\ error\ on\ line\ %l:\ %m, + \SyntaxError:\ In\ %f\\,\ %m, + \%f:%l:%c:\ error:\ %m, + \%-G%.%# +endfunction diff --git a/vim/bundle/vim-coffee-script/compiler/cake.vim b/vim/bundle/vim-coffee-script/compiler/cake.vim new file mode 100644 index 0000000..b49638e --- /dev/null +++ b/vim/bundle/vim-coffee-script/compiler/cake.vim @@ -0,0 +1,15 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +if exists('current_compiler') + finish +endif + +let current_compiler = 'cake' +call coffee#CoffeeSetUpVariables() + +exec 'CompilerSet makeprg=' . escape(g:coffee_cake . ' ' . +\ g:coffee_cake_options . ' $*', ' ') +call coffee#CoffeeSetUpErrorFormat() diff --git a/vim/bundle/vim-coffee-script/compiler/coffee.vim b/vim/bundle/vim-coffee-script/compiler/coffee.vim new file mode 100644 index 0000000..5a91457 --- /dev/null +++ b/vim/bundle/vim-coffee-script/compiler/coffee.vim @@ -0,0 +1,82 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +" All this is needed to support compiling filenames with spaces, quotes, and +" such. The filename is escaped and embedded into the `makeprg` setting. +" +" Because of this, `makeprg` must be updated on every file rename. And because +" of that, `CompilerSet` can't be used because it doesn't exist when the +" rename autocmd is ran. So, we have to do some checks to see whether `compiler` +" was called locally or globally, and respect that in the rest of the script. + +if exists('current_compiler') + finish +endif + +let current_compiler = 'coffee' +call coffee#CoffeeSetUpVariables() + +" Pattern to check if coffee is the compiler +let s:pat = '^' . current_compiler + +" Get a `makeprg` for the current filename. +function! s:GetMakePrg() + return g:coffee_compiler . + \ ' -c' . + \ ' ' . b:coffee_litcoffee . + \ ' ' . g:coffee_make_options . + \ ' $*' . + \ ' ' . fnameescape(expand('%')) +endfunction + +" Set `makeprg` and return 1 if coffee is still the compiler, else return 0. +function! s:SetMakePrg() + if &l:makeprg =~ s:pat + let &l:makeprg = s:GetMakePrg() + elseif &g:makeprg =~ s:pat + let &g:makeprg = s:GetMakePrg() + else + return 0 + endif + + return 1 +endfunction + +" Set a dummy compiler so we can check whether to set locally or globally. +exec 'CompilerSet makeprg=' . current_compiler +" Then actually set the compiler. +call s:SetMakePrg() +call coffee#CoffeeSetUpErrorFormat() + +function! s:CoffeeMakeDeprecated(bang, args) + echoerr 'CoffeeMake is deprecated! Please use :make instead, its behavior ' . + \ 'is identical.' + sleep 5 + exec 'make' . a:bang a:args +endfunction + +" Compile the current file. +command! -bang -bar -nargs=* CoffeeMake +\ call s:CoffeeMakeDeprecated(, ) + +" Set `makeprg` on rename since we embed the filename in the setting. +augroup CoffeeUpdateMakePrg + autocmd! + + " Update `makeprg` if coffee is still the compiler, else stop running this + " function. + function! s:UpdateMakePrg() + if !s:SetMakePrg() + autocmd! CoffeeUpdateMakePrg + endif + endfunction + + " Set autocmd locally if compiler was set locally. + if &l:makeprg =~ s:pat + autocmd BufWritePre,BufFilePost call s:UpdateMakePrg() + else + autocmd BufWritePre,BufFilePost call s:UpdateMakePrg() + endif +augroup END diff --git a/vim/bundle/vim-coffee-script/doc/coffee-script.txt b/vim/bundle/vim-coffee-script/doc/coffee-script.txt new file mode 100644 index 0000000..1b43cf3 --- /dev/null +++ b/vim/bundle/vim-coffee-script/doc/coffee-script.txt @@ -0,0 +1,4 @@ +Please see the project readme for up-to-date docs: +https://github.com/kchmck/vim-coffee-script + + vim:tw=78:ts=8:ft=help:norl: diff --git a/vim/bundle/vim-coffee-script/ftdetect/coffee.vim b/vim/bundle/vim-coffee-script/ftdetect/coffee.vim new file mode 100644 index 0000000..e6c4d69 --- /dev/null +++ b/vim/bundle/vim-coffee-script/ftdetect/coffee.vim @@ -0,0 +1,17 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +autocmd BufNewFile,BufRead *.coffee set filetype=coffee +autocmd BufNewFile,BufRead *Cakefile set filetype=coffee +autocmd BufNewFile,BufRead *.coffeekup,*.ck set filetype=coffee +autocmd BufNewFile,BufRead *._coffee set filetype=coffee + +function! s:DetectCoffee() + if getline(1) =~ '^#!.*\' + set filetype=coffee + endif +endfunction + +autocmd BufNewFile,BufRead * call s:DetectCoffee() diff --git a/vim/bundle/vim-coffee-script/ftplugin/coffee.vim b/vim/bundle/vim-coffee-script/ftplugin/coffee.vim new file mode 100644 index 0000000..755e58e --- /dev/null +++ b/vim/bundle/vim-coffee-script/ftplugin/coffee.vim @@ -0,0 +1,409 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +if exists('b:did_ftplugin') + finish +endif + +let b:did_ftplugin = 1 +call coffee#CoffeeSetUpVariables() + +setlocal formatoptions-=t formatoptions+=croql +setlocal comments=:# commentstring=#\ %s +setlocal omnifunc=javascriptcomplete#CompleteJS +setlocal suffixesadd+=coffee +setlocal shiftwidth=2 " Addition by P.S. + +" Create custom augroups. +augroup CoffeeBufUpdate | augroup END +augroup CoffeeBufNew | augroup END + +" Enter to run the current CoffeeScript file. Addition by P.S. +map :!coffee % + +" Enable coffee compiler if a compiler isn't set already. +if !len(&l:makeprg) + compiler coffee +endif + +" Switch to the window for buf. +function! s:SwitchWindow(buf) + exec bufwinnr(a:buf) 'wincmd w' +endfunction + +" Create a new scratch buffer and return the bufnr of it. After the function +" returns, vim remains in the scratch buffer so more set up can be done. +function! s:ScratchBufBuild(src, vert, size) + if a:size <= 0 + if a:vert + let size = winwidth(bufwinnr(a:src)) / 2 + else + let size = winheight(bufwinnr(a:src)) / 2 + endif + endif + + if a:vert + vertical belowright new + exec 'vertical resize' size + else + belowright new + exec 'resize' size + endif + + setlocal bufhidden=wipe buftype=nofile nobuflisted noswapfile nomodifiable + nnoremap q :hide + + return bufnr('%') +endfunction + +" Replace buffer contents with text and delete the last empty line. +function! s:ScratchBufUpdate(buf, text) + " Move to the scratch buffer. + call s:SwitchWindow(a:buf) + + " Double check we're in the scratch buffer before overwriting. + if bufnr('%') != a:buf + throw 'unable to change to scratch buffer' + endif + + setlocal modifiable + silent exec '% delete _' + silent put! =a:text + silent exec '$ delete _' + setlocal nomodifiable +endfunction + +" Parse the output of coffee into a qflist entry for src buffer. +function! s:ParseCoffeeError(output, src, startline) + " Coffee error is always on first line? + let match = matchlist(a:output, + \ '^\(\f\+\|\[stdin\]\):\(\d\):\(\d\): error: \(.\{-}\)' . "\n") + + if !len(match) + return + endif + + " Consider the line number from coffee as relative and add it to the beginning + " line number of the range the command was called on, then subtract one for + " zero-based relativity. + call setqflist([{'bufnr': a:src, 'lnum': a:startline + str2nr(match[2]) - 1, + \ 'type': 'E', 'col': str2nr(match[3]), 'text': match[4]}], 'r') +endfunction + +" Reset source buffer variables. +function! s:CoffeeCompileResetVars() + " Variables defined in source buffer: + " b:coffee_compile_buf: bufnr of output buffer + " Variables defined in output buffer: + " b:coffee_src_buf: bufnr of source buffer + " b:coffee_compile_pos: previous cursor position in output buffer + + let b:coffee_compile_buf = -1 +endfunction + +function! s:CoffeeWatchResetVars() + " Variables defined in source buffer: + " b:coffee_watch_buf: bufnr of output buffer + " Variables defined in output buffer: + " b:coffee_src_buf: bufnr of source buffer + " b:coffee_watch_pos: previous cursor position in output buffer + + let b:coffee_watch_buf = -1 +endfunction + +function! s:CoffeeRunResetVars() + " Variables defined in CoffeeRun source buffer: + " b:coffee_run_buf: bufnr of output buffer + " Variables defined in CoffeeRun output buffer: + " b:coffee_src_buf: bufnr of source buffer + " b:coffee_run_pos: previous cursor position in output buffer + + let b:coffee_run_buf = -1 +endfunction + +" Clean things up in the source buffers. +function! s:CoffeeCompileClose() + " Switch to the source buffer if not already in it. + silent! call s:SwitchWindow(b:coffee_src_buf) + call s:CoffeeCompileResetVars() +endfunction + +function! s:CoffeeWatchClose() + silent! call s:SwitchWindow(b:coffee_src_buf) + silent! autocmd! CoffeeAuWatch * + call s:CoffeeWatchResetVars() +endfunction + +function! s:CoffeeRunClose() + silent! call s:SwitchWindow(b:coffee_src_buf) + call s:CoffeeRunResetVars() +endfunction + +" Compile the lines between startline and endline and put the result into buf. +function! s:CoffeeCompileToBuf(buf, startline, endline) + let src = bufnr('%') + let input = join(getline(a:startline, a:endline), "\n") + + " Coffee doesn't like empty input. + if !len(input) + " Function should still return within output buffer. + call s:SwitchWindow(a:buf) + return + endif + + " Pipe lines into coffee. + let output = system(g:coffee_compiler . + \ ' -scb' . + \ ' ' . b:coffee_litcoffee . + \ ' 2>&1', input) + + " Paste output into output buffer. + call s:ScratchBufUpdate(a:buf, output) + + " Highlight as JavaScript if there were no compile errors. + if v:shell_error + call s:ParseCoffeeError(output, src, a:startline) + setlocal filetype= + else + " Clear the quickfix list. + call setqflist([], 'r') + setlocal filetype=javascript + endif +endfunction + +" Peek at compiled CoffeeScript in a scratch buffer. We handle ranges like this +" to prevent the cursor from being moved (and its position saved) before the +" function is called. +function! s:CoffeeCompile(startline, endline, args) + if a:args =~ '\' + echoerr 'CoffeeCompile watch is deprecated! Please use CoffeeWatch instead' + sleep 5 + call s:CoffeeWatch(a:args) + return + endif + + " Switch to the source buffer if not already in it. + silent! call s:SwitchWindow(b:coffee_src_buf) + + " Bail if not in source buffer. + if !exists('b:coffee_compile_buf') + return + endif + + " Build the output buffer if it doesn't exist. + if bufwinnr(b:coffee_compile_buf) == -1 + let src = bufnr('%') + + let vert = exists('g:coffee_compile_vert') || a:args =~ '\' + let size = str2nr(matchstr(a:args, '\<\d\+\>')) + + " Build the output buffer and save the source bufnr. + let buf = s:ScratchBufBuild(src, vert, size) + let b:coffee_src_buf = src + + " Set the buffer name. + exec 'silent! file [CoffeeCompile ' . src . ']' + + " Clean up the source buffer when the output buffer is closed. + autocmd BufWipeout call s:CoffeeCompileClose() + " Save the cursor when leaving the output buffer. + autocmd BufLeave let b:coffee_compile_pos = getpos('.') + + " Run user-defined commands on new buffer. + silent doautocmd CoffeeBufNew User CoffeeCompile + + " Switch back to the source buffer and save the output bufnr. This also + " triggers BufLeave above. + call s:SwitchWindow(src) + let b:coffee_compile_buf = buf + endif + + " Fill the scratch buffer. + call s:CoffeeCompileToBuf(b:coffee_compile_buf, a:startline, a:endline) + " Reset cursor to previous position. + call setpos('.', b:coffee_compile_pos) + + " Run any user-defined commands on the scratch buffer. + silent doautocmd CoffeeBufUpdate User CoffeeCompile +endfunction + +" Update the scratch buffer and switch back to the source buffer. +function! s:CoffeeWatchUpdate() + call s:CoffeeCompileToBuf(b:coffee_watch_buf, 1, '$') + call setpos('.', b:coffee_watch_pos) + silent doautocmd CoffeeBufUpdate User CoffeeWatch + call s:SwitchWindow(b:coffee_src_buf) +endfunction + +" Continually compile a source buffer. +function! s:CoffeeWatch(args) + silent! call s:SwitchWindow(b:coffee_src_buf) + + if !exists('b:coffee_watch_buf') + return + endif + + if bufwinnr(b:coffee_watch_buf) == -1 + let src = bufnr('%') + + let vert = exists('g:coffee_watch_vert') || a:args =~ '\' + let size = str2nr(matchstr(a:args, '\<\d\+\>')) + + let buf = s:ScratchBufBuild(src, vert, size) + let b:coffee_src_buf = src + + exec 'silent! file [CoffeeWatch ' . src . ']' + + autocmd BufWipeout call s:CoffeeWatchClose() + autocmd BufLeave let b:coffee_watch_pos = getpos('.') + + silent doautocmd CoffeeBufNew User CoffeeWatch + + call s:SwitchWindow(src) + let b:coffee_watch_buf = buf + endif + + " Make sure only one watch autocmd is defined on this buffer. + silent! autocmd! CoffeeAuWatch * + + augroup CoffeeAuWatch + autocmd InsertLeave call s:CoffeeWatchUpdate() + autocmd BufWritePost call s:CoffeeWatchUpdate() + augroup END + + call s:CoffeeWatchUpdate() +endfunction + +" Run a snippet of CoffeeScript between startline and endline. +function! s:CoffeeRun(startline, endline, args) + silent! call s:SwitchWindow(b:coffee_src_buf) + + if !exists('b:coffee_run_buf') + return + endif + + if bufwinnr(b:coffee_run_buf) == -1 + let src = bufnr('%') + + let buf = s:ScratchBufBuild(src, exists('g:coffee_run_vert'), 0) + let b:coffee_src_buf = src + + exec 'silent! file [CoffeeRun ' . src . ']' + + autocmd BufWipeout call s:CoffeeRunClose() + autocmd BufLeave let b:coffee_run_pos = getpos('.') + + silent doautocmd CoffeeBufNew User CoffeeRun + + call s:SwitchWindow(src) + let b:coffee_run_buf = buf + endif + + if a:startline == 1 && a:endline == line('$') + let output = system(g:coffee_compiler . + \ ' ' . b:coffee_litcoffee . + \ ' ' . fnameescape(expand('%')) . + \ ' ' . a:args) + else + let input = join(getline(a:startline, a:endline), "\n") + + if !len(input) + return + endif + + let output = system(g:coffee_compiler . + \ ' -s' . + \ ' ' . b:coffee_litcoffee . + \ ' ' . a:args, input) + endif + + call s:ScratchBufUpdate(b:coffee_run_buf, output) + call setpos('.', b:coffee_run_pos) + + silent doautocmd CoffeeBufUpdate User CoffeeRun +endfunction + +" Run coffeelint on a file, and add any errors between startline and endline +" to the quickfix list. +function! s:CoffeeLint(startline, endline, bang, args) + let input = join(getline(a:startline, a:endline), "\n") + + if !len(input) + return + endif + + let output = system(g:coffee_linter . + \ ' -s --reporter csv' . + \ ' ' . b:coffee_litcoffee . + \ ' ' . g:coffee_lint_options . + \ ' ' . a:args . + \ ' 2>&1', input) + + " Convert output into an array and strip off the csv header. + let lines = split(output, "\n")[1:] + let buf = bufnr('%') + let qflist = [] + + for line in lines + let match = matchlist(line, '^stdin,\(\d\+\),\d*,\(error\|warn\),\(.\+\)$') + + " Ignore unmatched lines. + if !len(match) + continue + endif + + " The 'type' will result in either 'E' or 'W'. + call add(qflist, {'bufnr': buf, 'lnum': a:startline + str2nr(match[1]) - 1, + \ 'type': toupper(match[2][0]), 'text': match[3]}) + endfor + + " Replace the quicklist with our items. + call setqflist(qflist, 'r') + + " If not given a bang, jump to first error. + if !len(a:bang) + silent! cc 1 + endif +endfunction + +" Complete arguments for Coffee* commands. +function! s:CoffeeComplete(cmd, cmdline, cursor) + let args = ['vertical'] + + " If no partial command, return all possibilities. + if !len(a:cmd) + return args + endif + + let pat = '^' . a:cmd + + for arg in args + if arg =~ pat + return [arg] + endif + endfor +endfunction + +" Set initial state variables if they don't exist +if !exists('b:coffee_compile_buf') + call s:CoffeeCompileResetVars() +endif + +if !exists('b:coffee_watch_buf') + call s:CoffeeWatchResetVars() +endif + +if !exists('b:coffee_run_buf') + call s:CoffeeRunResetVars() +endif + +command! -buffer -range=% -bar -nargs=* -complete=customlist,s:CoffeeComplete +\ CoffeeCompile call s:CoffeeCompile(, , ) +command! -buffer -bar -nargs=* -complete=customlist,s:CoffeeComplete +\ CoffeeWatch call s:CoffeeWatch() +command! -buffer -range=% -bar -nargs=* CoffeeRun +\ call s:CoffeeRun(, , ) +command! -buffer -range=% -bang -bar -nargs=* CoffeeLint +\ call s:CoffeeLint(, , , ) diff --git a/vim/bundle/vim-coffee-script/indent/coffee.vim b/vim/bundle/vim-coffee-script/indent/coffee.vim new file mode 100644 index 0000000..4f4570a --- /dev/null +++ b/vim/bundle/vim-coffee-script/indent/coffee.vim @@ -0,0 +1,428 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +if exists('b:did_indent') + finish +endif + +let b:did_indent = 1 + +setlocal autoindent +setlocal indentexpr=GetCoffeeIndent(v:lnum) +" Make sure GetCoffeeIndent is run when these are typed so they can be +" indented or outdented. +setlocal indentkeys+=0],0),0.,=else,=when,=catch,=finally + +" If no indenting or outdenting is needed, either keep the indent of the cursor +" (use autoindent) or match the indent of the previous line. +if exists('g:coffee_indent_keep_current') + let s:DEFAULT_LEVEL = '-1' +else + let s:DEFAULT_LEVEL = 'indent(prevnlnum)' +endif + +" Only define the function once. +if exists('*GetCoffeeIndent') + finish +endif + +" Keywords that begin a block +let s:BEGIN_BLOCK_KEYWORD = '\C^\%(if\|unless\|else\|for\|while\|until\|' +\ . 'loop\|switch\|when\|try\|catch\|finally\|' +\ . 'class\)\>\%(\s*:\)\@!' + +" An expression that uses the result of a statement +let s:COMPOUND_EXPRESSION = '\C\%([^-]-\|[^+]+\|[^/]/\|[:=*%&|^<>]\)\s*' +\ . '\%(if\|unless\|for\|while\|until\|loop\|switch\|' +\ . 'try\|class\)\>' + +" Combine the two above +let s:BEGIN_BLOCK = s:BEGIN_BLOCK_KEYWORD . '\|' . s:COMPOUND_EXPRESSION + +" Operators that begin a block but also count as a continuation +let s:BEGIN_BLOCK_OP = '[([{:=]$' + +" Begins a function block +let s:FUNCTION = '[-=]>$' + +" Operators that continue a line onto the next line +let s:CONTINUATION_OP = '\C\%(\<\%(is\|isnt\|and\|or\)\>\|' +\ . '[^-]-\|[^+]+\|[^-=]>\|[^.]\.\|[<*/%&|^,]\)$' + +" Ancestor operators that prevent continuation indenting +let s:CONTINUATION = s:CONTINUATION_OP . '\|' . s:BEGIN_BLOCK_OP + +" A closing bracket by itself on a line followed by a continuation +let s:BRACKET_CONTINUATION = '^\s*[}\])]\s*' . s:CONTINUATION_OP + +" A continuation dot access +let s:DOT_ACCESS = '^\.' + +" Keywords that break out of a block +let s:BREAK_BLOCK_OP = '\C^\%(return\|break\|continue\|throw\)\>' + +" A condition attached to the end of a statement +let s:POSTFIX_CONDITION = '\C\S\s\+\zs\<\%(if\|unless\|when\|while\|until\)\>' + +" A then contained in brackets +let s:CONTAINED_THEN = '\C[(\[].\{-}\.\{-\}[)\]]' + +" An else with a condition attached +let s:ELSE_COND = '\C^\s*else\s\+\<\%(if\|unless\)\>' + +" A single-line else statement (without a condition attached) +let s:SINGLE_LINE_ELSE = '\C^else\s\+\%(\<\%(if\|unless\)\>\)\@!' + +" Pairs of starting and ending keywords, with an initial pattern to match +let s:KEYWORD_PAIRS = [ +\ ['\C^else\>', '\C\<\%(if\|unless\|when\|else\s\+\%(if\|unless\)\)\>', +\ '\C\'], +\ ['\C^catch\>', '\C\', '\C\'], +\ ['\C^finally\>', '\C\', '\C\'] +\] + +" Pairs of starting and ending brackets +let s:BRACKET_PAIRS = {']': '\[', '}': '{', ')': '('} + +" Max lines to look back for a match +let s:MAX_LOOKBACK = 50 + +" Syntax names for strings +let s:SYNTAX_STRING = 'coffee\%(String\|AssignString\|Embed\|Regex\|Heregex\|' +\ . 'Heredoc\)' + +" Syntax names for comments +let s:SYNTAX_COMMENT = 'coffee\%(Comment\|BlockComment\|HeregexComment\)' + +" Syntax names for strings and comments +let s:SYNTAX_STRING_COMMENT = s:SYNTAX_STRING . '\|' . s:SYNTAX_COMMENT + +" Compatibility code for shiftwidth() as recommended by the docs, but modified +" so there isn't as much of a penalty if shiftwidth() exists. +if exists('*shiftwidth') + let s:ShiftWidth = function('shiftwidth') +else + function! s:ShiftWidth() + return &shiftwidth + endfunction +endif + +" Get the linked syntax name of a character. +function! s:SyntaxName(lnum, col) + return synIDattr(synID(a:lnum, a:col, 1), 'name') +endfunction + +" Check if a character is in a comment. +function! s:IsComment(lnum, col) + return s:SyntaxName(a:lnum, a:col) =~ s:SYNTAX_COMMENT +endfunction + +" Check if a character is in a string. +function! s:IsString(lnum, col) + return s:SyntaxName(a:lnum, a:col) =~ s:SYNTAX_STRING +endfunction + +" Check if a character is in a comment or string. +function! s:IsCommentOrString(lnum, col) + return s:SyntaxName(a:lnum, a:col) =~ s:SYNTAX_STRING_COMMENT +endfunction + +" Search a line for a regex until one is found outside a string or comment. +function! s:SearchCode(lnum, regex) + " Start at the first column and look for an initial match (including at the + " cursor.) + call cursor(a:lnum, 1) + let pos = search(a:regex, 'c', a:lnum) + + while pos + if !s:IsCommentOrString(a:lnum, col('.')) + return 1 + endif + + " Move to the match and continue searching (don't accept matches at the + " cursor.) + let pos = search(a:regex, '', a:lnum) + endwhile + + return 0 +endfunction + +" Search for the nearest previous line that isn't a comment. +function! s:GetPrevNormalLine(startlnum) + let curlnum = a:startlnum + + while curlnum + let curlnum = prevnonblank(curlnum - 1) + + " Return the line if the first non-whitespace character isn't a comment. + if !s:IsComment(curlnum, indent(curlnum) + 1) + return curlnum + endif + endwhile + + return 0 +endfunction + +function! s:SearchPair(startlnum, lookback, skip, open, close) + " Go to the first column so a:close will be matched even if it's at the + " beginning of the line. + call cursor(a:startlnum, 1) + return searchpair(a:open, '', a:close, 'bnW', a:skip, max([1, a:lookback])) +endfunction + +" Skip if a match +" - is in a string or comment +" - is a single-line statement that isn't immediately +" adjacent +" - has a postfix condition and isn't an else statement or compound +" expression +function! s:ShouldSkip(startlnum, lnum, col) + return s:IsCommentOrString(a:lnum, a:col) || + \ s:SearchCode(a:lnum, '\C\') && a:startlnum - a:lnum > 1 || + \ s:SearchCode(a:lnum, s:POSTFIX_CONDITION) && + \ getline(a:lnum) !~ s:ELSE_COND && + \ !s:SearchCode(a:lnum, s:COMPOUND_EXPRESSION) +endfunction + +" Search for the nearest and farthest match for a keyword pair. +function! s:SearchMatchingKeyword(startlnum, open, close) + let skip = 's:ShouldSkip(' . a:startlnum . ", line('.'), line('.'))" + + " Search for the nearest match. + let nearestlnum = s:SearchPair(a:startlnum, a:startlnum - s:MAX_LOOKBACK, + \ skip, a:open, a:close) + + if !nearestlnum + return [] + endif + + " Find the nearest previous line with indent less than or equal to startlnum. + let ind = indent(a:startlnum) + let lookback = s:GetPrevNormalLine(a:startlnum) + + while lookback && indent(lookback) > ind + let lookback = s:GetPrevNormalLine(lookback) + endwhile + + " Search for the farthest match. If there are no other matches, then the + " nearest match is also the farthest one. + let matchlnum = nearestlnum + + while matchlnum + let lnum = matchlnum + let matchlnum = s:SearchPair(matchlnum, lookback, skip, a:open, a:close) + endwhile + + return [nearestlnum, lnum] +endfunction + +" Strip a line of a trailing comment and surrounding whitespace. +function! s:GetTrimmedLine(lnum) + " Try to find a comment starting at the first column. + call cursor(a:lnum, 1) + let pos = search('#', 'c', a:lnum) + + " Keep searching until a comment is found or search returns 0. + while pos + if s:IsComment(a:lnum, col('.')) + break + endif + + let pos = search('#', '', a:lnum) + endwhile + + if !pos + " No comment was found so use the whole line. + let line = getline(a:lnum) + else + " Subtract 1 to get to the column before the comment and another 1 for + " column indexing -> zero-based indexing. + let line = getline(a:lnum)[:col('.') - 2] + endif + + return substitute(substitute(line, '^\s\+', '', ''), + \ '\s\+$', '', '') +endfunction + +" Get the indent policy when no special rules are used. +function! s:GetDefaultPolicy(curlnum) + " Check whether equalprg is being ran on existing lines. + if strlen(getline(a:curlnum)) == indent(a:curlnum) + " If not indenting an existing line, use the default policy. + return s:DEFAULT_LEVEL + else + " Otherwise let autoindent determine what to do with an existing line. + return '-1' + endif +endfunction + +function! GetCoffeeIndent(curlnum) + " Get the previous non-blank line (may be a comment.) + let prevlnum = prevnonblank(a:curlnum - 1) + + " Bail if there's no code before. + if !prevlnum + return -1 + endif + + " Bail if inside a multiline string. + if s:IsString(a:curlnum, 1) + let prevnlnum = prevlnum + exec 'return' s:GetDefaultPolicy(a:curlnum) + endif + + " Get the code part of the current line. + let curline = s:GetTrimmedLine(a:curlnum) + " Get the previous non-comment line. + let prevnlnum = s:GetPrevNormalLine(a:curlnum) + + " Check if the current line is the closing bracket in a bracket pair. + if has_key(s:BRACKET_PAIRS, curline[0]) + " Search for a matching opening bracket. + let matchlnum = s:SearchPair(a:curlnum, a:curlnum - s:MAX_LOOKBACK, + \ "s:IsCommentOrString(line('.'), col('.'))", + \ s:BRACKET_PAIRS[curline[0]], curline[0]) + + if matchlnum + " Match the indent of the opening bracket. + return indent(matchlnum) + else + " No opening bracket found (bad syntax), so bail. + exec 'return' s:GetDefaultPolicy(a:curlnum) + endif + endif + + " Check if the current line is the closing keyword in a keyword pair. + for pair in s:KEYWORD_PAIRS + if curline =~ pair[0] + " Find the nearest and farthest matches within the same indent level. + let matches = s:SearchMatchingKeyword(a:curlnum, pair[1], pair[2]) + + if len(matches) + " Don't force indenting/outdenting as long as line is already lined up + " with a valid match + return max([min([indent(a:curlnum), indent(matches[0])]), + \ indent(matches[1])]) + else + " No starting keyword found (bad syntax), so bail. + exec 'return' s:GetDefaultPolicy(a:curlnum) + endif + endif + endfor + + " Check if the current line is a `when` and not the first in a switch block. + if curline =~ '\C^when\>' && !s:SearchCode(prevnlnum, '\C\') + " Look back for a `when`. + while prevnlnum + if getline(prevnlnum) =~ '\C^\s*when\>' + " Indent to match the found `when`, but don't force indenting (for when + " indenting nested switch blocks.) + return min([indent(a:curlnum), indent(prevnlnum)]) + endif + + let prevnlnum = s:GetPrevNormalLine(prevnlnum) + endwhile + + " No matching `when` found (bad syntax), so bail. + exec 'return' s:GetDefaultPolicy(a:curlnum) + endif + + " If the previous line is a comment, use its indentation, but don't force + " indenting. + if prevlnum != prevnlnum + return min([indent(a:curlnum), indent(prevlnum)]) + endif + + let prevline = s:GetTrimmedLine(prevnlnum) + + " Always indent after these operators. + if prevline =~ s:BEGIN_BLOCK_OP + return indent(prevnlnum) + s:ShiftWidth() + endif + + " Indent if the previous line starts a function block, but don't force + " indenting if the line is non-blank (for empty function bodies.) + if prevline =~ s:FUNCTION + if strlen(getline(a:curlnum)) > indent(a:curlnum) + return min([indent(prevnlnum) + s:ShiftWidth(), indent(a:curlnum)]) + else + return indent(prevnlnum) + s:ShiftWidth() + endif + endif + + " Check if continuation indenting is needed. If the line ends in a slash, make + " sure it isn't a regex. + if prevline =~ s:CONTINUATION_OP && + \ !(prevline =~ '/$' && s:IsString(prevnlnum, col([prevnlnum, '$']) - 1)) + " Don't indent if the continuation follows a closing bracket. + if prevline =~ s:BRACKET_CONTINUATION + exec 'return' s:GetDefaultPolicy(a:curlnum) + endif + + let prevprevnlnum = s:GetPrevNormalLine(prevnlnum) + + " Don't indent if not the first continuation. + if prevprevnlnum && s:GetTrimmedLine(prevprevnlnum) =~ s:CONTINUATION + exec 'return' s:GetDefaultPolicy(a:curlnum) + endif + + " Continuation indenting seems to vary between programmers, so if the line + " is non-blank, don't override the indentation + if strlen(getline(a:curlnum)) > indent(a:curlnum) + exec 'return' s:GetDefaultPolicy(a:curlnum) + endif + + " Otherwise indent a level. + return indent(prevnlnum) + s:ShiftWidth() + endif + + " Check if the previous line starts with a keyword that begins a block. + if prevline =~ s:BEGIN_BLOCK + " Indent if the current line doesn't start with `then` and the previous line + " isn't a single-line statement. + if curline !~ '\C^\' && !s:SearchCode(prevnlnum, '\C\') && + \ prevline !~ s:SINGLE_LINE_ELSE + return indent(prevnlnum) + s:ShiftWidth() + else + exec 'return' s:GetDefaultPolicy(a:curlnum) + endif + endif + + " Indent a dot access if it's the first. + if curline =~ s:DOT_ACCESS + if prevline !~ s:DOT_ACCESS + return indent(prevnlnum) + s:ShiftWidth() + else + exec 'return' s:GetDefaultPolicy(a:curlnum) + endif + endif + + " Outdent if a keyword breaks out of a block as long as it doesn't have a + " postfix condition (and the postfix condition isn't a single-line statement.) + if prevline =~ s:BREAK_BLOCK_OP + if !s:SearchCode(prevnlnum, s:POSTFIX_CONDITION) || + \ s:SearchCode(prevnlnum, '\C\') && + \ !s:SearchCode(prevnlnum, s:CONTAINED_THEN) + " Don't force indenting. + return min([indent(a:curlnum), indent(prevnlnum) - s:ShiftWidth()]) + else + exec 'return' s:GetDefaultPolicy(a:curlnum) + endif + endif + + " Check if inside brackets. + let matchlnum = s:SearchPair(a:curlnum, a:curlnum - s:MAX_LOOKBACK, + \ "s:IsCommentOrString(line('.'), col('.'))", + \ '\[\|(\|{', '\]\|)\|}') + + " If inside brackets, indent relative to the brackets, but don't outdent an + " already indented line. + if matchlnum + return max([indent(a:curlnum), indent(matchlnum) + s:ShiftWidth()]) + endif + + " No special rules applied, so use the default policy. + exec 'return' s:GetDefaultPolicy(a:curlnum) +endfunction diff --git a/vim/bundle/vim-coffee-script/syntax/coffee.vim b/vim/bundle/vim-coffee-script/syntax/coffee.vim new file mode 100644 index 0000000..b578433 --- /dev/null +++ b/vim/bundle/vim-coffee-script/syntax/coffee.vim @@ -0,0 +1,221 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +" Bail if our syntax is already loaded. +if exists('b:current_syntax') && b:current_syntax == 'coffee' + finish +endif + +" Include JavaScript for coffeeEmbed. +syn include @coffeeJS syntax/javascript.vim +silent! unlet b:current_syntax + +" Highlight long strings. +syntax sync fromstart + +" These are `matches` instead of `keywords` because vim's highlighting +" priority for keywords is higher than matches. This causes keywords to be +" highlighted inside matches, even if a match says it shouldn't contain them -- +" like with coffeeAssign and coffeeDot. +syn match coffeeStatement /\<\%(return\|break\|continue\|throw\)\>/ display +hi def link coffeeStatement Statement + +syn match coffeeRepeat /\<\%(for\|while\|until\|loop\)\>/ display +hi def link coffeeRepeat Repeat + +syn match coffeeConditional /\<\%(if\|else\|unless\|switch\|when\|then\)\>/ +\ display +hi def link coffeeConditional Conditional + +syn match coffeeException /\<\%(try\|catch\|finally\)\>/ display +hi def link coffeeException Exception + +syn match coffeeKeyword /\<\%(new\|in\|of\|by\|and\|or\|not\|is\|isnt\|class\|extends\|super\|do\)\>/ +\ display +" The `own` keyword is only a keyword after `for`. +syn match coffeeKeyword /\/ contained containedin=coffeeRepeat +\ display +hi def link coffeeKeyword Keyword + +syn match coffeeOperator /\<\%(instanceof\|typeof\|delete\)\>/ display +hi def link coffeeOperator Operator + +" The first case matches symbol operators only if they have an operand before. +syn match coffeeExtendedOp /\%(\S\s*\)\@<=[+\-*/%&|\^=!<>?.]\{-1,}\|[-=]>\|--\|++\|:/ +\ display +syn match coffeeExtendedOp /\<\%(and\|or\)=/ display +hi def link coffeeExtendedOp coffeeOperator + +" This is separate from `coffeeExtendedOp` to help differentiate commas from +" dots. +syn match coffeeSpecialOp /[,;]/ display +hi def link coffeeSpecialOp SpecialChar + +syn match coffeeBoolean /\<\%(true\|on\|yes\|false\|off\|no\)\>/ display +hi def link coffeeBoolean Boolean + +syn match coffeeGlobal /\<\%(null\|undefined\)\>/ display +hi def link coffeeGlobal Type + +" A special variable +syn match coffeeSpecialVar /\<\%(this\|prototype\|arguments\)\>/ display +hi def link coffeeSpecialVar Special + +" An @-variable +syn match coffeeSpecialIdent /@\%(\%(\I\|\$\)\%(\i\|\$\)*\)\?/ display +hi def link coffeeSpecialIdent Identifier + +" A class-like name that starts with a capital letter +syn match coffeeObject /\<\u\w*\>/ display +hi def link coffeeObject Structure + +" A constant-like name in SCREAMING_CAPS +syn match coffeeConstant /\<\u[A-Z0-9_]\+\>/ display +hi def link coffeeConstant Constant + +" A variable name +syn cluster coffeeIdentifier contains=coffeeSpecialVar,coffeeSpecialIdent, +\ coffeeObject,coffeeConstant + +" A non-interpolated string +syn cluster coffeeBasicString contains=@Spell,coffeeEscape +" An interpolated string +syn cluster coffeeInterpString contains=@coffeeBasicString,coffeeInterp + +" Regular strings +syn region coffeeString start=/"/ skip=/\\\\\|\\"/ end=/"/ +\ contains=@coffeeInterpString +syn region coffeeString start=/'/ skip=/\\\\\|\\'/ end=/'/ +\ contains=@coffeeBasicString +hi def link coffeeString String + +" A integer, including a leading plus or minus +syn match coffeeNumber /\%(\i\|\$\)\@/ display +syn match coffeeNumber /\<0[bB][01]\+\>/ display +syn match coffeeNumber /\<0[oO][0-7]\+\>/ display +syn match coffeeNumber /\<\%(Infinity\|NaN\)\>/ display +hi def link coffeeNumber Number + +" A floating-point number, including a leading plus or minus +syn match coffeeFloat /\%(\i\|\$\)\@/ +\ display +hi def link coffeeReservedError Error + +" A normal object assignment +syn match coffeeObjAssign /@\?\%(\I\|\$\)\%(\i\|\$\)*\s*\ze::\@!/ contains=@coffeeIdentifier display +hi def link coffeeObjAssign Identifier + +syn keyword coffeeTodo TODO FIXME XXX contained +hi def link coffeeTodo Todo + +syn match coffeeComment /#.*/ contains=@Spell,coffeeTodo +hi def link coffeeComment Comment + +syn region coffeeBlockComment start=/####\@!/ end=/###/ +\ contains=@Spell,coffeeTodo +hi def link coffeeBlockComment coffeeComment + +" A comment in a heregex +syn region coffeeHeregexComment start=/#/ end=/\ze\/\/\/\|$/ contained +\ contains=@Spell,coffeeTodo +hi def link coffeeHeregexComment coffeeComment + +" Embedded JavaScript +syn region coffeeEmbed matchgroup=coffeeEmbedDelim +\ start=/`/ skip=/\\\\\|\\`/ end=/`/ keepend +\ contains=@coffeeJS +hi def link coffeeEmbedDelim Delimiter + +syn region coffeeInterp matchgroup=coffeeInterpDelim start=/#{/ end=/}/ contained +\ contains=@coffeeAll +hi def link coffeeInterpDelim PreProc + +" A string escape sequence +syn match coffeeEscape /\\\d\d\d\|\\x\x\{2\}\|\\u\x\{4\}\|\\./ contained display +hi def link coffeeEscape SpecialChar + +" A regex -- must not follow a parenthesis, number, or identifier, and must not +" be followed by a number +syn region coffeeRegex start=#\%(\%()\|\%(\i\|\$\)\@> #{ == { { { } } } == } << " +" >> #{ == { abc: { def: 42 } } == } << " diff --git a/vim/bundle/vim-coffee-script/test/test-ops.coffee b/vim/bundle/vim-coffee-script/test/test-ops.coffee new file mode 100644 index 0000000..54be8db --- /dev/null +++ b/vim/bundle/vim-coffee-script/test/test-ops.coffee @@ -0,0 +1,90 @@ +# Various operators +abc instanceof def +typeof abc +delete abc +abc::def + +abc + def +abc - def +abc * def +abc / def +abc % def +abc & def +abc | def +abc ^ def +abc >> def +abc << def +abc >>> def +abc ? def +abc && def +abc and def +abc || def +abc or def + +abc += def +abc -= def +abc *= def +abc /= def +abc %= def +abc &= def +abc |= def +abc ^= def +abc >>= def +abc <<= def +abc >>>= def +abc ?= def +abc &&= def +abc ||= def + +abc and= def +abc or= def + +abc.def.ghi +abc?.def?.ghi + +abc < def +abc > def +abc = def +abc == def +abc != def +abc <= def +abc >= def + +abc++ +abc-- +++abc +--abc + +# Nested operators +abc[def] = ghi +abc[def[ghi: jkl]] = 42 +@abc[def] = ghi + +abc["#{def = 42}"] = 42 +abc["#{def.ghi = 42}"] = 42 +abc["#{def[ghi] = 42}"] = 42 +abc["#{def['ghi']}"] = 42 + +# Object assignments +abc = + def: 123 + DEF: 123 + @def: 123 + Def: 123 + 'def': 123 + 42: 123 + +# Operators shouldn't be highlighted +vector= +wand= + +abc+++ +abc--- +abc ** def +abc &&& def +abc ^^ def +abc ===== def +abc <==== def +abc >==== def +abc +== def +abc =^= def diff --git a/vim/bundle/vim-coffee-script/test/test-reserved.coffee b/vim/bundle/vim-coffee-script/test/test-reserved.coffee new file mode 100644 index 0000000..b841760 --- /dev/null +++ b/vim/bundle/vim-coffee-script/test/test-reserved.coffee @@ -0,0 +1,27 @@ +# Should be an error +function = 42 +var = 42 + +# Shouldn't be an error +abc.with = 42 +function: 42 +var: 42 + +# Keywords shouldn't be highlighted +abc.function +abc.do +abc.break +abc.true + +abc::function +abc::do +abc::break +abc::true + +abc:: function +abc. function + +# Numbers should be highlighted +def.42 +def .42 +def::42 diff --git a/vim/bundle/vim-coffee-script/test/test.haml b/vim/bundle/vim-coffee-script/test/test.haml new file mode 100644 index 0000000..ae19fba --- /dev/null +++ b/vim/bundle/vim-coffee-script/test/test.haml @@ -0,0 +1,3 @@ +:coffeescript + class Hello + # test diff --git a/vim/bundle/vim-coffee-script/test/test.html b/vim/bundle/vim-coffee-script/test/test.html new file mode 100644 index 0000000..3479145 --- /dev/null +++ b/vim/bundle/vim-coffee-script/test/test.html @@ -0,0 +1,7 @@ + + + diff --git a/vim/bundle/vim-commentary/.gitignore b/vim/bundle/vim-commentary/.gitignore new file mode 100644 index 0000000..0a56e3f --- /dev/null +++ b/vim/bundle/vim-commentary/.gitignore @@ -0,0 +1 @@ +/doc/tags diff --git a/vim/bundle/vim-commentary/CONTRIBUTING.markdown b/vim/bundle/vim-commentary/CONTRIBUTING.markdown new file mode 100644 index 0000000..b3f0095 --- /dev/null +++ b/vim/bundle/vim-commentary/CONTRIBUTING.markdown @@ -0,0 +1 @@ +See the [contribution guidelines for pathogen.vim](https://github.com/tpope/vim-pathogen/blob/master/CONTRIBUTING.markdown). diff --git a/vim/bundle/vim-commentary/README.markdown b/vim/bundle/vim-commentary/README.markdown new file mode 100644 index 0000000..a39b19c --- /dev/null +++ b/vim/bundle/vim-commentary/README.markdown @@ -0,0 +1,51 @@ +# commentary.vim + +Comment stuff out. Use `gcc` to comment out a line (takes a count), +`gc` to comment out the target of a motion (for example, `gcap` to +comment out a paragraph), `gc` in visual mode to comment out the selection, +and `gc` in operator pending mode to target a comment. You can also use +it as a command, either with a range like `:7,17Commentary`, or as part of a +`:global` invocation like with `:g/TODO/Commentary`. That's it. + +I wrote this because 5 years after Vim added support for mapping an +operator, I still couldn't find a commenting plugin that leveraged that +feature (I overlooked +[tcomment.vim](https://github.com/tomtom/tcomment_vim)). Striving for +minimalism, it weighs in at under 100 lines of code. + +Oh, and it uncomments, too. The above maps actually toggle, and `gcgc` +uncomments a set of adjacent commented lines. + +## Installation + +If you don't have a preferred installation method, I recommend +installing [pathogen.vim](https://github.com/tpope/vim-pathogen), and +then simply copy and paste: + + cd ~/.vim/bundle + git clone git://github.com/tpope/vim-commentary.git + +Once help tags have been generated, you can view the manual with +`:help commentary`. + +## FAQ + +> My favorite file type isn't supported! + +Relax! You just have to adjust `'commentstring'`: + + autocmd FileType apache set commentstring=#\ %s + +## Self-Promotion + +Like commentary.vim? Follow the repository on +[GitHub](https://github.com/tpope/vim-commentary) and vote for it on +[vim.org](http://www.vim.org/scripts/script.php?script_id=3695). And if +you're feeling especially charitable, follow [tpope](http://tpo.pe/) on +[Twitter](http://twitter.com/tpope) and +[GitHub](https://github.com/tpope). + +## License + +Copyright (c) Tim Pope. Distributed under the same terms as Vim itself. +See `:help license`. diff --git a/vim/bundle/vim-commentary/doc/commentary.txt b/vim/bundle/vim-commentary/doc/commentary.txt new file mode 100644 index 0000000..d6deed0 --- /dev/null +++ b/vim/bundle/vim-commentary/doc/commentary.txt @@ -0,0 +1,35 @@ +*commentary.txt* Comment stuff out + +Author: Tim Pope +License: Same terms as Vim itself (see |license|) + +Comment stuff out. Then uncomment it later. Relies on 'commentstring' to be +correctly set, or uses b:commentary_format if it is set. + +The gc mappings are preferred, while the \\ mappings are provided for +backwards compatibility. + + *gc* +gc{motion} Comment or uncomment lines that {motion} moves over. + + *gcc* +gcc Comment or uncomment [count] lines. + + *v_gc* +{Visual}gc Comment or uncomment the highlighted lines. + + *o_gc* +gc Text object for a comment (operator pending mode + only.) + + *gcgc* *gcu* +gcgc Uncomment the current and adjacent commented lines. +gcu + + *:Commentary* +:[range]Commentary Comment or uncomment [range] lines + +The |User| CommentaryPost autocommand fires after a successful operation and +can be used for advanced customization. + + vim:tw=78:et:ft=help:norl: diff --git a/vim/bundle/vim-commentary/plugin/commentary.vim b/vim/bundle/vim-commentary/plugin/commentary.vim new file mode 100644 index 0000000..9da6a30 --- /dev/null +++ b/vim/bundle/vim-commentary/plugin/commentary.vim @@ -0,0 +1,100 @@ +" commentary.vim - Comment stuff out +" Maintainer: Tim Pope +" Version: 1.2 +" GetLatestVimScripts: 3695 1 :AutoInstall: commentary.vim + +if exists("g:loaded_commentary") || &cp || v:version < 700 + finish +endif +let g:loaded_commentary = 1 + +function! s:surroundings() abort + return split(substitute(substitute( + \ get(b:, 'commentary_format', &commentstring) + \ ,'\S\zs%s',' %s','') ,'%s\ze\S', '%s ', ''), '%s', 1) +endfunction + +function! s:go(type,...) abort + if a:0 + let [lnum1, lnum2] = [a:type, a:1] + else + let [lnum1, lnum2] = [line("'["), line("']")] + endif + + let [l, r] = s:surroundings() + let uncomment = 2 + for lnum in range(lnum1,lnum2) + let line = matchstr(getline(lnum),'\S.*\s\@ 2 && l.r !~# '\\' + let line = substitute(line, + \'\M'.r[0:-2].'\zs\d\*\ze'.r[-1:-1].'\|'.l[0].'\zs\d\*\ze'.l[1:-1], + \'\=substitute(submatch(0)+1-uncomment,"^0$\\|^-\\d*$","","")','g') + endif + if uncomment + let line = substitute(line,'\S.*\s\@ Commentary :call go(line("'<"),line("'>")) +nnoremap Commentary :set opfunc=gog@ +nnoremap CommentaryLine :set opfunc=goexe 'norm! 'v:count1.'g@_' +onoremap Commentary :call textobject(0) +nnoremap ChangeCommentary c:call textobject(1) +nmap CommentaryUndo CommentaryCommentary +command! -range -bar Commentary call s:go(,) + +if !hasmapto('Commentary') || maparg('gc','n') ==# '' + xmap gc Commentary + nmap gc Commentary + omap gc Commentary + nmap gcc CommentaryLine + nmap cgc ChangeCommentary + nmap gcu CommentaryCommentary +endif + +if maparg('\\','n') ==# '' && maparg('\','n') ==# '' && get(g:, 'commentary_map_backslash', 1) + xmap \\ Commentary:echomsg '\\ is deprecated. Use gc' + nmap \\ :echomsg '\\ is deprecated. Use gc'Commentary + nmap \\\ CommentaryLine:echomsg '\\ is deprecated. Use gc' + nmap \\u CommentaryUndo:echomsg '\\ is deprecated. Use gc' +endif + +" vim:set et sw=2: diff --git a/vim/bundle/vim-fugitive/.gitignore b/vim/bundle/vim-fugitive/.gitignore new file mode 100644 index 0000000..0a56e3f --- /dev/null +++ b/vim/bundle/vim-fugitive/.gitignore @@ -0,0 +1 @@ +/doc/tags diff --git a/vim/bundle/vim-fugitive/CONTRIBUTING.markdown b/vim/bundle/vim-fugitive/CONTRIBUTING.markdown new file mode 100644 index 0000000..e651dca --- /dev/null +++ b/vim/bundle/vim-fugitive/CONTRIBUTING.markdown @@ -0,0 +1,18 @@ +Before reporting a bug, you should try stripping down your Vim configuration +and removing other plugins. The sad truth about VimScript is that it is +fraught with incompatibilities waiting to happen. I'm happy to work around +them where I can, but it's up to you to isolate the conflict. + +Fugitive is particularly prone to regressions due to Git version issues, +platform issues, and interactions with other plugins. I end up bisecting a +lot more than other projects, and thus I'm especially meticulous here about +maintaining a clean, readable, history. Squash and force push any requested +changes to a pull request. And if your [commit message +sucks](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), +I'm not going to accept it. Period. + +Beyond that, don't be shy about asking before patching. What takes you hours +might take me minutes simply because I have both domain knowledge and a +perverse knowledge of VimScript so vast that many would consider it a symptom +of mental illness. On the flip side, some ideas I'll reject no matter how +good the implementation is. "Send a patch" is an edge case answer in my book. diff --git a/vim/bundle/vim-fugitive/README.markdown b/vim/bundle/vim-fugitive/README.markdown new file mode 100644 index 0000000..71b8bc4 --- /dev/null +++ b/vim/bundle/vim-fugitive/README.markdown @@ -0,0 +1,118 @@ +# fugitive.vim + +I'm not going to lie to you; fugitive.vim may very well be the best +Git wrapper of all time. Check out these features: + +View any blob, tree, commit, or tag in the repository with `:Gedit` (and +`:Gsplit`, `:Gvsplit`, `:Gtabedit`, ...). Edit a file in the index and +write to it to stage the changes. Use `:Gdiff` to bring up the staged +version of the file side by side with the working tree version and use +Vim's diff handling capabilities to stage a subset of the file's +changes. + +Bring up the output of `git status` with `:Gstatus`. Press `-` to +`add`/`reset` a file's changes, or `p` to `add`/`reset` `--patch`. And guess +what `:Gcommit` does! + +`:Gblame` brings up an interactive vertical split with `git blame` +output. Press enter on a line to edit the commit where the line +changed, or `o` to open it in a split. When you're done, use `:Gedit` +in the historic buffer to go back to the work tree version. + +`:Gmove` does a `git mv` on a file and simultaneously renames the +buffer. `:Gremove` does a `git rm` on a file and simultaneously deletes +the buffer. + +Use `:Ggrep` to search the work tree (or any arbitrary commit) with +`git grep`, skipping over that which is not tracked in the repository. +`:Glog` loads all previous revisions of a file into the quickfix list so +you can iterate over them and watch the file evolve! + +`:Gread` is a variant of `git checkout -- filename` that operates on the +buffer rather than the filename. This means you can use `u` to undo it +and you never get any warnings about the file changing outside Vim. +`:Gwrite` writes to both the work tree and index versions of a file, +making it like `git add` when called from a work tree file and like +`git checkout` when called from the index or a blob in history. + +Use `:Gbrowse` to open the current file on GitHub, with optional line +range (try it in visual mode!). If your current repository isn't on +GitHub, `git instaweb` will be spun up instead. + +Add `%{fugitive#statusline()}` to `'statusline'` to get an indicator +with the current branch in (surprise!) your statusline. + +Last but not least, there's `:Git` for running any arbitrary command, +and `Git!` to open the output of a command in a temp file. + +## Screencasts + +* [A complement to command line git](http://vimcasts.org/e/31) +* [Working with the git index](http://vimcasts.org/e/32) +* [Resolving merge conflicts with vimdiff](http://vimcasts.org/e/33) +* [Browsing the git object database](http://vimcasts.org/e/34) +* [Exploring the history of a git repository](http://vimcasts.org/e/35) + +## Installation + +If you don't have a preferred installation method, one option is to install +[pathogen.vim](https://github.com/tpope/vim-pathogen), and then copy +and paste: + + cd ~/.vim/bundle + git clone git://github.com/tpope/vim-fugitive.git + vim -u NONE -c "helptags vim-fugitive/doc" -c q + +If your Vim version is below 7.2, I recommend also installing +[vim-git](https://github.com/tpope/vim-git) for syntax highlighting and +other Git niceties. + +## FAQ + +> I installed the plugin and started Vim. Why don't any of the commands +> exist? + +Fugitive cares about the current file, not the current working +directory. Edit a file from the repository. + +> I opened a new tab. Why don't any of the commands exist? + +Fugitive cares about the current file, not the current working +directory. Edit a file from the repository. + +> Why is `:Gbrowse` not using the right browser? + +`:Gbrowse` delegates to `git web--browse`, which is less than perfect +when it comes to finding the right browser. You can tell it the correct +browser to use with `git config --global web.browser ...`. On OS X, for +example, you might want to set this to `open`. See `git web--browse --help` +for details. + +> Here's a patch that automatically opens the quickfix window after +> `:Ggrep`. + +This is a great example of why I recommend asking before patching. +There are valid arguments to be made both for and against automatically +opening the quickfix window. Whenever I have to make an arbitrary +decision like this, I ask what Vim would do. And Vim does not open a +quickfix window after `:grep`. + +Luckily, it's easy to implement the desired behavior without changing +fugitive.vim. The following autocommand will cause the quickfix window +to open after any grep invocation: + + autocmd QuickFixCmdPost *grep* cwindow + +## Self-Promotion + +Like fugitive.vim? Follow the repository on +[GitHub](https://github.com/tpope/vim-fugitive) and vote for it on +[vim.org](http://www.vim.org/scripts/script.php?script_id=2975). And if +you're feeling especially charitable, follow [tpope](http://tpo.pe/) on +[Twitter](http://twitter.com/tpope) and +[GitHub](https://github.com/tpope). + +## License + +Copyright (c) Tim Pope. Distributed under the same terms as Vim itself. +See `:help license`. diff --git a/vim/bundle/vim-fugitive/doc/fugitive.txt b/vim/bundle/vim-fugitive/doc/fugitive.txt new file mode 100644 index 0000000..0d186bf --- /dev/null +++ b/vim/bundle/vim-fugitive/doc/fugitive.txt @@ -0,0 +1,345 @@ +*fugitive.txt* A Git wrapper so awesome, it should be illegal + +Author: Tim Pope +License: Same terms as Vim itself (see |license|) + +This plugin is only available if 'compatible' is not set. + +INTRODUCTION *fugitive* + +Whenever you edit a file from a Git repository, a set of commands is defined +that serve as a gateway to Git. + +COMMANDS *fugitive-commands* + +These commands are local to the buffers in which they work (generally, buffers +that are part of Git repositories). + + *fugitive-:Git* +:Git [args] Run an arbitrary git command. Similar to :!git [args] + but chdir to the repository tree first. + + *fugitive-:Git!* +:Git! [args] Like |:Git|, but capture the output into a temp file, + and edit that temp file. + + *fugitive-:Gcd* +:Gcd [directory] |:cd| relative to the repository. + + *fugitive-:Glcd* +:Glcd [directory] |:lcd| relative to the repository. + + *fugitive-:Gstatus* +:Gstatus Bring up the output of git-status in the preview + window. The following maps, which work on the cursor + line file where sensible, are provided: + + g? show this help + next file + previous file + |:Gedit| + - |:Git| add + - |:Git| reset (staged files) + cA |:Gcommit| --amend --reuse-message=HEAD + ca |:Gcommit| --amend + cc |:Gcommit| + cva |:Gcommit| --amend --verbose + cvc |:Gcommit| --verbose + D |:Gdiff| + ds |:Gsdiff| + dp |:Git!| diff (p for patch; use :Gw to apply) + dp |:Git| add --intent-to-add (untracked files) + dv |:Gvdiff| + O |:Gtabedit| + o |:Gsplit| + p |:Git| add --patch + p |:Git| reset --patch (staged files) + q close status + r reload status + S |:Gvsplit| + + *fugitive-:Gcommit* +:Gcommit [args] A wrapper around git-commit. If there is nothing + to commit, |:Gstatus| is called instead. Unless the + arguments given would skip the invocation of an editor + (e.g., -m), a split window will be used to obtain a + commit message, or a new tab if -v is given. Write + and close that window (:wq or |:Gwrite|) to finish the + commit. Unlike when running the actual git-commit + command, it is possible (but unadvisable) to alter the + index with commands like git-add and git-reset while a + commit message is pending. + + *fugitive-:Gmerge* +:Gmerge [args] Calls git-merge and loads errors and conflicted files + into the quickfix list. Opens a |:Gcommit| style + split window for the commit message if the merge + succeeds. If called during a merge conflict, the + conflicted files from the current index are loaded + into the quickfix list. + + *fugitive-:Gpull* +:Gpull [args] Like |:Gmerge|, but for git-pull. + + *fugitive-:Gpush* +:Gpush [args] Invoke git-push, load the results into the quickfix + list, and invoke |:cwindow| to reveal any errors. + |:Dispatch| is used if available for asynchronous + invocation. + + *fugitive-:Gfetch* +:Gfetch [args] Like |:Gpush|, but for git-fetch. + + *fugitive-:Ggrep* +:Ggrep [args] |:grep| with git-grep as 'grepprg'. + + *fugitive-:Glgrep* +:Glgrep [args] |:lgrep| with git-grep as 'grepprg'. + + *fugitive-:Glog* +:Glog [args] Load all previous revisions of the current file into + the quickfix list. Additional git-log arguments can + be given (for example, --reverse). If "--" appears as + an argument, no file specific filtering is done, and + previous commits rather than previous file revisions + are loaded. + +:{range}Glog [args] Use git-log -L to load previous revisions of the given + range of the current file into the quickfix list. The + cursor is positioned on the first line of the first + diff hunk for each commit. + + *fugitive-:Gllog* +:Gllog [args] Like |:Glog|, but use the location list instead of the + quickfix list. + + *fugitive-:Gedit* *fugitive-:Ge* +:Gedit [revision] |:edit| a |fugitive-revision|. + + *fugitive-:Gsplit* +:Gsplit [revision] |:split| a |fugitive-revision|. + + *fugitive-:Gvsplit* +:Gvsplit [revision] |:vsplit| a |fugitive-revision|. + + *fugitive-:Gtabedit* +:Gtabedit [revision] |:tabedit| a |fugitive-revision|. + + *fugitive-:Gpedit* +:Gpedit [revision] |:pedit| a |fugitive-revision|. + +:Gsplit! [args] *fugitive-:Gsplit!* *fugitive-:Gvsplit!* +:Gvsplit! [args] *fugitive-:Gtabedit!* *fugitive-:Gpedit!* +:Gtabedit! [args] Like |:Git!|, but open the resulting temp file in a +:Gpedit! [args] split, tab, or preview window. + + *fugitive-:Gread* +:Gread [revision] Empty the buffer and |:read| a |fugitive-revision|. + When the argument is omitted, this is similar to + git-checkout on a work tree file or git-add on a stage + file, but without writing anything to disk. + +:{range}Gread [revision] + |:read| in a |fugitive-revision| after {range}. + + *fugitive-:Gread!* +:Gread! [args] Empty the buffer and |:read| the output of a Git + command. For example, :Gread! show HEAD:%. + +:{range}Gread! [args] |:read| the output of a Git command after {range}. + + *fugitive-:Gw* *fugitive-:Gwrite* +:Gwrite Write to the current file's path and stage the results. + When run in a work tree file, it is effectively git + add. Elsewhere, it is effectively git-checkout. A + great deal of effort is expended to behave sensibly + when the work tree or index version of the file is + open in another buffer. + +:Gwrite {path} You can give |:Gwrite| an explicit path of where in + the work tree to write. You can also give a path like + :0:foo.txt or even :0 to write to just that stage in + the index. + + *fugitive-:Gwq* +:Gwq [path] Like |:Gwrite| followed by |:quit| if the write + succeeded. + +:Gwq! [path] Like |:Gwrite|! followed by |:quit|! if the write + succeeded. + + *fugitive-:Gdiff* +:Gdiff [revision] Perform a |vimdiff| against the current file in the + given revision. With no argument, the version in the + index is used (which means a three-way diff during a + merge conflict, making it a git-mergetool + alternative). The newer of the two files is placed + to the right or bottom, depending on 'diffopt' and + the width of the window relative to 'textwidth'. Use + |do| and |dp| and write to the index file to simulate + "git add --patch". + + *fugitive-:Gsdiff* +:Gsdiff [revision] Like |:Gdiff|, but always split horizontally. + + *fugitive-:Gvdiff* +:Gvdiff [revision] Like |:Gdiff|, but always split vertically. + + *fugitive-:Gmove* +:Gmove {destination} Wrapper around git-mv that renames the buffer + afterward. The destination is relative to the current + directory except when started with a /, in which case + it is relative to the work tree. Add a ! to pass -f. + + *fugitive-:Gremove* +:Gremove Wrapper around git-rm that deletes the buffer + afterward. When invoked in an index file, --cached is + passed. Add a ! to pass -f and forcefully discard the + buffer. + + *fugitive-:Gblame* +:Gblame [flags] Run git-blame on the file and open the results in a + scroll bound vertical split. You can give any of + ltfnsewMC as flags and they will be passed along to + git-blame. The following maps, which work on the + cursor line commit where sensible, are provided: + + g? show this help + A resize to end of author column + C resize to end of commit column + D resize to end of date/time column + q close blame and return to blamed window + gq q, then |:Gedit| to return to work tree version + q, then open commit + o open commit in horizontal split + O open commit in new tab + - reblame at commit + ~ reblame at [count]th first grandparent + P reblame at [count]th parent (like HEAD^[count]) + +:[range]Gblame [flags] Run git-blame on the given range. + + *fugitive-:Gbrowse* +:[range]Gbrowse If the remote for the current branch is on GitHub, + open the current file, blob, tree, commit, or tag + (with git-web--browse) on GitHub. Otherwise, open the + current file, blob, tree, commit, or tag in + git-instaweb (if you have issues, verify you can run + "git instaweb" from a terminal). If a range is given, + it is appropriately appended to the URL as an anchor. + + To use with GitHub FI, point g:fugitive_github_domains + at a list of domains: +> + let g:fugitive_github_domains = ['https://example.com'] +~ +:[range]Gbrowse! Like :Gbrowse, but put the URL on the clipboard rather + than opening it. + +:[range]Gbrowse {revision} + Like :Gbrowse, but for a given |fugitive-revision|. A + useful value here is -, which ties the URL to the + latest commit rather than a volatile branch. + +:[range]Gbrowse [...]@{remote} + Force using the given remote rather than the remote + for the current branch. The remote is used to + determine which GitHub repository to link to. + +MAPPINGS *fugitive-mappings* + +These maps are available everywhere. + + *fugitive-c_CTRL-R_CTRL-G* + On the command line, recall the path to the current + object (that is, a representation of the object + recognized by |:Gedit|). + + *fugitive-y_CTRL-G* +["x]y Yank the commit SHA and path to the current object. + +These maps are available in Git objects. + + *fugitive-* + Jump to the revision under the cursor. + + *fugitive-o* +o Jump to the revision under the cursor in a new split. + + *fugitive-S* +S Jump to the revision under the cursor in a new + vertical split. + + *fugitive-O* +O Jump to the revision under the cursor in a new tab. + + *fugitive--* +- Go to the tree containing the current tree or blob. + + *fugitive-~* +~ Go to the current file in the [count]th first + ancestor. + + *fugitive-P* +P Go to the current file in the [count]th parent. + + *fugitive-C* +C Go to the commit containing the current file. + + *fugitive-.* +. Start a |:| command line with the current revision + prepopulated at the end of the line. + + *fugitive-a* +a Show the current tag, commit, or tree in an alternate + format. + +SPECIFYING REVISIONS *fugitive-revision* + +Fugitive revisions are similar to Git revisions as defined in the "SPECIFYING +REVISIONS" section in the git-rev-parse man page. For commands that accept an +optional revision, the default is the file in the index for work tree files +and the work tree file for everything else. Example revisions follow. + +Revision Meaning ~ +HEAD .git/HEAD +master .git/refs/heads/master +HEAD^{} The commit referenced by HEAD +HEAD^ The parent of the commit referenced by HEAD +HEAD: The tree referenced by HEAD +/HEAD The file named HEAD in the work tree +Makefile The file named Makefile in the work tree +HEAD^:Makefile The file named Makefile in the parent of HEAD +:Makefile The file named Makefile in the index (writable) +- The current file in HEAD +^ The current file in the previous commit +~3 The current file 3 commits ago +: .git/index (Same as |:Gstatus|) +:0 The current file in the index +:1 The current file's common ancestor during a conflict +:2 The current file in the target branch during a conflict +:3 The current file in the merged branch during a conflict +:/foo The most recent commit with "foo" in the message + +STATUSLINE *fugitive-statusline* + + *fugitive#statusline()* +Add %{fugitive#statusline()} to your statusline to get an indicator including +the current branch and the currently edited file's commit. If you don't have +a statusline, this one matches the default when 'ruler' is set: +> + set statusline=%<%f\ %h%m%r%{fugitive#statusline()}%=%-14.(%l,%c%V%)\ %P +< + *fugitive#head(...)* +Use fugitive#head() to return the name of the current branch. If the current +HEAD is detached, fugitive#head() will return the empty string, unless the +optional argument is given, in which case the hash of the current commit will +be truncated to the given number of characters. + +ABOUT *fugitive-about* + +Grab the latest version or report a bug on GitHub: + +http://github.com/tpope/vim-fugitive + + vim:tw=78:et:ft=help:norl: diff --git a/vim/bundle/vim-fugitive/plugin/fugitive.vim b/vim/bundle/vim-fugitive/plugin/fugitive.vim new file mode 100644 index 0000000..279289d --- /dev/null +++ b/vim/bundle/vim-fugitive/plugin/fugitive.vim @@ -0,0 +1,2916 @@ +" fugitive.vim - A Git wrapper so awesome, it should be illegal +" Maintainer: Tim Pope +" Version: 2.1 +" GetLatestVimScripts: 2975 1 :AutoInstall: fugitive.vim + +if exists('g:loaded_fugitive') || &cp + finish +endif +let g:loaded_fugitive = 1 + +if !exists('g:fugitive_git_executable') + let g:fugitive_git_executable = 'git' +endif + +" Section: Utility + +function! s:function(name) abort + return function(substitute(a:name,'^s:',matchstr(expand(''), '\d\+_'),'')) +endfunction + +function! s:sub(str,pat,rep) abort + return substitute(a:str,'\v\C'.a:pat,a:rep,'') +endfunction + +function! s:gsub(str,pat,rep) abort + return substitute(a:str,'\v\C'.a:pat,a:rep,'g') +endfunction + +function! s:winshell() abort + return &shell =~? 'cmd' || exists('+shellslash') && !&shellslash +endfunction + +function! s:shellesc(arg) abort + if a:arg =~ '^[A-Za-z0-9_/.-]\+$' + return a:arg + elseif s:winshell() + return '"'.s:gsub(s:gsub(a:arg, '"', '""'), '\%', '"%"').'"' + else + return shellescape(a:arg) + endif +endfunction + +function! s:fnameescape(file) abort + if exists('*fnameescape') + return fnameescape(a:file) + else + return escape(a:file," \t\n*?[{`$\\%#'\"|!<") + endif +endfunction + +function! s:throw(string) abort + let v:errmsg = 'fugitive: '.a:string + throw v:errmsg +endfunction + +function! s:warn(str) abort + echohl WarningMsg + echomsg a:str + echohl None + let v:warningmsg = a:str +endfunction + +function! s:shellslash(path) abort + if s:winshell() + return s:gsub(a:path,'\\','/') + else + return a:path + endif +endfunction + +let s:git_versions = {} + +function! fugitive#git_version(...) abort + if !has_key(s:git_versions, g:fugitive_git_executable) + let s:git_versions[g:fugitive_git_executable] = matchstr(system(g:fugitive_git_executable.' --version'), "\\S\\+\n") + endif + return s:git_versions[g:fugitive_git_executable] +endfunction + +function! s:recall() abort + let rev = s:sub(s:buffer().rev(), '^/', '') + if rev ==# ':' + return matchstr(getline('.'),'^#\t\%([[:alpha:] ]\+: *\)\=\zs.\{-\}\ze\%( ([^()[:digit:]]\+)\)\=$\|^\d\{6} \x\{40\} \d\t\zs.*') + elseif s:buffer().type('tree') + let file = matchstr(getline('.'), '\t\zs.*') + if empty(file) && line('.') > 2 + let file = s:sub(getline('.'), '/$', '') + endif + if !empty(file) && rev !~# ':$' + return rev . '/' . file + else + return rev . file + endif + endif + return rev +endfunction + +function! s:add_methods(namespace, method_names) abort + for name in a:method_names + let s:{a:namespace}_prototype[name] = s:function('s:'.a:namespace.'_'.name) + endfor +endfunction + +let s:commands = [] +function! s:command(definition) abort + let s:commands += [a:definition] +endfunction + +function! s:define_commands() abort + for command in s:commands + exe 'command! -buffer '.command + endfor +endfunction + +augroup fugitive_utility + autocmd! + autocmd User Fugitive call s:define_commands() +augroup END + +let s:abstract_prototype = {} + +" Section: Initialization + +function! fugitive#is_git_dir(path) abort + let path = s:sub(a:path, '[\/]$', '') . '/' + return isdirectory(path.'objects') && isdirectory(path.'refs') && getfsize(path.'HEAD') > 10 +endfunction + +function! fugitive#extract_git_dir(path) abort + if s:shellslash(a:path) =~# '^fugitive://.*//' + return matchstr(s:shellslash(a:path), '\C^fugitive://\zs.\{-\}\ze//') + endif + let root = s:shellslash(simplify(fnamemodify(a:path, ':p:s?[\/]$??'))) + let previous = "" + while root !=# previous + if root =~# '\v^//%([^/]+/?)?$' + " This is for accessing network shares from Cygwin Vim. There won't be + " any git directory called //.git or //serverName/.git so let's avoid + " checking for them since such checks are extremely slow. + break + endif + if index(split($GIT_CEILING_DIRECTORIES, ':'), root) >= 0 + break + endif + if root ==# $GIT_WORK_TREE && fugitive#is_git_dir($GIT_DIR) + return $GIT_DIR + endif + if fugitive#is_git_dir($GIT_DIR) + " Ensure that we've cached the worktree + call s:configured_tree($GIT_DIR) + if has_key(s:dir_for_worktree, root) + return s:dir_for_worktree[root] + endif + endif + let dir = s:sub(root, '[\/]$', '') . '/.git' + let type = getftype(dir) + if type ==# 'dir' && fugitive#is_git_dir(dir) + return dir + elseif type ==# 'link' && fugitive#is_git_dir(dir) + return resolve(dir) + elseif type !=# '' && filereadable(dir) + let line = get(readfile(dir, '', 1), 0, '') + if line =~# '^gitdir: \.' && fugitive#is_git_dir(root.'/'.line[8:-1]) + return simplify(root.'/'.line[8:-1]) + elseif line =~# '^gitdir: ' && fugitive#is_git_dir(line[8:-1]) + return line[8:-1] + endif + elseif fugitive#is_git_dir(root) + return root + endif + let previous = root + let root = fnamemodify(root, ':h') + endwhile + return '' +endfunction + +function! fugitive#detect(path) abort + if exists('b:git_dir') && (b:git_dir ==# '' || b:git_dir =~# '/$') + unlet b:git_dir + endif + if !exists('b:git_dir') + let dir = fugitive#extract_git_dir(a:path) + if dir !=# '' + let b:git_dir = dir + endif + endif + if exists('b:git_dir') + silent doautocmd User FugitiveBoot + cnoremap fnameescape(recall()) + nnoremap y :call setreg(v:register, recall()) + let buffer = fugitive#buffer() + if expand('%:p') =~# '//' + call buffer.setvar('&path', s:sub(buffer.getvar('&path'), '^\.%(,|$)', '')) + endif + if stridx(buffer.getvar('&tags'), escape(b:git_dir, ', ')) == -1 + if filereadable(b:git_dir.'/tags') + call buffer.setvar('&tags', escape(b:git_dir.'/tags', ', ').','.buffer.getvar('&tags')) + endif + if &filetype !=# '' && filereadable(b:git_dir.'/'.&filetype.'.tags') + call buffer.setvar('&tags', escape(b:git_dir.'/'.&filetype.'.tags', ', ').','.buffer.getvar('&tags')) + endif + endif + silent doautocmd User Fugitive + endif +endfunction + +augroup fugitive + autocmd! + autocmd BufNewFile,BufReadPost * call fugitive#detect(expand(':p')) + autocmd FileType netrw call fugitive#detect(expand('%:p')) + autocmd User NERDTreeInit,NERDTreeNewRoot call fugitive#detect(b:NERDTreeRoot.path.str()) + autocmd VimEnter * if expand('')==''|call fugitive#detect(getcwd())|endif + autocmd CmdWinEnter * call fugitive#detect(expand('#:p')) + autocmd BufWinLeave * execute getwinvar(+bufwinnr(+expand('')), 'fugitive_leave') +augroup END + +" Section: Repository + +let s:repo_prototype = {} +let s:repos = {} +let s:worktree_for_dir = {} +let s:dir_for_worktree = {} + +function! s:repo(...) abort + let dir = a:0 ? a:1 : (exists('b:git_dir') && b:git_dir !=# '' ? b:git_dir : fugitive#extract_git_dir(expand('%:p'))) + if dir !=# '' + if has_key(s:repos, dir) + let repo = get(s:repos, dir) + else + let repo = {'git_dir': dir} + let s:repos[dir] = repo + endif + return extend(extend(repo, s:repo_prototype, 'keep'), s:abstract_prototype, 'keep') + endif + call s:throw('not a git repository: '.expand('%:p')) +endfunction + +function! fugitive#repo(...) abort + return call('s:repo', a:000) +endfunction + +function! s:repo_dir(...) dict abort + return join([self.git_dir]+a:000,'/') +endfunction + +function! s:configured_tree(git_dir) abort + if !has_key(s:worktree_for_dir, a:git_dir) + let s:worktree_for_dir[a:git_dir] = '' + let config_file = a:git_dir . '/config' + if filereadable(config_file) + let config = readfile(config_file,'',10) + call filter(config,'v:val =~# "^\\s*worktree *="') + if len(config) == 1 + let s:worktree_for_dir[a:git_dir] = matchstr(config[0], '= *\zs.*') + let s:dir_for_worktree[s:worktree_for_dir[a:git_dir]] = a:git_dir + endif + endif + endif + if s:worktree_for_dir[a:git_dir] =~# '^\.' + return simplify(a:git_dir . '/' . s:worktree_for_dir[a:git_dir]) + else + return s:worktree_for_dir[a:git_dir] + endif +endfunction + +function! s:repo_tree(...) dict abort + if self.dir() =~# '/\.git$' + let dir = self.dir()[0:-6] + else + let dir = s:configured_tree(self.git_dir) + endif + if dir ==# '' + call s:throw('no work tree') + else + return join([dir]+a:000,'/') + endif +endfunction + +function! s:repo_bare() dict abort + if self.dir() =~# '/\.git$' + return 0 + else + return s:configured_tree(self.git_dir) ==# '' + endif +endfunction + +function! s:repo_translate(spec) dict abort + if a:spec ==# '.' || a:spec ==# '/.' + return self.bare() ? self.dir() : self.tree() + elseif a:spec =~# '^/\=\.git$' && self.bare() + return self.dir() + elseif a:spec =~# '^/\=\.git/' + return self.dir(s:sub(a:spec, '^/=\.git/', '')) + elseif a:spec =~# '^/' + return self.tree().a:spec + elseif a:spec =~# '^:[0-3]:' + return 'fugitive://'.self.dir().'//'.a:spec[1].'/'.a:spec[3:-1] + elseif a:spec ==# ':' + if $GIT_INDEX_FILE =~# '/[^/]*index[^/]*\.lock$' && fnamemodify($GIT_INDEX_FILE,':p')[0:strlen(self.dir())] ==# self.dir('') && filereadable($GIT_INDEX_FILE) + return fnamemodify($GIT_INDEX_FILE,':p') + else + return self.dir('index') + endif + elseif a:spec =~# '^:/' + let ref = self.rev_parse(matchstr(a:spec,'.[^:]*')) + return 'fugitive://'.self.dir().'//'.ref + elseif a:spec =~# '^:' + return 'fugitive://'.self.dir().'//0/'.a:spec[1:-1] + elseif a:spec =~# 'HEAD\|^refs/' && a:spec !~ ':' && filereadable(self.dir(a:spec)) + return self.dir(a:spec) + elseif filereadable(self.dir('refs/'.a:spec)) + return self.dir('refs/'.a:spec) + elseif filereadable(self.dir('refs/tags/'.a:spec)) + return self.dir('refs/tags/'.a:spec) + elseif filereadable(self.dir('refs/heads/'.a:spec)) + return self.dir('refs/heads/'.a:spec) + elseif filereadable(self.dir('refs/remotes/'.a:spec)) + return self.dir('refs/remotes/'.a:spec) + elseif filereadable(self.dir('refs/remotes/'.a:spec.'/HEAD')) + return self.dir('refs/remotes/'.a:spec,'/HEAD') + else + try + let ref = self.rev_parse(matchstr(a:spec,'[^:]*')) + let path = s:sub(matchstr(a:spec,':.*'),'^:','/') + return 'fugitive://'.self.dir().'//'.ref.path + catch /^fugitive:/ + return self.tree(a:spec) + endtry + endif +endfunction + +function! s:repo_head(...) dict abort + let head = s:repo().head_ref() + + if head =~# '^ref: ' + let branch = s:sub(head,'^ref: %(refs/%(heads/|remotes/|tags/)=)=','') + elseif head =~# '^\x\{40\}$' + " truncate hash to a:1 characters if we're in detached head mode + let len = a:0 ? a:1 : 0 + let branch = len ? head[0:len-1] : '' + else + return '' + endif + + return branch +endfunction + +call s:add_methods('repo',['dir','tree','bare','translate','head']) + +function! s:repo_git_command(...) dict abort + let git = g:fugitive_git_executable . ' --git-dir='.s:shellesc(self.git_dir) + return git.join(map(copy(a:000),'" ".s:shellesc(v:val)'),'') +endfunction + +function! s:repo_git_chomp(...) dict abort + return s:sub(system(call(self.git_command,a:000,self)),'\n$','') +endfunction + +function! s:repo_git_chomp_in_tree(...) dict abort + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + try + execute cd.'`=s:repo().tree()`' + return call(s:repo().git_chomp, a:000, s:repo()) + finally + execute cd.'`=dir`' + endtry +endfunction + +function! s:repo_rev_parse(rev) dict abort + let hash = self.git_chomp('rev-parse','--verify',a:rev) + if hash =~ '\<\x\{40\}$' + return matchstr(hash,'\<\x\{40\}$') + endif + call s:throw('rev-parse '.a:rev.': '.hash) +endfunction + +call s:add_methods('repo',['git_command','git_chomp','git_chomp_in_tree','rev_parse']) + +function! s:repo_dirglob(base) dict abort + let base = s:sub(a:base,'^/','') + let matches = split(glob(self.tree(s:gsub(base,'/','*&').'*/')),"\n") + call map(matches,'v:val[ strlen(self.tree())+(a:base !~ "^/") : -1 ]') + return matches +endfunction + +function! s:repo_superglob(base) dict abort + if a:base =~# '^/' || a:base !~# ':' + let results = [] + if a:base !~# '^/' + let heads = ["HEAD","ORIG_HEAD","FETCH_HEAD","MERGE_HEAD"] + let heads += sort(split(s:repo().git_chomp("rev-parse","--symbolic","--branches","--tags","--remotes"),"\n")) + call filter(heads,'v:val[ 0 : strlen(a:base)-1 ] ==# a:base') + let results += heads + endif + if !self.bare() + let base = s:sub(a:base,'^/','') + let matches = split(glob(self.tree(s:gsub(base,'/','*&').'*')),"\n") + call map(matches,'s:shellslash(v:val)') + call map(matches,'v:val !~ "/$" && isdirectory(v:val) ? v:val."/" : v:val') + call map(matches,'v:val[ strlen(self.tree())+(a:base !~ "^/") : -1 ]') + let results += matches + endif + return results + + elseif a:base =~# '^:' + let entries = split(self.git_chomp('ls-files','--stage'),"\n") + call map(entries,'s:sub(v:val,".*(\\d)\\t(.*)",":\\1:\\2")') + if a:base !~# '^:[0-3]\%(:\|$\)' + call filter(entries,'v:val[1] == "0"') + call map(entries,'v:val[2:-1]') + endif + call filter(entries,'v:val[ 0 : strlen(a:base)-1 ] ==# a:base') + return entries + + else + let tree = matchstr(a:base,'.*[:/]') + let entries = split(self.git_chomp('ls-tree',tree),"\n") + call map(entries,'s:sub(v:val,"^04.*\\zs$","/")') + call map(entries,'tree.s:sub(v:val,".*\t","")') + return filter(entries,'v:val[ 0 : strlen(a:base)-1 ] ==# a:base') + endif +endfunction + +call s:add_methods('repo',['dirglob','superglob']) + +function! s:repo_config(conf) dict abort + return matchstr(system(s:repo().git_command('config').' '.a:conf),"[^\r\n]*") +endfun + +function! s:repo_user() dict abort + let username = s:repo().config('user.name') + let useremail = s:repo().config('user.email') + return username.' <'.useremail.'>' +endfun + +function! s:repo_aliases() dict abort + if !has_key(self,'_aliases') + let self._aliases = {} + for line in split(self.git_chomp('config','--get-regexp','^alias[.]'),"\n") + let self._aliases[matchstr(line,'\.\zs\S\+')] = matchstr(line,' \zs.*') + endfor + endif + return self._aliases +endfunction + +call s:add_methods('repo',['config', 'user', 'aliases']) + +function! s:repo_keywordprg() dict abort + let args = ' --git-dir='.escape(self.dir(),"\\\"' ") + if has('gui_running') && !has('win32') + return g:fugitive_git_executable . ' --no-pager' . args . ' log -1' + else + return g:fugitive_git_executable . args . ' show' + endif +endfunction + +call s:add_methods('repo',['keywordprg']) + +" Section: Buffer + +let s:buffer_prototype = {} + +function! s:buffer(...) abort + let buffer = {'#': bufnr(a:0 ? a:1 : '%')} + call extend(extend(buffer,s:buffer_prototype,'keep'),s:abstract_prototype,'keep') + if buffer.getvar('git_dir') !=# '' + return buffer + endif + call s:throw('not a git repository: '.expand('%:p')) +endfunction + +function! fugitive#buffer(...) abort + return s:buffer(a:0 ? a:1 : '%') +endfunction + +function! s:buffer_getvar(var) dict abort + return getbufvar(self['#'],a:var) +endfunction + +function! s:buffer_setvar(var,value) dict abort + return setbufvar(self['#'],a:var,a:value) +endfunction + +function! s:buffer_getline(lnum) dict abort + return get(getbufline(self['#'], a:lnum), 0, '') +endfunction + +function! s:buffer_repo() dict abort + return s:repo(self.getvar('git_dir')) +endfunction + +function! s:buffer_type(...) dict abort + if self.getvar('fugitive_type') != '' + let type = self.getvar('fugitive_type') + elseif fnamemodify(self.spec(),':p') =~# '.\git/refs/\|\.git/\w*HEAD$' + let type = 'head' + elseif self.getline(1) =~ '^tree \x\{40\}$' && self.getline(2) == '' + let type = 'tree' + elseif self.getline(1) =~ '^\d\{6\} \w\{4\} \x\{40\}\>\t' + let type = 'tree' + elseif self.getline(1) =~ '^\d\{6\} \x\{40\}\> \d\t' + let type = 'index' + elseif isdirectory(self.spec()) + let type = 'directory' + elseif self.spec() == '' + let type = 'null' + else + let type = 'file' + endif + if a:0 + return !empty(filter(copy(a:000),'v:val ==# type')) + else + return type + endif +endfunction + +if has('win32') + + function! s:buffer_spec() dict abort + let bufname = bufname(self['#']) + let retval = '' + for i in split(bufname,'[^:]\zs\\') + let retval = fnamemodify((retval==''?'':retval.'\').i,':.') + endfor + return s:shellslash(fnamemodify(retval,':p')) + endfunction + +else + + function! s:buffer_spec() dict abort + let bufname = bufname(self['#']) + return s:shellslash(bufname == '' ? '' : fnamemodify(bufname,':p')) + endfunction + +endif + +function! s:buffer_name() dict abort + return self.spec() +endfunction + +function! s:buffer_commit() dict abort + return matchstr(self.spec(),'^fugitive://.\{-\}//\zs\w*') +endfunction + +function! s:buffer_path(...) dict abort + let rev = matchstr(self.spec(),'^fugitive://.\{-\}//\zs.*') + if rev != '' + let rev = s:sub(rev,'\w*','') + elseif self.spec()[0 : len(self.repo().dir())] ==# self.repo().dir() . '/' + let rev = '/.git'.self.spec()[strlen(self.repo().dir()) : -1] + elseif !self.repo().bare() && self.spec()[0 : len(self.repo().tree())] ==# self.repo().tree() . '/' + let rev = self.spec()[strlen(self.repo().tree()) : -1] + endif + return s:sub(s:sub(rev,'.\zs/$',''),'^/',a:0 ? a:1 : '') +endfunction + +function! s:buffer_rev() dict abort + let rev = matchstr(self.spec(),'^fugitive://.\{-\}//\zs.*') + if rev =~ '^\x/' + return ':'.rev[0].':'.rev[2:-1] + elseif rev =~ '.' + return s:sub(rev,'/',':') + elseif self.spec() =~ '\.git/index$' + return ':' + elseif self.spec() =~ '\.git/refs/\|\.git/.*HEAD$' + return self.spec()[strlen(self.repo().dir())+1 : -1] + else + return self.path('/') + endif +endfunction + +function! s:buffer_sha1() dict abort + if self.spec() =~ '^fugitive://' || self.spec() =~ '\.git/refs/\|\.git/.*HEAD$' + return self.repo().rev_parse(self.rev()) + else + return '' + endif +endfunction + +function! s:buffer_expand(rev) dict abort + if a:rev =~# '^:[0-3]$' + let file = a:rev.self.path(':') + elseif a:rev =~# '^[-:]/$' + let file = '/'.self.path() + elseif a:rev =~# '^-' + let file = 'HEAD^{}'.a:rev[1:-1].self.path(':') + elseif a:rev =~# '^@{' + let file = 'HEAD'.a:rev.self.path(':') + elseif a:rev =~# '^[~^]' + let commit = s:sub(self.commit(),'^\d=$','HEAD') + let file = commit.a:rev.self.path(':') + else + let file = a:rev + endif + return s:sub(s:sub(file,'\%$',self.path()),'\.\@<=/$','') +endfunction + +function! s:buffer_containing_commit() dict abort + if self.commit() =~# '^\d$' + return ':' + elseif self.commit() =~# '.' + return self.commit() + else + return 'HEAD' + endif +endfunction + +function! s:buffer_up(...) dict abort + let rev = self.rev() + let c = a:0 ? a:1 : 1 + while c + if rev =~# '^[/:]$' + let rev = 'HEAD' + elseif rev =~# '^:' + let rev = ':' + elseif rev =~# '^refs/[^^~:]*$\|^[^^~:]*HEAD$' + let rev .= '^{}' + elseif rev =~# '^/\|:.*/' + let rev = s:sub(rev, '.*\zs/.*', '') + elseif rev =~# ':.' + let rev = matchstr(rev, '^[^:]*:') + elseif rev =~# ':$' + let rev = rev[0:-2] + else + return rev.'~'.c + endif + let c -= 1 + endwhile + return rev +endfunction + +call s:add_methods('buffer',['getvar','setvar','getline','repo','type','spec','name','commit','path','rev','sha1','expand','containing_commit','up']) + +" Section: Git + +call s:command("-bang -nargs=? -complete=customlist,s:GitComplete Git :execute s:Git(0,)") + +function! s:ExecuteInTree(cmd) abort + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + try + execute cd.'`=s:repo().tree()`' + execute a:cmd + finally + execute cd.'`=dir`' + endtry +endfunction + +function! s:Git(bang, args) abort + if a:bang + return s:Edit('edit', 1, a:args) + endif + let git = g:fugitive_git_executable + if has('gui_running') && !has('win32') + let git .= ' --no-pager' + endif + let args = matchstr(a:args,'\v\C.{-}%($|\\@ `=s:repo().bare() ? s:repo().dir() : s:repo().tree()`") +call s:command("-bar -bang -nargs=? -complete=customlist,s:DirComplete Glcd :lcd `=s:repo().bare() ? s:repo().dir() : s:repo().tree()`") + +" Section: Gstatus + +call s:command("-bar Gstatus :execute s:Status()") +augroup fugitive_status + autocmd! + if !has('win32') + autocmd FocusGained,ShellCmdPost * call fugitive#reload_status() + endif +augroup END + +function! s:Status() abort + try + Gpedit : + wincmd P + setlocal foldmethod=syntax foldlevel=1 + nnoremap q :bdelete + catch /^fugitive:/ + return 'echoerr v:errmsg' + endtry + return '' +endfunction + +function! fugitive#reload_status() abort + if exists('s:reloading_status') + return + endif + try + let s:reloading_status = 1 + let mytab = tabpagenr() + for tab in [mytab] + range(1,tabpagenr('$')) + for winnr in range(1,tabpagewinnr(tab,'$')) + if getbufvar(tabpagebuflist(tab)[winnr-1],'fugitive_type') ==# 'index' + execute 'tabnext '.tab + if winnr != winnr() + execute winnr.'wincmd w' + let restorewinnr = 1 + endif + try + if !&modified + call s:BufReadIndex() + endif + finally + if exists('restorewinnr') + wincmd p + endif + execute 'tabnext '.mytab + endtry + endif + endfor + endfor + finally + unlet! s:reloading_status + endtry +endfunction + +function! s:stage_info(lnum) abort + let filename = matchstr(getline(a:lnum),'^#\t\zs.\{-\}\ze\%( ([^()[:digit:]]\+)\)\=$') + let lnum = a:lnum + if has('multi_byte_encoding') + let colon = '\%(:\|\%uff1a\)' + else + let colon = ':' + endif + while lnum && getline(lnum) !~# colon.'$' + let lnum -= 1 + endwhile + if !lnum + return ['', ''] + elseif (getline(lnum+1) =~# '^# .*\$' + return 'CtrlP '.fnameescape(s:repo().tree()) + else + for i in range(a:count) + call search('^#\t.*','Wbe') + endfor + return '.' + endif +endfunction + +function! s:StageReloadSeek(target,lnum1,lnum2) abort + let jump = a:target + let f = matchstr(getline(a:lnum1-1),'^#\t\%([[:alpha:] ]\+: *\|.*\%uff1a *\)\=\zs.*') + if f !=# '' | let jump = f | endif + let f = matchstr(getline(a:lnum2+1),'^#\t\%([[:alpha:] ]\+: *\|.*\%uff1a *\)\=\zs.*') + if f !=# '' | let jump = f | endif + silent! edit! + 1 + redraw + call search('^#\t\%([[:alpha:] ]\+: *\|.*\%uff1a *\)\=\V'.jump.'\%( ([^()[:digit:]]\+)\)\=\$','W') +endfunction + +function! s:StageUndo() abort + let [filename, section] = s:stage_info(line('.')) + if empty(filename) + return '' + endif + let repo = s:repo() + let hash = repo.git_chomp('hash-object', '-w', filename) + if !empty(hash) + if section ==# 'untracked' + call delete(s:repo().tree(filename)) + elseif section ==# 'unstaged' + call repo.git_chomp_in_tree('checkout', '--', filename) + else + call repo.git_chomp_in_tree('checkout', 'HEAD', '--', filename) + endif + call s:StageReloadSeek(filename, line('.'), line('.')) + let @" = hash + return 'checktime|redraw|echomsg ' . + \ string('To restore, :Git cat-file blob '.hash[0:6].' > '.filename) + endif +endfunction + +function! s:StageDiff(diff) abort + let [filename, section] = s:stage_info(line('.')) + if filename ==# '' && section ==# 'staged' + return 'Git! diff --no-ext-diff --cached' + elseif filename ==# '' + return 'Git! diff --no-ext-diff' + elseif filename =~# ' -> ' + let [old, new] = split(filename,' -> ') + execute 'Gedit '.s:fnameescape(':0:'.new) + return a:diff.' HEAD:'.s:fnameescape(old) + elseif section ==# 'staged' + execute 'Gedit '.s:fnameescape(':0:'.filename) + return a:diff.' -' + else + execute 'Gedit '.s:fnameescape('/'.filename) + return a:diff + endif +endfunction + +function! s:StageDiffEdit() abort + let [filename, section] = s:stage_info(line('.')) + let arg = (filename ==# '' ? '.' : filename) + if section ==# 'staged' + return 'Git! diff --no-ext-diff --cached '.s:shellesc(arg) + elseif section ==# 'untracked' + let repo = s:repo() + call repo.git_chomp_in_tree('add','--intent-to-add',arg) + if arg ==# '.' + silent! edit! + 1 + if !search('^# .*:\n#.*\n# .*"git checkout \|^# Changes not staged for commit:$','W') + call search('^# .*:$','W') + endif + else + call s:StageReloadSeek(arg,line('.'),line('.')) + endif + return '' + else + return 'Git! diff --no-ext-diff '.s:shellesc(arg) + endif +endfunction + +function! s:StageToggle(lnum1,lnum2) abort + if a:lnum1 == 1 && a:lnum2 == 1 + return 'Gedit /.git|call search("^index$", "wc")' + endif + try + let output = '' + for lnum in range(a:lnum1,a:lnum2) + let [filename, section] = s:stage_info(lnum) + let repo = s:repo() + if getline('.') =~# '^# .*:$' + if section ==# 'staged' + call repo.git_chomp_in_tree('reset','-q') + silent! edit! + 1 + if !search('^# .*:\n# .*"git add .*\n#\n\|^# Untracked files:$','W') + call search('^# .*:$','W') + endif + return '' + elseif section ==# 'unstaged' + call repo.git_chomp_in_tree('add','-u') + silent! edit! + 1 + if !search('^# .*:\n# .*"git add .*\n#\n\|^# Untracked files:$','W') + call search('^# .*:$','W') + endif + return '' + else + call repo.git_chomp_in_tree('add','.') + silent! edit! + 1 + call search('^# .*:$','W') + return '' + endif + endif + if filename ==# '' + continue + endif + execute lnum + if filename =~ ' -> ' + let cmd = ['mv','--'] + reverse(split(filename,' -> ')) + let filename = cmd[-1] + elseif section ==# 'staged' + let cmd = ['reset','-q','--',filename] + elseif getline(lnum) =~# '^#\tdeleted:' + let cmd = ['rm','--',filename] + elseif getline(lnum) =~# '^#\tmodified:' + let cmd = ['add','--',filename] + else + let cmd = ['add','-A','--',filename] + endif + if !exists('first_filename') + let first_filename = filename + endif + let output .= call(repo.git_chomp_in_tree,cmd,s:repo())."\n" + endfor + if exists('first_filename') + call s:StageReloadSeek(first_filename,a:lnum1,a:lnum2) + endif + echo s:sub(s:gsub(output,'\n+','\n'),'\n$','') + catch /^fugitive:/ + return 'echoerr v:errmsg' + endtry + return 'checktime' +endfunction + +function! s:StagePatch(lnum1,lnum2) abort + let add = [] + let reset = [] + + for lnum in range(a:lnum1,a:lnum2) + let [filename, section] = s:stage_info(lnum) + if getline('.') =~# '^# .*:$' && section ==# 'staged' + return 'Git reset --patch' + elseif getline('.') =~# '^# .*:$' && section ==# 'unstaged' + return 'Git add --patch' + elseif getline('.') =~# '^# .*:$' && section ==# 'untracked' + return 'Git add -N .' + elseif filename ==# '' + continue + endif + if !exists('first_filename') + let first_filename = filename + endif + execute lnum + if filename =~ ' -> ' + let reset += [split(filename,' -> ')[1]] + elseif section ==# 'staged' + let reset += [filename] + elseif getline(lnum) !~# '^#\tdeleted:' + let add += [filename] + endif + endfor + try + if !empty(add) + execute "Git add --patch -- ".join(map(add,'s:shellesc(v:val)')) + endif + if !empty(reset) + execute "Git reset --patch -- ".join(map(add,'s:shellesc(v:val)')) + endif + if exists('first_filename') + silent! edit! + 1 + redraw + call search('^#\t\%([[:alpha:] ]\+: *\)\=\V'.first_filename.'\%( ([^()[:digit:]]\+)\)\=\$','W') + endif + catch /^fugitive:/ + return 'echoerr v:errmsg' + endtry + return 'checktime' +endfunction + +" Section: Gcommit + +call s:command("-nargs=? -complete=customlist,s:CommitComplete Gcommit :execute s:Commit()") + +function! s:Commit(args, ...) abort + let repo = a:0 ? a:1 : s:repo() + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + let msgfile = repo.dir('COMMIT_EDITMSG') + let outfile = tempname() + let errorfile = tempname() + try + try + execute cd.s:fnameescape(repo.tree()) + if s:winshell() + let command = '' + let old_editor = $GIT_EDITOR + let $GIT_EDITOR = 'false' + else + let command = 'env GIT_EDITOR=false ' + endif + let command .= repo.git_command('commit').' '.a:args + if &shell =~# 'csh' + noautocmd silent execute '!('.command.' > '.outfile.') >& '.errorfile + elseif a:args =~# '\%(^\| \)-\%(-interactive\|p\|-patch\)\>' + noautocmd execute '!'.command.' 2> '.errorfile + else + noautocmd silent execute '!'.command.' > '.outfile.' 2> '.errorfile + endif + finally + execute cd.'`=dir`' + endtry + if !has('gui_running') + redraw! + endif + if !v:shell_error + if filereadable(outfile) + for line in readfile(outfile) + echo line + endfor + endif + return '' + else + let errors = readfile(errorfile) + let error = get(errors,-2,get(errors,-1,'!')) + if error =~# 'false''\=\.$' + let args = a:args + let args = s:gsub(args,'%(%(^| )-- )@' + let args = '--cleanup=strip '.args + endif + if bufname('%') == '' && line('$') == 1 && getline(1) == '' && !&mod + execute 'keepalt edit '.s:fnameescape(msgfile) + elseif a:args =~# '\%(^\| \)-\%(-verbose\|\w*v\)\>' + execute 'keepalt tabedit '.s:fnameescape(msgfile) + elseif s:buffer().type() ==# 'index' + execute 'keepalt edit '.s:fnameescape(msgfile) + execute (search('^#','n')+1).'wincmd+' + setlocal nopreviewwindow + else + execute 'keepalt split '.s:fnameescape(msgfile) + endif + let b:fugitive_commit_arguments = args + setlocal bufhidden=wipe filetype=gitcommit + return '1' + elseif error ==# '!' + return s:Status() + else + call s:throw(error) + endif + endif + catch /^fugitive:/ + return 'echoerr v:errmsg' + finally + if exists('old_editor') + let $GIT_EDITOR = old_editor + endif + call delete(outfile) + call delete(errorfile) + call fugitive#reload_status() + endtry +endfunction + +function! s:CommitComplete(A,L,P) abort + if a:A =~ '^-' || type(a:A) == type(0) " a:A is 0 on :Gcommit - + let args = ['-C', '-F', '-a', '-c', '-e', '-i', '-m', '-n', '-o', '-q', '-s', '-t', '-u', '-v', '--all', '--allow-empty', '--amend', '--author=', '--cleanup=', '--dry-run', '--edit', '--file=', '--include', '--interactive', '--message=', '--no-verify', '--only', '--quiet', '--reedit-message=', '--reuse-message=', '--signoff', '--template=', '--untracked-files', '--verbose'] + return filter(args,'v:val[0 : strlen(a:A)-1] ==# a:A') + else + return s:repo().superglob(a:A) + endif +endfunction + +function! s:FinishCommit() abort + let args = getbufvar(+expand(''),'fugitive_commit_arguments') + if !empty(args) + call setbufvar(+expand(''),'fugitive_commit_arguments','') + return s:Commit(args, s:repo(getbufvar(+expand(''),'git_dir'))) + endif + return '' +endfunction + +" Section: Gmerge, Gpull + +call s:command("-nargs=? -bang -complete=custom,s:RevisionComplete Gmerge " . + \ "execute s:Merge('merge', 0, )") +call s:command("-nargs=? -bang -complete=custom,s:RemoteComplete Gpull " . + \ "execute s:Merge('pull --progress', 0, )") + +function! s:RevisionComplete(A, L, P) abort + return s:repo().git_chomp('rev-parse', '--symbolic', '--branches', '--tags', '--remotes') + \ . "\nHEAD\nFETCH_HEAD\nORIG_HEAD" +endfunction + +function! s:RemoteComplete(A, L, P) abort + let remote = matchstr(a:L, ' \zs\S\+\ze ') + if !empty(remote) + let matches = split(s:repo().git_chomp('ls-remote', remote), "\n") + call filter(matches, 'v:val =~# "\t" && v:val !~# "{"') + call map(matches, 's:sub(v:val, "^.*\t%(refs/%(heads/|tags/)=)=", "")') + else + let matches = split(s:repo().git_chomp('remote'), "\n") + endif + return join(matches, "\n") +endfunction + +function! fugitive#cwindow() abort + if &buftype == 'quickfix' + cwindow + else + botright cwindow + if &buftype == 'quickfix' + wincmd p + endif + endif +endfunction + +let s:common_efm = '' + \ . '%+Egit:%.%#,' + \ . '%+Eusage:%.%#,' + \ . '%+Eerror:%.%#,' + \ . '%+Efatal:%.%#,' + \ . '%-G%.%#%\e[K%.%#,' + \ . '%-G%.%#%\r%.%\+' + +function! s:Merge(cmd, bang, args) abort + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd' + let cwd = getcwd() + let [mp, efm] = [&l:mp, &l:efm] + let had_merge_msg = filereadable(s:repo().dir('MERGE_MSG')) + try + let &l:errorformat = '' + \ . '%-Gerror:%.%#false''.,' + \ . '%-G%.%# ''git commit'' %.%#,' + \ . '%+Emerge:%.%#,' + \ . s:common_efm . ',' + \ . '%+ECannot %.%#: You have unstaged changes.,' + \ . '%+ECannot %.%#: Your index contains uncommitted changes.,' + \ . '%+EThere is no tracking information for the current branch.,' + \ . '%+EYou are not currently on a branch. Please specify which,' + \ . 'CONFLICT (%m): %f deleted in %.%#,' + \ . 'CONFLICT (%m): Merge conflict in %f,' + \ . 'CONFLICT (%m): Rename \"%f\"->%.%#,' + \ . 'CONFLICT (%m): Rename %.%#->%f %.%#,' + \ . 'CONFLICT (%m): There is a directory with name %f in %.%#,' + \ . '%+ECONFLICT %.%#,' + \ . '%+EKONFLIKT %.%#,' + \ . '%+ECONFLIT %.%#,' + \ . "%+EXUNG \u0110\u1ed8T %.%#," + \ . "%+E\u51b2\u7a81 %.%#," + \ . 'U%\t%f' + if a:cmd =~# '^merge' && empty(a:args) && + \ (had_merge_msg || isdirectory(s:repo().dir('rebase-apply')) || + \ !empty(s:repo().git_chomp('diff-files', '--diff-filter=U'))) + let &l:makeprg = g:fugitive_git_executable.' diff-files --name-status --diff-filter=U' + else + let &l:makeprg = s:sub(g:fugitive_git_executable.' -c core.editor=false '. + \ a:cmd . (a:args =~# ' \%(--no-edit\|--abort\|-m\)\>' ? '' : ' --edit') . ' ' . a:args, + \ ' *$', '') + endif + if !empty($GIT_EDITOR) + let old_editor = $GIT_EDITOR + let $GIT_EDITOR = 'false' + endif + execute cd fnameescape(s:repo().tree()) + silent noautocmd make! + catch /^Vim\%((\a\+)\)\=:E211/ + let err = v:exception + finally + redraw! + let [&l:mp, &l:efm] = [mp, efm] + if exists('old_editor') + let $GIT_EDITOR = old_editor + endif + execute cd fnameescape(cwd) + endtry + call fugitive#reload_status() + if empty(filter(getqflist(),'v:val.valid')) + if !had_merge_msg && filereadable(s:repo().dir('MERGE_MSG')) + cclose + return 'Gcommit --no-status -n -t '.s:shellesc(s:repo().dir('MERGE_MSG')) + endif + endif + let qflist = getqflist() + let found = 0 + for e in qflist + if !empty(e.bufnr) + let found = 1 + let e.pattern = '^<<<<<<<' + endif + endfor + call fugitive#cwindow() + if found + call setqflist(qflist, 'r') + if !a:bang + return 'cfirst' + endif + endif + return exists('err') ? 'echoerr '.string(err) : '' +endfunction + +" Section: Ggrep, Glog + +if !exists('g:fugitive_summary_format') + let g:fugitive_summary_format = '%s' +endif + +call s:command("-bang -nargs=? -complete=customlist,s:EditComplete Ggrep :execute s:Grep('grep',0,)") +call s:command("-bang -nargs=? -complete=customlist,s:EditComplete Glgrep :execute s:Grep('lgrep',0,)") +call s:command("-bar -bang -nargs=* -range=0 -complete=customlist,s:EditComplete Glog :call s:Log('grep',,,)") +call s:command("-bar -bang -nargs=* -range=0 -complete=customlist,s:EditComplete Gllog :call s:Log('lgrep',,,)") + +function! s:Grep(cmd,bang,arg) abort + let grepprg = &grepprg + let grepformat = &grepformat + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + try + execute cd.'`=s:repo().tree()`' + let &grepprg = s:repo().git_command('--no-pager', 'grep', '-n') + let &grepformat = '%f:%l:%m' + exe a:cmd.'! '.escape(matchstr(a:arg,'\v\C.{-}%($|[''" ]\@=\|)@='),'|') + let list = a:cmd =~# '^l' ? getloclist(0) : getqflist() + for entry in list + if bufname(entry.bufnr) =~ ':' + let entry.filename = s:repo().translate(bufname(entry.bufnr)) + unlet! entry.bufnr + let changed = 1 + elseif a:arg =~# '\%(^\| \)--cached\>' + let entry.filename = s:repo().translate(':0:'.bufname(entry.bufnr)) + unlet! entry.bufnr + let changed = 1 + endif + endfor + if a:cmd =~# '^l' && exists('changed') + call setloclist(0, list, 'r') + elseif exists('changed') + call setqflist(list, 'r') + endif + if !a:bang && !empty(list) + return (a:cmd =~# '^l' ? 'l' : 'c').'first'.matchstr(a:arg,'\v\C[''" ]\zs\|.*') + else + return matchstr(a:arg,'\v\C[''" ]\|\zs.*') + endif + finally + let &grepprg = grepprg + let &grepformat = grepformat + execute cd.'`=dir`' + endtry +endfunction + +function! s:Log(cmd, line1, line2, ...) abort + let path = s:buffer().path('/') + if path =~# '^/\.git\%(/\|$\)' || index(a:000,'--') != -1 + let path = '' + endif + let cmd = ['--no-pager', 'log', '--no-color'] + let cmd += ['--pretty=format:fugitive://'.s:repo().dir().'//%H'.path.'::'.g:fugitive_summary_format] + if empty(filter(a:000[0 : index(a:000,'--')],'v:val !~# "^-"')) + if s:buffer().commit() =~# '\x\{40\}' + let cmd += [s:buffer().commit()] + elseif s:buffer().path() =~# '^\.git/refs/\|^\.git/.*HEAD$' + let cmd += [s:buffer().path()[5:-1]] + endif + end + let cmd += map(copy(a:000),'s:sub(v:val,"^\\%(%(:\\w)*)","\\=fnamemodify(s:buffer().path(),submatch(1))")') + if path =~# '/.' + if a:line2 + let cmd += ['-L', a:line1 . ',' . a:line2 . ':' . path[1:-1]] + else + let cmd += ['--', path[1:-1]] + endif + endif + let grepformat = &grepformat + let grepprg = &grepprg + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + try + execute cd.'`=s:repo().tree()`' + let &grepprg = escape(call(s:repo().git_command,cmd,s:repo()),'%#') + let &grepformat = '%Cdiff %.%#,%C--- %.%#,%C+++ %.%#,%Z@@ -%\d%\+\,%\d%\+ +%l\,%\d%\+ @@,%-G-%.%#,%-G+%.%#,%-G %.%#,%A%f::%m,%-G%.%#' + exe a:cmd + finally + let &grepformat = grepformat + let &grepprg = grepprg + execute cd.'`=dir`' + endtry +endfunction + +" Section: Gedit, Gpedit, Gsplit, Gvsplit, Gtabedit, Gread + +function! s:Edit(cmd,bang,...) abort + let buffer = s:buffer() + if a:cmd !~# 'read' + if &previewwindow && getbufvar('','fugitive_type') ==# 'index' + wincmd p + if &diff + let mywinnr = winnr() + for winnr in range(winnr('$'),1,-1) + if winnr != mywinnr && getwinvar(winnr,'&diff') + execute winnr.'wincmd w' + close + if winnr('$') > 1 + wincmd p + endif + endif + endfor + endif + endif + endif + + if a:bang + let arglist = map(copy(a:000), 's:gsub(v:val, ''\\@>>>>>> + if getline(1) !~# '^diff ' + setlocal readonly nomodifiable + endif + if a:cmd =~# 'pedit' + wincmd p + endif + return echo + endif + return '' + endif + + if a:0 && a:1 == '' + return '' + elseif a:0 + let file = buffer.expand(join(a:000, ' ')) + elseif expand('%') ==# '' + let file = ':' + elseif buffer.commit() ==# '' && buffer.path('/') !~# '^/.git\>' + let file = buffer.path(':') + else + let file = buffer.path('/') + endif + try + let file = buffer.repo().translate(file) + catch /^fugitive:/ + return 'echoerr v:errmsg' + endtry + if a:cmd ==# 'read' + return 'silent %delete_|read '.s:fnameescape(file).'|silent 1delete_|diffupdate|'.line('.') + else + return a:cmd.' '.s:fnameescape(file) + endif +endfunction + +function! s:EditComplete(A,L,P) abort + return map(s:repo().superglob(a:A), 'fnameescape(v:val)') +endfunction + +function! s:EditRunComplete(A,L,P) abort + if a:L =~# '^\w\+!' + return s:GitComplete(a:A,a:L,a:P) + else + return s:repo().superglob(a:A) + endif +endfunction + +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditComplete Ge :execute s:Edit('edit',0,)") +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditComplete Gedit :execute s:Edit('edit',0,)") +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditRunComplete Gpedit :execute s:Edit('pedit',0,)") +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditRunComplete Gsplit :execute s:Edit('split',0,)") +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditRunComplete Gvsplit :execute s:Edit('vsplit',0,)") +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditRunComplete Gtabedit :execute s:Edit('tabedit',0,)") +call s:command("-bar -bang -nargs=* -count -complete=customlist,s:EditRunComplete Gread :execute s:Edit((! && ? '' : ).'read',0,)") + +" Section: Gwrite, Gwq + +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditComplete Gwrite :execute s:Write(0,)") +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditComplete Gw :execute s:Write(0,)") +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditComplete Gwq :execute s:Wq(0,)") + +function! s:Write(force,...) abort + if exists('b:fugitive_commit_arguments') + return 'write|bdelete' + elseif expand('%:t') == 'COMMIT_EDITMSG' && $GIT_INDEX_FILE != '' + return 'wq' + elseif s:buffer().type() == 'index' + return 'Gcommit' + elseif s:buffer().path() ==# '' && getline(4) =~# '^+++ ' + let filename = getline(4)[6:-1] + setlocal buftype= + silent write + setlocal buftype=nowrite + if matchstr(getline(2),'index [[:xdigit:]]\+\.\.\zs[[:xdigit:]]\{7\}') ==# s:repo().rev_parse(':0:'.filename)[0:6] + let err = s:repo().git_chomp('apply','--cached','--reverse',s:buffer().spec()) + else + let err = s:repo().git_chomp('apply','--cached',s:buffer().spec()) + endif + if err !=# '' + let v:errmsg = split(err,"\n")[0] + return 'echoerr v:errmsg' + elseif a:force + return 'bdelete' + else + return 'Gedit '.fnameescape(filename) + endif + endif + let mytab = tabpagenr() + let mybufnr = bufnr('') + let path = a:0 ? join(a:000, ' ') : s:buffer().path() + if path =~# '^:\d\>' + return 'write'.(a:force ? '! ' : ' ').s:fnameescape(s:repo().translate(s:buffer().expand(path))) + endif + let always_permitted = (s:buffer().path() ==# path && s:buffer().commit() =~# '^0\=$') + if !always_permitted && !a:force && s:repo().git_chomp_in_tree('diff','--name-status','HEAD','--',path) . s:repo().git_chomp_in_tree('ls-files','--others','--',path) !=# '' + let v:errmsg = 'fugitive: file has uncommitted changes (use ! to override)' + return 'echoerr v:errmsg' + endif + let file = s:repo().translate(path) + let treebufnr = 0 + for nr in range(1,bufnr('$')) + if fnamemodify(bufname(nr),':p') ==# file + let treebufnr = nr + endif + endfor + + if treebufnr > 0 && treebufnr != bufnr('') + let temp = tempname() + silent execute '%write '.temp + for tab in [mytab] + range(1,tabpagenr('$')) + for winnr in range(1,tabpagewinnr(tab,'$')) + if tabpagebuflist(tab)[winnr-1] == treebufnr + execute 'tabnext '.tab + if winnr != winnr() + execute winnr.'wincmd w' + let restorewinnr = 1 + endif + try + let lnum = line('.') + let last = line('$') + silent execute '$read '.temp + silent execute '1,'.last.'delete_' + silent write! + silent execute lnum + let did = 1 + finally + if exists('restorewinnr') + wincmd p + endif + execute 'tabnext '.mytab + endtry + endif + endfor + endfor + if !exists('did') + call writefile(readfile(temp,'b'),file,'b') + endif + else + execute 'write! '.s:fnameescape(s:repo().translate(path)) + endif + + if a:force + let error = s:repo().git_chomp_in_tree('add', '--force', '--', path) + else + let error = s:repo().git_chomp_in_tree('add', '--', path) + endif + if v:shell_error + let v:errmsg = 'fugitive: '.error + return 'echoerr v:errmsg' + endif + if s:buffer().path() ==# path && s:buffer().commit() =~# '^\d$' + set nomodified + endif + + let one = s:repo().translate(':1:'.path) + let two = s:repo().translate(':2:'.path) + let three = s:repo().translate(':3:'.path) + for nr in range(1,bufnr('$')) + let name = fnamemodify(bufname(nr), ':p') + if bufloaded(nr) && !getbufvar(nr,'&modified') && (name ==# one || name ==# two || name ==# three) + execute nr.'bdelete' + endif + endfor + + unlet! restorewinnr + let zero = s:repo().translate(':0:'.path) + for tab in range(1,tabpagenr('$')) + for winnr in range(1,tabpagewinnr(tab,'$')) + let bufnr = tabpagebuflist(tab)[winnr-1] + let bufname = fnamemodify(bufname(bufnr), ':p') + if bufname ==# zero && bufnr != mybufnr + execute 'tabnext '.tab + if winnr != winnr() + execute winnr.'wincmd w' + let restorewinnr = 1 + endif + try + let lnum = line('.') + let last = line('$') + silent execute '$read '.s:fnameescape(file) + silent execute '1,'.last.'delete_' + silent execute lnum + set nomodified + diffupdate + finally + if exists('restorewinnr') + wincmd p + endif + execute 'tabnext '.mytab + endtry + break + endif + endfor + endfor + call fugitive#reload_status() + return 'checktime' +endfunction + +function! s:Wq(force,...) abort + let bang = a:force ? '!' : '' + if exists('b:fugitive_commit_arguments') + return 'wq'.bang + endif + let result = call(s:function('s:Write'),[a:force]+a:000) + if result =~# '^\%(write\|wq\|echoerr\)' + return s:sub(result,'^write','wq') + else + return result.'|quit'.bang + endif +endfunction + +augroup fugitive_commit + autocmd! + autocmd VimLeavePre,BufDelete COMMIT_EDITMSG execute s:sub(s:FinishCommit(), '^echoerr (.*)', 'echohl ErrorMsg|echo \1|echohl NONE') +augroup END + +" Section: Gpush, Gfetch + +call s:command("-nargs=? -bang -complete=custom,s:RemoteComplete Gpush execute s:Dispatch('', 'push '.)") +call s:command("-nargs=? -bang -complete=custom,s:RemoteComplete Gfetch execute s:Dispatch('', 'fetch '.)") + +function! s:Dispatch(bang, args) + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd' + let cwd = getcwd() + let [mp, efm, cc] = [&l:mp, &l:efm, get(b:, 'current_compiler', '')] + try + let b:current_compiler = 'git' + let &l:errorformat = s:common_efm + let &l:makeprg = g:fugitive_git_executable . ' ' . a:args + execute cd fnameescape(s:repo().tree()) + if exists(':Make') == 2 + noautocmd Make + else + silent noautocmd make! + redraw! + return 'call fugitive#cwindow()' + endif + return '' + finally + let [&l:mp, &l:efm, b:current_compiler] = [mp, efm, cc] + if empty(cc) | unlet! b:current_compiler | endif + execute cd fnameescape(cwd) + endtry +endfunction + +" Section: Gdiff + +call s:command("-bang -bar -nargs=* -complete=customlist,s:EditComplete Gdiff :execute s:Diff('',)") +call s:command("-bar -nargs=* -complete=customlist,s:EditComplete Gvdiff :execute s:Diff('keepalt vert ',)") +call s:command("-bar -nargs=* -complete=customlist,s:EditComplete Gsdiff :execute s:Diff('keepalt ',)") + +augroup fugitive_diff + autocmd! + autocmd BufWinLeave * + \ if s:can_diffoff(+expand('')) && s:diff_window_count() == 2 | + \ call s:diffoff_all(getbufvar(+expand(''), 'git_dir')) | + \ endif + autocmd BufWinEnter * + \ if s:can_diffoff(+expand('')) && s:diff_window_count() == 1 | + \ call s:diffoff() | + \ endif +augroup END + +function! s:can_diffoff(buf) abort + return getwinvar(bufwinnr(a:buf), '&diff') && + \ !empty(getbufvar(a:buf, 'git_dir')) && + \ !empty(getwinvar(bufwinnr(a:buf), 'fugitive_diff_restore')) +endfunction + +function! fugitive#can_diffoff(buf) abort + return s:can_diffoff(a:buf) +endfunction + +function! s:diff_modifier(count) abort + let fdc = matchstr(&diffopt, 'foldcolumn:\zs\d\+') + if &diffopt =~# 'horizontal' && &diffopt !~# 'vertical' + return 'keepalt ' + elseif &diffopt =~# 'vertical' + return 'keepalt vert ' + elseif winwidth(0) <= a:count * ((&tw ? &tw : 80) + (empty(fdc) ? 2 : fdc)) + return 'keepalt ' + else + return 'keepalt vert ' + endif +endfunction + +function! s:diff_window_count() abort + let c = 0 + for nr in range(1,winnr('$')) + let c += getwinvar(nr,'&diff') + endfor + return c +endfunction + +function! s:diff_restore() abort + let restore = 'setlocal nodiff noscrollbind' + \ . ' scrollopt=' . &l:scrollopt + \ . (&l:wrap ? ' wrap' : ' nowrap') + \ . ' foldlevel=999' + \ . ' foldmethod=' . &l:foldmethod + \ . ' foldcolumn=' . &l:foldcolumn + \ . ' foldlevel=' . &l:foldlevel + \ . (&l:foldenable ? ' foldenable' : ' nofoldenable') + if has('cursorbind') + let restore .= (&l:cursorbind ? ' ' : ' no') . 'cursorbind' + endif + return restore +endfunction + +function! s:diffthis() abort + if !&diff + let w:fugitive_diff_restore = s:diff_restore() + diffthis + endif +endfunction + +function! s:diffoff() abort + if exists('w:fugitive_diff_restore') + execute w:fugitive_diff_restore + unlet w:fugitive_diff_restore + else + diffoff + endif +endfunction + +function! s:diffoff_all(dir) abort + for nr in range(1,winnr('$')) + if getwinvar(nr,'&diff') + if nr != winnr() + execute nr.'wincmd w' + let restorewinnr = 1 + endif + if exists('b:git_dir') && b:git_dir ==# a:dir + call s:diffoff() + endif + endif + endfor +endfunction + +function! s:buffer_compare_age(commit) dict abort + let scores = {':0': 1, ':1': 2, ':2': 3, ':': 4, ':3': 5} + let my_score = get(scores,':'.self.commit(),0) + let their_score = get(scores,':'.a:commit,0) + if my_score || their_score + return my_score < their_score ? -1 : my_score != their_score + elseif self.commit() ==# a:commit + return 0 + endif + let base = self.repo().git_chomp('merge-base',self.commit(),a:commit) + if base ==# self.commit() + return -1 + elseif base ==# a:commit + return 1 + endif + let my_time = +self.repo().git_chomp('log','--max-count=1','--pretty=format:%at',self.commit()) + let their_time = +self.repo().git_chomp('log','--max-count=1','--pretty=format:%at',a:commit) + return my_time < their_time ? -1 : my_time != their_time +endfunction + +call s:add_methods('buffer',['compare_age']) + +function! s:Diff(vert,...) abort + let vert = empty(a:vert) ? s:diff_modifier(2) : a:vert + if exists(':DiffGitCached') + return 'DiffGitCached' + elseif (!a:0 || a:1 == ':') && s:buffer().commit() =~# '^[0-1]\=$' && s:repo().git_chomp_in_tree('ls-files', '--unmerged', '--', s:buffer().path()) !=# '' + let vert = empty(a:vert) ? s:diff_modifier(3) : a:vert + let nr = bufnr('') + execute 'leftabove '.vert.'split `=fugitive#buffer().repo().translate(s:buffer().expand('':2''))`' + execute 'nnoremap dp :diffput '.nr.'diffupdate' + call s:diffthis() + wincmd p + execute 'rightbelow '.vert.'split `=fugitive#buffer().repo().translate(s:buffer().expand('':3''))`' + execute 'nnoremap dp :diffput '.nr.'diffupdate' + call s:diffthis() + wincmd p + call s:diffthis() + return '' + elseif a:0 + let arg = join(a:000, ' ') + if arg ==# '' + return '' + elseif arg ==# '/' + let file = s:buffer().path('/') + elseif arg ==# ':' + let file = s:buffer().path(':0:') + elseif arg =~# '^:/.' + try + let file = s:repo().rev_parse(arg).s:buffer().path(':') + catch /^fugitive:/ + return 'echoerr v:errmsg' + endtry + else + let file = s:buffer().expand(arg) + endif + if file !~# ':' && file !~# '^/' && s:repo().git_chomp('cat-file','-t',file) =~# '^\%(tag\|commit\)$' + let file = file.s:buffer().path(':') + endif + else + let file = s:buffer().path(s:buffer().commit() == '' ? ':0:' : '/') + endif + try + let spec = s:repo().translate(file) + let commit = matchstr(spec,'\C[^:/]//\zs\x\+') + let restore = s:diff_restore() + if exists('+cursorbind') + setlocal cursorbind + endif + let w:fugitive_diff_restore = restore + if s:buffer().compare_age(commit) < 0 + execute 'rightbelow '.vert.'diffsplit '.s:fnameescape(spec) + else + execute 'leftabove '.vert.'diffsplit '.s:fnameescape(spec) + endif + let w:fugitive_diff_restore = restore + let winnr = winnr() + if getwinvar('#', '&diff') + wincmd p + call feedkeys("\p", 'n') + endif + return '' + catch /^fugitive:/ + return 'echoerr v:errmsg' + endtry +endfunction + +" Section: Gmove, Gremove + +function! s:Move(force,destination) abort + if a:destination =~# '^/' + let destination = a:destination[1:-1] + else + let destination = s:shellslash(fnamemodify(s:sub(a:destination,'[%#]%(:\w)*','\=expand(submatch(0))'),':p')) + if destination[0:strlen(s:repo().tree())] ==# s:repo().tree('') + let destination = destination[strlen(s:repo().tree('')):-1] + endif + endif + if isdirectory(s:buffer().spec()) + " Work around Vim parser idiosyncrasy + let discarded = s:buffer().setvar('&swapfile',0) + endif + let message = call(s:repo().git_chomp_in_tree,['mv']+(a:force ? ['-f'] : [])+['--', s:buffer().path(), destination], s:repo()) + if v:shell_error + let v:errmsg = 'fugitive: '.message + return 'echoerr v:errmsg' + endif + let destination = s:repo().tree(destination) + if isdirectory(destination) + let destination = fnamemodify(s:sub(destination,'/$','').'/'.expand('%:t'),':.') + endif + call fugitive#reload_status() + if s:buffer().commit() == '' + if isdirectory(destination) + return 'keepalt edit '.s:fnameescape(destination) + else + return 'keepalt saveas! '.s:fnameescape(destination) + endif + else + return 'file '.s:fnameescape(s:repo().translate(':0:'.destination)) + endif +endfunction + +function! s:MoveComplete(A,L,P) abort + if a:A =~ '^/' + return s:repo().superglob(a:A) + else + let matches = split(glob(a:A.'*'),"\n") + call map(matches,'v:val !~ "/$" && isdirectory(v:val) ? v:val."/" : v:val') + return matches + endif +endfunction + +function! s:Remove(force) abort + if s:buffer().commit() ==# '' + let cmd = ['rm'] + elseif s:buffer().commit() ==# '0' + let cmd = ['rm','--cached'] + else + let v:errmsg = 'fugitive: rm not supported here' + return 'echoerr v:errmsg' + endif + if a:force + let cmd += ['--force'] + endif + let message = call(s:repo().git_chomp_in_tree,cmd+['--',s:buffer().path()],s:repo()) + if v:shell_error + let v:errmsg = 'fugitive: '.s:sub(message,'error:.*\zs\n\(.*-f.*',' (add ! to force)') + return 'echoerr '.string(v:errmsg) + else + call fugitive#reload_status() + return 'bdelete'.(a:force ? '!' : '') + endif +endfunction + +augroup fugitive_remove + autocmd! + autocmd User Fugitive if s:buffer().commit() =~# '^0\=$' | + \ exe "command! -buffer -bar -bang -nargs=1 -complete=customlist,s:MoveComplete Gmove :execute s:Move(0,)" | + \ exe "command! -buffer -bar -bang Gremove :execute s:Remove(0)" | + \ endif +augroup END + +" Section: Gblame + +augroup fugitive_blame + autocmd! + autocmd BufReadPost *.fugitiveblame setfiletype fugitiveblame + autocmd FileType fugitiveblame setlocal nomodeline | if exists('b:git_dir') | let &l:keywordprg = s:repo().keywordprg() | endif + autocmd Syntax fugitiveblame call s:BlameSyntax() + autocmd User Fugitive if s:buffer().type('file', 'blob') | exe "command! -buffer -bar -bang -range=0 -nargs=* Gblame :execute s:Blame(0,,,,[])" | endif + autocmd ColorScheme,GUIEnter * call s:RehighlightBlame() +augroup END + +function! s:linechars(pattern) abort + let chars = strlen(s:gsub(matchstr(getline('.'), a:pattern), '.', '.')) + if exists('*synconcealed') && &conceallevel > 1 + for col in range(1, chars) + let chars -= synconcealed(line('.'), col)[0] + endfor + endif + return chars +endfunction + +function! s:Blame(bang,line1,line2,count,args) abort + if exists('b:fugitive_blamed_bufnr') + return 'bdelete' + endif + try + if s:buffer().path() == '' + call s:throw('file or blob required') + endif + if filter(copy(a:args),'v:val !~# "^\\%(--root\|--show-name\\|-\\=\\%([ltfnsew]\\|[MC]\\d*\\)\\+\\)$"') != [] + call s:throw('unsupported option') + endif + call map(a:args,'s:sub(v:val,"^\\ze[^-]","-")') + let cmd = ['--no-pager', 'blame', '--show-number'] + a:args + if s:buffer().commit() =~# '\D\|..' + let cmd += [s:buffer().commit()] + else + let cmd += ['--contents', '-'] + endif + let cmd += ['--', s:buffer().path()] + let basecmd = escape(call(s:repo().git_command,cmd,s:repo()),'!') + try + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + if !s:repo().bare() + let dir = getcwd() + execute cd.'`=s:repo().tree()`' + endif + if a:count + execute 'write !'.substitute(basecmd,' blame ',' blame -L '.a:line1.','.a:line2.' ','g') + else + let error = resolve(tempname()) + let temp = error.'.fugitiveblame' + if &shell =~# 'csh' + silent! execute '%write !('.basecmd.' > '.temp.') >& '.error + else + silent! execute '%write !'.basecmd.' > '.temp.' 2> '.error + endif + if exists('l:dir') + execute cd.'`=dir`' + unlet dir + endif + if v:shell_error + call s:throw(join(readfile(error),"\n")) + endif + for winnr in range(winnr('$'),1,-1) + call setwinvar(winnr, '&scrollbind', 0) + if exists('+cursorbind') + call setwinvar(winnr, '&cursorbind', 0) + endif + if getbufvar(winbufnr(winnr), 'fugitive_blamed_bufnr') + execute winbufnr(winnr).'bdelete' + endif + endfor + let bufnr = bufnr('') + let restore = 'call setwinvar(bufwinnr('.bufnr.'),"&scrollbind",0)' + if exists('+cursorbind') + let restore .= '|call setwinvar(bufwinnr('.bufnr.'),"&cursorbind",0)' + endif + if &l:wrap + let restore .= '|call setwinvar(bufwinnr('.bufnr.'),"&wrap",1)' + endif + if &l:foldenable + let restore .= '|call setwinvar(bufwinnr('.bufnr.'),"&foldenable",1)' + endif + setlocal scrollbind nowrap nofoldenable + if exists('+cursorbind') + setlocal cursorbind + endif + let top = line('w0') + &scrolloff + let current = line('.') + let s:temp_files[tolower(temp)] = { 'dir': s:repo().dir(), 'args': cmd } + exe 'keepalt leftabove vsplit '.temp + let b:fugitive_blamed_bufnr = bufnr + let w:fugitive_leave = restore + let b:fugitive_blame_arguments = join(a:args,' ') + execute top + normal! zt + execute current + if exists('+cursorbind') + setlocal cursorbind + endif + setlocal nomodified nomodifiable nonumber scrollbind nowrap foldcolumn=0 nofoldenable winfixwidth filetype=fugitiveblame + if exists('+concealcursor') + setlocal concealcursor=nc conceallevel=2 + endif + if exists('+relativenumber') + setlocal norelativenumber + endif + execute "vertical resize ".(s:linechars('.\{-\}\ze\s\+\d\+)')+1) + nnoremap :help fugitive-:Gblame + nnoremap g? :help fugitive-:Gblame + nnoremap q :exe substitute(bufwinnr(b:fugitive_blamed_bufnr).' wincmd w'.bufnr('').'bdelete','^-1','','') + nnoremap gq :exe substitute(bufwinnr(b:fugitive_blamed_bufnr).' wincmd w'.bufnr('').'bdeleteif expand("%:p") =~# "^fugitive:[\\/][\\/]"Geditendif','^-1','','') + nnoremap :exe BlameCommit("exe 'norm q'edit") + nnoremap - :exe BlameJump('') + nnoremap P :exe BlameJump('^'.v:count1) + nnoremap ~ :exe BlameJump('~'.v:count1) + nnoremap i :exe BlameCommit("exe 'norm q'edit") + nnoremap o :exe BlameCommit((&splitbelow ? "botright" : "topleft")." split") + nnoremap O :exe BlameCommit("tabedit") + nnoremap A :exe "vertical resize ".(linechars('.\{-\}\ze [0-9:/+-][0-9:/+ -]* \d\+)')+1+v:count) + nnoremap C :exe "vertical resize ".(linechars('^\S\+')+1+v:count) + nnoremap D :exe "vertical resize ".(linechars('.\{-\}\ze\d\ze\s\+\d\+)')+1-v:count) + redraw + syncbind + endif + finally + if exists('l:dir') + execute cd.'`=dir`' + endif + endtry + return '' + catch /^fugitive:/ + return 'echoerr v:errmsg' + endtry +endfunction + +function! s:BlameCommit(cmd) abort + let cmd = s:Edit(a:cmd, 0, matchstr(getline('.'),'\x\+')) + if cmd =~# '^echoerr' + return cmd + endif + let lnum = matchstr(getline('.'),' \zs\d\+\ze\s\+[([:digit:]]') + let path = matchstr(getline('.'),'^\^\=\x\+\s\+\zs.\{-\}\ze\s*\d\+ ') + if path ==# '' + let path = s:buffer(b:fugitive_blamed_bufnr).path() + endif + execute cmd + if search('^diff .* b/\M'.escape(path,'\').'$','W') + call search('^+++') + let head = line('.') + while search('^@@ \|^diff ') && getline('.') =~# '^@@ ' + let top = +matchstr(getline('.'),' +\zs\d\+') + let len = +matchstr(getline('.'),' +\d\+,\zs\d\+') + if lnum >= top && lnum <= top + len + let offset = lnum - top + if &scrolloff + + + normal! zt + else + normal! zt + + + endif + while offset > 0 && line('.') < line('$') + + + if getline('.') =~# '^[ +]' + let offset -= 1 + endif + endwhile + return 'normal! zv' + endif + endwhile + execute head + normal! zt + endif + return '' +endfunction + +function! s:BlameJump(suffix) abort + let commit = matchstr(getline('.'),'^\^\=\zs\x\+') + if commit =~# '^0\+$' + let commit = ':0' + endif + let lnum = matchstr(getline('.'),' \zs\d\+\ze\s\+[([:digit:]]') + let path = matchstr(getline('.'),'^\^\=\x\+\s\+\zs.\{-\}\ze\s*\d\+ ') + if path ==# '' + let path = s:buffer(b:fugitive_blamed_bufnr).path() + endif + let args = b:fugitive_blame_arguments + let offset = line('.') - line('w0') + let bufnr = bufnr('%') + let winnr = bufwinnr(b:fugitive_blamed_bufnr) + if winnr > 0 + exe winnr.'wincmd w' + endif + execute s:Edit('edit', 0, commit.a:suffix.':'.path) + execute lnum + if winnr > 0 + exe bufnr.'bdelete' + endif + execute 'Gblame '.args + execute lnum + let delta = line('.') - line('w0') - offset + if delta > 0 + execute 'normal! '.delta."\" + elseif delta < 0 + execute 'normal! '.(-delta)."\" + endif + syncbind + return '' +endfunction + +let s:hash_colors = {} + +function! s:BlameSyntax() abort + let b:current_syntax = 'fugitiveblame' + let conceal = has('conceal') ? ' conceal' : '' + let arg = exists('b:fugitive_blame_arguments') ? b:fugitive_blame_arguments : '' + syn match FugitiveblameBoundary "^\^" + syn match FugitiveblameBlank "^\s\+\s\@=" nextgroup=FugitiveblameAnnotation,fugitiveblameOriginalFile,FugitiveblameOriginalLineNumber skipwhite + syn match FugitiveblameHash "\%(^\^\=\)\@<=\x\{7,40\}\>" nextgroup=FugitiveblameAnnotation,FugitiveblameOriginalLineNumber,fugitiveblameOriginalFile skipwhite + syn match FugitiveblameUncommitted "\%(^\^\=\)\@<=0\{7,40\}\>" nextgroup=FugitiveblameAnnotation,FugitiveblameOriginalLineNumber,fugitiveblameOriginalFile skipwhite + syn region FugitiveblameAnnotation matchgroup=FugitiveblameDelimiter start="(" end="\%( \d\+\)\@<=)" contained keepend oneline + syn match FugitiveblameTime "[0-9:/+-][0-9:/+ -]*[0-9:/+-]\%( \+\d\+)\)\@=" contained containedin=FugitiveblameAnnotation + exec 'syn match FugitiveblameLineNumber " *\d\+)\@=" contained containedin=FugitiveblameAnnotation'.conceal + exec 'syn match FugitiveblameOriginalFile " \%(\f\+\D\@<=\|\D\@=\f\+\)\%(\%(\s\+\d\+\)\=\s\%((\|\s*\d\+)\)\)\@=" contained nextgroup=FugitiveblameOriginalLineNumber,FugitiveblameAnnotation skipwhite'.(arg =~# 'f' ? '' : conceal) + exec 'syn match FugitiveblameOriginalLineNumber " *\d\+\%(\s(\)\@=" contained nextgroup=FugitiveblameAnnotation skipwhite'.(arg =~# 'n' ? '' : conceal) + exec 'syn match FugitiveblameOriginalLineNumber " *\d\+\%(\s\+\d\+)\)\@=" contained nextgroup=FugitiveblameShort skipwhite'.(arg =~# 'n' ? '' : conceal) + syn match FugitiveblameShort " \d\+)" contained contains=FugitiveblameLineNumber + syn match FugitiveblameNotCommittedYet "(\@<=Not Committed Yet\>" contained containedin=FugitiveblameAnnotation + hi def link FugitiveblameBoundary Keyword + hi def link FugitiveblameHash Identifier + hi def link FugitiveblameUncommitted Ignore + hi def link FugitiveblameTime PreProc + hi def link FugitiveblameLineNumber Number + hi def link FugitiveblameOriginalFile String + hi def link FugitiveblameOriginalLineNumber Float + hi def link FugitiveblameShort FugitiveblameDelimiter + hi def link FugitiveblameDelimiter Delimiter + hi def link FugitiveblameNotCommittedYet Comment + let seen = {} + for lnum in range(1, line('$')) + let hash = matchstr(getline(lnum), '^\^\=\zs\x\{6\}') + if hash ==# '' || hash ==# '000000' || has_key(seen, hash) + continue + endif + let seen[hash] = 1 + if &t_Co > 16 && exists('g:CSApprox_loaded') + \ && empty(get(s:hash_colors, hash)) + let [s, r, g, b; __] = map(matchlist(hash, '\(\x\x\)\(\x\x\)\(\x\x\)'), 'str2nr(v:val,16)') + let color = csapprox#per_component#Approximate(r, g, b) + if color == 16 && &background ==# 'dark' + let color = 8 + endif + let s:hash_colors[hash] = ' ctermfg='.color + else + let s:hash_colors[hash] = '' + endif + exe 'syn match FugitiveblameHash'.hash.' "\%(^\^\=\)\@<='.hash.'\x\{1,34\}\>" nextgroup=FugitiveblameAnnotation,FugitiveblameOriginalLineNumber,fugitiveblameOriginalFile skipwhite' + endfor + call s:RehighlightBlame() +endfunction + +function! s:RehighlightBlame() abort + for [hash, cterm] in items(s:hash_colors) + if !empty(cterm) || has('gui_running') + exe 'hi FugitiveblameHash'.hash.' guifg=#'.hash.get(s:hash_colors, hash, '') + else + exe 'hi link FugitiveblameHash'.hash.' Identifier' + endif + endfor +endfunction + +" Section: Gbrowse + +call s:command("-bar -bang -range -nargs=* -complete=customlist,s:EditComplete Gbrowse :execute s:Browse(0,,,)") + +function! s:Browse(bang,line1,count,...) abort + try + let rev = a:0 ? substitute(join(a:000, ' '),'@[[:alnum:]_-]*\%(://.\{-\}\)\=$','','') : '' + if rev ==# '' + let expanded = s:buffer().rev() + elseif rev ==# ':' + let expanded = s:buffer().path('/') + else + let expanded = s:buffer().expand(rev) + endif + let full = s:repo().translate(expanded) + let commit = '' + if full =~# '^fugitive://' + let commit = matchstr(full,'://.*//\zs\w\+') + let path = matchstr(full,'://.*//\w\+\zs/.*') + if commit =~ '..' + let type = s:repo().git_chomp('cat-file','-t',commit.s:sub(path,'^/',':')) + else + let type = 'blob' + endif + let path = path[1:-1] + elseif s:repo().bare() + let path = '.git/' . full[strlen(s:repo().dir())+1:-1] + let type = '' + else + let path = full[strlen(s:repo().tree())+1:-1] + if path =~# '^\.git/' + let type = '' + elseif isdirectory(full) + let type = 'tree' + else + let type = 'blob' + endif + endif + if path =~# '^\.git/.*HEAD' && filereadable(s:repo().dir(path[5:-1])) + let body = readfile(s:repo().dir(path[5:-1]))[0] + if body =~# '^\x\{40\}$' + let commit = body + let type = 'commit' + let path = '' + elseif body =~# '^ref: refs/' + let path = '.git/' . matchstr(body,'ref: \zs.*') + endif + endif + + if a:0 && join(a:000, ' ') =~# '@[[:alnum:]_-]*\%(://.\{-\}\)\=$' + let remote = matchstr(join(a:000, ' '),'@\zs[[:alnum:]_-]\+\%(://.\{-\}\)\=$') + elseif path =~# '^\.git/refs/remotes/.' + let remote = matchstr(path,'^\.git/refs/remotes/\zs[^/]\+') + else + let remote = 'origin' + let branch = matchstr(rev,'^[[:alnum:]/._-]\+\ze[:^~@]') + if branch ==# '' && path =~# '^\.git/refs/\w\+/' + let branch = s:sub(path,'^\.git/refs/\w+/','') + endif + if filereadable(s:repo().dir('refs/remotes/'.branch)) + let remote = matchstr(branch,'[^/]\+') + let rev = rev[strlen(remote)+1:-1] + else + if branch ==# '' + let branch = matchstr(s:repo().head_ref(),'\ 0 ? a:line1 : 0, + \ 'line2': a:count > 0 ? a:count : 0}]) + if !empty(url) + break + endif + endfor + + if empty(url) + call s:throw("Instaweb failed to start and '".remote."' is not a supported remote") + endif + + if a:bang + if has('clipboard') + let @* = url + endif + return 'echomsg '.string(url) + elseif exists(':Browse') == 2 + return 'echomsg '.string(url).'|Browse '.url + else + return 'echomsg '.string(url).'|call netrw#NetrwBrowseX('.string(url).', 0)' + endif + catch /^fugitive:/ + return 'echoerr v:errmsg' + endtry +endfunction + +function! s:github_url(opts, ...) abort + if a:0 || type(a:opts) != type({}) + return '' + endif + let domain_pattern = 'github\.com' + let domains = exists('g:fugitive_github_domains') ? g:fugitive_github_domains : [] + for domain in domains + let domain_pattern .= '\|' . escape(split(domain, '://')[-1], '.') + endfor + let repo = matchstr(get(a:opts, 'remote'), '^\%(https\=://\|git://\|git@\)\=\zs\('.domain_pattern.'\)[/:].\{-\}\ze\%(\.git\)\=$') + if repo ==# '' + return '' + endif + let path = a:opts.path + if index(domains, 'http://' . matchstr(repo, '^[^:/]*')) >= 0 + let root = 'http://' . s:sub(repo,':','/') + else + let root = 'https://' . s:sub(repo,':','/') + endif + if path =~# '^\.git/refs/heads/' + let branch = a:opts.repo.git_chomp('config','branch.'.path[16:-1].'.merge')[11:-1] + if branch ==# '' + return root . '/commits/' . path[16:-1] + else + return root . '/commits/' . branch + endif + elseif path =~# '^\.git/refs/.' + return root . '/commits/' . matchstr(path,'[^/]\+$') + elseif path =~# '.git/\%(config$\|hooks\>\)' + return root . '/admin' + elseif path =~# '^\.git\>' + return root + endif + if a:opts.revision =~# '^[[:alnum:]._-]\+:' + let commit = matchstr(a:opts.revision,'^[^:]*') + elseif a:opts.commit =~# '^\d\=$' + let local = matchstr(a:opts.repo.head_ref(),'\' + return root + endif + let url = root + if a:opts.commit =~# '^\x\{40\}$' + if a:opts.type ==# 'commit' + let url .= ';a=commit' + endif + let url .= ';h=' . a:opts.repo.rev_parse(a:opts.commit . (a:opts.path == '' ? '' : ':' . a:opts.path)) + else + if a:opts.type ==# 'blob' + let tmp = tempname() + silent execute 'write !'.a:opts.repo.git_command('hash-object','-w','--stdin').' > '.tmp + let url .= ';h=' . readfile(tmp)[0] + else + try + let url .= ';h=' . a:opts.repo.rev_parse((a:opts.commit == '' ? 'HEAD' : ':' . a:opts.commit) . ':' . a:opts.path) + catch /^fugitive:/ + call s:throw('fugitive: cannot browse uncommitted file') + endtry + endif + let root .= ';hb=' . matchstr(a:opts.repo.head_ref(),'[^ ]\+$') + endif + if a:opts.path !=# '' + let url .= ';f=' . a:opts.path + endif + if get(a:opts, 'line1') + let url .= '#l' . a:opts.line1 + endif + return url +endfunction + +if !exists('g:fugitive_browse_handlers') + let g:fugitive_browse_handlers = [] +endif + +call extend(g:fugitive_browse_handlers, + \ [s:function('s:github_url'), s:function('s:instaweb_url')]) + +" Section: File access + +function! s:ReplaceCmd(cmd,...) abort + let fn = expand('%:p') + let tmp = tempname() + let prefix = '' + try + if a:0 && a:1 != '' + if s:winshell() + let old_index = $GIT_INDEX_FILE + let $GIT_INDEX_FILE = a:1 + else + let prefix = 'env GIT_INDEX_FILE='.s:shellesc(a:1).' ' + endif + endif + if s:winshell() + let cmd_escape_char = &shellxquote == '(' ? '^' : '^^^' + call system('cmd /c "'.prefix.s:gsub(a:cmd,'[<>]', cmd_escape_char.'&').' > '.tmp.'"') + else + call system(' ('.prefix.a:cmd.' > '.tmp.') ') + endif + finally + if exists('old_index') + let $GIT_INDEX_FILE = old_index + endif + endtry + silent exe 'keepalt file '.tmp + try + silent edit! + finally + try + silent exe 'keepalt file '.s:fnameescape(fn) + catch /^Vim\%((\a\+)\)\=:E302/ + endtry + call delete(tmp) + if fnamemodify(bufname('$'), ':p') ==# tmp + silent execute 'bwipeout '.bufnr('$') + endif + silent exe 'doau BufReadPost '.s:fnameescape(fn) + endtry +endfunction + +function! s:BufReadIndex() abort + if !exists('b:fugitive_display_format') + let b:fugitive_display_format = filereadable(expand('%').'.lock') + endif + let b:fugitive_display_format = b:fugitive_display_format % 2 + let b:fugitive_type = 'index' + try + let b:git_dir = s:repo().dir() + setlocal noro ma nomodeline + if fnamemodify($GIT_INDEX_FILE !=# '' ? $GIT_INDEX_FILE : b:git_dir . '/index', ':p') ==# expand('%:p') + let index = '' + else + let index = expand('%:p') + endif + if b:fugitive_display_format + call s:ReplaceCmd(s:repo().git_command('ls-files','--stage'),index) + set ft=git nospell + else + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + if fugitive#git_version() =~# '^0\|^1\.[1-7]\.' + let cmd = s:repo().git_command('status') + else + let cmd = s:repo().git_command( + \ '-c', 'status.displayCommentPrefix=true', + \ '-c', 'color.status=false', + \ '-c', 'status.short=false', + \ 'status') + endif + try + execute cd.'`=s:repo().tree()`' + call s:ReplaceCmd(cmd, index) + finally + execute cd.'`=dir`' + endtry + set ft=gitcommit + set foldtext=fugitive#foldtext() + endif + setlocal ro noma nomod noswapfile + if &bufhidden ==# '' + setlocal bufhidden=delete + endif + call s:JumpInit() + nunmap P + nunmap ~ + nnoremap :execute StageNext(v:count1) + nnoremap :execute StagePrevious(v:count1) + nnoremap - :silent execute StageToggle(line('.'),line('.')+v:count1-1) + xnoremap - :silent execute StageToggle(line("'<"),line("'>")) + nnoremap a :let b:fugitive_display_format += 1exe BufReadIndex() + nnoremap i :let b:fugitive_display_format -= 1exe BufReadIndex() + nnoremap C :Gcommit + nnoremap cA :Gcommit --amend --reuse-message=HEAD + nnoremap ca :Gcommit --amend + nnoremap cc :Gcommit + nnoremap cva :Gcommit --amend --verbose + nnoremap cvc :Gcommit --verbose + nnoremap D :execute StageDiff('Gdiff') + nnoremap dd :execute StageDiff('Gdiff') + nnoremap dh :execute StageDiff('Gsdiff') + nnoremap ds :execute StageDiff('Gsdiff') + nnoremap dp :execute StageDiffEdit() + nnoremap dv :execute StageDiff('Gvdiff') + nnoremap p :execute StagePatch(line('.'),line('.')+v:count1-1) + xnoremap p :execute StagePatch(line("'<"),line("'>")) + nnoremap q :if bufnr('$') == 1quitelsebdeleteendif + nnoremap r :edit + nnoremap R :edit + nnoremap U :execute StageUndo() + nnoremap g? :help fugitive-:Gstatus + nnoremap :help fugitive-:Gstatus + catch /^fugitive:/ + return 'echoerr v:errmsg' + endtry +endfunction + +function! s:FileRead() abort + try + let repo = s:repo(fugitive#extract_git_dir(expand(''))) + let path = s:sub(s:sub(matchstr(expand(''),'fugitive://.\{-\}//\zs.*'),'/',':'),'^\d:',':&') + let hash = repo.rev_parse(path) + if path =~ '^:' + let type = 'blob' + else + let type = repo.git_chomp('cat-file','-t',hash) + endif + " TODO: use count, if possible + return "read !".escape(repo.git_command('cat-file',type,hash),'%#\') + catch /^fugitive:/ + return 'echoerr v:errmsg' + endtry +endfunction + +function! s:BufReadIndexFile() abort + try + let b:fugitive_type = 'blob' + let b:git_dir = s:repo().dir() + try + call s:ReplaceCmd(s:repo().git_command('cat-file','blob',s:buffer().sha1())) + finally + if &bufhidden ==# '' + setlocal bufhidden=delete + endif + setlocal noswapfile + endtry + return '' + catch /^fugitive: rev-parse/ + silent exe 'doau BufNewFile '.s:fnameescape(expand('%:p')) + return '' + catch /^fugitive:/ + return 'echoerr v:errmsg' + endtry +endfunction + +function! s:BufWriteIndexFile() abort + let tmp = tempname() + try + let path = matchstr(expand(''),'//\d/\zs.*') + let stage = matchstr(expand(''),'//\zs\d') + silent execute 'write !'.s:repo().git_command('hash-object','-w','--stdin').' > '.tmp + let sha1 = readfile(tmp)[0] + let old_mode = matchstr(s:repo().git_chomp('ls-files','--stage',path),'^\d\+') + if old_mode == '' + let old_mode = executable(s:repo().tree(path)) ? '100755' : '100644' + endif + let info = old_mode.' '.sha1.' '.stage."\t".path + call writefile([info],tmp) + if s:winshell() + let error = system('type '.s:gsub(tmp,'/','\\').'|'.s:repo().git_command('update-index','--index-info')) + else + let error = system(s:repo().git_command('update-index','--index-info').' < '.tmp) + endif + if v:shell_error == 0 + setlocal nomodified + silent execute 'doautocmd BufWritePost '.s:fnameescape(expand('%:p')) + call fugitive#reload_status() + return '' + else + return 'echoerr '.string('fugitive: '.error) + endif + finally + call delete(tmp) + endtry +endfunction + +function! s:BufReadObject() abort + try + setlocal noro ma + let b:git_dir = s:repo().dir() + let hash = s:buffer().sha1() + if !exists("b:fugitive_type") + let b:fugitive_type = s:repo().git_chomp('cat-file','-t',hash) + endif + if b:fugitive_type !~# '^\%(tag\|commit\|tree\|blob\)$' + return "echoerr 'fugitive: unrecognized git type'" + endif + let firstline = getline('.') + if !exists('b:fugitive_display_format') && b:fugitive_type != 'blob' + let b:fugitive_display_format = +getbufvar('#','fugitive_display_format') + endif + + if b:fugitive_type !=# 'blob' + setlocal nomodeline + endif + + let pos = getpos('.') + silent keepjumps %delete_ + setlocal endofline + + try + if b:fugitive_type ==# 'tree' + let b:fugitive_display_format = b:fugitive_display_format % 2 + if b:fugitive_display_format + call s:ReplaceCmd(s:repo().git_command('ls-tree',hash)) + else + call s:ReplaceCmd(s:repo().git_command('show','--no-color',hash)) + endif + elseif b:fugitive_type ==# 'tag' + let b:fugitive_display_format = b:fugitive_display_format % 2 + if b:fugitive_display_format + call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash)) + else + call s:ReplaceCmd(s:repo().git_command('cat-file','-p',hash)) + endif + elseif b:fugitive_type ==# 'commit' + let b:fugitive_display_format = b:fugitive_display_format % 2 + if b:fugitive_display_format + call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash)) + else + call s:ReplaceCmd(s:repo().git_command('show','--no-color','--pretty=format:tree %T%nparent %P%nauthor %an <%ae> %ad%ncommitter %cn <%ce> %cd%nencoding %e%n%n%s%n%n%b',hash)) + keepjumps call search('^parent ') + if getline('.') ==# 'parent ' + silent keepjumps delete_ + else + silent keepjumps s/\%(^parent\)\@\)\=$','W',line('.')+3) + if lnum + silent keepjumps delete_ + end + keepjumps 1 + endif + elseif b:fugitive_type ==# 'blob' + call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash)) + setlocal nomodeline + endif + finally + keepjumps call setpos('.',pos) + setlocal ro noma nomod noswapfile + if &bufhidden ==# '' + setlocal bufhidden=delete + endif + if b:fugitive_type !=# 'blob' + setlocal filetype=git foldmethod=syntax + nnoremap a :let b:fugitive_display_format += v:count1exe BufReadObject() + nnoremap i :let b:fugitive_display_format -= v:count1exe BufReadObject() + else + call s:JumpInit() + endif + endtry + + return '' + catch /^fugitive:/ + return 'echoerr v:errmsg' + endtry +endfunction + +augroup fugitive_files + autocmd! + autocmd BufReadCmd index{,.lock} + \ if fugitive#is_git_dir(expand(':p:h')) | + \ exe s:BufReadIndex() | + \ elseif filereadable(expand('')) | + \ read | + \ 1delete | + \ endif + autocmd FileReadCmd fugitive://**//[0-3]/** exe s:FileRead() + autocmd BufReadCmd fugitive://**//[0-3]/** exe s:BufReadIndexFile() + autocmd BufWriteCmd fugitive://**//[0-3]/** exe s:BufWriteIndexFile() + autocmd BufReadCmd fugitive://**//[0-9a-f][0-9a-f]* exe s:BufReadObject() + autocmd FileReadCmd fugitive://**//[0-9a-f][0-9a-f]* exe s:FileRead() + autocmd FileType git + \ if exists('b:git_dir') | + \ call s:JumpInit() | + \ endif +augroup END + +" Section: Temp files + +if !exists('s:temp_files') + let s:temp_files = {} +endif + +augroup fugitive_temp + autocmd! + autocmd BufNewFile,BufReadPost * + \ if has_key(s:temp_files,tolower(expand(':p'))) | + \ let b:git_dir = s:temp_files[tolower(expand(':p'))].dir | + \ let b:git_type = 'temp' | + \ let b:git_args = s:temp_files[tolower(expand(':p'))].args | + \ call fugitive#detect(expand(':p')) | + \ setlocal bufhidden=delete nobuflisted | + \ nnoremap q :bdelete| + \ endif +augroup END + +" Section: Go to file + +function! s:JumpInit() abort + nnoremap :exe GF("edit") + if !&modifiable + nnoremap o :exe GF("split") + nnoremap S :exe GF("vsplit") + nnoremap O :exe GF("tabedit") + nnoremap - :exe Edit('edit',0,buffer().up(v:count1)) if fugitive#buffer().type('tree')call search('^'.escape(expand('#:t'),'.*[]~\').'/\=$','wc')endif + nnoremap P :exe Edit('edit',0,buffer().commit().'^'.v:count1.buffer().path(':')) + nnoremap ~ :exe Edit('edit',0,buffer().commit().'~'.v:count1.buffer().path(':')) + nnoremap C :exe Edit('edit',0,buffer().containing_commit()) + nnoremap cc :exe Edit('edit',0,buffer().containing_commit()) + nnoremap co :exe Edit('split',0,buffer().containing_commit()) + nnoremap cS :exe Edit('vsplit',0,buffer().containing_commit()) + nnoremap cO :exe Edit('tabedit',0,buffer().containing_commit()) + nnoremap cP :exe Edit('pedit',0,buffer().containing_commit()) + nnoremap . : =fnameescape(recall()) + endif +endfunction + +function! s:GF(mode) abort + try + let buffer = s:buffer() + let myhash = buffer.sha1() + if myhash ==# '' && getline(1) =~# '^\%(commit\|tag\) \w' + let myhash = matchstr(getline(1),'^\w\+ \zs\S\+') + endif + + if buffer.type('tree') + let showtree = (getline(1) =~# '^tree ' && getline(2) == "") + if showtree && line('.') == 1 + return "" + elseif showtree && line('.') > 2 + return s:Edit(a:mode,0,buffer.commit().':'.s:buffer().path().(buffer.path() =~# '^$\|/$' ? '' : '/').s:sub(getline('.'),'/$','')) + elseif getline('.') =~# '^\d\{6\} \l\{3,8\} \x\{40\}\t' + return s:Edit(a:mode,0,buffer.commit().':'.s:buffer().path().(buffer.path() =~# '^$\|/$' ? '' : '/').s:sub(matchstr(getline('.'),'\t\zs.*'),'/$','')) + endif + + elseif buffer.type('blob') + let ref = expand("") + try + let sha1 = buffer.repo().rev_parse(ref) + catch /^fugitive:/ + endtry + if exists('sha1') + return s:Edit(a:mode,0,ref) + endif + + else + + " Index + if getline('.') =~# '^\d\{6\} \x\{40\} \d\t' + let ref = matchstr(getline('.'),'\x\{40\}') + let file = ':'.s:sub(matchstr(getline('.'),'\d\t.*'),'\t',':') + return s:Edit(a:mode,0,file) + + elseif getline('.') =~# '^#\trenamed:.* -> ' + let file = '/'.matchstr(getline('.'),' -> \zs.*') + return s:Edit(a:mode,0,file) + elseif getline('.') =~# '^#\t[[:alpha:] ]\+: *.' + let file = '/'.matchstr(getline('.'),': *\zs.\{-\}\ze\%( ([^()[:digit:]]\+)\)\=$') + return s:Edit(a:mode,0,file) + elseif getline('.') =~# '^#\t.' + let file = '/'.matchstr(getline('.'),'#\t\zs.*') + return s:Edit(a:mode,0,file) + elseif getline('.') =~# ': needs merge$' + let file = '/'.matchstr(getline('.'),'.*\ze: needs merge$') + return s:Edit(a:mode,0,file).'|Gdiff' + + elseif getline('.') ==# '# Not currently on any branch.' + return s:Edit(a:mode,0,'HEAD') + elseif getline('.') =~# '^# On branch ' + let file = 'refs/heads/'.getline('.')[12:] + return s:Edit(a:mode,0,file) + elseif getline('.') =~# "^# Your branch .*'" + let file = matchstr(getline('.'),"'\\zs\\S\\+\\ze'") + return s:Edit(a:mode,0,file) + endif + + let showtree = (getline(1) =~# '^tree ' && getline(2) == "") + + if getline('.') =~# '^ref: ' + let ref = strpart(getline('.'),5) + + elseif getline('.') =~# '^commit \x\{40\}\>' + let ref = matchstr(getline('.'),'\x\{40\}') + return s:Edit(a:mode,0,ref) + + elseif getline('.') =~# '^parent \x\{40\}\>' + let ref = matchstr(getline('.'),'\x\{40\}') + let line = line('.') + let parent = 0 + while getline(line) =~# '^parent ' + let parent += 1 + let line -= 1 + endwhile + return s:Edit(a:mode,0,ref) + + elseif getline('.') =~ '^tree \x\{40\}$' + let ref = matchstr(getline('.'),'\x\{40\}') + if s:repo().rev_parse(myhash.':') == ref + let ref = myhash.':' + endif + return s:Edit(a:mode,0,ref) + + elseif getline('.') =~# '^object \x\{40\}$' && getline(line('.')+1) =~ '^type \%(commit\|tree\|blob\)$' + let ref = matchstr(getline('.'),'\x\{40\}') + let type = matchstr(getline(line('.')+1),'type \zs.*') + + elseif getline('.') =~# '^\l\{3,8\} '.myhash.'$' + return '' + + elseif getline('.') =~# '^\l\{3,8\} \x\{40\}\>' + let ref = matchstr(getline('.'),'\x\{40\}') + echoerr "warning: unknown context ".matchstr(getline('.'),'^\l*') + + elseif getline('.') =~# '^[+-]\{3\} [ab/]' + let ref = getline('.')[4:] + + elseif getline('.') =~# '^[+-]' && search('^@@ -\d\+,\d\+ +\d\+,','bnW') + let type = getline('.')[0] + let lnum = line('.') - 1 + let offset = -1 + while getline(lnum) !~# '^@@ -\d\+,\d\+ +\d\+,' + if getline(lnum) =~# '^[ '.type.']' + let offset += 1 + endif + let lnum -= 1 + endwhile + let offset += matchstr(getline(lnum), type.'\zs\d\+') + let ref = getline(search('^'.type.'\{3\} [ab]/','bnW'))[4:-1] + let dcmd = '+'.offset.'|normal! zv' + let dref = '' + + elseif getline('.') =~# '^rename from ' + let ref = 'a/'.getline('.')[12:] + elseif getline('.') =~# '^rename to ' + let ref = 'b/'.getline('.')[10:] + + elseif getline('.') =~# '^diff --git \%(a/.*\|/dev/null\) \%(b/.*\|/dev/null\)' + let dref = matchstr(getline('.'),'\Cdiff --git \zs\%(a/.*\|/dev/null\)\ze \%(b/.*\|/dev/null\)') + let ref = matchstr(getline('.'),'\Cdiff --git \%(a/.*\|/dev/null\) \zs\%(b/.*\|/dev/null\)') + let dcmd = 'Gdiff' + + elseif getline('.') =~# '^index ' && getline(line('.')-1) =~# '^diff --git \%(a/.*\|/dev/null\) \%(b/.*\|/dev/null\)' + let line = getline(line('.')-1) + let dref = matchstr(line,'\Cdiff --git \zs\%(a/.*\|/dev/null\)\ze \%(b/.*\|/dev/null\)') + let ref = matchstr(line,'\Cdiff --git \%(a/.*\|/dev/null\) \zs\%(b/.*\|/dev/null\)') + let dcmd = 'Gdiff!' + + elseif line('$') == 1 && getline('.') =~ '^\x\{40\}$' + let ref = getline('.') + + elseif expand('') =~# '^\x\{7,40\}\>' + return s:Edit(a:mode,0,expand('')) + + else + let ref = '' + endif + + if myhash ==# '' + let ref = s:sub(ref,'^a/','HEAD:') + let ref = s:sub(ref,'^b/',':0:') + if exists('dref') + let dref = s:sub(dref,'^a/','HEAD:') + endif + else + let ref = s:sub(ref,'^a/',myhash.'^:') + let ref = s:sub(ref,'^b/',myhash.':') + if exists('dref') + let dref = s:sub(dref,'^a/',myhash.'^:') + endif + endif + + if ref ==# '/dev/null' + " Empty blob + let ref = 'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391' + endif + + if exists('dref') + return s:Edit(a:mode,0,ref) . '|'.dcmd.' '.s:fnameescape(dref) + elseif ref != "" + return s:Edit(a:mode,0,ref) + endif + + endif + return '' + catch /^fugitive:/ + return 'echoerr v:errmsg' + endtry +endfunction + +" Section: Statusline + +function! s:repo_head_ref() dict abort + if !filereadable(self.dir('HEAD')) + return '' + endif + return readfile(self.dir('HEAD'))[0] +endfunction + +call s:add_methods('repo',['head_ref']) + +function! fugitive#statusline(...) abort + if !exists('b:git_dir') + return '' + endif + let status = '' + if s:buffer().commit() != '' + let status .= ':' . s:buffer().commit()[0:7] + endif + let status .= '('.fugitive#head(7).')' + if &statusline =~# '%[MRHWY]' && &statusline !~# '%[mrhwy]' + return ',GIT'.status + else + return '[Git'.status.']' + endif +endfunction + +function! fugitive#head(...) abort + if !exists('b:git_dir') + return '' + endif + + return s:repo().head(a:0 ? a:1 : 0) +endfunction + +" Section: Folding + +function! fugitive#foldtext() abort + if &foldmethod !=# 'syntax' + return foldtext() + elseif getline(v:foldstart) =~# '^diff ' + let [add, remove] = [-1, -1] + let filename = '' + for lnum in range(v:foldstart, v:foldend) + if filename ==# '' && getline(lnum) =~# '^[+-]\{3\} [abciow12]/' + let filename = getline(lnum)[6:-1] + endif + if getline(lnum) =~# '^+' + let add += 1 + elseif getline(lnum) =~# '^-' + let remove += 1 + elseif getline(lnum) =~# '^Binary ' + let binary = 1 + endif + endfor + if filename ==# '' + let filename = matchstr(getline(v:foldstart), '^diff .\{-\} a/\zs.*\ze b/') + endif + if filename ==# '' + let filename = getline(v:foldstart)[5:-1] + endif + if exists('binary') + return 'Binary: '.filename + else + return (add<10&&remove<100?' ':'') . add . '+ ' . (remove<10&&add<100?' ':'') . remove . '- ' . filename + endif + elseif getline(v:foldstart) =~# '^# .*:$' + let lines = getline(v:foldstart, v:foldend) + call filter(lines, 'v:val =~# "^#\t"') + cal map(lines,'s:sub(v:val, "^#\t%(modified: +|renamed: +)=", "")') + cal map(lines,'s:sub(v:val, "^([[:alpha:] ]+): +(.*)", "\\2 (\\1)")') + return getline(v:foldstart).' '.join(lines, ', ') + endif + return foldtext() +endfunction + +augroup fugitive_foldtext + autocmd! + autocmd User Fugitive + \ if &filetype =~# '^git\%(commit\)\=$' && &foldtext ==# 'foldtext()' | + \ set foldtext=fugitive#foldtext() | + \ endif +augroup END diff --git a/vim/bundle/vim-jade/README.markdown b/vim/bundle/vim-jade/README.markdown new file mode 100644 index 0000000..2c2222e --- /dev/null +++ b/vim/bundle/vim-jade/README.markdown @@ -0,0 +1,19 @@ +# vim-jade # + +Vim syntax highlighting for Jade templates. + +Installation +------------ + +I prefer to install plugins using Tim Pope's +[pathogen.vim](https://github.com/tpope/vim-pathogen). Installation using +pathogen is quite simple. + + cd ~/.vim/bundle + git clone git://github.com/digitaltoad/vim-jade.git + +If you do not want to use pathogen. You can always install vim-jade in the +normal manner by copying each directory to your ~/.vim directory. Make sure +not to overwrite any existing directory of the same name and instead copy only +the contents of the source directory to the directory of the same name in your +~/.vim directory. diff --git a/vim/bundle/vim-jade/ftdetect/jade.vim b/vim/bundle/vim-jade/ftdetect/jade.vim new file mode 100644 index 0000000..c21dcff --- /dev/null +++ b/vim/bundle/vim-jade/ftdetect/jade.vim @@ -0,0 +1,2 @@ +" Jade +autocmd BufNewFile,BufReadPost *.jade set filetype=jade diff --git a/vim/bundle/vim-jade/ftplugin/jade.vim b/vim/bundle/vim-jade/ftplugin/jade.vim new file mode 100644 index 0000000..235770d --- /dev/null +++ b/vim/bundle/vim-jade/ftplugin/jade.vim @@ -0,0 +1,55 @@ +" Vim filetype plugin +" Language: Jade +" Maintainer: Joshua Borton +" Credits: Tim Pope + +" Only do this when not done yet for this buffer +if exists("b:did_ftplugin") + finish +endif + +let s:save_cpo = &cpo +set cpo-=C + +" Define some defaults in case the included ftplugins don't set them. +let s:undo_ftplugin = "" +let s:browsefilter = "All Files (*.*)\t*.*\n" +let s:match_words = "" + +runtime! ftplugin/html.vim ftplugin/html_*.vim ftplugin/html/*.vim +unlet! b:did_ftplugin + +" Override our defaults if these were set by an included ftplugin. +if exists("b:undo_ftplugin") + let s:undo_ftplugin = b:undo_ftplugin + unlet b:undo_ftplugin +endif +if exists("b:browsefilter") + let s:browsefilter = b:browsefilter + unlet b:browsefilter +endif +if exists("b:match_words") + let s:match_words = b:match_words + unlet b:match_words +endif + +" Change the browse dialog on Win32 to show mainly Haml-related files +if has("gui_win32") + let b:browsefilter="Jade Files (*.jade)\t*.jade\n" . s:browsefilter +endif + +" Load the combined list of match_words for matchit.vim +if exists("loaded_matchit") + let b:match_words = s:match_words +endif + +setlocal comments=://-,:// commentstring=//\ %s + +setlocal suffixesadd+=.jade + +let b:undo_ftplugin = "setl cms< com< " + \ " | unlet! b:browsefilter b:match_words | " . s:undo_ftplugin + +let &cpo = s:save_cpo + +" vim:set sw=2: diff --git a/vim/bundle/vim-jade/indent/jade.vim b/vim/bundle/vim-jade/indent/jade.vim new file mode 100644 index 0000000..8cfa656 --- /dev/null +++ b/vim/bundle/vim-jade/indent/jade.vim @@ -0,0 +1,70 @@ +" Vim indent file +" Language: Jade +" Maintainer: Joshua Borton +" Credits: Tim Pope (vim-jade) +" Last Change: 2010 Sep 22 + +if exists("b:did_indent") + finish +endif + +unlet! b:did_indent +let b:did_indent = 1 + +setlocal autoindent +setlocal indentexpr=GetJadeIndent() +setlocal indentkeys=o,O,*,},],0),!^F + +" Only define the function once. +if exists("*GetJadeIndent") + finish +endif + +let s:attributes = '\%((.\{-\})\)' +let s:tag = '\([%.#][[:alnum:]_-]\+\|'.s:attributes.'\)*[<>]*' + +if !exists('g:jade_self_closing_tags') + let g:jade_self_closing_tags = 'meta|link|img|hr|br|input' +endif + +setlocal formatoptions+=r +setlocal comments+=n:\| + +function! GetJadeIndent() + let lnum = prevnonblank(v:lnum-1) + if lnum == 0 + return 0 + endif + let line = substitute(getline(lnum),'\s\+$','','') + let cline = substitute(substitute(getline(v:lnum),'\s\+$','',''),'^\s\+','','') + let lastcol = strlen(line) + let line = substitute(line,'^\s\+','','') + let indent = indent(lnum) + let cindent = indent(v:lnum) + let increase = indent + &sw + if indent == indent(lnum) + let indent = cindent <= indent ? -1 : increase + endif + + let group = synIDattr(synID(lnum,lastcol,1),'name') + + if line =~ '^!!!' + return indent + elseif line =~ '^/\%(\[[^]]*\]\)\=$' + return increase + elseif line =~ '^\%(if\|else\|unless\|for\|each\|block\|mixin\|append\|case\|when\)' + return increase + elseif line =~ '^'.s:tag.'[&!]\=[=~-].*,\s*$' + return increase + elseif line == '-#' + return increase + elseif line =~? '^\v%('.g:jade_self_closing_tags.')>' + return indent + elseif group =~? '\v^%(jadeAttributesDelimiter|jadeClass|jadeId|htmlTagName|htmlSpecialTagName|jadeFilter|jadeTagBlockChar)$' + return increase + else + return indent + endif +endfunction + +" vim:set sw=2: diff --git a/vim/bundle/vim-jade/syntax/jade.vim b/vim/bundle/vim-jade/syntax/jade.vim new file mode 100644 index 0000000..ab488d1 --- /dev/null +++ b/vim/bundle/vim-jade/syntax/jade.vim @@ -0,0 +1,99 @@ +" Vim syntax file +" Language: Jade +" Maintainer: Joshua Borton +" Credits: Tim Pope +" Filenames: *.jade + +if exists("b:current_syntax") + finish +endif + +if !exists("main_syntax") + let main_syntax = 'jade' +endif + +silent! syntax include @htmlCoffeescript syntax/coffee.vim +unlet! b:current_syntax +silent! syntax include @htmlStylus syntax/stylus.vim +unlet! b:current_syntax +silent! syntax include @htmlMarkdown syntax/markdown.vim +unlet! b:current_syntax + +syn case match + +syn region javascriptParenthesisBlock start="(" end=")" contains=@htmlJavascript contained keepend +syn cluster htmlJavascript add=javascriptParenthesisBlock + +syn region jadeJavascript matchgroup=jadeJavascriptOutputChar start="[!&]\==\|\~" skip=",\s*$" end="$" contained contains=@htmlJavascript keepend +syn region jadeJavascript matchgroup=jadeJavascriptChar start="-" skip=",\s*$" end="$" contained contains=@htmlJavascript keepend +syn cluster jadeTop contains=jadeBegin,jadeComment,jadeHtmlComment,jadeJavascript +syn match jadeBegin "^\s*\%([<>]\|&[^=~ ]\)\@!" nextgroup=jadeTag,jadeClassChar,jadeIdChar,jadePlainChar,jadeJavascript,jadeScriptConditional,jadeScriptStatement,jadePipedText +syn match jadeTag "+\?\w\+\%(:\w\+\)\=" contained contains=htmlTagName,htmlSpecialTagName nextgroup=@jadeComponent +syn cluster jadeComponent contains=jadeAttributes,jadeIdChar,jadeBlockExpansionChar,jadeClassChar,jadePlainChar,jadeJavascript,jadeTagBlockChar,jadeTagInlineText +syn match jadeComment '\s*\/\/.*$' +syn region jadeHtmlConditionalComment start="" +syn region jadeAttributes matchgroup=jadeAttributesDelimiter start="(" end=")" contained contains=@htmlJavascript,jadeHtmlArg,htmlArg,htmlEvent,htmlCssDefinition nextgroup=@jadeComponent +syn match jadeClassChar "\." contained nextgroup=jadeClass +syn match jadeBlockExpansionChar ":\s\+" contained nextgroup=jadeTag +syn match jadeIdChar "#[[{]\@!" contained nextgroup=jadeId +syn match jadeClass "\%(\w\|-\)\+" contained nextgroup=@jadeComponent +syn match jadeId "\%(\w\|-\)\+" contained nextgroup=@jadeComponent +syn region jadeDocType start="^\s*\(!!!\|doctype\)" end="$" +" Unless I'm mistaken, syntax/html.vim requires +" that the = sign be present for these matches. +" This adds the matches back for jade. +syn keyword jadeHtmlArg contained href title + +syn match jadePlainChar "\\" contained +syn region jadeInterpolation matchgroup=jadeInterpolationDelimiter start="#{" end="}" contains=@htmlJavascript +syn match jadeInterpolationEscape "\\\@[?!]\@!" +syn match jadeScriptStatement "^\s*\<\%(each\|for\|block\|prepend\|append\|mixin\|extends\|include\)\>[?!]\@!" +syn region jadeScriptLoopRegion start="^\s*\(for \)" end="$" contains=jadeScriptLoopKeywords +syn keyword jadeScriptLoopKeywords for in contained + +syn region jadeJavascript start="^\z(\s*\)script\%(:\w\+\)\=" end="^\%(\z1\s\|\s*$\)\@!" contains=@htmlJavascript,jadeJavascriptTag keepend +syn region jadeJavascriptTag contained start="^\z(\s*\)script\%(:\w\+\)\=" end="$" contains=jadeBegin,jadeTag +syn region jadeCssBlock start="^\z(\s*\)style" nextgroup=@jadeComponent,jadeError end="^\%(\z1\s\|\s*$\)\@!" contains=@jadeTop,@htmlCss keepend + +syn match jadeError "\$" contained + +hi def link jadePlainChar Special +hi def link jadeScriptConditional PreProc +hi def link jadeScriptLoopKeywords PreProc +hi def link jadeScriptStatement PreProc +hi def link jadeHtmlArg htmlArg +hi def link jadeAttributeString String +hi def link jadeAttributesDelimiter Identifier +hi def link jadeIdChar Special +hi def link jadeClassChar Special +hi def link jadeBlockExpansionChar Special +hi def link jadePipeChar Special +hi def link jadeTagBlockChar Special +hi def link jadeId Identifier +hi def link jadeClass Type +hi def link jadeInterpolationDelimiter Delimiter +hi def link jadeInlineDelimiter Delimiter +hi def link jadeFilter PreProc +hi def link jadeDocType PreProc +hi def link jadeComment Comment +hi def link jadeHtmlConditionalComment jadeComment + +let b:current_syntax = "jade" + +if main_syntax == "jade" + unlet main_syntax +endif diff --git a/vim/bundle/vim-repeat/README.markdown b/vim/bundle/vim-repeat/README.markdown new file mode 100644 index 0000000..d914131 --- /dev/null +++ b/vim/bundle/vim-repeat/README.markdown @@ -0,0 +1,53 @@ +repeat.vim +========== + +If you've ever tried using the `.` command after a plugin map, you were +likely disappointed to discover it only repeated the last native command +inside that map, rather than the map as a whole. That disappointment +ends today. Repeat.vim remaps `.` in a way that plugins can tap into +it. + +The following plugins support repeat.vim: + +* [surround.vim](https://github.com/tpope/vim-surround) +* [speeddating.vim](https://github.com/tpope/vim-speeddating) +* [abolish.vim](https://github.com/tpope/vim-abolish) +* [unimpaired.vim](https://github.com/tpope/vim-unimpaired) +* [commentary.vim](https://github.com/tpope/vim-commentary) + +Adding support to a plugin is generally as simple as the following +command at the end of your map functions. + + silent! call repeat#set("\MyWonderfulMap", v:count) + +Installation +------------ + +If you don't have a preferred installation method, I recommend +installing [pathogen.vim](https://github.com/tpope/vim-pathogen), and +then simply copy and paste: + + cd ~/.vim/bundle + git clone git://github.com/tpope/vim-repeat.git + +Contributing +------------ + +See the contribution guidelines for +[pathogen.vim](https://github.com/tpope/vim-pathogen#readme). + +Self-Promotion +-------------- + +Like repeat.vim? Follow the repository on +[GitHub](https://github.com/tpope/vim-repeat) and vote for it on +[vim.org](http://www.vim.org/scripts/script.php?script_id=2136). And if +you're feeling especially charitable, follow [tpope](http://tpo.pe/) on +[Twitter](http://twitter.com/tpope) and +[GitHub](https://github.com/tpope). + +License +------- + +Copyright (c) Tim Pope. Distributed under the same terms as Vim itself. +See `:help license`. diff --git a/vim/bundle/vim-repeat/autoload/repeat.vim b/vim/bundle/vim-repeat/autoload/repeat.vim new file mode 100644 index 0000000..18b1280 --- /dev/null +++ b/vim/bundle/vim-repeat/autoload/repeat.vim @@ -0,0 +1,119 @@ +" repeat.vim - Let the repeat command repeat plugin maps +" Maintainer: Tim Pope +" Version: 1.1 +" GetLatestVimScripts: 2136 1 :AutoInstall: repeat.vim + +" Installation: +" Place in either ~/.vim/plugin/repeat.vim (to load at start up) or +" ~/.vim/autoload/repeat.vim (to load automatically as needed). +" +" License: +" Copyright (c) Tim Pope. Distributed under the same terms as Vim itself. +" See :help license +" +" Developers: +" Basic usage is as follows: +" +" silent! call repeat#set("\MappingToRepeatCommand",3) +" +" The first argument is the mapping that will be invoked when the |.| key is +" pressed. Typically, it will be the same as the mapping the user invoked. +" This sequence will be stuffed into the input queue literally. Thus you must +" encode special keys by prefixing them with a backslash inside double quotes. +" +" The second argument is the default count. This is the number that will be +" prefixed to the mapping if no explicit numeric argument was given. The +" value of the v:count variable is usually correct and it will be used if the +" second parameter is omitted. If your mapping doesn't accept a numeric +" argument and you never want to receive one, pass a value of -1. +" +" Make sure to call the repeat#set function _after_ making changes to the +" file. +" +" For mappings that use a register and want the same register used on +" repetition, use: +" +" silent! call repeat#setreg("\MappingToRepeatCommand", v:register) +" +" This function can (and probably needs to be) called before making changes to +" the file (as those typically clear v:register). Therefore, the call sequence +" in your mapping will look like this: +" +" nnoremap MyMap +" \ :execute 'silent! call repeat#setreg("\Plug>MyMap", v:register)' +" \ call MyFunction(v:register, ...) +" \ silent! call repeat#set("\Plug>MyMap") + +if exists("g:loaded_repeat") || &cp || v:version < 700 + finish +endif +let g:loaded_repeat = 1 + +let g:repeat_tick = -1 +let g:repeat_reg = ['', ''] + +" Special function to avoid spurious repeats in a related, naturally repeating +" mapping when your repeatable mapping doesn't increase b:changedtick. +function! repeat#invalidate() + let g:repeat_tick = -1 +endfunction + +function! repeat#set(sequence,...) + let g:repeat_sequence = a:sequence + let g:repeat_count = a:0 ? a:1 : v:count + let g:repeat_tick = b:changedtick + augroup repeat_custom_motion + autocmd! + autocmd CursorMoved let g:repeat_tick = b:changedtick | autocmd! repeat_custom_motion + augroup END +endfunction + +function! repeat#setreg(sequence,register) + let g:repeat_reg = [a:sequence, a:register] +endfunction + +function! repeat#run(count) + if g:repeat_tick == b:changedtick + let r = '' + if g:repeat_reg[0] ==# g:repeat_sequence && !empty(g:repeat_reg[1]) + if g:repeat_reg[1] ==# '=' + " This causes a re-evaluation of the expression on repeat, which + " is what we want. + let r = '"=' . getreg('=', 1) . "\" + else + let r = '"' . g:repeat_reg[1] + endif + endif + + let c = g:repeat_count + let s = g:repeat_sequence + let cnt = c == -1 ? "" : (a:count ? a:count : (c ? c : '')) + call feedkeys(r . cnt, 'n') + call feedkeys(s) + else + call feedkeys((a:count ? a:count : '') . '.', 'n') + endif +endfunction + +function! repeat#wrap(command,count) + let preserve = (g:repeat_tick == b:changedtick) + exe 'norm! '.(a:count ? a:count : '').a:command . (&foldopen =~# 'undo' ? 'zv' : '') + if preserve + let g:repeat_tick = b:changedtick + endif +endfunction + +nnoremap . :call repeat#run(v:count) +nnoremap u :call repeat#wrap('u',v:count) +if maparg('U','n') ==# '' + nnoremap U :call repeat#wrap('U',v:count) +endif +nnoremap :call repeat#wrap("\C-R>",v:count) + +augroup repeatPlugin + autocmd! + autocmd BufLeave,BufWritePre,BufReadPre * let g:repeat_tick = (g:repeat_tick == b:changedtick || g:repeat_tick == 0) ? 0 : -1 + autocmd BufEnter,BufWritePost * if g:repeat_tick == 0|let g:repeat_tick = b:changedtick|endif +augroup END + +" vim:set ft=vim et sw=4 sts=4: diff --git a/vim/bundle/vim-stylus/changelog.md b/vim/bundle/vim-stylus/changelog.md new file mode 100644 index 0000000..fc81ca9 --- /dev/null +++ b/vim/bundle/vim-stylus/changelog.md @@ -0,0 +1,41 @@ + +0.9.1 / 2014-05-21 +================== + + * add; css property user-select added [gmunkhbaatarmn] + * fix; cssDefineBlock: do not contain stylusImportList [itchyny] + * fix; pointer events highlighting + * mod; make installs slightly easier [dbryand] + +0.9.0 / 2014-02-27 +================== + + * add; Enable jump to file on abbreviated @import + * add; broadened defintion of keyword to include [#-]; unnecessarily complained about single-line comments. + * add; css3 syntax as part of project + * add; example of require fix + * add; function interpolations Fixes #7 + * add; the 'Stylus' command (to validate the current file) + * del; local set overrides + * fix; braces indenting + * fix; highlighting variables without $ Closes #22 + * fix; indentation + * fix; line comments (//). + * fix; single line comment ignore http:// + * fix; stylus comment after property + * fix; support space between property value GH #11 + * fix; syntax highlighting for comments + * fix; syntax highlighting for stylus import/require + * fix; unsetting main_syntax fixes issues with other plugins + * mod; Extends highlighted hex colors to include #n and #nn. + +0.8.3 / 2011-09-26 +================== + + * Added missing background properties Fixes #5 + +0.8.2 / 2011-09-01 +================== + + * updated function list + * removed extra stylus from properties cluster diff --git a/vim/bundle/vim-stylus/ftdetect/stylus.vim b/vim/bundle/vim-stylus/ftdetect/stylus.vim new file mode 100644 index 0000000..49e04ec --- /dev/null +++ b/vim/bundle/vim-stylus/ftdetect/stylus.vim @@ -0,0 +1,3 @@ +" Stylus +autocmd BufNewFile,BufReadPost *.styl set filetype=stylus +autocmd BufNewFile,BufReadPost *.stylus set filetype=stylus diff --git a/vim/bundle/vim-stylus/ftplugin/stylus.vim b/vim/bundle/vim-stylus/ftplugin/stylus.vim new file mode 100644 index 0000000..419f471 --- /dev/null +++ b/vim/bundle/vim-stylus/ftplugin/stylus.vim @@ -0,0 +1,63 @@ +" Vim filetype plugin +" Language: Stylus +" Maintainer: Marc Harter +" Credits: Tim Pope + +" Only do this when not done yet for this buffer +if exists("b:did_ftplugin") + finish +endif + +let s:save_cpo = &cpo +set cpo-=C + +" Define some defaults in case the included ftplugins don't set them. +let s:undo_ftplugin = "" +let s:browsefilter = "All Files (*.*)\t*.*\n" +let s:match_words = "" + +runtime! ftplugin/html.vim ftplugin/html_*.vim ftplugin/html/*.vim +unlet! b:did_ftplugin + +" Override our defaults if these were set by an included ftplugin. +if exists("b:undo_ftplugin") + let s:undo_ftplugin = b:undo_ftplugin + unlet b:undo_ftplugin +endif +if exists("b:browsefilter") + let s:browsefilter = b:browsefilter + unlet b:browsefilter +endif +if exists("b:match_words") + let s:match_words = b:match_words + unlet b:match_words +endif + +" Change the browse dialog on Win32 to show mainly Styl-related files +if has("gui_win32") + let b:browsefilter="Stylus Files (*.styl)\t*.styl\n" . s:browsefilter +endif + +" Load the combined list of match_words for matchit.vim +if exists("loaded_matchit") + let b:match_words = s:match_words +endif + +setlocal comments= commentstring=//\ %s + +setlocal suffixesadd=.styl + +" Add '-' and '#' to the what makes up a keyword. +" This means that 'e' and 'w' work properly now, for properties +" and valid variable names. +setl iskeyword+=#,- + +let b:undo_ftplugin = "setl cms< com< " + \ " | unlet! b:browsefilter b:match_words | " . s:undo_ftplugin + +let &cpo = s:save_cpo + +" Add a Stylus command (to see if it's valid) +command! Stylus !clear; cat % | stylus + +" vim:set sw=2: diff --git a/vim/bundle/vim-stylus/indent/stylus.vim b/vim/bundle/vim-stylus/indent/stylus.vim new file mode 100644 index 0000000..8707e61 --- /dev/null +++ b/vim/bundle/vim-stylus/indent/stylus.vim @@ -0,0 +1,129 @@ +" Vim indent file +" Language: Stylus +" Maintainer: Marc Harter +" Last Change: 2010 May 21 +" Based On: sass.vim from Tim Pope +" +if exists("b:did_indent") + finish +endif +unlet! b:did_indent +let b:did_indent = 1 + +setlocal indentexpr=GetStylusIndent() +setlocal indentkeys=o,O,*,},],0),!^F +setlocal formatoptions+=r + +if exists("*GetStylusIndent") " only define once + finish +endif + +function s:prevnonblanknoncomment(lnum) + let lnum = a:lnum + while lnum > 1 + let lnum = prevnonblank(lnum) + let line = getline(lnum) + if line =~ '\*/' + while lnum > 1 && line !~ '/\*' + let lnum -= 1 + endwhile + if line =~ '^\s*/\*' + let lnum -= 1 + else + break + endif + else + break + endif + endwhile + return lnum +endfunction + +function s:count_braces(lnum, count_open) + let n_open = 0 + let n_close = 0 + let line = getline(a:lnum) + let pattern = '[{}]' + let i = match(line, pattern) + while i != -1 + if synIDattr(synID(a:lnum, i + 1, 0), 'name') !~ 'css\%(Comment\|StringQ\{1,2}\)' + if line[i] == '{' + let n_open += 1 + elseif line[i] == '}' + if n_open > 0 + let n_open -= 1 + else + let n_close += 1 + endif + endif + endif + let i = match(line, pattern, i + 1) + endwhile + return a:count_open ? n_open : n_close +endfunction + +" function CheckCSSIndent() +" let line = getline(v:lnum) +" if line =~ '^\s*\*' +" return cindent(v:lnum) +" endif +" +" let pnum = s:prevnonblanknoncomment(v:lnum - 1) +" if pnum == 0 +" return 0 +" endif +" +" return indent(pnum) + s:count_braces(pnum, 1) * &sw +" \ - s:count_braces(v:lnum, 0) * &sw +" endfunction + +function! GetStylusIndent() + let line = getline(v:lnum) + if line =~ '^\s*\*' + return cindent(v:lnum) + endif + + let pnum = s:prevnonblanknoncomment(v:lnum - 1) + if pnum == 0 + return 0 + endif + + let lnum = prevnonblank(v:lnum-1) + if lnum == 0 + return 0 + endif + + let pline = getline(pnum) + + if pline =~ '[}{]' + return indent(pnum) + s:count_braces(pnum, 1) * &sw - s:count_braces(v:lnum, 0) * &sw + endif + + let line = substitute(getline(lnum),'[\s()]\+$','','') " get last line strip ending whitespace + let cline = substitute(substitute(getline(v:lnum),'\s\+$','',''),'^\s\+','','') " get current line, trimmed + let lastcol = strlen(line) " get last col in prev line + let line = substitute(line,'^\s\+','','') " then remove preceeding whitespace + let indent = indent(lnum) " get indent on prev line + let cindent = indent(v:lnum) " get indent on current line + let increase = indent + &sw " increase indent by the shift width + if indent == indent(lnum) + let indent = cindent <= indent ? indent : increase + endif + + let group = synIDattr(synID(lnum,lastcol,1),'name') + + " for debugging only + echo group + + " if group !~? 'css.*' && line =~? ')\s*$' " match user functions + " return increase + if group =~? '\v^%(cssTagName|cssClassName|cssIdentifier|cssSelectorOp|cssSelectorOp2|cssBraces|cssAttributeSelector|cssPseudoClass|cssPseudoClassId|stylusId|stylusClass)$' + return increase + elseif (group == 'stylusUserFunction') && (indent(lnum) == '0') " mixin definition + return increase + else + return indent + endif +endfunction + +" vim:set sw=2; diff --git a/vim/bundle/vim-stylus/readme.md b/vim/bundle/vim-stylus/readme.md new file mode 100644 index 0000000..53d1e90 --- /dev/null +++ b/vim/bundle/vim-stylus/readme.md @@ -0,0 +1,19 @@ +# stylus.vim +Syntax highlighting for [Stylus](http://learnboost.github.com/stylus/). + +CSS3/HTML5 bundled in and adapted from [css3.vim](http://www.vim.org/scripts/script.php?script_id=3042) by Hsiaoming Young + +## Installation + +### Manual install +Unzip into your `.vim` directory + +### Pathogen install + +Clone this repo into your `.vim/bundle` directory. For example: + + cd ~/.vim/bundle + git clone git://github.com/wavded/vim-stylus.git + +## Creds +This is based on the excellent work from Tim Pope on sass.vim. diff --git a/vim/bundle/vim-stylus/syntax/stylus.vim b/vim/bundle/vim-stylus/syntax/stylus.vim new file mode 100644 index 0000000..f3edaf2 --- /dev/null +++ b/vim/bundle/vim-stylus/syntax/stylus.vim @@ -0,0 +1,376 @@ +" Vim syntax file +" Language: CSS3 +" Maintainer: Hsiaoming Yang +" URL: http://lepture.me/work/css3/ +" Created: Dec 14, 2011 +" Modified: Sep 4, 2012 + +" For version 5.x: Clear all syntax items +" For version 6.x: Quit when a syntax file was already loaded +if !exists("main_syntax") + if version < 600 + syntax clear + elseif exists("b:current_syntax") + finish + endif + let main_syntax = 'css' +endif + +syn case ignore +syn region cssString start='"' end='"' contained +syn region cssString start="'" end="'" contained + +" HTML4 tags +syn keyword cssTagName abbr acronym address applet area base a b +syn keyword cssTagName basefont bdo big blockquote body button br +syn keyword cssTagName caption cite code col colgroup dd del +syn keyword cssTagName dfn dir div dl dt em fieldset form frame +syn keyword cssTagName frameset h1 h2 h3 h4 h5 h6 head hr html img i +syn keyword cssTagName iframe img input ins isindex kbd label legend li +syn keyword cssTagName link map menu meta noframes noscript ol optgroup +syn keyword cssTagName option p param pre q s samp script select +syn keyword cssTagName span strike strong style sub sup tbody td +syn keyword cssTagName textarea tfoot th thead title tr tt ul u var +syn match cssTagName "\*" +syn match cssTagName /\/ +syn match cssTagName /\/ +syn match cssTagName /\/ +" HTML5 tags +syn keyword cssTagName article aside audio bb canvas command datagrid +syn keyword cssTagName datalist details dialog embed figure footer figcaption +syn keyword cssTagName header hgroup keygen mark meter nav output +syn keyword cssTagName progress time rt rp section time video +syn match cssTagName /\/ +" class select +syn match cssSelector /\.[A-Za-z][A-Za-z0-9_-]\+/ +" id select +syn match cssSelector /#[A-Za-z][A-Za-z0-9_-]\+/ +syn region cssSelector start='\[' end='\]' contains=cssString + +syn region cssDefineBlock start="{" end="}" transparent contains=TOP + +syn keyword cssCommonVal inherit initial auto both normal hidden none medium contained + + +" Comment +syn keyword cssTodo FIXME TODO contained +syn region cssComment start="/\*" end="\*/" contains=cssTodo +syn match cssImportant "!\s*important\>" contained + +syn match cssValueInteger "[-+]\=\d\+" contained +syn match cssValueNumber "[-+]\=\d\+\(\.\d*\)\=" +syn match cssValueLength "[-+]\=\d\+\(\.\d*\)\=\(%\|mm\|cm\|in\|pt\|pc\|em\|ex\|px\|rem\|vh\|vw\|vm\|fr\|gr\)" contained +syn match cssValueAngle "[-+]\=\d\+\(\.\d*\)\=\(deg\|grad\|rad\|turn\)" contained +syn match cssValueTime "+\=\d\+\(\.\d*\)\=\(ms\|s\)" contained +syn match cssValueFrequency "+\=\d\+\(\.\d*\)\=\(Hz\|kHz\)" contained + + +" Properties http://www.w3.org/community/webed/wiki/CSS/Properties +" background http://www.w3.org/TR/css3-background/ +syn match cssBackgroundProp /\(background-\(color\|image\|repeat\|attachment\|position\)\|background\)/ contained +syn match cssBackgroundProp /background-\(origin\|\(repeat\|position\)-[xy]\|clip\|size\)/ contained +syn match cssBackgroundProp /object-\(fit\|position\)/ contained +" http://www.evotech.net/blog/2010/02/css3-properties-values-browser-support/ +syn keyword cssBackgroundVal tb lr rl snap cover contain widthLength heightLength contained +syn match cssBackgroundVal /\(scale-down\|from-image\)/ contained +syn match cssBackgroundVal /repeat-[xy]/ contained +syn match cssBackgroundVal /no-repeat/ contained +syn keyword cssBackgroundVal circle ellipse to at contained +syn match cssBackgroundVal /\(closest\|farthest\)-\(side\|corner\)/ contained + +syn region cssFuncVal start="\(url\|calc\|min\|max\|counter\|cycle(\)" end=")" oneline contained contains=cssString,cssValueLength,cssValueInteger,cssValueNumber,cssValueAngle,cssValueTime,cssValueFrequency +syn region cssFuncVal start="\(linear\|radial\|repeating-linear\|repeating-radial\)-gradient(" end=")" oneline contained contains=cssString,cssValueLength,cssValueInteger,cssValueNumber,cssValueAngle,cssValueTime,cssValueFrequency,cssVisualProp,cssColorVal + +syn match cssBorderProp /\(border-\(color\|style\|width\|radius\)\|border\)/ contained +syn match cssBorderProp /border-\(image-\(source\|slice\|width\|outset\|repeat\)\|image\)/ contained +syn match cssBorderProp /border-\(\(top\|right\|bottom\|left\)-\(color\|style\|width\)\|\(top\|right\|bottom\|left\)\)/ contained +syn match cssBorderProp /border-\(top\|bottom\)-\(left\|right\)-radius/ contained +syn keyword cssBorderVal dotted dashed solid double groove ridge inset outset contained +syn match cssBorderVal /\/ contained +syn match cssBorderVal /\/ contained +syn match cssBorderVal /\/ contained + +" Font +syn match cssFontProp /\(font-\(family\|style\|variant\|weight\|size-adjust\|size\|stretch\)\|font\)/ contained +syn match cssFontVal /\(sans-serif\|small-caps\)/ contained +syn match cssFontVal /\/ contained +syn keyword cssFontVal cursive fantasy monospace italic oblique serif contained +syn keyword cssFontVal bold bolder lighter larger smaller contained +syn keyword cssFontVal icon narrower wider contained + +" Color +syn match cssColorVal /transparent/ contained +syn match cssColorVal "#[0-9A-Fa-f]\{3\}\>" contained +syn match cssColorVal "#[0-9A-Fa-f]\{6\}\>" contained +syn match cssFuncVal /rgb(\(\d\{1,3\}\s*,\s*\)\{2\}\d\{1,3\})/ contained contains=cssString,cssValueLength,cssValueInteger,cssValueNumber,cssValueAngle,cssValueTime,cssValueFrequency +syn match cssFuncVal /rgba(\(\d\{1,3\}\s*,\s*\)\{3\}\(1\|0\(\.\d\+\)\?\))/ contained contains=cssString,cssValueLength,cssValueInteger,cssValueNumber,cssValueAngle,cssValueTime,cssValueFrequency +syn match cssFuncVal /hsl(\d\{1,3\}\s*,\s*\(100\|\d\{1,2\}\(\.\d\+\)\?\)%\s*,\s*\(100\|\d\{1,2\}\(\.\d\+\)\?\)%)/ contained contains=cssString,cssValueLength,cssValueInteger,cssValueNumber,cssValueAngle,cssValueTime,cssValueFrequency +syn match cssFuncVal /hsla(\d\{1,3\}\s*,\s*\(\(100\|\d\{1,2\}\(\.\d\+\)\?\)%\s*,\s*\)\{2\}\(1\|0\(\.\d\+\)\?\))/ contained contains=cssString,cssValueLength,cssValueInteger,cssValueNumber,cssValueAngle,cssValueTime,cssValueFrequency +syn keyword cssColorVal aliceblue antiquewhite aqua aquamarine azure contained +syn keyword cssColorVal beige bisque black blanchedalmond blue blueviolet brown burlywood contained +syn keyword cssColorVal cadetblue chartreuse chocolate coral cornflowerblue cornsilk crimson cyan contained +syn match cssColorVal /dark\(blue\|cyan\|goldenrod\|gray\|green\|grey\|khaki\)/ contained +syn match cssColorVal /dark\(magenta\|olivegreen\|orange\|orchid\|red\|salmon\|seagreen\)/ contained +syn match cssColorVal /darkslate\(blue\|gray\|grey\)/ contained +syn match cssColorVal /dark\(turquoise\|violet\)/ contained +syn keyword cssColorVal deeppink deepskyblue dimgray dimgrey dodgerblue firebrick contained +syn keyword cssColorVal floralwhite forestgreen fuchsia gainsboro ghostwhite gold contained +syn keyword cssColorVal goldenrod gray green greenyellow grey honeydew hotpink contained +syn keyword cssColorVal indianred indigo ivory khaki lavender lavenderblush lawngreen contained +syn keyword cssColorVal lemonchiffon lime limegreen linen magenta maroon contained +syn match cssColorVal /light\(blue\|coral\|cyan\|goldenrodyellow\|gray\|green\)/ contained +syn match cssColorVal /light\(grey\|pink\|salmon\|seagreen\|skyblue\|yellow\)/ contained +syn match cssColorVal /light\(slategray\|slategrey\|steelblue\)/ contained +syn match cssColorVal /medium\(aquamarine\|blue\|orchid\|purple\|seagreen\)/ contained +syn match cssColorVal /medium\(slateblue\|springgreen\|turquoise\|violetred\)/ contained +syn keyword cssColorVal midnightblue mintcream mistyrose moccasin navajowhite contained +syn keyword cssColorVal navy oldlace olive olivedrab orange orangered orchid contained +syn match cssColorVal /pale\(goldenrod\|green\|turquoise\|violetred\)/ contained +syn keyword cssColorVal papayawhip peachpuff peru pink plum powderblue purple contained +syn keyword cssColorVal red rosybrown royalblue saddlebrown salmon sandybrown contained +syn keyword cssColorVal seagreen seashell sienna silver skyblue slateblue contained +syn keyword cssColorVal slategray slategrey snow springgreen steelblue tan contained +syn keyword cssColorVal teal thistle tomato turquoise violet wheat contained +syn keyword cssColorVal whitesmoke yellow yellowgreen contained +syn match cssColorVal "\" contained +syn keyword cssColorProp color opaticy contained +syn match cssColorProp /color-profile/ contained + +" Box +syn match cssBoxProp /\(\(margin\|padding\)-\(top\|right\|bottom\|left\)\|\(margin\|padding\)\)/ contained +syn match cssBoxProp /\(min\|max\)-\(width\|height\)/ contained +syn match cssBoxProp /box-\(align\|decoration-break\|direction\|flex-group\|flex\|lines\)/ contained +syn match cssBoxProp /box-\(ordinal-group\|orient\|pack\|shadow\|sizing\)/ contained +syn match cssBoxProp /\(outline-\(color\|offset\|style\|width\)\|outline\)/ contained +syn keyword cssBoxProp width height contained + +" Text +syn match cssTextProp /text-\(align-last\|align\|decoration\|emphasis\|height\|indent\|justify\|outline\|shadow\|transform\|wrap\|overflow\)\|text/ contained +syn match cssTextProp /\(line-stacking-\(ruby\|shift\|strategy\)\|line-stacking\|line-height\)/ contained +syn match cssTextProp /vertical-align/ contained +syn match cssTextProp /letter-spacing/ contained +syn match cssTextProp /user-select/ contained +syn match cssTextProp /white-\(space-collapse\|space\)/ contained +syn match cssTextProp /word-\(break\|spacing\|wrap\)/ contained +syn match cssTextProp "\" contained +syn match cssTextVal "\" contained +syn match cssTextVal "\" contained +syn match cssTextVal "\" contained +syn match cssTextVal /text-\(top\|bottom\)/ contained +syn keyword cssTextVal uppercase lowercase ellipsis middle contained + +" List +syn match cssListProp /\(list-style-\(type\|image\|position\)\|list-style\)/ contained +syn keyword cssListVal armenian circle disc georgian hebrew square contained +syn match cssListVal /cjk-ideographic/ contained +syn match cssListVal /\(decimal-leading-zero\|decimal\)/ contained +syn match cssListVal /\(\(hiragana\|katakana\)-iroha\|\(hiragana\|katakana\)\)/ contained +syn match cssListVal /\(lower\|upper\)-\(alpha\|latin\|roman\)/ contained +syn match cssListVal /lower-greek/ contained + +" Visual formatting +syn keyword cssVisualProp display position top right bottom left float clear clip contained +syn keyword cssVisualProp zoom visibility cursor direction outline resize contained +syn keyword cssVisualProp opacity contained +syn match cssVisualProp /z-index/ contained +syn match cssVisualProp /\(overflow-\(style\|[xy]\)\|overflow\)/ contained +syn keyword cssVisualVal inline block compact contained +syn match cssVisualVal '\' contained +syn match cssVisualVal /\(inline-\(block\|table\)\|list-item\|run-in\)/ contained +syn match cssVisualVal /table-\(row-group\|header-group\|footer-group\|row\|column-group\|column\|cell\|caption\)/ contained +syn match cssVisualVal /\-\(base-group\|text-group\|base\|text\)/ contained +syn keyword cssVisualVal static relative absolute fixed contained +syn keyword cssVisualVal ltr rtl embed bidi-override pre nowrap contained +syn keyword cssVisualVal crosshair help move pointer progress wait contained +syn keyword cssVisualVal e-resize n-resize ne-resize nw-resize s-resize se-resize sw-resize w-resize contained + +" Table +syn match cssTableProp /border-\(collapse\|spacing\)/ contained +syn match cssTableProp /\(table-layout\|caption-side\|empty-cells\)/ contained + +" Generated content +syn match cssCommonProp /counter-\(reset\|increment\)/ contained +syn keyword cssCommonProp content quotes contained + +" Print +syn match cssPrintProp /break-\(before\|after\|inside\)/ +syn match cssPrintProp /\(page-break-\(before\|after\|inside\)\|page-policy\)/ +syn keyword cssPrintProp orphans windows + +" special keywords +syn match cssSpecialProp /-\(webkit\|moz\|ms\|o\)-/ +syn match cssRuleProp /@\(media\|font-face\|charset\|import\|page\|namespace\)/ +" http://www.w3.org/TR/selectors/ +syn match cssPseudo /:\(link\|visited\|active\|hover\|focus\|before\|after\)/ +syn match cssPseudo /:\(target\|lang\|enabled\|disabled\|checked\|indeterminate\)/ +syn match cssPseudo /:\(root\|\(first\|last\|only\)-\(child\|of-type\)\|empty\)/ +syn match cssPseudo /:\(nth-last-\|nth-\)\(child\|of-type\)(\<\S\+\>)/ +syn match cssPseudo /:not(\<\S*\>)/ +syn match cssPseudo /:first-\(line\|letter\)/ +syn match cssPseudo /::\(first-\(line\|letter\)\|before\|after\|selection\)/ + +" CSS3 Advanced http://meiert.com/en/indices/css-properties/ +syn keyword cssAdvancedProp appearance azimuth binding bleed columns crop hyphens icon +syn keyword cssAdvancedProp phonemes resize richness size volumne +syn match cssAdvancedProp /\(animation-\(delay\|direction\|duration\|name\|iteration-count\|play-state\|timing-function\)\|animation\)/ +syn match cssAdvancedProp /alignment-\(adjust\|baseline\)/ +syn match cssAdvancedProp /\(backface-visibility\baseline-shift\)/ +syn match cssAdvancedProp /bookmark-\(label\|level\|state\|target\)/ +syn match cssAdvancedProp /column-\(count\|fill\|gap\|rule-\(color\|style\|width\)\|rule\|span\|width\)/ +syn match cssAdvancedProp /\(cue-\(after\|before\)\|cue\)/ +syn match cssAdvancedProp /dominant-baseline/ +syn match cssAdvancedProp /drop-initial-\(size\|value\|\(after\|before\)-\(adjust\|align\)\)/ +syn match cssAdvancedProp /\(fit-position\|fit\)/ +syn match cssAdvancedProp /\(float-offset\|hanging-punctuation\)/ +syn match cssAdvancedProp /grid-\(columns\|rows\)/ +syn match cssAdvancedProp /hyphenate-\(after\|before\|character\|lines\|resource\)/ +syn match cssAdvancedProp /image-\(orientation\|rendering\|resolution\)/ +syn match cssAdvancedProp /inline-box-align/ +syn match cssAdvancedProp /\(mark-\(after\|before\)\|mark\|marks\)/ +syn match cssAdvancedProp /marquee-\(direction\|loop\|play-count\|speed\|style\)/ +syn match cssAdvancedProp /move-to/ +syn match cssAdvancedProp /nav-\(down\|index\|left\|right\|up\)/ +syn match cssAdvancedProp /\(pause-\(after\|before\)\|pause\)/ +syn match cssAdvancedProp /\(perspective-origin\|perspective\)/ +syn match cssAdvancedProp /\(pitch-range\|pitch\)/ +syn match cssAdvancedProp /presentation-level/ +syn match cssAdvancedProp /punctuation-trim/ +syn match cssAdvancedProp /rendering-intent/ +syn match cssAdvancedProp /pointer-events/ +syn match cssAdvancedProp /\(rest-\(after\|before\)\|rest\)/ +syn match cssAdvancedProp /\(rotation-point\|rotation\)/ +syn match cssAdvancedProp /ruby-\(align\|overhang\|position\|span\)/ +syn match cssAdvancedProp /\(target-\(name\|new\|position\)\|target\)/ +syn match cssAdvancedProp /\(transform-\(origin\|style\)\|transform\)/ +syn match cssAdvancedProp /\(transition-\(delay\|duration\|property\|timing-function\)\|transition\)/ +syn match cssAdvancedProp /voice-\(balance\|duration\|family\|pitch-range\|pitch\|rate\|stress\|volume\)/ + +syn match cssAdvancedVal /\(ease-\(in\|out\|in-out\)\|ease\)/ contained + +" CSS3 Advanced value +"syn match cssAdvancedVal + + +if main_syntax == "css" + syn sync minlines=10 +endif + +" Define the default highlighting. +" For version 5.7 and earlier: only when not done already +" For version 5.8 and later: only when an item doesn't have highlighting yet +if version >= 508 || !exists("did_css_syn_inits") + if version < 508 + let did_css_syn_inits = 1 + command -nargs=+ HiLink hi link + else + command -nargs=+ HiLink hi def link + endif + + HiLink cssString String + HiLink cssComment Comment + HiLink cssTagName Statement + HiLink cssSelector Function + HiLink cssBackgroundProp StorageClass + HiLink cssTableProp StorageClass + HiLink cssBorderProp StorageClass + HiLink cssFontProp StorageClass + HiLink cssColorProp StorageClass + HiLink cssBoxProp StorageClass + HiLink cssTextProp StorageClass + HiLink cssListProp StorageClass + HiLink cssVisualProp StorageClass + HiLink cssAdvancedProp StorageClass + HiLink cssCommonProp StorageClass + HiLink cssSpecialProp Special + HiLink cssImportant Special + HiLink cssRuleProp PreProc + HiLink cssPseudo PreProc + + HiLink cssColorVal Constant + HiLink cssCommonVal Type + HiLink cssFontVal Type + HiLink cssListVal Type + HiLink cssTextVal Type + HiLink cssVisualVal Type + HiLink cssBorderVal Type + HiLink cssBackgroundVal Type + HiLink cssFuncVal Function + HiLink cssAdvancedVal Function + + HiLink cssValueLength Number + HiLink cssValueInteger Number + HiLink cssValueNumber Number + HiLink cssValueAngle Number + HiLink cssValueTime Number + HiLink cssValueFrequency Number + delcommand HiLink +endif + +" let b:current_syntax = "css" +" +if main_syntax == 'css' + unlet main_syntax +endif + +" Vim syntax file +" Language: Stylus +" Maintainer: Marc Harter +" Filenames: *.styl, *.stylus +" Based On: Tim Pope (sass.vim) + +syn case ignore + +syn cluster stylusCssSelectors contains=cssTagName,cssSelector,cssPseudo +syn cluster stylusCssValues contains=cssValueLength,cssValueInteger,cssValueNumber,cssValueAngle,cssValueTime,cssValueFrequency,cssColorVal,cssCommonVal,cssFontVal,cssListVal,cssTextVal,cssVisualVal,cssBorderVal,cssBackgroundVal,cssFuncVal,cssAdvancedVal +syn cluster stylusCssProperties contains=cssBackgroundProp,cssTableProp,cssBorderProp,cssFontProp,cssColorProp,cssBoxProp,cssTextProp,cssListProp,cssVisualProp,cssAdvancedProp,cssCommonProp,cssSpecialProp + +syn match stylusVariable "$\?[[:alnum:]_-]\+" +syn match stylusVariableAssignment "\%([[:alnum:]_-]\+\s*\)\@<==" nextgroup=stylusCssAttribute,stylusVariable skipwhite + +syn match stylusProperty "\%([{};]\s*\|^\)\@<=\%([[:alnum:]-]\|#{[^{}]*}\)\+:" contains=@stylusCssProperties,@stylusCssSelectors skipwhite nextgroup=stylusCssAttribute contained containedin=cssDefineBlock +syn match stylusProperty "^\s*\zs\s\%(\%([[:alnum:]-]\|#{[^{}]*}\)\+[ :]\|:[[:alnum:]-]\+\)"hs=s+1 contains=@stylusCssProperties,@stylusCssSelectors skipwhite nextgroup=stylusCssAttribute +syn match stylusProperty "^\s*\zs\s\%(:\=[[:alnum:]-]\+\s*=\)"hs=s+1 contains=@stylusCssProperties,@stylusCssSelectors skipwhite nextgroup=stylusCssAttribute + +syn match stylusCssAttribute +\%("\%([^"]\|\\"\)*"\|'\%([^']\|\\'\)*'\|#{[^{}]*}\|[^{};]\)*+ contained contains=@stylusCssValues,cssImportant,stylusFunction,stylusVariable,stylusControl,stylusUserFunction,stylusInterpolation,cssString,stylusComment,cssComment + +syn match stylusInterpolation %{[[:alnum:]_-]\+}% + +syn match stylusFunction "\<\%(red\|green\|blue\|alpha\|dark\|light\)\>(\@=" contained +syn match stylusFunction "\<\%(hue\|saturation\|lightness\|push\|unshift\|typeof\|unit\|match\)\>(\@=" contained +syn match stylusFunction "\<\%(hsla\|hsl\|rgba\|rgb\|lighten\|darken\)\>(\@=" contained +syn match stylusFunction "\<\%(abs\|ceil\|floor\|round\|min\|max\|even\|odd\|sum\|avg\|sin\|cos\|join\)\>(\@=" contained +syn match stylusFunction "\<\%(desaturate\|saturate\|invert\|unquote\|quote\|s\)\>(\@=" contained +syn match stylusFunction "\<\%(operate\|length\|warn\|error\|last\|p\|\)\>(\@=" contained +syn match stylusFunction "\<\%(opposite-position\|image-size\|add-property\)\>(\@=" contained + +syn keyword stylusVariable null true false arguments +syn keyword stylusControl if else unless for in return + +syn match stylusImport "@\%(import\|require\)" nextgroup=stylusImportList +syn match stylusImportList "[^;]\+" contained contains=cssString.*,cssMediaType,cssURL + +syn match stylusAmpersand "&" +syn match stylusClass "[[:alnum:]_-]\+" contained +syn match stylusClassChar "\.[[:alnum:]_-]\@=" nextgroup=stylusClass +syn match stylusEscape "^\s*\zs\\" +syn match stylusId "[[:alnum:]_-]\+" contained +syn match stylusIdChar "#[[:alnum:]_-]\@=" nextgroup=stylusId + +syn region stylusComment start="//" end="$" contains=cssTodo,@Spell fold + +hi def link stylusComment Comment +hi def link stylusVariable Identifier +hi def link stylusControl PreProc +hi def link stylusFunction Function +hi def link stylusInterpolation Delimiter + +hi def link stylusAmpersand Character +hi def link stylusClass Type +hi def link stylusClassChar Special +hi def link stylusEscape Special +hi def link stylusId Identifier +hi def link stylusIdChar Special + +let b:current_syntax = "stylus" + +" vim:set sw=2: diff --git a/vim/bundle/vim-stylus/test.styl b/vim/bundle/vim-stylus/test.styl new file mode 100644 index 0000000..2acc0da --- /dev/null +++ b/vim/bundle/vim-stylus/test.styl @@ -0,0 +1,80 @@ +@import "nib" +@require "../../lib/*" + +// comment test + +padding-overloaded = true; +padding = 2px; +primary-color = red; +$hello = world; + +if padding-overloaded + padding(x,y) + margin 15px + +border-radius() + -webkit-border-radius arguments // comment test + -moz-border-radius arguments //comment test + border-radius arguments + pointer-events arguments + +#myid { + -moz-transform: scale(1.2); + font-family: arial; +} + +.a-class + border-radius border-radius() + -moz-transform scale(1.2) + +body a:hover + font 12px/1.4 "Lucida Grande", Arial, sans-serif + background black !important + text-shadow 2px 2px 2px #fff + td a:hover + font 12px + td + font 12px + +[name="myprop"] + background rgba(255,255,255,0.5) + +#container + user-select none + border-radius 5px + color #000 + float left + display: block + background url('http://i.imgur.com/Q4RObrY.jpg') + +#myid + font 12px/1.4 "Lucida Grande", Arial, sans-serif + +h1 { + color: red; +} + +body a:hover + font 12px/1.4 "Lucida Grande", Arial, sans-serif + background black !important + background rgb(255,255,0) + border-top 1px solid rgb(255,255,0) + text-shadow 2px 2px #000 + color #ccc + +#butter.gump tr + border min(2px) + min-width min(2px) + color red(10) lighten(he) border-radius() image-size() + border-radius border-radius() + +form input { + padding: 5px; + border: 1px solid; + border-radius: 5px; +} + +vendor(prop, args) + {prop} args + -moz-{prop} args + -webkit-{prop} args diff --git a/vim/bundle/vim-surround/.gitignore b/vim/bundle/vim-surround/.gitignore new file mode 100644 index 0000000..0a56e3f --- /dev/null +++ b/vim/bundle/vim-surround/.gitignore @@ -0,0 +1 @@ +/doc/tags diff --git a/vim/bundle/vim-surround/README.markdown b/vim/bundle/vim-surround/README.markdown new file mode 100644 index 0000000..fef61a8 --- /dev/null +++ b/vim/bundle/vim-surround/README.markdown @@ -0,0 +1,97 @@ +surround.vim +============ + +Surround.vim is all about "surroundings": parentheses, brackets, quotes, +XML tags, and more. The plugin provides mappings to easily delete, +change and add such surroundings in pairs. + +It's easiest to explain with examples. Press `cs"'` inside + + "Hello world!" + +to change it to + + 'Hello world!' + +Now press `cs'` to change it to + + Hello world! + +To go full circle, press `cst"` to get + + "Hello world!" + +To remove the delimiters entirely, press `ds"`. + + Hello world! + +Now with the cursor on "Hello", press `ysiw]` (`iw` is a text object). + + [Hello] world! + +Let's make that braces and add some space (use `}` instead of `{` for no +space): `cs]{` + + { Hello } world! + +Now wrap the entire line in parentheses with `yssb` or `yss)`. + + ({ Hello } world!) + +Revert to the original text: `ds{ds)` + + Hello world! + +Emphasize hello: `ysiw` + + Hello world! + +Finally, let's try out visual mode. Press a capital V (for linewise +visual mode) followed by `S

`. + +

+ Hello world! +

+ +This plugin is very powerful for HTML and XML editing, a niche which +currently seems underfilled in Vim land. (As opposed to HTML/XML +*inserting*, for which many plugins are available). Adding, changing, +and removing pairs of tags simultaneously is a breeze. + +The `.` command will work with `ds`, `cs`, and `yss` if you install +[repeat.vim](https://github.com/tpope/vim-repeat). + +Installation +------------ + +If you don't have a preferred installation method, I recommend +installing [pathogen.vim](https://github.com/tpope/vim-pathogen), and +then simply copy and paste: + + cd ~/.vim/bundle + git clone git://github.com/tpope/vim-surround.git + +Once help tags have been generated, you can view the manual with +`:help surround`. + +Contributing +------------ + +See the contribution guidelines for +[pathogen.vim](https://github.com/tpope/vim-pathogen#readme). + +Self-Promotion +-------------- + +Like surround.vim? Follow the repository on +[GitHub](https://github.com/tpope/vim-surround) and vote for it on +[vim.org](http://www.vim.org/scripts/script.php?script_id=1697). And if +you're feeling especially charitable, follow [tpope](http://tpo.pe/) on +[Twitter](http://twitter.com/tpope) and +[GitHub](https://github.com/tpope). + +License +------- + +Copyright (c) Tim Pope. Distributed under the same terms as Vim itself. +See `:help license`. diff --git a/vim/bundle/vim-surround/doc/surround.txt b/vim/bundle/vim-surround/doc/surround.txt new file mode 100644 index 0000000..30a642a --- /dev/null +++ b/vim/bundle/vim-surround/doc/surround.txt @@ -0,0 +1,205 @@ +*surround.txt* Plugin for deleting, changing, and adding "surroundings" + +Author: Tim Pope +License: Same terms as Vim itself (see |license|) + +This plugin is only available if 'compatible' is not set. + +INTRODUCTION *surround* + +This plugin is a tool for dealing with pairs of "surroundings." Examples +of surroundings include parentheses, quotes, and HTML tags. They are +closely related to what Vim refers to as |text-objects|. Provided +are mappings to allow for removing, changing, and adding surroundings. + +Details follow on the exact semantics, but first, consider the following +examples. An asterisk (*) is used to denote the cursor position. + + Old text Command New text ~ + "Hello *world!" ds" Hello world! + [123+4*56]/2 cs]) (123+456)/2 + "Look ma, I'm *HTML!" cs" Look ma, I'm HTML! + if *x>3 { ysW( if ( x>3 ) { + my $str = *whee!; vllllS' my $str = 'whee!'; + +While a few features of this plugin will work in older versions of Vim, +Vim 7 is recommended for full functionality. + +MAPPINGS *surround-mappings* + +Delete surroundings is *ds* . The next character given determines the target +to delete. The exact nature of the target is explained in |surround-targets| +but essentially it is the last character of a |text-object|. This mapping +deletes the difference between the "i"nner object and "a"n object. This is +easiest to understand with some examples: + + Old text Command New text ~ + "Hello *world!" ds" Hello world! + (123+4*56)/2 ds) 123+456/2 +
Yo!*
dst Yo! + +Change surroundings is *cs* . It takes two arguments, a target like with +|ds|, and a replacement. Details about the second argument can be found +below in |surround-replacements|. Once again, examples are in order. + + Old text Command New text ~ + "Hello *world!" cs"' 'Hello world!' + "Hello *world!" cs" Hello world! + (123+4*56)/2 cs)] [123+456]/2 + (123+4*56)/2 cs)[ [ 123+456 ]/2 +
Yo!*
cst

Yo!

+ +*ys* takes a valid Vim motion or text object as the first object, and wraps +it using the second argument as with |cs|. (It's a stretch, but a good +mnemonic for "ys" is "you surround".) + + Old text Command New text ~ + Hello w*orld! ysiw) Hello (world)! + +As a special case, *yss* operates on the current line, ignoring leading +whitespace. + + Old text Command New text ~ + Hello w*orld! yssB {Hello world!} + +There is also *yS* and *ySS* which indent the surrounded text and place it +on a line of its own. + +In visual mode, a simple "S" with an argument wraps the selection. This is +referred to as the *vS* mapping, although ordinarily there will be +additional keystrokes between the v and S. In linewise visual mode, the +surroundings are placed on separate lines and indented. In blockwise visual +mode, each line is surrounded. + +A "gS" in visual mode, known as *vgS* , behaves similarly. In linewise visual +mode, the automatic indenting is suppressed. In blockwise visual mode, this +enables surrounding past the end of the line with 'virtualedit' set (there +seems to be no way in Vim Script to differentiate between a jagged end of line +selection and a virtual block selected past the end of the line, so two maps +were needed). + + *i_CTRL-G_s* *i_CTRL-G_S* +Finally, there is an experimental insert mode mapping on s and . +Beware that the latter won't work on terminals with flow control (if you +accidentally freeze your terminal, use to unfreeze it). The mapping +inserts the specified surroundings and puts the cursor between them. If, +immediately after the mapping and before the replacement, a second or +carriage return is pressed, the prefix, cursor, and suffix will be placed on +three separate lines. S (not s) also exhibits this behavior. + +TARGETS *surround-targets* + +The |ds| and |cs| commands both take a target as their first argument. The +possible targets are based closely on the |text-objects| provided by Vim. +All targets are currently just one character. + +Eight punctuation marks, (, ), {, }, [, ], <, and >, represent themselves +and their counterparts. If the opening mark is used, contained whitespace is +also trimmed. The targets b, B, r, and a are aliases for ), }, ], and > +(the first two mirror Vim; the second two are completely arbitrary and +subject to change). + +Three quote marks, ', ", `, represent themselves, in pairs. They are only +searched for on the current line. + +A t is a pair of HTML or XML tags. See |tag-blocks| for details. Remember +that you can specify a numerical argument if you want to get to a tag other +than the innermost one. + +The letters w, W, and s correspond to a |word|, a |WORD|, and a |sentence|, +respectively. These are special in that they have nothing to delete, and +used with |ds| they are a no-op. With |cs|, one could consider them a +slight shortcut for ysi (cswb == ysiwb, more or less). + +A p represents a |paragraph|. This behaves similarly to w, W, and s above; +however, newlines are sometimes added and/or removed. + +REPLACEMENTS *surround-replacements* + +A replacement argument is a single character, and is required by |cs|, |ys|, +and |vS|. Undefined replacement characters (with the exception of alphabetic +characters) default to placing themselves at the beginning and end of the +destination, which can be useful for characters like / and |. + +If either ), }, ], or > is used, the text is wrapped in the appropriate pair +of characters. Similar behavior can be found with (, {, and [ (but not <), +which append an additional space to the inside. Like with the targets above, +b, B, r, and a are aliases for ), }, ], and >. To fulfill the common need for +code blocks in C-style languages, (which is really ) adds braces on +lines separate from the content. + +If t or < is used, Vim prompts for an HTML/XML tag to insert. You may specify +attributes here and they will be stripped from the closing tag. End your +input by pressing or >. If is used, the tags will appear on lines +by themselves. + +If s is used, a leading but not trailing space is added. This is useful for +removing parentheses from a function call with csbs. + +CUSTOMIZING *surround-customizing* + +The following adds a potential replacement on "-" (ASCII 45) in PHP files. +(To determine the ASCII code to use, :echo char2nr("-")). The carriage +return will be replaced by the original text. +> + autocmd FileType php let b:surround_45 = "" +< +This can be used in a PHP file as in the following example. + + Old text Command New text ~ + print "Hello *world!" yss- + +Additionally, one can use a global variable for globally available +replacements. +> + let g:surround_45 = "<% \r %>" + let g:surround_61 = "<%= \r %>" +< +Advanced, experimental, and subject to change: One can also prompt for +replacement text. The syntax for this is to surround the replacement in pairs +of low numbered control characters. If this sounds confusing, that's because +it is (but it makes the parsing easy). Consider the following example for a +LaTeX environment on the "l" replacement. +> + let g:surround_108 = "\\begin{\1environment: \1}\r\\end{\1\1}" +< +When this replacement is used, the user is prompted with an "environment: " +prompt for input. This input is inserted between each set of \1's. +Additional inputs up to \7 can be used. + +Furthermore, one can specify a regular expression substitution to apply. +> + let g:surround_108 = "\\begin{\1environment: \1}\r\\end{\1\r}.*\r\1}" +< +This will remove anything after the first } in the input when the text is +placed within the \end{} slot. The first \r marks where the pattern begins, +and the second where the replacement text begins. + +Here's a second example for creating an HTML
. The substitution cleverly +prompts for an id, but only adds id="" if it is non-blank. You may have to +read this one a few times slowly before you understand it. +> + let g:surround_{char2nr("d")} = "\r
" +< +Inputting text replacements is a proof of concept at this point. The ugly, +unintuitive interface and the brevity of the documentation reflect this. + +Finally, It is possible to always append a string to surroundings in insert +mode (and only insert mode). This is useful with certain plugins and mappings +that allow you to jump to such markings. +> + let g:surround_insert_tail = "<++>" +< +ISSUES *surround-issues* + +Vim could potentially get confused when deleting/changing occurs at the very +end of the line. Please report any repeatable instances of this. + +Do we need to use |inputsave()|/|inputrestore()| with the tag replacement? + +Indenting is handled haphazardly. Need to decide the most appropriate +behavior and implement it. Right now one can do :let b:surround_indent = 1 +(or the global equivalent) to enable automatic re-indenting by Vim via |=|; +should this be the default? + + vim:tw=78:ts=8:ft=help:norl: diff --git a/vim/bundle/vim-surround/plugin/surround.vim b/vim/bundle/vim-surround/plugin/surround.vim new file mode 100644 index 0000000..148a5c9 --- /dev/null +++ b/vim/bundle/vim-surround/plugin/surround.vim @@ -0,0 +1,590 @@ +" surround.vim - Surroundings +" Author: Tim Pope +" Version: 2.0 +" GetLatestVimScripts: 1697 1 :AutoInstall: surround.vim + +if exists("g:loaded_surround") || &cp || v:version < 700 + finish +endif +let g:loaded_surround = 1 + +" Input functions {{{1 + +function! s:getchar() + let c = getchar() + if c =~ '^\d\+$' + let c = nr2char(c) + endif + return c +endfunction + +function! s:inputtarget() + let c = s:getchar() + while c =~ '^\d\+$' + let c .= s:getchar() + endwhile + if c == " " + let c .= s:getchar() + endif + if c =~ "\\|\\|\0" + return "" + else + return c + endif +endfunction + +function! s:inputreplacement() + let c = s:getchar() + if c == " " + let c .= s:getchar() + endif + if c =~ "\" || c =~ "\" + return "" + else + return c + endif +endfunction + +function! s:beep() + exe "norm! \" + return "" +endfunction + +function! s:redraw() + redraw + return "" +endfunction + +" }}}1 + +" Wrapping functions {{{1 + +function! s:extractbefore(str) + if a:str =~ '\r' + return matchstr(a:str,'.*\ze\r') + else + return matchstr(a:str,'.*\ze\n') + endif +endfunction + +function! s:extractafter(str) + if a:str =~ '\r' + return matchstr(a:str,'\r\zs.*') + else + return matchstr(a:str,'\n\zs.*') + endif +endfunction + +function! s:fixindent(str,spc) + let str = substitute(a:str,'\t',repeat(' ',&sw),'g') + let spc = substitute(a:spc,'\t',repeat(' ',&sw),'g') + let str = substitute(str,'\(\n\|\%^\).\@=','\1'.spc,'g') + if ! &et + let str = substitute(str,'\s\{'.&ts.'\}',"\t",'g') + endif + return str +endfunction + +function! s:process(string) + let i = 0 + for i in range(7) + let repl_{i} = '' + let m = matchstr(a:string,nr2char(i).'.\{-\}\ze'.nr2char(i)) + if m != '' + let m = substitute(strpart(m,1),'\r.*','','') + let repl_{i} = input(substitute(m,':\s*$','','').': ') + endif + endfor + let s = "" + let i = 0 + while i < strlen(a:string) + let char = strpart(a:string,i,1) + if char2nr(char) < 8 + let next = stridx(a:string,char,i+1) + if next == -1 + let s .= char + else + let insertion = repl_{char2nr(char)} + let subs = strpart(a:string,i+1,next-i-1) + let subs = matchstr(subs,'\r.*') + while subs =~ '^\r.*\r' + let sub = matchstr(subs,"^\r\\zs[^\r]*\r[^\r]*") + let subs = strpart(subs,strlen(sub)+1) + let r = stridx(sub,"\r") + let insertion = substitute(insertion,strpart(sub,0,r),strpart(sub,r+1),'') + endwhile + let s .= insertion + let i = next + endif + else + let s .= char + endif + let i += 1 + endwhile + return s +endfunction + +function! s:wrap(string,char,type,...) + let keeper = a:string + let newchar = a:char + let s:input = "" + let type = a:type + let linemode = type ==# 'V' ? 1 : 0 + let special = a:0 ? a:1 : 0 + let before = "" + let after = "" + if type ==# "V" + let initspaces = matchstr(keeper,'\%^\s*') + else + let initspaces = matchstr(getline('.'),'\%^\s*') + endif + let pairs = "b()B{}r[]a<>" + let extraspace = "" + if newchar =~ '^ ' + let newchar = strpart(newchar,1) + let extraspace = ' ' + endif + let idx = stridx(pairs,newchar) + if newchar == ' ' + let before = '' + let after = '' + elseif exists("b:surround_".char2nr(newchar)) + let all = s:process(b:surround_{char2nr(newchar)}) + let before = s:extractbefore(all) + let after = s:extractafter(all) + elseif exists("g:surround_".char2nr(newchar)) + let all = s:process(g:surround_{char2nr(newchar)}) + let before = s:extractbefore(all) + let after = s:extractafter(all) + elseif newchar ==# "p" + let before = "\n" + let after = "\n\n" + elseif newchar ==# 's' + let before = ' ' + let after = '' + elseif newchar ==# ':' + let before = ':' + let after = '' + elseif newchar =~# "[tT\<,]" + let dounmapp = 0 + let dounmapb = 0 + if !maparg(">","c") + let dounmapb = 1 + " Hide from AsNeeded + exe "cn"."oremap > " + endif + let default = "" + if newchar ==# "T" + if !exists("s:lastdel") + let s:lastdel = "" + endif + let default = matchstr(s:lastdel,'<\zs.\{-\}\ze>') + endif + let tag = input("<",default) + echo "<".substitute(tag,'>*$','>','') + if dounmapb + silent! cunmap > + endif + let s:input = tag + if tag != "" + let tag = substitute(tag,'>*$','','') + let s:input = tag . '>' + let before = '<'.tag.'>' + if tag =~ '/$' + let after = '' + else + let after = '' + endif + if newchar == "\" || newchar == "," + if type ==# "v" || type ==# "V" + let before .= "\n\t" + endif + if type ==# "v" + let after = "\n". after + endif + endif + endif + elseif newchar ==# 'l' || newchar == '\' + " LaTeX + let env = input('\begin{') + let env = '{' . env + let env .= s:closematch(env) + echo '\begin'.env + if env != "" + let before = '\begin'.env + let after = '\end'.matchstr(env,'[^}]*').'}' + endif + elseif newchar ==# 'f' || newchar ==# 'F' + let fnc = input('function: ') + if fnc != "" + let s:input = fnc."\" + let before = substitute(fnc,'($','','').'(' + let after = ')' + if newchar ==# 'F' + let before .= ' ' + let after = ' ' . after + endif + endif + elseif newchar ==# "\" + let fnc = input('function: ') + let s:input = fnc."\" + let before = '('.fnc.' ' + let after = ')' + elseif idx >= 0 + let spc = (idx % 3) == 1 ? " " : "" + let idx = idx / 3 * 3 + let before = strpart(pairs,idx+1,1) . spc + let after = spc . strpart(pairs,idx+2,1) + elseif newchar == "\" || newchar == "\" + let before = "{\n\t" + let after = "\n}" + elseif newchar !~ '\a' + let before = newchar + let after = newchar + else + let before = '' + let after = '' + endif + let after = substitute(after ,'\n','\n'.initspaces,'g') + if type ==# 'V' || (special && type ==# "v") + let before = substitute(before,' \+$','','') + let after = substitute(after ,'^ \+','','') + if after !~ '^\n' + let after = initspaces.after + endif + if keeper !~ '\n$' && after !~ '^\n' + let keeper .= "\n" + elseif keeper =~ '\n$' && after =~ '^\n' + let after = strpart(after,1) + endif + if before !~ '\n\s*$' + let before .= "\n" + if special + let before .= "\t" + endif + endif + endif + if type ==# 'V' + let before = initspaces.before + endif + if before =~ '\n\s*\%$' + if type ==# 'v' + let keeper = initspaces.keeper + endif + let padding = matchstr(before,'\n\zs\s\+\%$') + let before = substitute(before,'\n\s\+\%$','\n','') + let keeper = s:fixindent(keeper,padding) + endif + if type ==# 'V' + let keeper = before.keeper.after + elseif type =~ "^\" + " Really we should be iterating over the buffer + let repl = substitute(before,'[\\~]','\\&','g').'\1'.substitute(after,'[\\~]','\\&','g') + let repl = substitute(repl,'\n',' ','g') + let keeper = substitute(keeper."\n",'\(.\{-\}\)\(\n\)',repl.'\n','g') + let keeper = substitute(keeper,'\n\%$','','') + else + let keeper = before.extraspace.keeper.extraspace.after + endif + return keeper +endfunction + +function! s:wrapreg(reg,char,...) + let orig = getreg(a:reg) + let type = substitute(getregtype(a:reg),'\d\+$','','') + let special = a:0 ? a:1 : 0 + let new = s:wrap(orig,a:char,type,special) + call setreg(a:reg,new,type) +endfunction +" }}}1 + +function! s:insert(...) " {{{1 + " Optional argument causes the result to appear on 3 lines, not 1 + let linemode = a:0 ? a:1 : 0 + let char = s:inputreplacement() + while char == "\" || char == "\" + " TODO: use total count for additional blank lines + let linemode += 1 + let char = s:inputreplacement() + endwhile + if char == "" + return "" + endif + let cb_save = &clipboard + set clipboard-=unnamed clipboard-=unnamedplus + let reg_save = @@ + call setreg('"',"\r",'v') + call s:wrapreg('"',char,linemode) + " If line mode is used and the surrounding consists solely of a suffix, + " remove the initial newline. This fits a use case of mine but is a + " little inconsistent. Is there anyone that would prefer the simpler + " behavior of just inserting the newline? + if linemode && match(getreg('"'),'^\n\s*\zs.*') == 0 + call setreg('"',matchstr(getreg('"'),'^\n\s*\zs.*'),getregtype('"')) + endif + " This can be used to append a placeholder to the end + if exists("g:surround_insert_tail") + call setreg('"',g:surround_insert_tail,"a".getregtype('"')) + endif + if col('.') >= col('$') + norm! ""p + else + norm! ""P + endif + if linemode + call s:reindent() + endif + norm! `] + call search('\r','bW') + let @@ = reg_save + let &clipboard = cb_save + return "\" +endfunction " }}}1 + +function! s:reindent() " {{{1 + if exists("b:surround_indent") ? b:surround_indent : (!exists("g:surround_indent") || g:surround_indent) + silent norm! '[='] + endif +endfunction " }}}1 + +function! s:dosurround(...) " {{{1 + let scount = v:count1 + let char = (a:0 ? a:1 : s:inputtarget()) + let spc = "" + if char =~ '^\d\+' + let scount = scount * matchstr(char,'^\d\+') + let char = substitute(char,'^\d\+','','') + endif + if char =~ '^ ' + let char = strpart(char,1) + let spc = 1 + endif + if char == 'a' + let char = '>' + endif + if char == 'r' + let char = ']' + endif + let newchar = "" + if a:0 > 1 + let newchar = a:2 + if newchar == "\" || newchar == "\" || newchar == "" + return s:beep() + endif + endif + let cb_save = &clipboard + set clipboard-=unnamed clipboard-=unnamedplus + let append = "" + let original = getreg('"') + let otype = getregtype('"') + call setreg('"',"") + let strcount = (scount == 1 ? "" : scount) + if char == '/' + exe 'norm! '.strcount.'[/d'.strcount.']/' + elseif char =~# '[[:punct:]]' && char !~# '[][(){}<>"''`]' + exe 'norm! T'.char + if getline('.')[col('.')-1] == char + exe 'norm! l' + endif + exe 'norm! dt'.char + else + exe 'norm! d'.strcount.'i'.char + endif + let keeper = getreg('"') + let okeeper = keeper " for reindent below + if keeper == "" + call setreg('"',original,otype) + let &clipboard = cb_save + return "" + endif + let oldline = getline('.') + let oldlnum = line('.') + if char ==# "p" + call setreg('"','','V') + elseif char ==# "s" || char ==# "w" || char ==# "W" + " Do nothing + call setreg('"','') + elseif char =~ "[\"'`]" + exe "norm! i \d2i".char + call setreg('"',substitute(getreg('"'),' ','','')) + elseif char == '/' + norm! "_x + call setreg('"','/**/',"c") + let keeper = substitute(substitute(keeper,'^/\*\s\=','',''),'\s\=\*$','','') + elseif char =~# '[[:punct:]]' && char !~# '[][(){}<>]' + exe 'norm! F'.char + exe 'norm! df'.char + else + " One character backwards + call search('\m.', 'bW') + exe "norm! da".char + endif + let removed = getreg('"') + let rem2 = substitute(removed,'\n.*','','') + let oldhead = strpart(oldline,0,strlen(oldline)-strlen(rem2)) + let oldtail = strpart(oldline, strlen(oldline)-strlen(rem2)) + let regtype = getregtype('"') + if char =~# '[\[({Dsurround".char,scount) + else + silent! call repeat#set("\Csurround".char.newchar.s:input,scount) + endif +endfunction " }}}1 + +function! s:changesurround() " {{{1 + let a = s:inputtarget() + if a == "" + return s:beep() + endif + let b = s:inputreplacement() + if b == "" + return s:beep() + endif + call s:dosurround(a,b) +endfunction " }}}1 + +function! s:opfunc(type,...) " {{{1 + let char = s:inputreplacement() + if char == "" + return s:beep() + endif + let reg = '"' + let sel_save = &selection + let &selection = "inclusive" + let cb_save = &clipboard + set clipboard-=unnamed clipboard-=unnamedplus + let reg_save = getreg(reg) + let reg_type = getregtype(reg) + let type = a:type + if a:type == "char" + silent exe 'norm! v`[o`]"'.reg.'y' + let type = 'v' + elseif a:type == "line" + silent exe 'norm! `[V`]"'.reg.'y' + let type = 'V' + elseif a:type ==# "v" || a:type ==# "V" || a:type ==# "\" + let &selection = sel_save + let ve = &virtualedit + if !(a:0 && a:1) + set virtualedit= + endif + silent exe 'norm! gv"'.reg.'y' + let &virtualedit = ve + elseif a:type =~ '^\d\+$' + let type = 'v' + silent exe 'norm! ^v'.a:type.'$h"'.reg.'y' + if mode() ==# 'v' + norm! v + return s:beep() + endif + else + let &selection = sel_save + let &clipboard = cb_save + return s:beep() + endif + let keeper = getreg(reg) + if type ==# "v" && a:type !=# "v" + let append = matchstr(keeper,'\_s\@Y".(a:0 && a:1 ? "S" : "s")."surround".char.s:input,a:type) + else + silent! call repeat#set("\SurroundRepeat".char.s:input) + endif +endfunction + +function! s:opfunc2(arg) + call s:opfunc(a:arg,1) +endfunction " }}}1 + +function! s:closematch(str) " {{{1 + " Close an open (, {, [, or < on the command line. + let tail = matchstr(a:str,'.[^\[\](){}<>]*$') + if tail =~ '^\[.\+' + return "]" + elseif tail =~ '^(.\+' + return ")" + elseif tail =~ '^{.\+' + return "}" + elseif tail =~ '^<.+' + return ">" + else + return "" + endif +endfunction " }}}1 + +nnoremap SurroundRepeat . +nnoremap Dsurround :call dosurround(inputtarget()) +nnoremap Csurround :call changesurround() +nnoremap Yssurround :call opfunc(v:count1) +nnoremap YSsurround :call opfunc2(v:count1) +" discards the numerical argument but there's not much we can do with it +nnoremap Ysurround :set opfunc=opfuncg@ +nnoremap YSurround :set opfunc=opfunc2g@ +vnoremap VSurround :call opfunc(visualmode(),visualmode() ==# 'V' ? 1 : 0) +vnoremap VgSurround :call opfunc(visualmode(),visualmode() ==# 'V' ? 0 : 1) +inoremap Isurround =insert() +inoremap ISurround =insert(1) + +if !exists("g:surround_no_mappings") || ! g:surround_no_mappings + nmap ds Dsurround + nmap cs Csurround + nmap ys Ysurround + nmap yS YSurround + nmap yss Yssurround + nmap ySs YSsurround + nmap ySS YSsurround + xmap S VSurround + xmap gS VgSurround + if !exists("g:surround_no_insert_mappings") || ! g:surround_no_insert_mappings + if !hasmapto("Isurround","i") && "" == mapcheck("","i") + imap Isurround + endif + imap s Isurround + imap S ISurround + endif +endif + +" vim:set ft=vim sw=2 sts=2 et: diff --git a/vim/colors/wombat.vim b/vim/colors/wombat.vim new file mode 100644 index 0000000..9ad1e56 --- /dev/null +++ b/vim/colors/wombat.vim @@ -0,0 +1,51 @@ +" Maintainer: Lars H. Nielsen (dengmao@gmail.com) +" Last Change: January 22 2007 + +set background=dark + +hi clear + +if exists("syntax_on") + syntax reset +endif + +let colors_name = "wombat" + + +" Vim >= 7.0 specific colors +if version >= 700 + hi CursorLine guibg=#2d2d2d + hi CursorColumn guibg=#2d2d2d + hi MatchParen guifg=#f6f3e8 guibg=#857b6f gui=bold + hi Pmenu guifg=#f6f3e8 guibg=#444444 + hi PmenuSel guifg=#000000 guibg=#cae682 +endif + +" General colors +hi Cursor guifg=NONE guibg=#656565 gui=none +hi Normal guifg=#f6f3e8 guibg=#242424 gui=none +hi NonText guifg=#808080 guibg=#303030 gui=none +hi LineNr guifg=#857b6f guibg=#000000 gui=none +hi StatusLine guifg=#f6f3e8 guibg=#444444 gui=italic +hi StatusLineNC guifg=#857b6f guibg=#444444 gui=none +hi VertSplit guifg=#444444 guibg=#444444 gui=none +hi Folded guibg=#384048 guifg=#a0a8b0 gui=none +hi Title guifg=#f6f3e8 guibg=NONE gui=bold +hi Visual guifg=#f6f3e8 guibg=#444444 gui=none +hi SpecialKey guifg=#808080 guibg=#343434 gui=none + +" Syntax highlighting +hi Comment guifg=#99968b gui=italic +hi Todo guifg=#8f8f8f gui=italic +hi Constant guifg=#e5786d gui=none +hi String guifg=#95e454 gui=italic +hi Identifier guifg=#cae682 gui=none +hi Function guifg=#cae682 gui=none +hi Type guifg=#cae682 gui=none +hi Statement guifg=#8ac6f2 gui=none +hi Keyword guifg=#8ac6f2 gui=none +hi PreProc guifg=#e5786d gui=none +hi Number guifg=#e5786d gui=none +hi Special guifg=#e7f6da gui=none + + -- 2.51.2