aboutsummaryrefslogtreecommitdiff
path: root/vim/plugin
diff options
context:
space:
mode:
authorBen Beltran <ben@freshout.us>2012-10-08 11:44:10 -0500
committerBen Beltran <ben@freshout.us>2012-10-08 11:44:10 -0500
commit0d23b6e515a01a5782532351821ebfa11f3d6cf2 (patch)
treeaa395b7e50ccb533d6b48b809016ac06f2d5bc8c /vim/plugin
parenta91731eac872b7837c2821341db5888702125cef (diff)
Add vim again :)
Diffstat (limited to 'vim/plugin')
-rw-r--r--vim/plugin/.DS_Storebin0 -> 6148 bytes
-rw-r--r--vim/plugin/31-create-scala.vim55
-rw-r--r--vim/plugin/AlignMapsPlugin.vim242
-rw-r--r--vim/plugin/AlignPlugin.vim41
-rwxr-xr-xvim/plugin/EasyMotion.vim73
-rw-r--r--vim/plugin/NERD_commenter.vim2790
-rw-r--r--vim/plugin/NERD_tree.vim4049
-rw-r--r--vim/plugin/SearchComplete.vim100
-rw-r--r--vim/plugin/ZoomWinPlugin.vim49
-rw-r--r--vim/plugin/ack.vim79
-rw-r--r--vim/plugin/cecutil.vim510
-rw-r--r--vim/plugin/color_sample_pack.vim164
-rw-r--r--vim/plugin/conque_term.vim93
-rw-r--r--vim/plugin/delimitMate.vim434
-rw-r--r--vim/plugin/endwise.vim134
-rw-r--r--vim/plugin/fugitive.vim2220
-rw-r--r--vim/plugin/gist.vim826
-rw-r--r--vim/plugin/indent-object.vim224
-rw-r--r--vim/plugin/rails.vim339
-rw-r--r--vim/plugin/searchfold_0.9.vim319
-rw-r--r--vim/plugin/showmarks.vim507
-rw-r--r--vim/plugin/snipMate.vim271
-rw-r--r--vim/plugin/supertab.vim737
-rw-r--r--vim/plugin/surround.vim625
-rw-r--r--vim/plugin/syntastic.vim614
-rw-r--r--vim/plugin/tagbar.vim118
-rw-r--r--vim/plugin/taglist.vim4546
-rw-r--r--vim/plugin/unimpaired.vim315
-rw-r--r--vim/plugin/vim-rspec.rb32
-rw-r--r--vim/plugin/vim-rspec.vim174
-rw-r--r--vim/plugin/vim-rspec.xsl55
31 files changed, 20735 insertions, 0 deletions
diff --git a/vim/plugin/.DS_Store b/vim/plugin/.DS_Store
new file mode 100644
index 0000000..5008ddf
--- /dev/null
+++ b/vim/plugin/.DS_Store
Binary files differ
diff --git a/vim/plugin/31-create-scala.vim b/vim/plugin/31-create-scala.vim
new file mode 100644
index 0000000..e4ecb44
--- /dev/null
+++ b/vim/plugin/31-create-scala.vim
@@ -0,0 +1,55 @@
+" Vim plugin that generates new Scala source file when you type
+" vim nonexistent.scala.
+" Scripts tries to detect package name from the directory path, e. g.
+" .../src/main/scala/com/mycompany/myapp/app.scala gets header
+" package com.mycompany.myapp
+"
+" Author : Stepan Koltsov <yozh@mx1.ru>
+
+function! MakeScalaFile()
+ if exists("b:template_used") && b:template_used
+ return
+ endif
+
+ let b:template_used = 1
+
+ let filename = expand("<afile>:p")
+ let x = substitute(filename, "\.scala$", "", "")
+
+ let p = substitute(x, "/[^/]*$", "", "")
+ let p = substitute(p, "/", ".", "g")
+ let p = substitute(p, ".*\.src$", "@", "") " unnamed package
+ let p = substitute(p, ".*\.src\.", "!", "")
+ let p = substitute(p, "^!main\.scala\.", "!", "") "
+ let p = substitute(p, "^!.*\.ru\.", "!ru.", "")
+ let p = substitute(p, "^!.*\.org\.", "!org.", "")
+ let p = substitute(p, "^!.*\.com\.", "!com.", "")
+
+ " ! marks that we found package name.
+ if match(p, "^!") == 0
+ let p = substitute(p, "^!", "", "")
+ else
+ " Don't know package name.
+ let p = "@"
+ endif
+
+ let class = substitute(x, ".*/", "", "")
+
+ if p != "@"
+ call append("0", "package " . p)
+ endif
+
+ "norm G
+ "call append(".", "class " . class . " {")
+
+ "norm G
+ "call append(".", "} /// end of " . class)
+
+ call append(".", "// vim: set ts=4 sw=4 et:")
+ call append(".", "")
+
+endfunction
+
+au BufNewFile *.scala call MakeScalaFile()
+
+" vim: set ts=4 sw=4 et:
diff --git a/vim/plugin/AlignMapsPlugin.vim b/vim/plugin/AlignMapsPlugin.vim
new file mode 100644
index 0000000..eed0293
--- /dev/null
+++ b/vim/plugin/AlignMapsPlugin.vim
@@ -0,0 +1,242 @@
+" AlignMapsPlugin: Alignment maps based upon <Align.vim> and <AlignMaps.vim>
+" Maintainer: Dr. Charles E. Campbell, Jr. <NdrOchipS@PcampbellAfamily.Mbiz>
+" Date: Mar 03, 2009
+"
+" NOTE: the code herein needs vim 6.0 or later
+" needs <Align.vim> v6 or later
+" needs <cecutil.vim> v5 or later
+" Copyright: Copyright (C) 1999-2008 Charles E. Campbell, Jr. {{{1
+" Permission is hereby granted to use and distribute this code,
+" with or without modifications, provided that this copyright
+" notice is copied with it. Like anything else that's free,
+" AlignMaps.vim is provided *as is* and comes with no warranty
+" of any kind, either expressed or implied. By using this
+" plugin, you agree that in no event will the copyright
+" holder be liable for any damages resulting from the use
+" of this software.
+"
+" Usage: {{{1
+" Use 'a to mark beginning of to-be-aligned region, Alternative: use V
+" move cursor to end of region, and execute map. (linewise visual mode) to
+" The maps also set up marks 'y and 'z, and retain mark region, execute same
+" 'a at the beginning of region. map. Uses 'a, 'y, and 'z.
+"
+" The start/end wrappers save and restore marks 'y and 'z.
+"
+" Although the comments indicate the maps use a leading backslash,
+" actually they use <Leader> (:he mapleader), so the user can
+" specify that the maps start how he or she prefers.
+"
+" Note: these maps all use <Align.vim>.
+"
+" Romans 1:20 For the invisible things of Him since the creation of the {{{1
+" world are clearly seen, being perceived through the things that are
+" made, even His everlasting power and divinity; that they may be
+" without excuse.
+
+" ---------------------------------------------------------------------
+" Load Once: {{{1
+if &cp || exists("g:loaded_AlignMapsPlugin")
+ finish
+endif
+let s:keepcpo = &cpo
+let g:loaded_AlignMapsPlugin = "v41"
+set cpo&vim
+
+" =====================================================================
+" Maps: {{{1
+
+" ---------------------------------------------------------------------
+" WS: wrapper start map (internal) {{{2
+" Produces a blank line above and below, marks with 'y and 'z
+if !hasmapto('<Plug>WrapperStart')
+ map <unique> <SID>WS <Plug>AlignMapsWrapperStart
+endif
+nmap <silent> <script> <Plug>AlignMapsWrapperStart :set lz<CR>:call AlignMaps#WrapperStart(0)<CR>
+vmap <silent> <script> <Plug>AlignMapsWrapperStart :<c-u>set lz<CR>:call AlignMaps#WrapperStart(1)<CR>
+
+" ---------------------------------------------------------------------
+" WE: wrapper end (internal) {{{2
+" Removes guard lines, restores marks y and z, and restores search pattern
+if !hasmapto('<Plug>WrapperEnd')
+ nmap <unique> <SID>WE <Plug>AlignMapsWrapperEnd
+endif
+nmap <silent> <script> <Plug>AlignMapsWrapperEnd :call AlignMaps#WrapperEnd()<CR>:set nolz<CR>
+
+" ---------------------------------------------------------------------
+" Complex C-code alignment maps: {{{2
+if !hasmapto('<Plug>AM_a?') |map <unique> <Leader>a? <Plug>AM_a?|endif
+if !hasmapto('<Plug>AM_a,') |map <unique> <Leader>a, <Plug>AM_a,|endif
+if !hasmapto('<Plug>AM_a<') |map <unique> <Leader>a< <Plug>AM_a<|endif
+if !hasmapto('<Plug>AM_a=') |map <unique> <Leader>a= <Plug>AM_a=|endif
+if !hasmapto('<Plug>AM_a(') |map <unique> <Leader>a( <Plug>AM_a(|endif
+if !hasmapto('<Plug>AM_abox') |map <unique> <Leader>abox <Plug>AM_abox|endif
+if !hasmapto('<Plug>AM_acom') |map <unique> <Leader>acom <Plug>AM_acom|endif
+if !hasmapto('<Plug>AM_adcom')|map <unique> <Leader>adcom <Plug>AM_adcom|endif
+if !hasmapto('<Plug>AM_aocom')|map <unique> <Leader>aocom <Plug>AM_aocom|endif
+if !hasmapto('<Plug>AM_ascom')|map <unique> <Leader>ascom <Plug>AM_ascom|endif
+if !hasmapto('<Plug>AM_adec') |map <unique> <Leader>adec <Plug>AM_adec|endif
+if !hasmapto('<Plug>AM_adef') |map <unique> <Leader>adef <Plug>AM_adef|endif
+if !hasmapto('<Plug>AM_afnc') |map <unique> <Leader>afnc <Plug>AM_afnc|endif
+if !hasmapto('<Plug>AM_afnc') |map <unique> <Leader>afnc <Plug>AM_afnc|endif
+if !hasmapto('<Plug>AM_aunum')|map <unique> <Leader>aunum <Plug>AM_aenum|endif
+if !hasmapto('<Plug>AM_aenum')|map <unique> <Leader>aenum <Plug>AM_aunum|endif
+if exists("g:alignmaps_euronumber") && !exists("g:alignmaps_usanumber")
+ if !hasmapto('<Plug>AM_anum')|map <unique> <Leader>anum <Plug>AM_aenum|endif
+else
+ if !hasmapto('<Plug>AM_anum')|map <unique> <Leader>anum <Plug>AM_aunum|endif
+endif
+
+map <silent> <script> <Plug>AM_a? <SID>WS:AlignCtrl mIp1P1lC ? : : : : <CR>:'a,.Align<CR>:'a,'z-1s/\(\s\+\)? /?\1/e<CR><SID>WE
+map <silent> <script> <Plug>AM_a, <SID>WS:'y,'zs/\(\S\)\s\+/\1 /ge<CR>'yjma'zk:call AlignMaps#CharJoiner(",")<cr>:silent 'y,'zg/,/call AlignMaps#FixMultiDec()<CR>'z:exe "norm \<Plug>AM_adec"<cr><SID>WE
+map <silent> <script> <Plug>AM_a< <SID>WS:AlignCtrl mIp1P1=l << >><CR>:'a,.Align<CR><SID>WE
+map <silent> <script> <Plug>AM_a( <SID>WS:AlignCtrl mIp0P1=l<CR>:'a,.Align [(,]<CR>:sil 'y+1,'z-1s/\(\s\+\),/,\1/ge<CR><SID>WE
+map <silent> <script> <Plug>AM_a= <SID>WS:AlignCtrl mIp1P1=l<CR>:AlignCtrl g :=<CR>:'a,'zAlign :\==<CR><SID>WE
+map <silent> <script> <Plug>AM_abox <SID>WS:let g:alignmaps_iws=substitute(getline("'a"),'^\(\s*\).*$','\1','e')<CR>:'a,'z-1s/^\s\+//e<CR>:'a,'z-1s/^.*$/@&@/<CR>:AlignCtrl m=p01P0w @<CR>:'a,.Align<CR>:'a,'z-1s/@/ * /<CR>:'a,'z-1s/@$/*/<CR>'aYP:s/./*/g<CR>0r/'zkYp:s/./*/g<CR>0r A/<Esc>:exe "'a-1,'z-1s/^/".g:alignmaps_iws."/e"<CR><SID>WE
+map <silent> <script> <Plug>AM_acom <SID>WS:'a,.s/\/[*/]\/\=/@&@/e<CR>:'a,.s/\*\//@&/e<CR>:'y,'zs/^\( *\) @/\1@/e<CR>'zk:call AlignMaps#StdAlign(2)<CR>:'y,'zs/^\(\s*\) @/\1/e<CR>:'y,'zs/ @//eg<CR><SID>WE
+map <silent> <script> <Plug>AM_adcom <SID>WS:'a,.v/^\s*\/[/*]/s/\/[*/]\*\=/@&@/e<CR>:'a,.v/^\s*\/[/*]/s/\*\//@&/e<CR>:'y,'zv/^\s*\/[/*]/s/^\( *\) @/\1@/e<CR>'zk:call AlignMaps#StdAlign(3)<cr>:'y,'zv/^\s*\/[/*]/s/^\(\s*\) @/\1/e<CR>:'y,'zs/ @//eg<CR><SID>WE
+map <silent> <script> <Plug>AM_aocom <SID>WS:AlignPush<CR>:AlignCtrl g /[*/]<CR>:exe "norm \<Plug>AM_acom"<cr>:AlignPop<CR><SID>WE
+map <silent> <script> <Plug>AM_ascom <SID>WS:'a,.s/\/[*/]/@&@/e<CR>:'a,.s/\*\//@&/e<CR>:silent! 'a,.g/^\s*@\/[*/]/s/@//ge<CR>:AlignCtrl v ^\s*\/[*/]<CR>:AlignCtrl g \/[*/]<CR>'zk:call AlignMaps#StdAlign(2)<cr>:'y,'zs/^\(\s*\) @/\1/e<CR>:'y,'zs/ @//eg<CR><SID>WE
+map <silent> <script> <Plug>AM_adec <SID>WS:'a,'zs/\([^ \t/(]\)\([*&]\)/\1 \2/e<CR>:'y,'zv/^\//s/\([^ \t]\)\s\+/\1 /ge<CR>:'y,'zv/^\s*[*/]/s/\([^/][*&]\)\s\+/\1/ge<CR>:'y,'zv/^\s*[*/]/s/^\(\s*\%(\K\k*\s\+\%([a-zA-Z_*(&]\)\@=\)\+\)\([*(&]*\)\s*\([a-zA-Z0-9_()]\+\)\s*\(\(\[.\{-}]\)*\)\s*\(=\)\=\s*\(.\{-}\)\=\s*;/\1@\2#@\3\4@\6@\7;@/e<CR>:'y,'zv/^\s*[*/]/s/\*\/\s*$/@*\//e<CR>:'y,'zv/^\s*[*/]/s/^\s\+\*/@@@@@* /e<CR>:'y,'zv/^\s*[*/]/s/^@@@@@\*\(.*[^*/]\)$/&@*/e<CR>'yjma'zk:AlignCtrl v ^\s*[*/#]<CR>:call AlignMaps#StdAlign(1)<cr>:'y,'zv/^\s*[*/]/s/@ //ge<CR>:'y,'zv/^\s*[*/]/s/\(\s*\);/;\1/e<CR>:'y,'zv/^#/s/# //e<CR>:'y,'zv/^\s\+[*/#]/s/\([^/*]\)\(\*\+\)\( \+\)/\1\3\2/e<CR>:'y,'zv/^\s\+[*/#]/s/\((\+\)\( \+\)\*/\2\1*/e<CR>:'y,'zv/^\s\+[*/#]/s/^\(\s\+\) \*/\1*/e<CR>:'y,'zv/^\s\+[*/#]/s/[ \t@]*$//e<CR>:'y,'zs/^[*]/ */e<CR><SID>WE
+map <silent> <script> <Plug>AM_adef <SID>WS:AlignPush<CR>:AlignCtrl v ^\s*\(\/\*\<bar>\/\/\)<CR>:'a,.v/^\s*\(\/\*\<bar>\/\/\)/s/^\(\s*\)#\(\s\)*define\s*\(\I[a-zA-Z_0-9(),]*\)\s*\(.\{-}\)\($\<Bar>\/\*\)/#\1\2define @\3@\4@\5/e<CR>:'a,.v/^\s*\(\/\*\<bar>\/\/\)/s/\($\<Bar>\*\/\)/@&/e<CR>'zk:call AlignMaps#StdAlign(1)<cr>'yjma'zk:'a,.v/^\s*\(\/\*\<bar>\/\/\)/s/ @//g<CR><SID>WE
+map <silent> <script> <Plug>AM_afnc :<c-u>set lz<CR>:silent call AlignMaps#Afnc()<CR>:set nolz<CR>
+map <silent> <script> <Plug>AM_aunum <SID>WS:'a,'zs/\%([0-9.]\)\s\+\zs\([-+.]\=\d\)/@\1/ge<CR>:'a,'zs/\(\(^\|\s\)\d\+\)\(\s\+\)@/\1@\3@/ge<CR>:'a,'zs/\.@/\.0@/ge<CR>:AlignCtrl wmp0P0r<CR>:'a,'zAlign [.@]<CR>:'a,'zs/@/ /ge<CR>:'a,'zs/\(\.\)\(\s\+\)\([0-9.,eE+]\+\)/\1\3\2/ge<CR>:'a,'zs/\([eE]\)\(\s\+\)\([0-9+\-+]\+\)/\1\3\2/ge<CR><SID>WE
+map <silent> <script> <Plug>AM_aenum <SID>WS:'a,'zs/\%([0-9.]\)\s\+\([-+]\=\d\)/\1@\2/ge<CR>:'a,'zs/\.@/\.0@/ge<CR>:AlignCtrl wmp0P0r<CR>:'a,'zAlign [,@]<CR>:'a,'zs/@/ /ge<CR>:'a,'zs/\(,\)\(\s\+\)\([-0-9.,eE+]\+\)/\1\3\2/ge<CR>:'a,'zs/\([eE]\)\(\s\+\)\([0-9+\-+]\+\)/\1\3\2/ge<CR><SID>WE
+
+" ---------------------------------------------------------------------
+" html table alignment {{{2
+if !hasmapto('<Plug>AM_Htd')|map <unique> <Leader>Htd <Plug>AM_Htd|endif
+map <silent> <script> <Plug>AM_Htd <SID>WS:'y,'zs%<[tT][rR]><[tT][dD][^>]\{-}>\<Bar></[tT][dD]><[tT][dD][^>]\{-}>\<Bar></[tT][dD]></[tT][rR]>%@&@%g<CR>'yjma'zk:AlignCtrl m=Ilp1P0 @<CR>:'a,.Align<CR>:'y,'zs/ @/@/<CR>:'y,'zs/@ <[tT][rR]>/<[tT][rR]>/ge<CR>:'y,'zs/@//ge<CR><SID>WE
+
+" ---------------------------------------------------------------------
+" character-based right-justified alignment maps {{{2
+if !hasmapto('<Plug>AM_T|')|map <unique> <Leader>T| <Plug>AM_T||endif
+if !hasmapto('<Plug>AM_T#') |map <unique> <Leader>T# <Plug>AM_T#|endif
+if !hasmapto('<Plug>AM_T,') |map <unique> <Leader>T, <Plug>AM_T,o|endif
+if !hasmapto('<Plug>AM_Ts,') |map <unique> <Leader>Ts, <Plug>AM_Ts,|endif
+if !hasmapto('<Plug>AM_T:') |map <unique> <Leader>T: <Plug>AM_T:|endif
+if !hasmapto('<Plug>AM_T;') |map <unique> <Leader>T; <Plug>AM_T;|endif
+if !hasmapto('<Plug>AM_T<') |map <unique> <Leader>T< <Plug>AM_T<|endif
+if !hasmapto('<Plug>AM_T=') |map <unique> <Leader>T= <Plug>AM_T=|endif
+if !hasmapto('<Plug>AM_T?') |map <unique> <Leader>T? <Plug>AM_T?|endif
+if !hasmapto('<Plug>AM_T@') |map <unique> <Leader>T@ <Plug>AM_T@|endif
+if !hasmapto('<Plug>AM_Tab') |map <unique> <Leader>Tab <Plug>AM_Tab|endif
+if !hasmapto('<Plug>AM_Tsp') |map <unique> <Leader>Tsp <Plug>AM_Tsp|endif
+if !hasmapto('<Plug>AM_T~') |map <unique> <Leader>T~ <Plug>AM_T~|endif
+
+map <silent> <script> <Plug>AM_T| <SID>WS:AlignCtrl mIp0P0=r <Bar><CR>:'a,.Align<CR><SID>WE
+map <silent> <script> <Plug>AM_T# <SID>WS:AlignCtrl mIp0P0=r #<CR>:'a,.Align<CR><SID>WE
+map <silent> <script> <Plug>AM_T, <SID>WS:AlignCtrl mIp0P1=r ,<CR>:'a,.Align<CR><SID>WE
+map <silent> <script> <Plug>AM_Ts, <SID>WS:AlignCtrl mIp0P1=r ,<CR>:'a,.Align<CR>:'a,.s/\(\s*\),/,\1/ge<CR><SID>WE
+map <silent> <script> <Plug>AM_T: <SID>WS:AlignCtrl mIp1P1=r :<CR>:'a,.Align<CR><SID>WE
+map <silent> <script> <Plug>AM_T; <SID>WS:AlignCtrl mIp0P0=r ;<CR>:'a,.Align<CR><SID>WE
+map <silent> <script> <Plug>AM_T< <SID>WS:AlignCtrl mIp0P0=r <<CR>:'a,.Align<CR><SID>WE
+map <silent> <script> <Plug>AM_T= <SID>WS:'a,'z-1s/\s\+\([*/+\-%<Bar>&\~^]\==\)/ \1/e<CR>:'a,'z-1s@ \+\([*/+\-%<Bar>&\~^]\)=@\1=@ge<CR>:'a,'z-1s/; */;@/e<CR>:'a,'z-1s/==/\="\<Char-0x0f>\<Char-0x0f>"/ge<CR>:'a,'z-1s/!=/\x="!\<Char-0x0f>"/ge<CR>:AlignCtrl mIp1P1=r = @<CR>:AlignCtrl g =<CR>:'a,'z-1Align<CR>:'a,'z-1s/; *@/;/e<CR>:'a,'z-1s/; *$/;/e<CR>:'a,'z-1s@\([*/+\-%<Bar>&\~^]\)\( \+\)=@\2\1=@ge<CR>:'a,'z-1s/\( \+\);/;\1/ge<CR>:'a,'z-1s/\xff/=/ge<CR><SID>WE:exe "norm <Plug>acom"
+map <silent> <script> <Plug>AM_T? <SID>WS:AlignCtrl mIp0P0=r ?<CR>:'a,.Align<CR>:'y,'zs/ \( *\);/;\1/ge<CR><SID>WE
+map <silent> <script> <Plug>AM_T@ <SID>WS:AlignCtrl mIp0P0=r @<CR>:'a,.Align<CR><SID>WE
+map <silent> <script> <Plug>AM_Tab <SID>WS:'a,.s/^\(\t*\)\(.*\)/\=submatch(1).escape(substitute(submatch(2),'\t','@','g'),'\')/<CR>:AlignCtrl mI=r @<CR>:'a,.Align<CR>:'y+1,'z-1s/@/ /g<CR><SID>WE
+map <silent> <script> <Plug>AM_Tsp <SID>WS:'a,.s/^\(\s*\)\(.*\)/\=submatch(1).escape(substitute(submatch(2),'\s\+','@','g'),'\')/<CR>:AlignCtrl mI=r @<CR>:'a,.Align<CR>:'y+1,'z-1s/@/ /g<CR><SID>WE
+map <silent> <script> <Plug>AM_T~ <SID>WS:AlignCtrl mIp0P0=r ~<CR>:'a,.Align<CR>:'y,'zs/ \( *\);/;\1/ge<CR><SID>WE
+
+" ---------------------------------------------------------------------
+" character-based left-justified alignment maps {{{2
+if !hasmapto('<Plug>AM_t|') |map <unique> <Leader>t| <Plug>AM_t||endif
+if !hasmapto('<Plug>AM_t#') |map <unique> <Leader>t# <Plug>AM_t#|endif
+if !hasmapto('<Plug>AM_t,') |map <unique> <Leader>t, <Plug>AM_t,|endif
+if !hasmapto('<Plug>AM_t:') |map <unique> <Leader>t: <Plug>AM_t:|endif
+if !hasmapto('<Plug>AM_t;') |map <unique> <Leader>t; <Plug>AM_t;|endif
+if !hasmapto('<Plug>AM_t<') |map <unique> <Leader>t< <Plug>AM_t<|endif
+if !hasmapto('<Plug>AM_t=') |map <unique> <Leader>t= <Plug>AM_t=|endif
+if !hasmapto('<Plug>AM_ts,') |map <unique> <Leader>ts, <Plug>AM_ts,|endif
+if !hasmapto('<Plug>AM_ts:') |map <unique> <Leader>ts: <Plug>AM_ts:|endif
+if !hasmapto('<Plug>AM_ts;') |map <unique> <Leader>ts; <Plug>AM_ts;|endif
+if !hasmapto('<Plug>AM_ts<') |map <unique> <Leader>ts< <Plug>AM_ts<|endif
+if !hasmapto('<Plug>AM_ts=') |map <unique> <Leader>ts= <Plug>AM_ts=|endif
+if !hasmapto('<Plug>AM_w=') |map <unique> <Leader>w= <Plug>AM_w=|endif
+if !hasmapto('<Plug>AM_t?') |map <unique> <Leader>t? <Plug>AM_t?|endif
+if !hasmapto('<Plug>AM_t~') |map <unique> <Leader>t~ <Plug>AM_t~|endif
+if !hasmapto('<Plug>AM_t@') |map <unique> <Leader>t@ <Plug>AM_t@|endif
+if !hasmapto('<Plug>AM_m=') |map <unique> <Leader>m= <Plug>AM_m=|endif
+if !hasmapto('<Plug>AM_tab') |map <unique> <Leader>tab <Plug>AM_tab|endif
+if !hasmapto('<Plug>AM_tml') |map <unique> <Leader>tml <Plug>AM_tml|endif
+if !hasmapto('<Plug>AM_tsp') |map <unique> <Leader>tsp <Plug>AM_tsp|endif
+if !hasmapto('<Plug>AM_tsq') |map <unique> <Leader>tsq <Plug>AM_tsq|endif
+if !hasmapto('<Plug>AM_tt') |map <unique> <Leader>tt <Plug>AM_tt|endif
+
+map <silent> <script> <Plug>AM_t| <SID>WS:AlignCtrl mIp0P0=l <Bar><CR>:'a,.Align<CR><SID>WE
+map <silent> <script> <Plug>AM_t# <SID>WS:AlignCtrl mIp0P0=l #<CR>:'a,.Align<CR><SID>WE
+map <silent> <script> <Plug>AM_t, <SID>WS:AlignCtrl mIp0P1=l ,<CR>:'a,.Align<CR><SID>WE
+map <silent> <script> <Plug>AM_t: <SID>WS:AlignCtrl mIp1P1=l :<CR>:'a,.Align<CR><SID>WE
+map <silent> <script> <Plug>AM_t; <SID>WS:AlignCtrl mIp0P1=l ;<CR>:'a,.Align<CR>:sil 'y,'zs/\( *\);/;\1/ge<CR><SID>WE
+map <silent> <script> <Plug>AM_t< <SID>WS:AlignCtrl mIp0P0=l <<CR>:'a,.Align<CR><SID>WE
+map <silent> <script> <Plug>AM_t= <SID>WS:call AlignMaps#Equals()<CR><SID>WE
+map <silent> <script> <Plug>AM_ts, <SID>WS:AlignCtrl mIp0P1=l #<CR>:'a,.Align<CR>:sil 'y+1,'z-1s/\(\s*\)#/,\1/ge<CR><SID>WE
+map <silent> <script> <Plug>AM_ts, <SID>WS:AlignCtrl mIp0P1=l ,<CR>:'a,.Align<CR>:sil 'y+1,'z-1s/\(\s*\),/,\1/ge<CR><SID>WE
+map <silent> <script> <Plug>AM_ts: <SID>WS:AlignCtrl mIp1P1=l :<CR>:'a,.Align<CR>:sil 'y+1,'z-1s/\(\s*\):/:\1/ge<CR><SID>WE
+map <silent> <script> <Plug>AM_ts; <SID>WS:AlignCtrl mIp1P1=l ;<CR>:'a,.Align<CR>:sil 'y+1,'z-1s/\(\s*\);/;\1/ge<CR><SID>WE
+map <silent> <script> <Plug>AM_ts< <SID>WS:AlignCtrl mIp1P1=l <<CR>:'a,.Align<CR>:sil 'y+1,'z-1s/\(\s*\)</<\1/ge<CR><SID>WE
+map <silent> <script> <Plug>AM_ts= <SID>WS:AlignCtrl mIp1P1=l =<CR>:'a,.Align<CR>:sil 'y+1,'z-1s/\(\s*\)=/=\1/ge<CR><SID>WE
+map <silent> <script> <Plug>AM_w= <SID>WS:'a,'zg/=/s/\s\+\([*/+\-%<Bar>&\~^]\==\)/ \1/e<CR>:'a,'zg/=/s@ \+\([*/+\-%<Bar>&\~^]\)=@\1=@ge<CR>:'a,'zg/=/s/==/\="\<Char-0x0f>\<Char-0x0f>"/ge<CR>:'a,'zg/=/s/!=/\="!\<Char-0x0f>"/ge<CR>'zk:AlignCtrl mWp1P1=l =<CR>:AlignCtrl g =<CR>:'a,'z-1g/=/Align<CR>:'a,'z-1g/=/s@\([*/+\-%<Bar>&\~^!=]\)\( \+\)=@\2\1=@ge<CR>:'a,'z-1g/=/s/\( \+\);/;\1/ge<CR>:'a,'z-1v/^\s*\/[*/]/s/\/[*/]/@&@/e<CR>:'a,'z-1v/^\s*\/[*/]/s/\*\//@&/e<CR>'zk:call AlignMaps#StdAlign(1)<cr>:'y,'zs/^\(\s*\) @/\1/e<CR>:'a,'z-1g/=/s/\xff/=/ge<CR>:'y,'zg/=/s/ @//eg<CR><SID>WE
+map <silent> <script> <Plug>AM_t? <SID>WS:AlignCtrl mIp0P0=l ?<CR>:'a,.Align<CR>:.,'zs/ \( *\);/;\1/ge<CR><SID>WE
+map <silent> <script> <Plug>AM_t~ <SID>WS:AlignCtrl mIp0P0=l ~<CR>:'a,.Align<CR>:'y,'zs/ \( *\);/;\1/ge<CR><SID>WE
+map <silent> <script> <Plug>AM_t@ <SID>WS::call AlignMaps#StdAlign(1)<cr>:<SID>WE
+map <silent> <script> <Plug>AM_m= <SID>WS:'a,'zs/\s\+\([*/+\-%<Bar>&\~^]\==\)/ \1/e<CR>:'a,'zs@ \+\([*/+\-%<Bar>&\~^]\)=@\1=@ge<CR>:'a,'zs/==/\="\<Char-0x0f>\<Char-0x0f>"/ge<CR>:'a,'zs/!=/\="!\<Char-0x0f>"/ge<CR>'zk:AlignCtrl mIp1P1=l =<CR>:AlignCtrl g =<CR>:'a,'z-1Align<CR>:'a,'z-1s@\([*/+\-%<Bar>&\~^!=]\)\( \+\)=@\2\1=@ge<CR>:'a,'z-1s/\( \+\);/;\1/ge<CR>:'a,'z-s/%\ze[^=]/ @%@ /e<CR>'zk:call AlignMaps#StdAlign(1)<cr>:'y,'zs/^\(\s*\) @/\1/e<CR>:'a,'z-1s/\xff/=/ge<CR>:'y,'zs/ @//eg<CR><SID>WE
+map <silent> <script> <Plug>AM_tab <SID>WS:'a,.s/^\(\t*\)\(.*\)$/\=submatch(1).escape(substitute(submatch(2),'\t',"\<Char-0x0f>",'g'),'\')/<CR>:if &ts == 1<bar>exe "AlignCtrl mI=lp0P0 \<Char-0x0f>"<bar>else<bar>exe "AlignCtrl mI=l \<Char-0x0f>"<bar>endif<CR>:'a,.Align<CR>:exe "'y+1,'z-1s/\<Char-0x0f>/".((&ts == 1)? '\t' : ' ')."/g"<CR><SID>WE
+map <silent> <script> <Plug>AM_tml <SID>WS:AlignCtrl mWp1P0=l \\\@<!\\\s*$<CR>:'a,.Align<CR><SID>WE
+map <silent> <script> <Plug>AM_tsp <SID>WS:'a,.s/^\(\s*\)\(.*\)/\=submatch(1).escape(substitute(submatch(2),'\s\+','@','g'),'\')/<CR>:AlignCtrl mI=lp0P0 @<CR>:'a,.Align<CR>:'y+1,'z-1s/@/ /g<CR><SID>WE
+map <silent> <script> <Plug>AM_tsq <SID>WS:'a,.AlignReplaceQuotedSpaces<CR>:'a,.s/^\(\s*\)\(.*\)/\=submatch(1).substitute(submatch(2),'\s\+','@','g')/<CR>:AlignCtrl mIp0P0=l @<CR>:'a,.Align<CR>:'y+1,'z-1s/[%@]/ /g<CR><SID>WE
+map <silent> <script> <Plug>AM_tt <SID>WS:AlignCtrl mIp1P1=l \\\@<!& \\\\<CR>:'a,.Align<CR><SID>WE
+
+" =====================================================================
+" Menu Support: {{{1
+" ma ..move.. use menu
+" v V or ctrl-v ..move.. use menu
+if has("menu") && has("gui_running") && &go =~ 'm' && !exists("s:firstmenu")
+ let s:firstmenu= 1
+ if !exists("g:DrChipTopLvlMenu")
+ let g:DrChipTopLvlMenu= "DrChip."
+ endif
+ if g:DrChipTopLvlMenu != ""
+ let s:mapleader = exists("g:mapleader")? g:mapleader : '\'
+ let s:emapleader= escape(s:mapleader,'\ ')
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.<<\ and\ >><tab>'.s:emapleader.'a< '.s:mapleader.'a<'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Assignment\ =<tab>'.s:emapleader.'t= '.s:mapleader.'t='
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Assignment\ :=<tab>'.s:emapleader.'a= '.s:mapleader.'a='
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Backslashes<tab>'.s:emapleader.'tml '.s:mapleader.'tml'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Breakup\ Comma\ Declarations<tab>'.s:emapleader.'a, '.s:mapleader.'a,'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.C\ Comment\ Box<tab>'.s:emapleader.'abox '.s:mapleader.'abox'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Commas<tab>'.s:emapleader.'t, '.s:mapleader.'t,'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Commas<tab>'.s:emapleader.'ts, '.s:mapleader.'ts,'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Commas\ With\ Strings<tab>'.s:emapleader.'tsq '.s:mapleader.'tsq'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Comments<tab>'.s:emapleader.'acom '.s:mapleader.'acom'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Comments\ Only<tab>'.s:emapleader.'aocom '.s:mapleader.'aocom'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Declaration\ Comments<tab>'.s:emapleader.'adcom '.s:mapleader.'adcom'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Declarations<tab>'.s:emapleader.'adec '.s:mapleader.'adec'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Definitions<tab>'.s:emapleader.'adef '.s:mapleader.'adef'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Function\ Header<tab>'.s:emapleader.'afnc '.s:mapleader.'afnc'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Html\ Tables<tab>'.s:emapleader.'Htd '.s:mapleader.'Htd'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.(\.\.\.)?\.\.\.\ :\ \.\.\.<tab>'.s:emapleader.'a? '.s:mapleader.'a?'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Numbers<tab>'.s:emapleader.'anum '.s:mapleader.'anum'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Numbers\ (American-Style)<tab>'.s:emapleader.'aunum <Leader>aunum '.s:mapleader.'aunum <Leader>aunum'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Numbers\ (Euro-Style)<tab>'.s:emapleader.'aenum '.s:mapleader.'aenum'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Spaces\ (Left\ Justified)<tab>'.s:emapleader.'tsp '.s:mapleader.'tsp'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Spaces\ (Right\ Justified)<tab>'.s:emapleader.'Tsp '.s:mapleader.'Tsp'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Statements\ With\ Percent\ Style\ Comments<tab>'.s:emapleader.'m= '.s:mapleader.'m='
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Symbol\ <<tab>'.s:emapleader.'t< '.s:mapleader.'t<'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Symbol\ \|<tab>'.s:emapleader.'t\| '.s:mapleader.'t|'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Symbol\ @<tab>'.s:emapleader.'t@ '.s:mapleader.'t@'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Symbol\ #<tab>'.s:emapleader.'t# '.s:mapleader.'t#'
+ exe 'menu '.g:DrChipTopLvlMenu.'AlignMaps.Tabs<tab>'.s:emapleader.'tab '.s:mapleader.'tab'
+ unlet s:mapleader
+ unlet s:emapleader
+ endif
+endif
+
+" =====================================================================
+" Restore: {{{1
+let &cpo= s:keepcpo
+unlet s:keepcpo
+
+" ==============================================================================
+" Modelines: {{{1
+" vim: ts=4 nowrap fdm=marker
diff --git a/vim/plugin/AlignPlugin.vim b/vim/plugin/AlignPlugin.vim
new file mode 100644
index 0000000..727fe7e
--- /dev/null
+++ b/vim/plugin/AlignPlugin.vim
@@ -0,0 +1,41 @@
+" AlignPlugin: tool to align multiple fields based on one or more separators
+" Author: Charles E. Campbell, Jr.
+" Date: Nov 02, 2008
+" GetLatestVimScripts: 294 1 :AutoInstall: Align.vim
+" GetLatestVimScripts: 1066 1 :AutoInstall: cecutil.vim
+" Copyright: Copyright (C) 1999-2007 Charles E. Campbell, Jr. {{{1
+" Permission is hereby granted to use and distribute this code,
+" with or without modifications, provided that this copyright
+" notice is copied with it. Like anything else that's free,
+" Align.vim is provided *as is* and comes with no warranty
+" of any kind, either expressed or implied. By using this
+" plugin, you agree that in no event will the copyright
+" holder be liable for any damages resulting from the use
+" of this software.
+"
+" Romans 1:16,17a : For I am not ashamed of the gospel of Christ, for it is {{{1
+" the power of God for salvation for everyone who believes; for the Jew first,
+" and also for the Greek. For in it is revealed God's righteousness from
+" faith to faith.
+" ---------------------------------------------------------------------
+" Load Once: {{{1
+if &cp || exists("g:loaded_AlignPlugin")
+ finish
+endif
+let g:loaded_AlignPlugin = "v35"
+let s:keepcpo = &cpo
+set cpo&vim
+
+" ---------------------------------------------------------------------
+" Public Interface: {{{1
+com! -bang -range -nargs=* Align <line1>,<line2>call Align#Align(<bang>0,<q-args>)
+com! -range -nargs=0 AlignReplaceQuotedSpaces <line1>,<line2>call Align#AlignReplaceQuotedSpaces()
+com! -nargs=* AlignCtrl call Align#AlignCtrl(<q-args>)
+com! -nargs=0 AlignPush call Align#AlignPush()
+com! -nargs=0 AlignPop call Align#AlignPop()
+
+" ---------------------------------------------------------------------
+" Restore: {{{1
+let &cpo= s:keepcpo
+unlet s:keepcpo
+" vim: ts=4 fdm=marker
diff --git a/vim/plugin/EasyMotion.vim b/vim/plugin/EasyMotion.vim
new file mode 100755
index 0000000..fff29dc
--- /dev/null
+++ b/vim/plugin/EasyMotion.vim
@@ -0,0 +1,73 @@
+" EasyMotion - Vim motions on speed!
+"
+" Author: Kim Silkebækken <kim.silkebaekken+vim@gmail.com>
+" Source repository: https://github.com/Lokaltog/vim-easymotion
+
+" Script initialization {{{
+ if exists('g:EasyMotion_loaded') || &compatible || version < 702
+ finish
+ endif
+
+ let g:EasyMotion_loaded = 1
+" }}}
+" Default configuration {{{
+ " Default options {{{
+ call EasyMotion#InitOptions({
+ \ 'leader_key' : '<Leader><Leader>'
+ \ , 'keys' : 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ \ , 'do_shade' : 1
+ \ , 'do_mapping' : 1
+ \ , 'grouping' : 1
+ \
+ \ , 'hl_group_target' : 'EasyMotionTarget'
+ \ , 'hl_group_shade' : 'EasyMotionShade'
+ \ })
+ " }}}
+ " Default highlighting {{{
+ let s:target_hl_defaults = {
+ \ 'gui' : ['NONE', '#ff0000' , 'bold']
+ \ , 'cterm256': ['NONE', '196' , 'bold']
+ \ , 'cterm' : ['NONE', 'red' , 'bold']
+ \ }
+
+ let s:shade_hl_defaults = {
+ \ 'gui' : ['NONE', '#777777' , 'NONE']
+ \ , 'cterm256': ['NONE', '242' , 'NONE']
+ \ , 'cterm' : ['NONE', 'grey' , 'NONE']
+ \ }
+
+ call EasyMotion#InitHL(g:EasyMotion_hl_group_target, s:target_hl_defaults)
+ call EasyMotion#InitHL(g:EasyMotion_hl_group_shade, s:shade_hl_defaults)
+
+ " Reset highlighting after loading a new color scheme {{{
+ augroup EasyMotionInitHL
+ autocmd!
+
+ autocmd ColorScheme * call EasyMotion#InitHL(g:EasyMotion_hl_group_target, s:target_hl_defaults)
+ autocmd ColorScheme * call EasyMotion#InitHL(g:EasyMotion_hl_group_shade, s:shade_hl_defaults)
+ augroup end
+ " }}}
+ " }}}
+ " Default key mapping {{{
+ call EasyMotion#InitMappings({
+ \ 'f' : { 'name': 'F' , 'dir': 0 }
+ \ , 'F' : { 'name': 'F' , 'dir': 1 }
+ \ , 't' : { 'name': 'T' , 'dir': 0 }
+ \ , 'T' : { 'name': 'T' , 'dir': 1 }
+ \ , 'w' : { 'name': 'WB' , 'dir': 0 }
+ \ , 'W' : { 'name': 'WBW', 'dir': 0 }
+ \ , 'b' : { 'name': 'WB' , 'dir': 1 }
+ \ , 'B' : { 'name': 'WBW', 'dir': 1 }
+ \ , 'e' : { 'name': 'E' , 'dir': 0 }
+ \ , 'E' : { 'name': 'EW' , 'dir': 0 }
+ \ , 'ge': { 'name': 'E' , 'dir': 1 }
+ \ , 'gE': { 'name': 'EW' , 'dir': 1 }
+ \ , 'j' : { 'name': 'JK' , 'dir': 0 }
+ \ , 'k' : { 'name': 'JK' , 'dir': 1 }
+ \ , 'n' : { 'name': 'Search' , 'dir': 0 }
+ \ , 'N' : { 'name': 'Search' , 'dir': 1 }
+ \ })
+ " }}}
+" }}}
+
+" vim: fdm=marker:noet:ts=4:sw=4:sts=4
diff --git a/vim/plugin/NERD_commenter.vim b/vim/plugin/NERD_commenter.vim
new file mode 100644
index 0000000..ef88dd4
--- /dev/null
+++ b/vim/plugin/NERD_commenter.vim
@@ -0,0 +1,2790 @@
+" ============================================================================
+" File: NERD_commenter.vim
+" Description: vim global plugin that provides easy code commenting
+" Maintainer: Martin Grenfell <martin.grenfell at gmail dot com>
+" Version: 2.3.0
+" Last Change: 08th December, 2010
+" 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_comments")
+ finish
+endif
+if v:version < 700
+ echoerr "NERDCommenter: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!"
+ finish
+endif
+let loaded_nerd_comments = 1
+
+" 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 . ' = ' . "'" . a:value . "'"
+ return 1
+ endif
+ return 0
+endfunction
+
+" Section: space string init{{{2
+" When putting spaces after the left delim and before the right we use
+" s:spaceStr for the space char. This way we can make it add anything after
+" the left and before the right by modifying this variable
+let s:spaceStr = ' '
+let s:lenSpaceStr = strlen(s:spaceStr)
+
+" Section: variable init calls {{{2
+call s:InitVariable("g:NERDAllowAnyVisualDelims", 1)
+call s:InitVariable("g:NERDBlockComIgnoreEmpty", 0)
+call s:InitVariable("g:NERDCommentWholeLinesInVMode", 0)
+call s:InitVariable("g:NERDCompactSexyComs", 0)
+call s:InitVariable("g:NERDCreateDefaultMappings", 1)
+call s:InitVariable("g:NERDDefaultNesting", 1)
+call s:InitVariable("g:NERDMenuMode", 3)
+call s:InitVariable("g:NERDLPlace", "[>")
+call s:InitVariable("g:NERDUsePlaceHolders", 1)
+call s:InitVariable("g:NERDRemoveAltComs", 1)
+call s:InitVariable("g:NERDRemoveExtraSpaces", 1)
+call s:InitVariable("g:NERDRPlace", "<]")
+call s:InitVariable("g:NERDSpaceDelims", 0)
+call s:InitVariable("g:NERDDelimiterRequests", 1)
+
+let s:NERDFileNameEscape="[]#*$%'\" ?`!&();<>\\"
+"vf ;;dA:hcs"'A {j^f(lyi(k$p0f{a A }0f{a 'left':jdd^
+
+let s:delimiterMap = {
+ \ 'aap': { 'left': '#' },
+ \ 'abc': { 'left': '%' },
+ \ 'acedb': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'actionscript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'ada': { 'left': '--', 'leftAlt': '-- ' },
+ \ 'ahdl': { 'left': '--' },
+ \ 'ahk': { 'left': ';', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'amiga': { 'left': ';' },
+ \ 'aml': { 'left': '/*' },
+ \ 'ampl': { 'left': '#' },
+ \ 'apache': { 'left': '#' },
+ \ 'apachestyle': { 'left': '#' },
+ \ 'asciidoc': { 'left': '//' },
+ \ 'applescript': { 'left': '--', 'leftAlt': '(*', 'rightAlt': '*)' },
+ \ 'asm68k': { 'left': ';' },
+ \ 'asm': { 'left': ';', 'leftAlt': '#' },
+ \ 'asn': { 'left': '--' },
+ \ 'aspvbs': { 'left': '''' },
+ \ 'asterisk': { 'left': ';' },
+ \ 'asy': { 'left': '//' },
+ \ 'atlas': { 'left': 'C', 'right': '$' },
+ \ 'autohotkey': { 'left': ';' },
+ \ 'autoit': { 'left': ';' },
+ \ 'ave': { 'left': "'" },
+ \ 'awk': { 'left': '#' },
+ \ 'basic': { 'left': "'", 'leftAlt': 'REM ' },
+ \ 'bbx': { 'left': '%' },
+ \ 'bc': { 'left': '#' },
+ \ 'bib': { 'left': '%' },
+ \ 'bindzone': { 'left': ';' },
+ \ 'bst': { 'left': '%' },
+ \ 'btm': { 'left': '::' },
+ \ 'caos': { 'left': '*' },
+ \ 'calibre': { 'left': '//' },
+ \ 'catalog': { 'left': '--', 'right': '--' },
+ \ 'c': { 'left': '/*','right': '*/', 'leftAlt': '//' },
+ \ 'cfg': { 'left': '#' },
+ \ 'cg': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'ch': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'cl': { 'left': '#' },
+ \ 'clean': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'clipper': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'clojure': { 'left': ';' },
+ \ 'cmake': { 'left': '#' },
+ \ 'conkyrc': { 'left': '#' },
+ \ 'cpp': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'crontab': { 'left': '#' },
+ \ 'cs': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'csp': { 'left': '--' },
+ \ 'cterm': { 'left': '*' },
+ \ 'cucumber': { 'left': '#' },
+ \ 'cvs': { 'left': 'CVS:' },
+ \ 'd': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'dcl': { 'left': '$!' },
+ \ 'dakota': { 'left': '#' },
+ \ 'debcontrol': { 'left': '#' },
+ \ 'debsources': { 'left': '#' },
+ \ 'def': { 'left': ';' },
+ \ 'desktop': { 'left': '#' },
+ \ 'dhcpd': { 'left': '#' },
+ \ 'diff': { 'left': '#' },
+ \ 'django': { 'left': '<!--','right': '-->', 'leftAlt': '{#', 'rightAlt': '#}' },
+ \ 'docbk': { 'left': '<!--', 'right': '-->' },
+ \ 'dns': { 'left': ';' },
+ \ 'dosbatch': { 'left': 'REM ', 'leftAlt': '::' },
+ \ 'dosini': { 'left': ';' },
+ \ 'dot': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'dracula': { 'left': ';' },
+ \ 'dsl': { 'left': ';' },
+ \ 'dtml': { 'left': '<dtml-comment>', 'right': '</dtml-comment>' },
+ \ 'dylan': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'ebuild': { 'left': '#' },
+ \ 'ecd': { 'left': '#' },
+ \ 'eclass': { 'left': '#' },
+ \ 'eiffel': { 'left': '--' },
+ \ 'elf': { 'left': "'" },
+ \ 'elmfilt': { 'left': '#' },
+ \ 'erlang': { 'left': '%' },
+ \ 'eruby': { 'left': '<%#', 'right': '%>', 'leftAlt': '<!--', 'rightAlt': '-->' },
+ \ 'expect': { 'left': '#' },
+ \ 'exports': { 'left': '#' },
+ \ 'factor': { 'left': '! ', 'leftAlt': '!# ' },
+ \ 'fgl': { 'left': '#' },
+ \ 'focexec': { 'left': '-*' },
+ \ 'form': { 'left': '*' },
+ \ 'foxpro': { 'left': '*' },
+ \ 'fstab': { 'left': '#' },
+ \ 'fvwm': { 'left': '#' },
+ \ 'fx': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'gams': { 'left': '*' },
+ \ 'gdb': { 'left': '#' },
+ \ 'gdmo': { 'left': '--' },
+ \ 'geek': { 'left': 'GEEK_COMMENT:' },
+ \ 'genshi': { 'left': '<!--','right': '-->', 'leftAlt': '{#', 'rightAlt': '#}' },
+ \ 'gentoo-conf-d': { 'left': '#' },
+ \ 'gentoo-env-d': { 'left': '#' },
+ \ 'gentoo-init-d': { 'left': '#' },
+ \ 'gentoo-make-conf': { 'left': '#' },
+ \ 'gentoo-package-keywords': { 'left': '#' },
+ \ 'gentoo-package-mask': { 'left': '#' },
+ \ 'gentoo-package-use': { 'left': '#' },
+ \ 'gitcommit': { 'left': '#' },
+ \ 'gitconfig': { 'left': ';' },
+ \ 'gitrebase': { 'left': '#' },
+ \ 'gnuplot': { 'left': '#' },
+ \ 'groovy': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'gsp': { 'left': '<%--', 'right': '--%>' },
+ \ 'gtkrc': { 'left': '#' },
+ \ 'haskell': { 'left': '{-','right': '-}', 'leftAlt': '--' },
+ \ 'hb': { 'left': '#' },
+ \ 'h': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'haml': { 'left': '-#', 'leftAlt': '/' },
+ \ 'hercules': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'hog': { 'left': '#' },
+ \ 'hostsaccess': { 'left': '#' },
+ \ 'htmlcheetah': { 'left': '##' },
+ \ 'htmldjango': { 'left': '<!--','right': '-->', 'leftAlt': '{#', 'rightAlt': '#}' },
+ \ 'htmlos': { 'left': '#', 'right': '/#' },
+ \ 'ia64': { 'left': '#' },
+ \ 'icon': { 'left': '#' },
+ \ 'idlang': { 'left': ';' },
+ \ 'idl': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'inform': { 'left': '!' },
+ \ 'inittab': { 'left': '#' },
+ \ 'ishd': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'iss': { 'left': ';' },
+ \ 'ist': { 'left': '%' },
+ \ 'java': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'javacc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'javascript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'javascript.jquery': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'jess': { 'left': ';' },
+ \ 'jgraph': { 'left': '(*', 'right': '*)' },
+ \ 'jproperties': { 'left': '#' },
+ \ 'jsp': { 'left': '<%--', 'right': '--%>' },
+ \ 'kix': { 'left': ';' },
+ \ 'kscript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'lace': { 'left': '--' },
+ \ 'ldif': { 'left': '#' },
+ \ 'lilo': { 'left': '#' },
+ \ 'lilypond': { 'left': '%' },
+ \ 'liquid': { 'left': '{%', 'right': '%}' },
+ \ 'lisp': { 'left': ';', 'leftAlt': '#|', 'rightAlt': '|#' },
+ \ 'llvm': { 'left': ';' },
+ \ 'lotos': { 'left': '(*', 'right': '*)' },
+ \ 'lout': { 'left': '#' },
+ \ 'lprolog': { 'left': '%' },
+ \ 'lscript': { 'left': "'" },
+ \ 'lss': { 'left': '#' },
+ \ 'lua': { 'left': '--', 'leftAlt': '--[[', 'rightAlt': ']]' },
+ \ 'lynx': { 'left': '#' },
+ \ 'lytex': { 'left': '%' },
+ \ 'mail': { 'left': '> ' },
+ \ 'mako': { 'left': '##' },
+ \ 'man': { 'left': '."' },
+ \ 'map': { 'left': '%' },
+ \ 'maple': { 'left': '#' },
+ \ 'markdown': { 'left': '<!--', 'right': '-->' },
+ \ 'masm': { 'left': ';' },
+ \ 'mason': { 'left': '<% #', 'right': '%>' },
+ \ 'master': { 'left': '$' },
+ \ 'matlab': { 'left': '%' },
+ \ 'mel': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'mib': { 'left': '--' },
+ \ 'mkd': { 'left': '>' },
+ \ 'mma': { 'left': '(*', 'right': '*)' },
+ \ 'model': { 'left': '$', 'right': '$' },
+ \ 'moduala.': { 'left': '(*', 'right': '*)' },
+ \ 'modula2': { 'left': '(*', 'right': '*)' },
+ \ 'modula3': { 'left': '(*', 'right': '*)' },
+ \ 'monk': { 'left': ';' },
+ \ 'mush': { 'left': '#' },
+ \ 'named': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'nasm': { 'left': ';' },
+ \ 'nastran': { 'left': '$' },
+ \ 'natural': { 'left': '/*' },
+ \ 'ncf': { 'left': ';' },
+ \ 'newlisp': { 'left': ';' },
+ \ 'nroff': { 'left': '\"' },
+ \ 'nsis': { 'left': '#' },
+ \ 'ntp': { 'left': '#' },
+ \ 'objc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'objcpp': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'objj': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'ocaml': { 'left': '(*', 'right': '*)' },
+ \ 'occam': { 'left': '--' },
+ \ 'omlet': { 'left': '(*', 'right': '*)' },
+ \ 'omnimark': { 'left': ';' },
+ \ 'openroad': { 'left': '//' },
+ \ 'opl': { 'left': "REM" },
+ \ 'ora': { 'left': '#' },
+ \ 'ox': { 'left': '//' },
+ \ 'pascal': { 'left': '{','right': '}', 'leftAlt': '(*', 'rightAlt': '*)' },
+ \ 'patran': { 'left': '$', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'pcap': { 'left': '#' },
+ \ 'pccts': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'pdf': { 'left': '%' },
+ \ 'pfmain': { 'left': '//' },
+ \ 'php': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'pic': { 'left': ';' },
+ \ 'pike': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'pilrc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'pine': { 'left': '#' },
+ \ 'plm': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'plsql': { 'left': '--', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'po': { 'left': '#' },
+ \ 'postscr': { 'left': '%' },
+ \ 'pov': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'povini': { 'left': ';' },
+ \ 'ppd': { 'left': '%' },
+ \ 'ppwiz': { 'left': ';;' },
+ \ 'processing': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'prolog': { 'left': '%', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'ps1': { 'left': '#' },
+ \ 'psf': { 'left': '#' },
+ \ 'ptcap': { 'left': '#' },
+ \ 'python': { 'left': '#' },
+ \ 'radiance': { 'left': '#' },
+ \ 'ratpoison': { 'left': '#' },
+ \ 'r': { 'left': '#' },
+ \ 'rc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'rebol': { 'left': ';' },
+ \ 'registry': { 'left': ';' },
+ \ 'remind': { 'left': '#' },
+ \ 'resolv': { 'left': '#' },
+ \ 'rgb': { 'left': '!' },
+ \ 'rib': { 'left': '#' },
+ \ 'robots': { 'left': '#' },
+ \ 'sa': { 'left': '--' },
+ \ 'samba': { 'left': ';', 'leftAlt': '#' },
+ \ 'sass': { 'left': '//', 'leftAlt': '/*' },
+ \ 'sather': { 'left': '--' },
+ \ 'scala': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'scilab': { 'left': '//' },
+ \ 'scsh': { 'left': ';' },
+ \ 'sed': { 'left': '#' },
+ \ 'sgmldecl': { 'left': '--', 'right': '--' },
+ \ 'sgmllnx': { 'left': '<!--', 'right': '-->' },
+ \ 'sicad': { 'left': '*' },
+ \ 'simula': { 'left': '%', 'leftAlt': '--' },
+ \ 'sinda': { 'left': '$' },
+ \ 'skill': { 'left': ';' },
+ \ 'slang': { 'left': '%' },
+ \ 'slice': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'slrnrc': { 'left': '%' },
+ \ 'sm': { 'left': '#' },
+ \ 'smarty': { 'left': '{*', 'right': '*}' },
+ \ 'smil': { 'left': '<!', 'right': '>' },
+ \ 'smith': { 'left': ';' },
+ \ 'sml': { 'left': '(*', 'right': '*)' },
+ \ 'snnsnet': { 'left': '#' },
+ \ 'snnspat': { 'left': '#' },
+ \ 'snnsres': { 'left': '#' },
+ \ 'snobol4': { 'left': '*' },
+ \ 'spec': { 'left': '#' },
+ \ 'specman': { 'left': '//' },
+ \ 'spectre': { 'left': '//', 'leftAlt': '*' },
+ \ 'spice': { 'left': '$' },
+ \ 'sql': { 'left': '--' },
+ \ 'sqlforms': { 'left': '--' },
+ \ 'sqlj': { 'left': '--' },
+ \ 'sqr': { 'left': '!' },
+ \ 'squid': { 'left': '#' },
+ \ 'st': { 'left': '"' },
+ \ 'stp': { 'left': '--' },
+ \ 'systemverilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'tads': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'tags': { 'left': ';' },
+ \ 'tak': { 'left': '$' },
+ \ 'tasm': { 'left': ';' },
+ \ 'tcl': { 'left': '#' },
+ \ 'texinfo': { 'left': "@c " },
+ \ 'texmf': { 'left': '%' },
+ \ 'tf': { 'left': ';' },
+ \ 'tidy': { 'left': '#' },
+ \ 'tli': { 'left': '#' },
+ \ 'tmux': { 'left': '#' },
+ \ 'trasys': { 'left': "$" },
+ \ 'tsalt': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'tsscl': { 'left': '#' },
+ \ 'tssgm': { 'left': "comment = '", 'right': "'" },
+ \ 'txt2tags': { 'left': '%' },
+ \ 'uc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'uil': { 'left': '!' },
+ \ 'vb': { 'left': "'" },
+ \ 'velocity': { 'left': "##", 'right': "", 'leftAlt': '#*', 'rightAlt': '*#' },
+ \ 'vera': { 'left': '/*','right': '*/', 'leftAlt': '//' },
+ \ 'verilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'verilog_systemverilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
+ \ 'vgrindefs': { 'left': '#' },
+ \ 'vhdl': { 'left': '--' },
+ \ 'vimperator': { 'left': '"' },
+ \ 'virata': { 'left': '%' },
+ \ 'vrml': { 'left': '#' },
+ \ 'vsejcl': { 'left': '/*' },
+ \ 'webmacro': { 'left': '##' },
+ \ 'wget': { 'left': '#' },
+ \ 'Wikipedia': { 'left': '<!--', 'right': '-->' },
+ \ 'winbatch': { 'left': ';' },
+ \ 'wml': { 'left': '#' },
+ \ 'wvdial': { 'left': ';' },
+ \ 'xdefaults': { 'left': '!' },
+ \ 'xkb': { 'left': '//' },
+ \ 'xmath': { 'left': '#' },
+ \ 'xpm2': { 'left': '!' },
+ \ 'xquery': { 'left': '(:', 'right': ':)' },
+ \ 'z8a': { 'left': ';' }
+ \ }
+
+" Section: Comment mapping functions, autocommands and commands {{{1
+" ============================================================================
+" Section: Comment enabler autocommands {{{2
+" ============================================================================
+
+augroup commentEnablers
+
+ "if the user enters a buffer or reads a buffer then we gotta set up
+ "the comment delimiters for that new filetype
+ autocmd BufEnter,BufRead * :call s:SetUpForNewFiletype(&filetype, 0)
+
+ "if the filetype of a buffer changes, force the script to reset the
+ "delims for the buffer
+ autocmd Filetype * :call s:SetUpForNewFiletype(&filetype, 1)
+augroup END
+
+
+" Function: s:SetUpForNewFiletype(filetype) function {{{2
+" This function is responsible for setting up buffer scoped variables for the
+" given filetype.
+"
+" Args:
+" -filetype: the filetype to set delimiters for
+" -forceReset: 1 if the delimiters should be reset if they have already be
+" set for this buffer.
+"
+function s:SetUpForNewFiletype(filetype, forceReset)
+ let b:NERDSexyComMarker = ''
+
+ if has_key(s:delimiterMap, a:filetype)
+ let b:NERDCommenterDelims = s:delimiterMap[a:filetype]
+ for i in ['left', 'leftAlt', 'right', 'rightAlt']
+ if !has_key(b:NERDCommenterDelims, i)
+ let b:NERDCommenterDelims[i] = ''
+ endif
+ endfor
+ else
+ let b:NERDCommenterDelims = s:CreateDelimMapFromCms()
+ endif
+
+endfunction
+
+function s:CreateDelimMapFromCms()
+ return {
+ \ 'left': substitute(&commentstring, '\([^ \t]*\)\s*%s.*', '\1', ''),
+ \ 'right': substitute(&commentstring, '.*%s\s*\(.*\)', '\1', 'g'),
+ \ 'leftAlt': '',
+ \ 'rightAlt': '' }
+endfunction
+
+" Function: s:SwitchToAlternativeDelimiters(printMsgs) function {{{2
+" This function is used to swap the delimiters that are being used to the
+" alternative delimiters for that filetype. For example, if a c++ file is
+" being edited and // comments are being used, after this function is called
+" /**/ comments will be used.
+"
+" Args:
+" -printMsgs: if this is 1 then a message is echoed to the user telling them
+" if this function changed the delimiters or not
+function s:SwitchToAlternativeDelimiters(printMsgs)
+ "if both of the alternative delimiters are empty then there is no
+ "alternative comment style so bail out
+ if b:NERDCommenterDelims['leftAlt'] == '' && b:NERDCommenterDelims['rightAlt'] == ''
+ if a:printMsgs
+ call s:NerdEcho("Cannot use alternative delimiters, none are specified", 0)
+ endif
+ return 0
+ endif
+
+ "save the current delimiters
+ let tempLeft = s:Left()
+ let tempRight = s:Right()
+
+ "swap current delimiters for alternative
+ let b:NERDCommenterDelims['left'] = b:NERDCommenterDelims['leftAlt']
+ let b:NERDCommenterDelims['right'] = b:NERDCommenterDelims['rightAlt']
+
+ "set the previously current delimiters to be the new alternative ones
+ let b:NERDCommenterDelims['leftAlt'] = tempLeft
+ let b:NERDCommenterDelims['rightAlt'] = tempRight
+
+ "tell the user what comment delimiters they are now using
+ if a:printMsgs
+ call s:NerdEcho("Now using " . s:Left() . " " . s:Right() . " to delimit comments", 1)
+ endif
+
+ return 1
+endfunction
+
+" Section: Comment delimiter add/removal functions {{{1
+" ============================================================================
+" Function: s:AppendCommentToLine(){{{2
+" This function appends comment delimiters at the EOL and places the cursor in
+" position to start typing the comment
+function s:AppendCommentToLine()
+ let left = s:Left({'space': 1})
+ let right = s:Right({'space': 1})
+
+ " get the len of the right delim
+ let lenRight = strlen(right)
+
+ let isLineEmpty = strlen(getline(".")) == 0
+ let insOrApp = (isLineEmpty==1 ? 'i' : 'A')
+
+ "stick the delimiters down at the end of the line. We have to format the
+ "comment with spaces as appropriate
+ execute ":normal! " . insOrApp . (isLineEmpty ? '' : ' ') . left . right . " "
+
+ " if there is a right delimiter then we gotta move the cursor left
+ " by the len of the right delimiter so we insert between the delimiters
+ if lenRight > 0
+ let leftMoveAmount = lenRight
+ execute ":normal! " . leftMoveAmount . "h"
+ endif
+ startinsert
+endfunction
+
+" Function: s:CommentBlock(top, bottom, lSide, rSide, forceNested ) {{{2
+" This function is used to comment out a region of code. This region is
+" specified as a bounding box by arguments to the function.
+"
+" Args:
+" -top: the line number for the top line of code in the region
+" -bottom: the line number for the bottom line of code in the region
+" -lSide: the column number for the left most column in the region
+" -rSide: the column number for the right most column in the region
+" -forceNested: a flag indicating whether comments should be nested
+function s:CommentBlock(top, bottom, lSide, rSide, forceNested )
+ " we need to create local copies of these arguments so we can modify them
+ let top = a:top
+ let bottom = a:bottom
+ let lSide = a:lSide
+ let rSide = a:rSide
+
+ "if the top or bottom line starts with tabs we have to adjust the left and
+ "right boundaries so that they are set as though the tabs were spaces
+ let topline = getline(top)
+ let bottomline = getline(bottom)
+ if s:HasLeadingTabs(topline, bottomline)
+
+ "find out how many tabs are in the top line and adjust the left
+ "boundary accordingly
+ let numTabs = s:NumberOfLeadingTabs(topline)
+ if lSide < numTabs
+ let lSide = &ts * lSide
+ else
+ let lSide = (lSide - numTabs) + (&ts * numTabs)
+ endif
+
+ "find out how many tabs are in the bottom line and adjust the right
+ "boundary accordingly
+ let numTabs = s:NumberOfLeadingTabs(bottomline)
+ let rSide = (rSide - numTabs) + (&ts * numTabs)
+ endif
+
+ "we must check that bottom IS actually below top, if it is not then we
+ "swap top and bottom. Similarly for left and right.
+ if bottom < top
+ let temp = top
+ let top = bottom
+ let bottom = top
+ endif
+ if rSide < lSide
+ let temp = lSide
+ let lSide = rSide
+ let rSide = temp
+ endif
+
+ "if the current delimiters arent multipart then we will switch to the
+ "alternative delims (if THEY are) as the comment will be better and more
+ "accurate with multipart delims
+ let switchedDelims = 0
+ if !s:Multipart() && g:NERDAllowAnyVisualDelims && s:AltMultipart()
+ let switchedDelims = 1
+ call s:SwitchToAlternativeDelimiters(0)
+ endif
+
+ "start the commenting from the top and keep commenting till we reach the
+ "bottom
+ let currentLine=top
+ while currentLine <= bottom
+
+ "check if we are allowed to comment this line
+ if s:CanCommentLine(a:forceNested, currentLine)
+
+ "convert the leading tabs into spaces
+ let theLine = getline(currentLine)
+ let lineHasLeadTabs = s:HasLeadingTabs(theLine)
+ if lineHasLeadTabs
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ endif
+
+ "dont comment lines that begin after the right boundary of the
+ "block unless the user has specified to do so
+ if theLine !~ '^ \{' . rSide . '\}' || !g:NERDBlockComIgnoreEmpty
+
+ "attempt to place the cursor in on the left of the boundary box,
+ "then check if we were successful, if not then we cant comment this
+ "line
+ call setline(currentLine, theLine)
+ if s:CanPlaceCursor(currentLine, lSide)
+
+ let leftSpaced = s:Left({'space': 1})
+ let rightSpaced = s:Right({'space': 1})
+
+ "stick the left delimiter down
+ let theLine = strpart(theLine, 0, lSide-1) . leftSpaced . strpart(theLine, lSide-1)
+
+ if s:Multipart()
+ "stick the right delimiter down
+ let theLine = strpart(theLine, 0, rSide+strlen(leftSpaced)) . rightSpaced . strpart(theLine, rSide+strlen(leftSpaced))
+
+ let firstLeftDelim = s:FindDelimiterIndex(s:Left(), theLine)
+ let lastRightDelim = s:LastIndexOfDelim(s:Right(), theLine)
+
+ if firstLeftDelim != -1 && lastRightDelim != -1
+ let searchStr = strpart(theLine, 0, lastRightDelim)
+ let searchStr = strpart(searchStr, firstLeftDelim+strlen(s:Left()))
+
+ "replace the outter most delims in searchStr with
+ "place-holders
+ let theLineWithPlaceHolders = s:ReplaceDelims(s:Left(), s:Right(), g:NERDLPlace, g:NERDRPlace, searchStr)
+
+ "add the right delimiter onto the line
+ let theLine = strpart(theLine, 0, firstLeftDelim+strlen(s:Left())) . theLineWithPlaceHolders . strpart(theLine, lastRightDelim)
+ endif
+ endif
+ endif
+ endif
+
+ "restore tabs if needed
+ if lineHasLeadTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+
+ call setline(currentLine, theLine)
+ endif
+
+ let currentLine = currentLine + 1
+ endwhile
+
+ "if we switched delims then we gotta go back to what they were before
+ if switchedDelims == 1
+ call s:SwitchToAlternativeDelimiters(0)
+ endif
+endfunction
+
+" Function: s:CommentLines(forceNested, alignLeft, alignRight, firstLine, lastLine) {{{2
+" This function comments a range of lines.
+"
+" Args:
+" -forceNested: a flag indicating whether the called is requesting the comment
+" to be nested if need be
+" -align: should be "left" or "both" or "none"
+" -firstLine/lastLine: the top and bottom lines to comment
+function s:CommentLines(forceNested, align, firstLine, lastLine)
+ " we need to get the left and right indexes of the leftmost char in the
+ " block of of lines and the right most char so that we can do alignment of
+ " the delimiters if the user has specified
+ let leftAlignIndx = s:LeftMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
+ let rightAlignIndx = s:RightMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
+
+ " gotta add the length of the left delimiter onto the rightAlignIndx cos
+ " we'll be adding a left delim to the line
+ let rightAlignIndx = rightAlignIndx + strlen(s:Left({'space': 1}))
+
+ " now we actually comment the lines. Do it line by line
+ let currentLine = a:firstLine
+ while currentLine <= a:lastLine
+
+ " get the next line, check commentability and convert spaces to tabs
+ let theLine = getline(currentLine)
+ let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ if s:CanCommentLine(a:forceNested, currentLine)
+ "if the user has specified forceNesting then we check to see if we
+ "need to switch delimiters for place-holders
+ if a:forceNested && g:NERDUsePlaceHolders
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+ endif
+
+ " find out if the line is commented using normal delims and/or
+ " alternate ones
+ let isCommented = s:IsCommented(s:Left(), s:Right(), theLine) || s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine)
+
+ " check if we can comment this line
+ if !isCommented || g:NERDUsePlaceHolders || s:Multipart()
+ if a:align == "left" || a:align == "both"
+ let theLine = s:AddLeftDelimAligned(s:Left({'space': 1}), theLine, leftAlignIndx)
+ else
+ let theLine = s:AddLeftDelim(s:Left({'space': 1}), theLine)
+ endif
+ if a:align == "both"
+ let theLine = s:AddRightDelimAligned(s:Right({'space': 1}), theLine, rightAlignIndx)
+ else
+ let theLine = s:AddRightDelim(s:Right({'space': 1}), theLine)
+ endif
+ endif
+ endif
+
+ " restore leading tabs if appropriate
+ if lineHasLeadingTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+
+ " we are done with this line
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+endfunction
+
+" Function: s:CommentLinesMinimal(firstLine, lastLine) {{{2
+" This function comments a range of lines in a minimal style. I
+"
+" Args:
+" -firstLine/lastLine: the top and bottom lines to comment
+function s:CommentLinesMinimal(firstLine, lastLine)
+ "check that minimal comments can be done on this filetype
+ if !s:HasMultipartDelims()
+ throw 'NERDCommenter.Delimiters exception: Minimal comments can only be used for filetypes that have multipart delimiters'
+ endif
+
+ "if we need to use place holders for the comment, make sure they are
+ "enabled for this filetype
+ if !g:NERDUsePlaceHolders && s:DoesBlockHaveMultipartDelim(a:firstLine, a:lastLine)
+ throw 'NERDCommenter.Settings exception: Place holders are required but disabled.'
+ endif
+
+ "get the left and right delims to smack on
+ let left = s:GetSexyComLeft(g:NERDSpaceDelims,0)
+ let right = s:GetSexyComRight(g:NERDSpaceDelims,0)
+
+ "make sure all multipart delims on the lines are replaced with
+ "placeholders to prevent illegal syntax
+ let currentLine = a:firstLine
+ while(currentLine <= a:lastLine)
+ let theLine = getline(currentLine)
+ let theLine = s:ReplaceDelims(left, right, g:NERDLPlace, g:NERDRPlace, theLine)
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+ "add the delim to the top line
+ let theLine = getline(a:firstLine)
+ let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ let theLine = s:AddLeftDelim(left, theLine)
+ if lineHasLeadingTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:firstLine, theLine)
+
+ "add the delim to the bottom line
+ let theLine = getline(a:lastLine)
+ let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ let theLine = s:AddRightDelim(right, theLine)
+ if lineHasLeadingTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:lastLine, theLine)
+endfunction
+
+" Function: s:CommentLinesSexy(topline, bottomline) function {{{2
+" This function is used to comment lines in the 'Sexy' style. eg in c:
+" /*
+" * This is a sexy comment
+" */
+" Args:
+" -topline: the line num of the top line in the sexy comment
+" -bottomline: the line num of the bottom line in the sexy comment
+function s:CommentLinesSexy(topline, bottomline)
+ let left = s:GetSexyComLeft(0, 0)
+ let right = s:GetSexyComRight(0, 0)
+
+ "check if we can do a sexy comment with the available delimiters
+ if left == -1 || right == -1
+ throw 'NERDCommenter.Delimiters exception: cannot perform sexy comments with available delimiters.'
+ endif
+
+ "make sure the lines arent already commented sexually
+ if !s:CanSexyCommentLines(a:topline, a:bottomline)
+ throw 'NERDCommenter.Nesting exception: cannot nest sexy comments'
+ endif
+
+
+ let sexyComMarker = s:GetSexyComMarker(0,0)
+ let sexyComMarkerSpaced = s:GetSexyComMarker(1,0)
+
+
+ " we jam the comment as far to the right as possible
+ let leftAlignIndx = s:LeftMostIndx(1, 1, a:topline, a:bottomline)
+
+ "check if we should use the compact style i.e that the left/right
+ "delimiters should appear on the first and last lines of the code and not
+ "on separate lines above/below the first/last lines of code
+ if g:NERDCompactSexyComs
+ let spaceString = (g:NERDSpaceDelims ? s:spaceStr : '')
+
+ "comment the top line
+ let theLine = getline(a:topline)
+ let lineHasTabs = s:HasLeadingTabs(theLine)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ endif
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+ let theLine = s:AddLeftDelimAligned(left . spaceString, theLine, leftAlignIndx)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:topline, theLine)
+
+ "comment the bottom line
+ if a:bottomline != a:topline
+ let theLine = getline(a:bottomline)
+ let lineHasTabs = s:HasLeadingTabs(theLine)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ endif
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+ endif
+ let theLine = s:AddRightDelim(spaceString . right, theLine)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:bottomline, theLine)
+ else
+
+ " add the left delimiter one line above the lines that are to be commented
+ call cursor(a:topline, 1)
+ execute 'normal! O'
+ let theLine = repeat(' ', leftAlignIndx) . left
+
+ " Make sure tabs are respected
+ if !&expandtab
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:topline, theLine)
+
+ " add the right delimiter after bottom line (we have to add 1 cos we moved
+ " the lines down when we added the left delim
+ call cursor(a:bottomline+1, 1)
+ execute 'normal! o'
+ let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . right
+
+ " Make sure tabs are respected
+ if !&expandtab
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:bottomline+2, theLine)
+
+ endif
+
+ " go thru each line adding the sexyComMarker marker to the start of each
+ " line in the appropriate place to align them with the comment delims
+ let currentLine = a:topline+1
+ while currentLine <= a:bottomline + !g:NERDCompactSexyComs
+ " get the line and convert the tabs to spaces
+ let theLine = getline(currentLine)
+ let lineHasTabs = s:HasLeadingTabs(theLine)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ endif
+
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+
+ " add the sexyComMarker
+ let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx)
+
+ if lineHasTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+
+
+ " set the line and move onto the next one
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+endfunction
+
+" Function: s:CommentLinesToggle(forceNested, firstLine, lastLine) {{{2
+" Applies "toggle" commenting to the given range of lines
+"
+" Args:
+" -forceNested: a flag indicating whether the called is requesting the comment
+" to be nested if need be
+" -firstLine/lastLine: the top and bottom lines to comment
+function s:CommentLinesToggle(forceNested, firstLine, lastLine)
+ let currentLine = a:firstLine
+ while currentLine <= a:lastLine
+
+ " get the next line, check commentability and convert spaces to tabs
+ let theLine = getline(currentLine)
+ let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ if s:CanToggleCommentLine(a:forceNested, currentLine)
+
+ "if the user has specified forceNesting then we check to see if we
+ "need to switch delimiters for place-holders
+ if g:NERDUsePlaceHolders
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+ endif
+
+ let theLine = s:AddLeftDelim(s:Left({'space': 1}), theLine)
+ let theLine = s:AddRightDelim(s:Right({'space': 1}), theLine)
+ endif
+
+ " restore leading tabs if appropriate
+ if lineHasLeadingTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+
+ " we are done with this line
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+endfunction
+
+" Function: s:CommentRegion(topline, topCol, bottomLine, bottomCol) function {{{2
+" This function comments chunks of text selected in visual mode.
+" It will comment exactly the text that they have selected.
+" Args:
+" -topLine: the line num of the top line in the sexy comment
+" -topCol: top left col for this comment
+" -bottomline: the line num of the bottom line in the sexy comment
+" -bottomCol: the bottom right col for this comment
+" -forceNested: whether the caller wants comments to be nested if the
+" line(s) are already commented
+function s:CommentRegion(topLine, topCol, bottomLine, bottomCol, forceNested)
+
+ "switch delims (if we can) if the current set isnt multipart
+ let switchedDelims = 0
+ if !s:Multipart() && s:AltMultipart() && !g:NERDAllowAnyVisualDelims
+ let switchedDelims = 1
+ call s:SwitchToAlternativeDelimiters(0)
+ endif
+
+ "if there is only one line in the comment then just do it
+ if a:topLine == a:bottomLine
+ call s:CommentBlock(a:topLine, a:bottomLine, a:topCol, a:bottomCol, a:forceNested)
+
+ "there are multiple lines in the comment
+ else
+ "comment the top line
+ call s:CommentBlock(a:topLine, a:topLine, a:topCol, strlen(getline(a:topLine)), a:forceNested)
+
+ "comment out all the lines in the middle of the comment
+ let topOfRange = a:topLine+1
+ let bottomOfRange = a:bottomLine-1
+ if topOfRange <= bottomOfRange
+ call s:CommentLines(a:forceNested, "none", topOfRange, bottomOfRange)
+ endif
+
+ "comment the bottom line
+ let bottom = getline(a:bottomLine)
+ let numLeadingSpacesTabs = strlen(substitute(bottom, '^\([ \t]*\).*$', '\1', ''))
+ call s:CommentBlock(a:bottomLine, a:bottomLine, numLeadingSpacesTabs+1, a:bottomCol, a:forceNested)
+
+ endif
+
+ "stick the cursor back on the char it was on before the comment
+ call cursor(a:topLine, a:topCol + strlen(s:Left()) + g:NERDSpaceDelims)
+
+ "if we switched delims then we gotta go back to what they were before
+ if switchedDelims == 1
+ call s:SwitchToAlternativeDelimiters(0)
+ endif
+
+endfunction
+
+" Function: s:InvertComment(firstLine, lastLine) function {{{2
+" Inverts the comments on the lines between and including the given line
+" numbers i.e all commented lines are uncommented and vice versa
+" Args:
+" -firstLine: the top of the range of lines to be inverted
+" -lastLine: the bottom of the range of lines to be inverted
+function s:InvertComment(firstLine, lastLine)
+
+ " go thru all lines in the given range
+ let currentLine = a:firstLine
+ while currentLine <= a:lastLine
+ let theLine = getline(currentLine)
+
+ let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
+
+ " if the line is commented normally, uncomment it
+ if s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)
+ call s:UncommentLines(currentLine, currentLine)
+ let currentLine = currentLine + 1
+
+ " check if the line is commented sexually
+ elseif !empty(sexyComBounds)
+ let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
+ call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
+
+ "move to the line after last line of the sexy comment
+ let numLinesAfterSexyComRemoved = s:NumLinesInBuf()
+ let currentLine = sexyComBounds[1] - (numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved) + 1
+
+ " the line isnt commented
+ else
+ call s:CommentLinesToggle(1, currentLine, currentLine)
+ let currentLine = currentLine + 1
+ endif
+
+ endwhile
+endfunction
+
+" Function: NERDComment(isVisual, type) function {{{2
+" This function is a Wrapper for the main commenting functions
+"
+" Args:
+" -isVisual: a flag indicating whether the comment is requested in visual
+" mode or not
+" -type: the type of commenting requested. Can be 'sexy', 'invert',
+" 'minimal', 'toggle', 'alignLeft', 'alignBoth', 'norm',
+" 'nested', 'toEOL', 'append', 'insert', 'uncomment', 'yank'
+function! NERDComment(isVisual, type) range
+ " we want case sensitivity when commenting
+ let oldIgnoreCase = &ignorecase
+ set noignorecase
+
+ if !exists("g:did_load_ftplugin") || g:did_load_ftplugin != 1
+ call s:NerdEcho("filetype plugins should be enabled. See :help NERDComInstallation and :help :filetype-plugin-on", 0)
+ endif
+
+ if a:isVisual
+ let firstLine = line("'<")
+ let lastLine = line("'>")
+ let firstCol = col("'<")
+ let lastCol = col("'>") - (&selection == 'exclusive' ? 1 : 0)
+ else
+ let firstLine = a:firstline
+ let lastLine = a:lastline
+ endif
+
+ let countWasGiven = (a:isVisual == 0 && firstLine != lastLine)
+
+ let forceNested = (a:type == 'nested' || g:NERDDefaultNesting)
+
+ if a:type == 'norm' || a:type == 'nested'
+ if a:isVisual && visualmode() == ""
+ call s:CommentBlock(firstLine, lastLine, firstCol, lastCol, forceNested)
+ elseif a:isVisual && visualmode() == "v" && (g:NERDCommentWholeLinesInVMode==0 || (g:NERDCommentWholeLinesInVMode==2 && s:HasMultipartDelims()))
+ call s:CommentRegion(firstLine, firstCol, lastLine, lastCol, forceNested)
+ else
+ call s:CommentLines(forceNested, "none", firstLine, lastLine)
+ endif
+
+ elseif a:type == 'alignLeft' || a:type == 'alignBoth'
+ let align = "none"
+ if a:type == "alignLeft"
+ let align = "left"
+ elseif a:type == "alignBoth"
+ let align = "both"
+ endif
+ call s:CommentLines(forceNested, align, firstLine, lastLine)
+
+ elseif a:type == 'invert'
+ call s:InvertComment(firstLine, lastLine)
+
+ elseif a:type == 'sexy'
+ try
+ call s:CommentLinesSexy(firstLine, lastLine)
+ catch /NERDCommenter.Delimiters/
+ call s:CommentLines(forceNested, "none", firstLine, lastLine)
+ catch /NERDCommenter.Nesting/
+ call s:NerdEcho("Sexy comment aborted. Nested sexy cannot be nested", 0)
+ endtry
+
+ elseif a:type == 'toggle'
+ let theLine = getline(firstLine)
+
+ if s:IsInSexyComment(firstLine) || s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)
+ call s:UncommentLines(firstLine, lastLine)
+ else
+ call s:CommentLinesToggle(forceNested, firstLine, lastLine)
+ endif
+
+ elseif a:type == 'minimal'
+ try
+ call s:CommentLinesMinimal(firstLine, lastLine)
+ catch /NERDCommenter.Delimiters/
+ call s:NerdEcho("Minimal comments can only be used for filetypes that have multipart delimiters.", 0)
+ catch /NERDCommenter.Settings/
+ call s:NerdEcho("Place holders are required but disabled.", 0)
+ endtry
+
+ elseif a:type == 'toEOL'
+ call s:SaveScreenState()
+ call s:CommentBlock(firstLine, firstLine, col("."), col("$")-1, 1)
+ call s:RestoreScreenState()
+
+ elseif a:type == 'append'
+ call s:AppendCommentToLine()
+
+ elseif a:type == 'insert'
+ call s:PlaceDelimitersAndInsBetween()
+
+ elseif a:type == 'uncomment'
+ call s:UncommentLines(firstLine, lastLine)
+
+ elseif a:type == 'yank'
+ if a:isVisual
+ normal! gvy
+ elseif countWasGiven
+ execute firstLine .','. lastLine .'yank'
+ else
+ normal! yy
+ endif
+ execute firstLine .','. lastLine .'call NERDComment('. a:isVisual .', "norm")'
+ endif
+
+ let &ignorecase = oldIgnoreCase
+endfunction
+
+" Function: s:PlaceDelimitersAndInsBetween() function {{{2
+" This is function is called to place comment delimiters down and place the
+" cursor between them
+function s:PlaceDelimitersAndInsBetween()
+ " get the left and right delimiters without any escape chars in them
+ let left = s:Left({'space': 1})
+ let right = s:Right({'space': 1})
+
+ let theLine = getline(".")
+ let lineHasLeadTabs = s:HasLeadingTabs(theLine) || (theLine =~ '^ *$' && !&expandtab)
+
+ "convert tabs to spaces and adjust the cursors column to take this into
+ "account
+ let untabbedCol = s:UntabbedCol(theLine, col("."))
+ call setline(line("."), s:ConvertLeadingTabsToSpaces(theLine))
+ call cursor(line("."), untabbedCol)
+
+ " get the len of the right delim
+ let lenRight = strlen(right)
+
+ let isDelimOnEOL = col(".") >= strlen(getline("."))
+
+ " if the cursor is in the first col then we gotta insert rather than
+ " append the comment delimiters here
+ let insOrApp = (col(".")==1 ? 'i' : 'a')
+
+ " place the delimiters down. We do it differently depending on whether
+ " there is a left AND right delimiter
+ if lenRight > 0
+ execute ":normal! " . insOrApp . left . right
+ execute ":normal! " . lenRight . "h"
+ else
+ execute ":normal! " . insOrApp . left
+
+ " if we are tacking the delim on the EOL then we gotta add a space
+ " after it cos when we go out of insert mode the cursor will move back
+ " one and the user wont be in position to type the comment.
+ if isDelimOnEOL
+ execute 'normal! a '
+ endif
+ endif
+ normal! l
+
+ "if needed convert spaces back to tabs and adjust the cursors col
+ "accordingly
+ if lineHasLeadTabs
+ let tabbedCol = s:TabbedCol(getline("."), col("."))
+ call setline(line("."), s:ConvertLeadingSpacesToTabs(getline(".")))
+ call cursor(line("."), tabbedCol)
+ endif
+
+ startinsert
+endfunction
+
+" Function: s:RemoveDelimiters(left, right, line) {{{2
+" this function is called to remove the first left comment delimiter and the
+" last right delimiter of the given line.
+"
+" The args left and right must be strings. If there is no right delimiter (as
+" is the case for e.g vim file comments) them the arg right should be ""
+"
+" Args:
+" -left: the left comment delimiter
+" -right: the right comment delimiter
+" -line: the line to remove the delimiters from
+function s:RemoveDelimiters(left, right, line)
+
+ let l:left = a:left
+ let l:right = a:right
+ let lenLeft = strlen(left)
+ let lenRight = strlen(right)
+
+ let delimsSpaced = (g:NERDSpaceDelims || g:NERDRemoveExtraSpaces)
+
+ let line = a:line
+
+ "look for the left delimiter, if we find it, remove it.
+ let leftIndx = s:FindDelimiterIndex(a:left, line)
+ if leftIndx != -1
+ let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+lenLeft)
+
+ "if the user has specified that there is a space after the left delim
+ "then check for the space and remove it if it is there
+ if delimsSpaced && strpart(line, leftIndx, s:lenSpaceStr) == s:spaceStr
+ let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+s:lenSpaceStr)
+ endif
+ endif
+
+ "look for the right delimiter, if we find it, remove it
+ let rightIndx = s:FindDelimiterIndex(a:right, line)
+ if rightIndx != -1
+ let line = strpart(line, 0, rightIndx) . strpart(line, rightIndx+lenRight)
+
+ "if the user has specified that there is a space before the right delim
+ "then check for the space and remove it if it is there
+ if delimsSpaced && strpart(line, rightIndx-s:lenSpaceStr, s:lenSpaceStr) == s:spaceStr && s:Multipart()
+ let line = strpart(line, 0, rightIndx-s:lenSpaceStr) . strpart(line, rightIndx)
+ endif
+ endif
+
+ return line
+endfunction
+
+" Function: s:UncommentLines(topLine, bottomLine) {{{2
+" This function uncomments the given lines
+"
+" Args:
+" topLine: the top line of the visual selection to uncomment
+" bottomLine: the bottom line of the visual selection to uncomment
+function s:UncommentLines(topLine, bottomLine)
+ "make local copies of a:firstline and a:lastline and, if need be, swap
+ "them around if the top line is below the bottom
+ let l:firstline = a:topLine
+ let l:lastline = a:bottomLine
+ if firstline > lastline
+ let firstline = lastline
+ let lastline = a:topLine
+ endif
+
+ "go thru each line uncommenting each line removing sexy comments
+ let currentLine = firstline
+ while currentLine <= lastline
+
+ "check the current line to see if it is part of a sexy comment
+ let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
+ if !empty(sexyComBounds)
+
+ "we need to store the num lines in the buf before the comment is
+ "removed so we know how many lines were removed when the sexy com
+ "was removed
+ let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
+
+ call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
+
+ "move to the line after last line of the sexy comment
+ let numLinesAfterSexyComRemoved = s:NumLinesInBuf()
+ let numLinesRemoved = numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved
+ let currentLine = sexyComBounds[1] - numLinesRemoved + 1
+ let lastline = lastline - numLinesRemoved
+
+ "no sexy com was detected so uncomment the line as normal
+ else
+ call s:UncommentLinesNormal(currentLine, currentLine)
+ let currentLine = currentLine + 1
+ endif
+ endwhile
+
+endfunction
+
+" Function: s:UncommentLinesSexy(topline, bottomline) {{{2
+" This function removes all the comment characters associated with the sexy
+" comment spanning the given lines
+" Args:
+" -topline/bottomline: the top/bottom lines of the sexy comment
+function s:UncommentLinesSexy(topline, bottomline)
+ let left = s:GetSexyComLeft(0,1)
+ let right = s:GetSexyComRight(0,1)
+
+
+ "check if it is even possible for sexy comments to exist with the
+ "available delimiters
+ if left == -1 || right == -1
+ throw 'NERDCommenter.Delimiters exception: cannot uncomment sexy comments with available delimiters.'
+ endif
+
+ let leftUnEsc = s:GetSexyComLeft(0,0)
+ let rightUnEsc = s:GetSexyComRight(0,0)
+
+ let sexyComMarker = s:GetSexyComMarker(0, 1)
+ let sexyComMarkerUnEsc = s:GetSexyComMarker(0, 0)
+
+ "the markerOffset is how far right we need to move the sexyComMarker to
+ "line it up with the end of the left delim
+ let markerOffset = strlen(leftUnEsc)-strlen(sexyComMarkerUnEsc)
+
+ " go thru the intermediate lines of the sexy comment and remove the
+ " sexy comment markers (eg the '*'s on the start of line in a c sexy
+ " comment)
+ let currentLine = a:topline+1
+ while currentLine < a:bottomline
+ let theLine = getline(currentLine)
+
+ " remove the sexy comment marker from the line. We also remove the
+ " space after it if there is one and if appropriate options are set
+ let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc)
+ if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
+ let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr)
+ else
+ let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
+ endif
+
+ let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
+
+ let theLine = s:ConvertLeadingWhiteSpace(theLine)
+
+ " move onto the next line
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+ " gotta make a copy of a:bottomline cos we modify the position of the
+ " last line it if we remove the topline
+ let bottomline = a:bottomline
+
+ " get the first line so we can remove the left delim from it
+ let theLine = getline(a:topline)
+
+ " if the first line contains only the left delim then just delete it
+ if theLine =~ '^[ \t]*' . left . '[ \t]*$' && !g:NERDCompactSexyComs
+ call cursor(a:topline, 1)
+ normal! dd
+ let bottomline = bottomline - 1
+
+ " topline contains more than just the left delim
+ else
+
+ " remove the delim. If there is a space after it
+ " then remove this too if appropriate
+ let delimIndx = stridx(theLine, leftUnEsc)
+ if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
+ let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)+s:lenSpaceStr)
+ else
+ let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc))
+ endif
+ let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
+ call setline(a:topline, theLine)
+ endif
+
+ " get the last line so we can remove the right delim
+ let theLine = getline(bottomline)
+
+ " if the bottomline contains only the right delim then just delete it
+ if theLine =~ '^[ \t]*' . right . '[ \t]*$'
+ call cursor(bottomline, 1)
+ normal! dd
+
+ " the last line contains more than the right delim
+ else
+ " remove the right delim. If there is a space after it and
+ " if the appropriate options are set then remove this too.
+ let delimIndx = s:LastIndexOfDelim(rightUnEsc, theLine)
+ if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
+ let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)+s:lenSpaceStr)
+ else
+ let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc))
+ endif
+
+ " if the last line also starts with a sexy comment marker then we
+ " remove this as well
+ if theLine =~ '^[ \t]*' . sexyComMarker
+
+ " remove the sexyComMarker. If there is a space after it then
+ " remove that too
+ let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc)
+ if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
+ let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr)
+ else
+ let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
+ endif
+ endif
+
+ let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
+ call setline(bottomline, theLine)
+ endif
+endfunction
+
+" Function: s:UncommentLineNormal(line) {{{2
+" uncomments the given line and returns the result
+" Args:
+" -line: the line to uncomment
+function s:UncommentLineNormal(line)
+ let line = a:line
+
+ "get the comment status on the line so we know how it is commented
+ let lineCommentStatus = s:IsCommentedOuttermost(s:Left(), s:Right(), s:Left({'alt': 1}), s:Right({'alt': 1}), line)
+
+ "it is commented with s:Left() and s:Right() so remove these delims
+ if lineCommentStatus == 1
+ let line = s:RemoveDelimiters(s:Left(), s:Right(), line)
+
+ "it is commented with s:Left({'alt': 1}) and s:Right({'alt': 1}) so remove these delims
+ elseif lineCommentStatus == 2 && g:NERDRemoveAltComs
+ let line = s:RemoveDelimiters(s:Left({'alt': 1}), s:Right({'alt': 1}), line)
+
+ "it is not properly commented with any delims so we check if it has
+ "any random left or right delims on it and remove the outtermost ones
+ else
+ "get the positions of all delim types on the line
+ let indxLeft = s:FindDelimiterIndex(s:Left(), line)
+ let indxLeftAlt = s:FindDelimiterIndex(s:Left({'alt': 1}), line)
+ let indxRight = s:FindDelimiterIndex(s:Right(), line)
+ let indxRightAlt = s:FindDelimiterIndex(s:Right({'alt': 1}), line)
+
+ "remove the outter most left comment delim
+ if indxLeft != -1 && (indxLeft < indxLeftAlt || indxLeftAlt == -1)
+ let line = s:RemoveDelimiters(s:Left(), '', line)
+ elseif indxLeftAlt != -1
+ let line = s:RemoveDelimiters(s:Left({'alt': 1}), '', line)
+ endif
+
+ "remove the outter most right comment delim
+ if indxRight != -1 && (indxRight < indxRightAlt || indxRightAlt == -1)
+ let line = s:RemoveDelimiters('', s:Right(), line)
+ elseif indxRightAlt != -1
+ let line = s:RemoveDelimiters('', s:Right({'alt': 1}), line)
+ endif
+ endif
+
+
+ let indxLeft = s:FindDelimiterIndex(s:Left(), line)
+ let indxLeftAlt = s:FindDelimiterIndex(s:Left({'alt': 1}), line)
+ let indxLeftPlace = s:FindDelimiterIndex(g:NERDLPlace, line)
+
+ let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line)
+ let indxRightAlt = s:FindDelimiterIndex(s:Right({'alt': 1}), line)
+ let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line)
+
+ let right = s:Right()
+ let left = s:Left()
+ if !s:Multipart()
+ let right = s:Right({'alt': 1})
+ let left = s:Left({'alt': 1})
+ endif
+
+
+ "if there are place-holders on the line then we check to see if they are
+ "the outtermost delimiters on the line. If so then we replace them with
+ "real delimiters
+ if indxLeftPlace != -1
+ if (indxLeftPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1)
+ let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line)
+ endif
+ elseif indxRightPlace != -1
+ if (indxRightPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1)
+ let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line)
+ endif
+
+ endif
+
+ let line = s:ConvertLeadingWhiteSpace(line)
+
+ return line
+endfunction
+
+" Function: s:UncommentLinesNormal(topline, bottomline) {{{2
+" This function is called to uncomment lines that arent a sexy comment
+" Args:
+" -topline/bottomline: the top/bottom line numbers of the comment
+function s:UncommentLinesNormal(topline, bottomline)
+ let currentLine = a:topline
+ while currentLine <= a:bottomline
+ let line = getline(currentLine)
+ call setline(currentLine, s:UncommentLineNormal(line))
+ let currentLine = currentLine + 1
+ endwhile
+endfunction
+
+
+" Section: Other helper functions {{{1
+" ============================================================================
+
+" Function: s:AddLeftDelim(delim, theLine) {{{2
+" Args:
+function s:AddLeftDelim(delim, theLine)
+ return substitute(a:theLine, '^\([ \t]*\)', '\1' . a:delim, '')
+endfunction
+
+" Function: s:AddLeftDelimAligned(delim, theLine) {{{2
+" Args:
+function s:AddLeftDelimAligned(delim, theLine, alignIndx)
+
+ "if the line is not long enough then bung some extra spaces on the front
+ "so we can align the delim properly
+ let theLine = a:theLine
+ if strlen(theLine) < a:alignIndx
+ let theLine = repeat(' ', a:alignIndx - strlen(theLine))
+ endif
+
+ return strpart(theLine, 0, a:alignIndx) . a:delim . strpart(theLine, a:alignIndx)
+endfunction
+
+" Function: s:AddRightDelim(delim, theLine) {{{2
+" Args:
+function s:AddRightDelim(delim, theLine)
+ if a:delim == ''
+ return a:theLine
+ else
+ return substitute(a:theLine, '$', a:delim, '')
+ endif
+endfunction
+
+" Function: s:AddRightDelimAligned(delim, theLine, alignIndx) {{{2
+" Args:
+function s:AddRightDelimAligned(delim, theLine, alignIndx)
+ if a:delim == ""
+ return a:theLine
+ else
+
+ " when we align the right delim we are just adding spaces
+ " so we get a string containing the needed spaces (it
+ " could be empty)
+ let extraSpaces = ''
+ let extraSpaces = repeat(' ', a:alignIndx-strlen(a:theLine))
+
+ " add the right delim
+ return substitute(a:theLine, '$', extraSpaces . a:delim, '')
+ endif
+endfunction
+
+" Function: s:AltMultipart() {{{2
+" returns 1 if the alternative delims are multipart
+function s:AltMultipart()
+ return b:NERDCommenterDelims['rightAlt'] != ''
+endfunction
+
+" Function: s:CanCommentLine(forceNested, line) {{{2
+"This function is used to determine whether the given line can be commented.
+"It returns 1 if it can be and 0 otherwise
+"
+" Args:
+" -forceNested: a flag indicating whether the caller wants comments to be nested
+" if the current line is already commented
+" -lineNum: the line num of the line to check for commentability
+function s:CanCommentLine(forceNested, lineNum)
+ let theLine = getline(a:lineNum)
+
+ " make sure we don't comment lines that are just spaces or tabs or empty.
+ if theLine =~ "^[ \t]*$"
+ return 0
+ endif
+
+ "if the line is part of a sexy comment then just flag it...
+ if s:IsInSexyComment(a:lineNum)
+ return 0
+ endif
+
+ let isCommented = s:IsCommentedNormOrSexy(a:lineNum)
+
+ "if the line isnt commented return true
+ if !isCommented
+ return 1
+ endif
+
+ "if the line is commented but nesting is allowed then return true
+ if a:forceNested && (!s:Multipart() || g:NERDUsePlaceHolders)
+ return 1
+ endif
+
+ return 0
+endfunction
+
+" Function: s:CanPlaceCursor(line, col) {{{2
+" returns 1 if the cursor can be placed exactly in the given position
+function s:CanPlaceCursor(line, col)
+ let c = col(".")
+ let l = line(".")
+ call cursor(a:line, a:col)
+ let success = (line(".") == a:line && col(".") == a:col)
+ call cursor(l,c)
+ return success
+endfunction
+
+" Function: s:CanSexyCommentLines(topline, bottomline) {{{2
+" Return: 1 if the given lines can be commented sexually, 0 otherwise
+function s:CanSexyCommentLines(topline, bottomline)
+ " see if the selected regions have any sexy comments
+ let currentLine = a:topline
+ while(currentLine <= a:bottomline)
+ if s:IsInSexyComment(currentLine)
+ return 0
+ endif
+ let currentLine = currentLine + 1
+ endwhile
+ return 1
+endfunction
+" Function: s:CanToggleCommentLine(forceNested, line) {{{2
+"This function is used to determine whether the given line can be toggle commented.
+"It returns 1 if it can be and 0 otherwise
+"
+" Args:
+" -lineNum: the line num of the line to check for commentability
+function s:CanToggleCommentLine(forceNested, lineNum)
+ let theLine = getline(a:lineNum)
+ if (s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)) && !a:forceNested
+ return 0
+ endif
+
+ " make sure we don't comment lines that are just spaces or tabs or empty.
+ if theLine =~ "^[ \t]*$"
+ return 0
+ endif
+
+ "if the line is part of a sexy comment then just flag it...
+ if s:IsInSexyComment(a:lineNum)
+ return 0
+ endif
+
+ return 1
+endfunction
+
+" Function: s:ConvertLeadingSpacesToTabs(line) {{{2
+" This function takes a line and converts all leading tabs on that line into
+" spaces
+"
+" Args:
+" -line: the line whose leading tabs will be converted
+function s:ConvertLeadingSpacesToTabs(line)
+ let toReturn = a:line
+ while toReturn =~ '^\t*' . s:TabSpace() . '\(.*\)$'
+ let toReturn = substitute(toReturn, '^\(\t*\)' . s:TabSpace() . '\(.*\)$' , '\1\t\2' , "")
+ endwhile
+
+ return toReturn
+endfunction
+
+
+" Function: s:ConvertLeadingTabsToSpaces(line) {{{2
+" This function takes a line and converts all leading spaces on that line into
+" tabs
+"
+" Args:
+" -line: the line whose leading spaces will be converted
+function s:ConvertLeadingTabsToSpaces(line)
+ let toReturn = a:line
+ while toReturn =~ '^\( *\)\t'
+ let toReturn = substitute(toReturn, '^\( *\)\t', '\1' . s:TabSpace() , "")
+ endwhile
+
+ return toReturn
+endfunction
+
+" Function: s:ConvertLeadingWhiteSpace(line) {{{2
+" Converts the leading white space to tabs/spaces depending on &ts
+"
+" Args:
+" -line: the line to convert
+function s:ConvertLeadingWhiteSpace(line)
+ let toReturn = a:line
+ while toReturn =~ '^ *\t'
+ let toReturn = substitute(toReturn, '^ *\zs\t\ze', s:TabSpace(), "g")
+ endwhile
+
+ if !&expandtab
+ let toReturn = s:ConvertLeadingSpacesToTabs(toReturn)
+ endif
+
+ return toReturn
+endfunction
+
+
+" Function: s:CountNonESCedOccurances(str, searchstr, escChar) {{{2
+" This function counts the number of substrings contained in another string.
+" These substrings are only counted if they are not escaped with escChar
+" Args:
+" -str: the string to look for searchstr in
+" -searchstr: the substring to search for in str
+" -escChar: the escape character which, when preceding an instance of
+" searchstr, will cause it not to be counted
+function s:CountNonESCedOccurances(str, searchstr, escChar)
+ "get the index of the first occurrence of searchstr
+ let indx = stridx(a:str, a:searchstr)
+
+ "if there is an instance of searchstr in str process it
+ if indx != -1
+ "get the remainder of str after this instance of searchstr is removed
+ let lensearchstr = strlen(a:searchstr)
+ let strLeft = strpart(a:str, indx+lensearchstr)
+
+ "if this instance of searchstr is not escaped, add one to the count
+ "and recurse. If it is escaped, just recurse
+ if !s:IsEscaped(a:str, indx, a:escChar)
+ return 1 + s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
+ else
+ return s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
+ endif
+ endif
+endfunction
+" Function: s:DoesBlockHaveDelim(delim, top, bottom) {{{2
+" Returns 1 if the given block of lines has a delimiter (a:delim) in it
+" Args:
+" -delim: the comment delimiter to check the block for
+" -top: the top line number of the block
+" -bottom: the bottom line number of the block
+function s:DoesBlockHaveDelim(delim, top, bottom)
+ let currentLine = a:top
+ while currentLine < a:bottom
+ let theline = getline(currentLine)
+ if s:FindDelimiterIndex(a:delim, theline) != -1
+ return 1
+ endif
+ let currentLine = currentLine + 1
+ endwhile
+ return 0
+endfunction
+
+" Function: s:DoesBlockHaveMultipartDelim(top, bottom) {{{2
+" Returns 1 if the given block has a >= 1 multipart delimiter in it
+" Args:
+" -top: the top line number of the block
+" -bottom: the bottom line number of the block
+function s:DoesBlockHaveMultipartDelim(top, bottom)
+ if s:HasMultipartDelims()
+ if s:Multipart()
+ return s:DoesBlockHaveDelim(s:Left(), a:top, a:bottom) || s:DoesBlockHaveDelim(s:Right(), a:top, a:bottom)
+ else
+ return s:DoesBlockHaveDelim(s:Left({'alt': 1}), a:top, a:bottom) || s:DoesBlockHaveDelim(s:Right({'alt': 1}), a:top, a:bottom)
+ endif
+ endif
+ return 0
+endfunction
+
+
+" Function: s:Esc(str) {{{2
+" Escapes all the tricky chars in the given string
+function s:Esc(str)
+ let charsToEsc = '*/\."&$+'
+ return escape(a:str, charsToEsc)
+endfunction
+
+" Function: s:FindDelimiterIndex(delimiter, line) {{{2
+" This function is used to get the string index of the input comment delimiter
+" on the input line. If no valid comment delimiter is found in the line then
+" -1 is returned
+" Args:
+" -delimiter: the delimiter we are looking to find the index of
+" -line: the line we are looking for delimiter on
+function s:FindDelimiterIndex(delimiter, line)
+
+ "make sure the delimiter isnt empty otherwise we go into an infinite loop.
+ if a:delimiter == ""
+ return -1
+ endif
+
+
+ let l:delimiter = a:delimiter
+ let lenDel = strlen(l:delimiter)
+
+ "get the index of the first occurrence of the delimiter
+ let delIndx = stridx(a:line, l:delimiter)
+
+ "keep looping thru the line till we either find a real comment delimiter
+ "or run off the EOL
+ while delIndx != -1
+
+ "if we are not off the EOL get the str before the possible delimiter
+ "in question and check if it really is a delimiter. If it is, return
+ "its position
+ if delIndx != -1
+ if s:IsDelimValid(l:delimiter, delIndx, a:line)
+ return delIndx
+ endif
+ endif
+
+ "we have not yet found a real comment delimiter so move past the
+ "current one we are lookin at
+ let restOfLine = strpart(a:line, delIndx + lenDel)
+ let distToNextDelim = stridx(restOfLine , l:delimiter)
+
+ "if distToNextDelim is -1 then there is no more potential delimiters
+ "on the line so set delIndx to -1. Otherwise, move along the line by
+ "distToNextDelim
+ if distToNextDelim == -1
+ let delIndx = -1
+ else
+ let delIndx = delIndx + lenDel + distToNextDelim
+ endif
+ endwhile
+
+ "there is no comment delimiter on this line
+ return -1
+endfunction
+
+" Function: s:FindBoundingLinesOfSexyCom(lineNum) {{{2
+" This function takes in a line number and tests whether this line number is
+" the top/bottom/middle line of a sexy comment. If it is then the top/bottom
+" lines of the sexy comment are returned
+" Args:
+" -lineNum: the line number that is to be tested whether it is the
+" top/bottom/middle line of a sexy com
+" Returns:
+" A string that has the top/bottom lines of the sexy comment encoded in it.
+" The format is 'topline,bottomline'. If a:lineNum turns out not to be the
+" top/bottom/middle of a sexy comment then -1 is returned
+function s:FindBoundingLinesOfSexyCom(lineNum)
+
+ "find which delimiters to look for as the start/end delims of the comment
+ let left = ''
+ let right = ''
+ if s:Multipart()
+ let left = s:Left({'esc': 1})
+ let right = s:Right({'esc': 1})
+ elseif s:AltMultipart()
+ let left = s:Left({'alt': 1, 'esc': 1})
+ let right = s:Right({'alt': 1, 'esc': 1})
+ else
+ return []
+ endif
+
+ let sexyComMarker = s:GetSexyComMarker(0, 1)
+
+ "initialise the top/bottom line numbers of the sexy comment to -1
+ let top = -1
+ let bottom = -1
+
+ let currentLine = a:lineNum
+ while top == -1 || bottom == -1
+ let theLine = getline(currentLine)
+
+ "check if the current line is the top of the sexy comment
+ if currentLine <= a:lineNum && theLine =~ '^[ \t]*' . left && theLine !~ '.*' . right && currentLine < s:NumLinesInBuf()
+ let top = currentLine
+ let currentLine = a:lineNum
+
+ "check if the current line is the bottom of the sexy comment
+ elseif theLine =~ '^[ \t]*' . right && theLine !~ '.*' . left && currentLine > 1
+ let bottom = currentLine
+
+ "the right delimiter is on the same line as the last sexyComMarker
+ elseif theLine =~ '^[ \t]*' . sexyComMarker . '.*' . right
+ let bottom = currentLine
+
+ "we have not found the top or bottom line so we assume currentLine is an
+ "intermediate line and look to prove otherwise
+ else
+
+ "if the line doesnt start with a sexyComMarker then it is not a sexy
+ "comment
+ if theLine !~ '^[ \t]*' . sexyComMarker
+ return []
+ endif
+
+ endif
+
+ "if top is -1 then we havent found the top yet so keep looking up
+ if top == -1
+ let currentLine = currentLine - 1
+ "if we have found the top line then go down looking for the bottom
+ else
+ let currentLine = currentLine + 1
+ endif
+
+ endwhile
+
+ return [top, bottom]
+endfunction
+
+
+" Function: s:GetSexyComMarker() {{{2
+" Returns the sexy comment marker for the current filetype.
+"
+" C style sexy comments are assumed if possible. If not then the sexy comment
+" marker is the last char of the delimiter pair that has both left and right
+" delims and has the longest left delim
+"
+" Args:
+" -space: specifies whether the marker is to have a space string after it
+" (the space string will only be added if NERDSpaceDelims is set)
+" -esc: specifies whether the tricky chars in the marker are to be ESCed
+function s:GetSexyComMarker(space, esc)
+ let sexyComMarker = b:NERDSexyComMarker
+
+ "if there is no hardcoded marker then we find one
+ if sexyComMarker == ''
+
+ "if the filetype has c style comments then use standard c sexy
+ "comments
+ if s:HasCStyleComments()
+ let sexyComMarker = '*'
+ else
+ "find a comment marker by getting the longest available left delim
+ "(that has a corresponding right delim) and taking the last char
+ let lenLeft = strlen(s:Left())
+ let lenLeftAlt = strlen(s:Left({'alt': 1}))
+ let left = ''
+ let right = ''
+ if s:Multipart() && lenLeft >= lenLeftAlt
+ let left = s:Left()
+ elseif s:AltMultipart()
+ let left = s:Left({'alt': 1})
+ else
+ return -1
+ endif
+
+ "get the last char of left
+ let sexyComMarker = strpart(left, strlen(left)-1)
+ endif
+ endif
+
+ if a:space && g:NERDSpaceDelims
+ let sexyComMarker = sexyComMarker . s:spaceStr
+ endif
+
+ if a:esc
+ let sexyComMarker = s:Esc(sexyComMarker)
+ endif
+
+ return sexyComMarker
+endfunction
+
+" Function: s:GetSexyComLeft(space, esc) {{{2
+" Returns the left delimiter for sexy comments for this filetype or -1 if
+" there is none. C style sexy comments are used if possible
+" Args:
+" -space: specifies if the delim has a space string on the end
+" (the space string will only be added if NERDSpaceDelims is set)
+" -esc: specifies whether the tricky chars in the string are ESCed
+function s:GetSexyComLeft(space, esc)
+ let lenLeft = strlen(s:Left())
+ let lenLeftAlt = strlen(s:Left({'alt': 1}))
+ let left = ''
+
+ "assume c style sexy comments if possible
+ if s:HasCStyleComments()
+ let left = '/*'
+ else
+ "grab the longest left delim that has a right
+ if s:Multipart() && lenLeft >= lenLeftAlt
+ let left = s:Left()
+ elseif s:AltMultipart()
+ let left = s:Left({'alt': 1})
+ else
+ return -1
+ endif
+ endif
+
+ if a:space && g:NERDSpaceDelims
+ let left = left . s:spaceStr
+ endif
+
+ if a:esc
+ let left = s:Esc(left)
+ endif
+
+ return left
+endfunction
+
+" Function: s:GetSexyComRight(space, esc) {{{2
+" Returns the right delimiter for sexy comments for this filetype or -1 if
+" there is none. C style sexy comments are used if possible.
+" Args:
+" -space: specifies if the delim has a space string on the start
+" (the space string will only be added if NERDSpaceDelims
+" is specified for the current filetype)
+" -esc: specifies whether the tricky chars in the string are ESCed
+function s:GetSexyComRight(space, esc)
+ let lenLeft = strlen(s:Left())
+ let lenLeftAlt = strlen(s:Left({'alt': 1}))
+ let right = ''
+
+ "assume c style sexy comments if possible
+ if s:HasCStyleComments()
+ let right = '*/'
+ else
+ "grab the right delim that pairs with the longest left delim
+ if s:Multipart() && lenLeft >= lenLeftAlt
+ let right = s:Right()
+ elseif s:AltMultipart()
+ let right = s:Right({'alt': 1})
+ else
+ return -1
+ endif
+ endif
+
+ if a:space && g:NERDSpaceDelims
+ let right = s:spaceStr . right
+ endif
+
+ if a:esc
+ let right = s:Esc(right)
+ endif
+
+ return right
+endfunction
+
+" Function: s:HasMultipartDelims() {{{2
+" Returns 1 iff the current filetype has at least one set of multipart delims
+function s:HasMultipartDelims()
+ return s:Multipart() || s:AltMultipart()
+endfunction
+
+" Function: s:HasLeadingTabs(...) {{{2
+" Returns 1 if any of the given strings have leading tabs
+function s:HasLeadingTabs(...)
+ for s in a:000
+ if s =~ '^\t.*'
+ return 1
+ end
+ endfor
+ return 0
+endfunction
+" Function: s:HasCStyleComments() {{{2
+" Returns 1 iff the current filetype has c style comment delimiters
+function s:HasCStyleComments()
+ return (s:Left() == '/*' && s:Right() == '*/') || (s:Left({'alt': 1}) == '/*' && s:Right({'alt': 1}) == '*/')
+endfunction
+
+" Function: s:IsCommentedNormOrSexy(lineNum) {{{2
+"This function is used to determine whether the given line is commented with
+"either set of delimiters or if it is part of a sexy comment
+"
+" Args:
+" -lineNum: the line number of the line to check
+function s:IsCommentedNormOrSexy(lineNum)
+ let theLine = getline(a:lineNum)
+
+ "if the line is commented normally return 1
+ if s:IsCommented(s:Left(), s:Right(), theLine) || s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine)
+ return 1
+ endif
+
+ "if the line is part of a sexy comment return 1
+ if s:IsInSexyComment(a:lineNum)
+ return 1
+ endif
+ return 0
+endfunction
+
+" Function: s:IsCommented(left, right, line) {{{2
+"This function is used to determine whether the given line is commented with
+"the given delimiters
+"
+" Args:
+" -line: the line that to check if commented
+" -left/right: the left and right delimiters to check for
+function s:IsCommented(left, right, line)
+ "if the line isnt commented return true
+ if s:FindDelimiterIndex(a:left, a:line) != -1 && (s:FindDelimiterIndex(a:right, a:line) != -1 || !s:Multipart())
+ return 1
+ endif
+ return 0
+endfunction
+
+" Function: s:IsCommentedFromStartOfLine(left, line) {{{2
+"This function is used to determine whether the given line is commented with
+"the given delimiters at the start of the line i.e the left delimiter is the
+"first thing on the line (apart from spaces\tabs)
+"
+" Args:
+" -line: the line that to check if commented
+" -left: the left delimiter to check for
+function s:IsCommentedFromStartOfLine(left, line)
+ let theLine = s:ConvertLeadingTabsToSpaces(a:line)
+ let numSpaces = strlen(substitute(theLine, '^\( *\).*$', '\1', ''))
+ let delimIndx = s:FindDelimiterIndex(a:left, theLine)
+ return delimIndx == numSpaces
+endfunction
+
+" Function: s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line) {{{2
+" Finds the type of the outtermost delims on the line
+"
+" Args:
+" -line: the line that to check if the outtermost comments on it are
+" left/right
+" -left/right: the left and right delimiters to check for
+" -leftAlt/rightAlt: the left and right alternative delimiters to check for
+"
+" Returns:
+" 0 if the line is not commented with either set of delims
+" 1 if the line is commented with the left/right delim set
+" 2 if the line is commented with the leftAlt/rightAlt delim set
+function s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line)
+ "get the first positions of the left delims and the last positions of the
+ "right delims
+ let indxLeft = s:FindDelimiterIndex(a:left, a:line)
+ let indxLeftAlt = s:FindDelimiterIndex(a:leftAlt, a:line)
+ let indxRight = s:LastIndexOfDelim(a:right, a:line)
+ let indxRightAlt = s:LastIndexOfDelim(a:rightAlt, a:line)
+
+ "check if the line has a left delim before a leftAlt delim
+ if (indxLeft <= indxLeftAlt || indxLeftAlt == -1) && indxLeft != -1
+ "check if the line has a right delim after any rightAlt delim
+ if (indxRight > indxRightAlt && indxRight > indxLeft) || !s:Multipart()
+ return 1
+ endif
+
+ "check if the line has a leftAlt delim before a left delim
+ elseif (indxLeftAlt <= indxLeft || indxLeft == -1) && indxLeftAlt != -1
+ "check if the line has a rightAlt delim after any right delim
+ if (indxRightAlt > indxRight && indxRightAlt > indxLeftAlt) || !s:AltMultipart()
+ return 2
+ endif
+ else
+ return 0
+ endif
+
+ return 0
+
+endfunction
+
+
+" Function: s:IsDelimValid(delimiter, delIndx, line) {{{2
+" This function is responsible for determining whether a given instance of a
+" comment delimiter is a real delimiter or not. For example, in java the
+" // string is a comment delimiter but in the line:
+" System.out.println("//");
+" it does not count as a comment delimiter. This function is responsible for
+" distinguishing between such cases. It does so by applying a set of
+" heuristics that are not fool proof but should work most of the time.
+"
+" Args:
+" -delimiter: the delimiter we are validating
+" -delIndx: the position of delimiter in line
+" -line: the line that delimiter occurs in
+"
+" Returns:
+" 0 if the given delimiter is not a real delimiter (as far as we can tell) ,
+" 1 otherwise
+function s:IsDelimValid(delimiter, delIndx, line)
+ "get the delimiter without the escchars
+ let l:delimiter = a:delimiter
+
+ "get the strings before and after the delimiter
+ let preComStr = strpart(a:line, 0, a:delIndx)
+ let postComStr = strpart(a:line, a:delIndx+strlen(delimiter))
+
+ "to check if the delimiter is real, make sure it isnt preceded by
+ "an odd number of quotes and followed by the same (which would indicate
+ "that it is part of a string and therefore is not a comment)
+ if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, '"', "\\"))
+ return 0
+ endif
+ if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "'", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "'", "\\"))
+ return 0
+ endif
+ if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "`", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "`", "\\"))
+ return 0
+ endif
+
+
+ "if the comment delimiter is escaped, assume it isnt a real delimiter
+ if s:IsEscaped(a:line, a:delIndx, "\\")
+ return 0
+ endif
+
+ "vim comments are so fuckin stupid!! Why the hell do they have comment
+ "delimiters that are used elsewhere in the syntax?!?! We need to check
+ "some conditions especially for vim
+ if &filetype == "vim"
+ if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\"))
+ return 0
+ endif
+
+ "if the delimiter is on the very first char of the line or is the
+ "first non-tab/space char on the line then it is a valid comment delimiter
+ if a:delIndx == 0 || a:line =~ "^[ \t]\\{" . a:delIndx . "\\}\".*$"
+ return 1
+ endif
+
+ let numLeftParen =s:CountNonESCedOccurances(preComStr, "(", "\\")
+ let numRightParen =s:CountNonESCedOccurances(preComStr, ")", "\\")
+
+ "if the quote is inside brackets then assume it isnt a comment
+ if numLeftParen > numRightParen
+ return 0
+ endif
+
+ "if the line has an even num of unescaped "'s then we can assume that
+ "any given " is not a comment delimiter
+ if s:IsNumEven(s:CountNonESCedOccurances(a:line, "\"", "\\"))
+ return 0
+ endif
+ endif
+
+ return 1
+
+endfunction
+
+" Function: s:IsNumEven(num) {{{2
+" A small function the returns 1 if the input number is even and 0 otherwise
+" Args:
+" -num: the number to check
+function s:IsNumEven(num)
+ return (a:num % 2) == 0
+endfunction
+
+" Function: s:IsEscaped(str, indx, escChar) {{{2
+" This function takes a string, an index into that string and an esc char and
+" returns 1 if the char at the index is escaped (i.e if it is preceded by an
+" odd number of esc chars)
+" Args:
+" -str: the string to check
+" -indx: the index into str that we want to check
+" -escChar: the escape char the char at indx may be ESCed with
+function s:IsEscaped(str, indx, escChar)
+ "initialise numEscChars to 0 and look at the char before indx
+ let numEscChars = 0
+ let curIndx = a:indx-1
+
+ "keep going back thru str until we either reach the start of the str or
+ "run out of esc chars
+ while curIndx >= 0 && strpart(a:str, curIndx, 1) == a:escChar
+
+ "we have found another esc char so add one to the count and move left
+ "one char
+ let numEscChars = numEscChars + 1
+ let curIndx = curIndx - 1
+
+ endwhile
+
+ "if there is an odd num of esc chars directly before the char at indx then
+ "the char at indx is escaped
+ return !s:IsNumEven(numEscChars)
+endfunction
+
+" Function: s:IsInSexyComment(line) {{{2
+" returns 1 if the given line number is part of a sexy comment
+function s:IsInSexyComment(line)
+ return !empty(s:FindBoundingLinesOfSexyCom(a:line))
+endfunction
+
+" Function: s:IsSexyComment(topline, bottomline) {{{2
+" This function takes in 2 line numbers and returns 1 if the lines between and
+" including the given line numbers are a sexy comment. It returns 0 otherwise.
+" Args:
+" -topline: the line that the possible sexy comment starts on
+" -bottomline: the line that the possible sexy comment stops on
+function s:IsSexyComment(topline, bottomline)
+
+ "get the delim set that would be used for a sexy comment
+ let left = ''
+ let right = ''
+ if s:Multipart()
+ let left = s:Left()
+ let right = s:Right()
+ elseif s:AltMultipart()
+ let left = s:Left({'alt': 1})
+ let right = s:Right({'alt': 1})
+ else
+ return 0
+ endif
+
+ "swap the top and bottom line numbers around if need be
+ let topline = a:topline
+ let bottomline = a:bottomline
+ if bottomline < topline
+ topline = bottomline
+ bottomline = a:topline
+ endif
+
+ "if there is < 2 lines in the comment it cannot be sexy
+ if (bottomline - topline) <= 0
+ return 0
+ endif
+
+ "if the top line doesnt begin with a left delim then the comment isnt sexy
+ if getline(a:topline) !~ '^[ \t]*' . left
+ return 0
+ endif
+
+ "if there is a right delim on the top line then this isnt a sexy comment
+ if s:FindDelimiterIndex(right, getline(a:topline)) != -1
+ return 0
+ endif
+
+ "if there is a left delim on the bottom line then this isnt a sexy comment
+ if s:FindDelimiterIndex(left, getline(a:bottomline)) != -1
+ return 0
+ endif
+
+ "if the bottom line doesnt begin with a right delim then the comment isnt
+ "sexy
+ if getline(a:bottomline) !~ '^.*' . right . '$'
+ return 0
+ endif
+
+ let sexyComMarker = s:GetSexyComMarker(0, 1)
+
+ "check each of the intermediate lines to make sure they start with a
+ "sexyComMarker
+ let currentLine = a:topline+1
+ while currentLine < a:bottomline
+ let theLine = getline(currentLine)
+
+ if theLine !~ '^[ \t]*' . sexyComMarker
+ return 0
+ endif
+
+ "if there is a right delim in an intermediate line then the block isnt
+ "a sexy comment
+ if s:FindDelimiterIndex(right, theLine) != -1
+ return 0
+ endif
+
+ let currentLine = currentLine + 1
+ endwhile
+
+ "we have not found anything to suggest that this isnt a sexy comment so
+ return 1
+
+endfunction
+
+" Function: s:LastIndexOfDelim(delim, str) {{{2
+" This function takes a string and a delimiter and returns the last index of
+" that delimiter in string
+" Args:
+" -delim: the delimiter to look for
+" -str: the string to look for delim in
+function s:LastIndexOfDelim(delim, str)
+ let delim = a:delim
+ let lenDelim = strlen(delim)
+
+ "set index to the first occurrence of delim. If there is no occurrence then
+ "bail
+ let indx = s:FindDelimiterIndex(delim, a:str)
+ if indx == -1
+ return -1
+ endif
+
+ "keep moving to the next instance of delim in str till there is none left
+ while 1
+
+ "search for the next delim after the previous one
+ let searchStr = strpart(a:str, indx+lenDelim)
+ let indx2 = s:FindDelimiterIndex(delim, searchStr)
+
+ "if we find a delim update indx to record the position of it, if we
+ "dont find another delim then indx is the last one so break out of
+ "this loop
+ if indx2 != -1
+ let indx = indx + indx2 + lenDelim
+ else
+ break
+ endif
+ endwhile
+
+ return indx
+
+endfunction
+
+" Function: s:Left(...) {{{2
+" returns left delimiter data
+function s:Left(...)
+ let params = a:0 ? a:1 : {}
+
+ let delim = has_key(params, 'alt') ? b:NERDCommenterDelims['leftAlt'] : b:NERDCommenterDelims['left']
+
+ if delim == ''
+ return ''
+ endif
+
+ if has_key(params, 'space') && g:NERDSpaceDelims
+ let delim = delim . s:spaceStr
+ endif
+
+ if has_key(params, 'esc')
+ let delim = s:Esc(delim)
+ endif
+
+ return delim
+endfunction
+
+" Function: s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2
+" This function takes in 2 line numbers and returns the index of the left most
+" char (that is not a space or a tab) on all of these lines.
+" Args:
+" -countCommentedLines: 1 if lines that are commented are to be checked as
+" well. 0 otherwise
+" -countEmptyLines: 1 if empty lines are to be counted in the search
+" -topline: the top line to be checked
+" -bottomline: the bottom line to be checked
+function s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline)
+
+ " declare the left most index as an extreme value
+ let leftMostIndx = 1000
+
+ " go thru the block line by line updating leftMostIndx
+ let currentLine = a:topline
+ while currentLine <= a:bottomline
+
+ " get the next line and if it is allowed to be commented, or is not
+ " commented, check it
+ let theLine = getline(currentLine)
+ if a:countEmptyLines || theLine !~ '^[ \t]*$'
+ if a:countCommentedLines || (!s:IsCommented(s:Left(), s:Right(), theLine) && !s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine))
+ " convert spaces to tabs and get the number of leading spaces for
+ " this line and update leftMostIndx if need be
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ let leadSpaceOfLine = strlen( substitute(theLine, '\(^[ \t]*\).*$','\1','') )
+ if leadSpaceOfLine < leftMostIndx
+ let leftMostIndx = leadSpaceOfLine
+ endif
+ endif
+ endif
+
+ " move on to the next line
+ let currentLine = currentLine + 1
+ endwhile
+
+ if leftMostIndx == 1000
+ return 0
+ else
+ return leftMostIndx
+ endif
+endfunction
+
+" Function: s:Multipart() {{{2
+" returns 1 if the current delims are multipart
+function s:Multipart()
+ return s:Right() != ''
+endfunction
+
+" Function: s:NerdEcho(msg, typeOfMsg) {{{2
+" Args:
+" -msg: the message to echo
+" -typeOfMsg: 0 = warning message
+" 1 = normal message
+function s:NerdEcho(msg, typeOfMsg)
+ if a:typeOfMsg == 0
+ echohl WarningMsg
+ echom 'NERDCommenter:' . a:msg
+ echohl None
+ elseif a:typeOfMsg == 1
+ echom 'NERDCommenter:' . a:msg
+ endif
+endfunction
+
+" Function: s:NumberOfLeadingTabs(s) {{{2
+" returns the number of leading tabs in the given string
+function s:NumberOfLeadingTabs(s)
+ return strlen(substitute(a:s, '^\(\t*\).*$', '\1', ""))
+endfunction
+
+" Function: s:NumLinesInBuf() {{{2
+" Returns the number of lines in the current buffer
+function s:NumLinesInBuf()
+ return line('$')
+endfunction
+
+" Function: s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) {{{2
+" This function takes in a string, 2 delimiters in that string and 2 strings
+" to replace these delimiters with.
+"
+" Args:
+" -toReplace1: the first delimiter to replace
+" -toReplace2: the second delimiter to replace
+" -replacor1: the string to replace toReplace1 with
+" -replacor2: the string to replace toReplace2 with
+" -str: the string that the delimiters to be replaced are in
+function s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str)
+ let line = s:ReplaceLeftMostDelim(a:toReplace1, a:replacor1, a:str)
+ let line = s:ReplaceRightMostDelim(a:toReplace2, a:replacor2, line)
+ return line
+endfunction
+
+" Function: s:ReplaceLeftMostDelim(toReplace, replacor, str) {{{2
+" This function takes a string and a delimiter and replaces the left most
+" occurrence of this delimiter in the string with a given string
+"
+" Args:
+" -toReplace: the delimiter in str that is to be replaced
+" -replacor: the string to replace toReplace with
+" -str: the string that contains toReplace
+function s:ReplaceLeftMostDelim(toReplace, replacor, str)
+ let toReplace = a:toReplace
+ let replacor = a:replacor
+ "get the left most occurrence of toReplace
+ let indxToReplace = s:FindDelimiterIndex(toReplace, a:str)
+
+ "if there IS an occurrence of toReplace in str then replace it and return
+ "the resulting string
+ if indxToReplace != -1
+ let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
+ return line
+ endif
+
+ return a:str
+endfunction
+
+" Function: s:ReplaceRightMostDelim(toReplace, replacor, str) {{{2
+" This function takes a string and a delimiter and replaces the right most
+" occurrence of this delimiter in the string with a given string
+"
+" Args:
+" -toReplace: the delimiter in str that is to be replaced
+" -replacor: the string to replace toReplace with
+" -str: the string that contains toReplace
+"
+function s:ReplaceRightMostDelim(toReplace, replacor, str)
+ let toReplace = a:toReplace
+ let replacor = a:replacor
+ let lenToReplace = strlen(toReplace)
+
+ "get the index of the last delim in str
+ let indxToReplace = s:LastIndexOfDelim(toReplace, a:str)
+
+ "if there IS a delimiter in str, replace it and return the result
+ let line = a:str
+ if indxToReplace != -1
+ let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
+ endif
+ return line
+endfunction
+
+"FUNCTION: s:RestoreScreenState() {{{2
+"
+"Sets the screen state back to what it was when s:SaveScreenState was last
+"called.
+"
+function s:RestoreScreenState()
+ if !exists("t:NERDComOldTopLine") || !exists("t:NERDComOldPos")
+ throw 'NERDCommenter exception: cannot restore screen'
+ endif
+
+ call cursor(t:NERDComOldTopLine, 0)
+ normal! zt
+ call setpos(".", t:NERDComOldPos)
+endfunction
+
+" Function: s:Right(...) {{{2
+" returns right delimiter data
+function s:Right(...)
+ let params = a:0 ? a:1 : {}
+
+ let delim = has_key(params, 'alt') ? b:NERDCommenterDelims['rightAlt'] : b:NERDCommenterDelims['right']
+
+ if delim == ''
+ return ''
+ endif
+
+ if has_key(params, 'space') && g:NERDSpaceDelims
+ let delim = s:spaceStr . delim
+ endif
+
+ if has_key(params, 'esc')
+ let delim = s:Esc(delim)
+ endif
+
+ return delim
+endfunction
+
+" Function: s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2
+" This function takes in 2 line numbers and returns the index of the right most
+" char on all of these lines.
+" Args:
+" -countCommentedLines: 1 if lines that are commented are to be checked as
+" well. 0 otherwise
+" -countEmptyLines: 1 if empty lines are to be counted in the search
+" -topline: the top line to be checked
+" -bottomline: the bottom line to be checked
+function s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline)
+ let rightMostIndx = -1
+
+ " go thru the block line by line updating rightMostIndx
+ let currentLine = a:topline
+ while currentLine <= a:bottomline
+
+ " get the next line and see if it is commentable, otherwise it doesnt
+ " count
+ let theLine = getline(currentLine)
+ if a:countEmptyLines || theLine !~ '^[ \t]*$'
+
+ if a:countCommentedLines || (!s:IsCommented(s:Left(), s:Right(), theLine) && !s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine))
+
+ " update rightMostIndx if need be
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ let lineLen = strlen(theLine)
+ if lineLen > rightMostIndx
+ let rightMostIndx = lineLen
+ endif
+ endif
+ endif
+
+ " move on to the next line
+ let currentLine = currentLine + 1
+ endwhile
+
+ return rightMostIndx
+endfunction
+
+"FUNCTION: s:SaveScreenState() {{{2
+"Saves the current cursor position in the current buffer and the window
+"scroll position
+function s:SaveScreenState()
+ let t:NERDComOldPos = getpos(".")
+ let t:NERDComOldTopLine = line("w0")
+endfunction
+
+" Function: s:SwapOutterMultiPartDelimsForPlaceHolders(line) {{{2
+" This function takes a line and swaps the outter most multi-part delims for
+" place holders
+" Args:
+" -line: the line to swap the delims in
+"
+function s:SwapOutterMultiPartDelimsForPlaceHolders(line)
+ " find out if the line is commented using normal delims and/or
+ " alternate ones
+ let isCommented = s:IsCommented(s:Left(), s:Right(), a:line)
+ let isCommentedAlt = s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), a:line)
+
+ let line2 = a:line
+
+ "if the line is commented and there is a right delimiter, replace
+ "the delims with place-holders
+ if isCommented && s:Multipart()
+ let line2 = s:ReplaceDelims(s:Left(), s:Right(), g:NERDLPlace, g:NERDRPlace, a:line)
+
+ "similarly if the line is commented with the alternative
+ "delimiters
+ elseif isCommentedAlt && s:AltMultipart()
+ let line2 = s:ReplaceDelims(s:Left({'alt': 1}), s:Right({'alt': 1}), g:NERDLPlace, g:NERDRPlace, a:line)
+ endif
+
+ return line2
+endfunction
+
+" Function: s:SwapOutterPlaceHoldersForMultiPartDelims(line) {{{2
+" This function takes a line and swaps the outtermost place holders for
+" multi-part delims
+" Args:
+" -line: the line to swap the delims in
+"
+function s:SwapOutterPlaceHoldersForMultiPartDelims(line)
+ let left = ''
+ let right = ''
+ if s:Multipart()
+ let left = s:Left()
+ let right = s:Right()
+ elseif s:AltMultipart()
+ let left = s:Left({'alt': 1})
+ let right = s:Right({'alt': 1})
+ endif
+
+ let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, a:line)
+ return line
+endfunction
+" Function: s:TabbedCol(line, col) {{{2
+" Gets the col number for given line and existing col number. The new col
+" number is the col number when all leading spaces are converted to tabs
+" Args:
+" -line:the line to get the rel col for
+" -col: the abs col
+function s:TabbedCol(line, col)
+ let lineTruncated = strpart(a:line, 0, a:col)
+ let lineSpacesToTabs = substitute(lineTruncated, s:TabSpace(), '\t', 'g')
+ return strlen(lineSpacesToTabs)
+endfunction
+"FUNCTION: s:TabSpace() {{{2
+"returns a string of spaces equal in length to &tabstop
+function s:TabSpace()
+ let tabSpace = ""
+ let spacesPerTab = &tabstop
+ while spacesPerTab > 0
+ let tabSpace = tabSpace . " "
+ let spacesPerTab = spacesPerTab - 1
+ endwhile
+ return tabSpace
+endfunction
+
+" Function: s:UnEsc(str, escChar) {{{2
+" This function removes all the escape chars from a string
+" Args:
+" -str: the string to remove esc chars from
+" -escChar: the escape char to be removed
+function s:UnEsc(str, escChar)
+ return substitute(a:str, a:escChar, "", "g")
+endfunction
+
+" Function: s:UntabbedCol(line, col) {{{2
+" Takes a line and a col and returns the absolute column of col taking into
+" account that a tab is worth 3 or 4 (or whatever) spaces.
+" Args:
+" -line:the line to get the abs col for
+" -col: the col that doesnt take into account tabs
+function s:UntabbedCol(line, col)
+ let lineTruncated = strpart(a:line, 0, a:col)
+ let lineTabsToSpaces = substitute(lineTruncated, '\t', s:TabSpace(), 'g')
+ return strlen(lineTabsToSpaces)
+endfunction
+" Section: Comment mapping setup {{{1
+" ===========================================================================
+
+" switch to/from alternative delimiters
+nnoremap <plug>NERDCommenterAltDelims :call <SID>SwitchToAlternativeDelimiters(1)<cr>
+
+" comment out lines
+nnoremap <silent> <plug>NERDCommenterComment :call NERDComment(0, "norm")<cr>
+vnoremap <silent> <plug>NERDCommenterComment <ESC>:call NERDComment(1, "norm")<cr>
+
+" toggle comments
+nnoremap <silent> <plug>NERDCommenterToggle :call NERDComment(0, "toggle")<cr>
+vnoremap <silent> <plug>NERDCommenterToggle <ESC>:call NERDComment(1, "toggle")<cr>
+
+" minimal comments
+nnoremap <silent> <plug>NERDCommenterMinimal :call NERDComment(0, "minimal")<cr>
+vnoremap <silent> <plug>NERDCommenterMinimal <ESC>:call NERDComment(1, "minimal")<cr>
+
+" sexy comments
+nnoremap <silent> <plug>NERDCommenterSexy :call NERDComment(0, "sexy")<CR>
+vnoremap <silent> <plug>NERDCommenterSexy <ESC>:call NERDComment(1, "sexy")<CR>
+
+" invert comments
+nnoremap <silent> <plug>NERDCommenterInvert :call NERDComment(0, "invert")<CR>
+vnoremap <silent> <plug>NERDCommenterInvert <ESC>:call NERDComment(1, "invert")<CR>
+
+" yank then comment
+nmap <silent> <plug>NERDCommenterYank :call NERDComment(0, "yank")<CR>
+vmap <silent> <plug>NERDCommenterYank <ESC>:call NERDComment(1, "yank")<CR>
+
+" left aligned comments
+nnoremap <silent> <plug>NERDCommenterAlignLeft :call NERDComment(0, "alignLeft")<cr>
+vnoremap <silent> <plug>NERDCommenterAlignLeft <ESC>:call NERDComment(1, "alignLeft")<cr>
+
+" left and right aligned comments
+nnoremap <silent> <plug>NERDCommenterAlignBoth :call NERDComment(0, "alignBoth")<cr>
+vnoremap <silent> <plug>NERDCommenterAlignBoth <ESC>:call NERDComment(1, "alignBoth")<cr>
+
+" nested comments
+nnoremap <silent> <plug>NERDCommenterNest :call NERDComment(0, "nested")<cr>
+vnoremap <silent> <plug>NERDCommenterNest <ESC>:call NERDComment(1, "nested")<cr>
+
+" uncomment
+nnoremap <silent> <plug>NERDCommenterUncomment :call NERDComment(0, "uncomment")<cr>
+vnoremap <silent> <plug>NERDCommenterUncomment :call NERDComment(1, "uncomment")<cr>
+
+" comment till the end of the line
+nnoremap <silent> <plug>NERDCommenterToEOL :call NERDComment(0, "toEOL")<cr>
+
+" append comments
+nmap <silent> <plug>NERDCommenterAppend :call NERDComment(0, "append")<cr>
+
+" insert comments
+inoremap <silent> <plug>NERDCommenterInInsert <SPACE><BS><ESC>:call NERDComment(0, "insert")<CR>
+
+
+function! s:CreateMaps(target, combo)
+ if !hasmapto(a:target, 'n')
+ exec 'nmap ' . a:combo . ' ' . a:target
+ endif
+
+ if !hasmapto(a:target, 'v')
+ exec 'vmap ' . a:combo . ' ' . a:target
+ endif
+endfunction
+
+if g:NERDCreateDefaultMappings
+ call s:CreateMaps('<plug>NERDCommenterComment', '<leader>cc')
+ call s:CreateMaps('<plug>NERDCommenterToggle', '<leader>c<space>')
+ call s:CreateMaps('<plug>NERDCommenterMinimal', '<leader>cm')
+ call s:CreateMaps('<plug>NERDCommenterSexy', '<leader>cs')
+ call s:CreateMaps('<plug>NERDCommenterInvert', '<leader>ci')
+ call s:CreateMaps('<plug>NERDCommenterYank', '<leader>cy')
+ call s:CreateMaps('<plug>NERDCommenterAlignLeft', '<leader>cl')
+ call s:CreateMaps('<plug>NERDCommenterAlignBoth', '<leader>cb')
+ call s:CreateMaps('<plug>NERDCommenterNest', '<leader>cn')
+ call s:CreateMaps('<plug>NERDCommenterUncomment', '<leader>cu')
+ call s:CreateMaps('<plug>NERDCommenterToEOL', '<leader>c$')
+ call s:CreateMaps('<plug>NERDCommenterAppend', '<leader>cA')
+
+ if !hasmapto('<plug>NERDCommenterAltDelims', 'n')
+ nmap <leader>ca <plug>NERDCommenterAltDelims
+ endif
+endif
+
+
+
+" Section: Menu item setup {{{1
+" ===========================================================================
+"check if the user wants the menu to be displayed
+if g:NERDMenuMode != 0
+
+ let menuRoot = ""
+ if g:NERDMenuMode == 1
+ let menuRoot = 'comment'
+ elseif g:NERDMenuMode == 2
+ let menuRoot = '&comment'
+ elseif g:NERDMenuMode == 3
+ let menuRoot = '&Plugin.&comment'
+ endif
+
+ function! s:CreateMenuItems(target, desc, root)
+ exec 'nmenu <silent> ' . a:root . '.' . a:desc . ' ' . a:target
+ exec 'vmenu <silent> ' . a:root . '.' . a:desc . ' ' . a:target
+ endfunction
+ call s:CreateMenuItems("<plug>NERDCommenterComment", 'Comment', menuRoot)
+ call s:CreateMenuItems("<plug>NERDCommenterToggle", 'Toggle', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterMinimal', 'Minimal', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterNest', 'Nested', menuRoot)
+ exec 'nmenu <silent> '. menuRoot .'.To\ EOL <plug>NERDCommenterToEOL'
+ call s:CreateMenuItems('<plug>NERDCommenterInvert', 'Invert', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterSexy', 'Sexy', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterYank', 'Yank\ then\ comment', menuRoot)
+ exec 'nmenu <silent> '. menuRoot .'.Append <plug>NERDCommenterAppend'
+ exec 'menu <silent> '. menuRoot .'.-Sep- :'
+ call s:CreateMenuItems('<plug>NERDCommenterAlignLeft', 'Left\ aligned', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterAlignBoth', 'Left\ and\ right\ aligned', menuRoot)
+ exec 'menu <silent> '. menuRoot .'.-Sep2- :'
+ call s:CreateMenuItems('<plug>NERDCommenterUncomment', 'Uncomment', menuRoot)
+ exec 'nmenu <silent> '. menuRoot .'.Switch\ Delimiters <plug>NERDCommenterAltDelims'
+ exec 'imenu <silent> '. menuRoot .'.Insert\ Comment\ Here <plug>NERDCommenterInInsert'
+ exec 'menu <silent> '. menuRoot .'.-Sep3- :'
+ exec 'menu <silent>'. menuRoot .'.Help :help NERDCommenterContents<CR>'
+endif
+" vim: set foldmethod=marker :
diff --git a/vim/plugin/NERD_tree.vim b/vim/plugin/NERD_tree.vim
new file mode 100644
index 0000000..669fd6c
--- /dev/null
+++ b/vim/plugin/NERD_tree.vim
@@ -0,0 +1,4049 @@
+" ============================================================================
+" File: NERD_tree.vim
+" Description: vim global plugin that provides a nice tree explorer
+" Maintainer: Martin Grenfell <martin.grenfell at gmail dot com>
+" Last Change: 1 December, 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.
+"
+" ============================================================================
+let s:NERD_tree_version = '4.1.0'
+
+" 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:NERDChristmasTree", 1)
+call s:initVariable("g:NERDTreeAutoCenter", 1)
+call s:initVariable("g:NERDTreeAutoCenterThreshold", 3)
+call s:initVariable("g:NERDTreeCaseSensitiveSort", 0)
+call s:initVariable("g:NERDTreeChDirMode", 0)
+if !exists("g:NERDTreeIgnore")
+ let g:NERDTreeIgnore = ['\~$']
+endif
+call s:initVariable("g:NERDTreeBookmarksFile", expand('$HOME') . '/.NERDTreeBookmarks')
+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: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)
+
+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
+
+"we need to use this number many times for sorting... so we calculate it only
+"once here
+let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*')
+
+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)
+
+let s:running_windows = has("win16") || has("win32") || has("win64")
+
+"init the shell commands that will be used to copy nodes, and remove dir trees
+"
+"Note: the space after the command is important
+if s:running_windows
+ 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", "<C-j>")
+call s:initVariable("g:NERDTreeMapJumpParent", "p")
+call s:initVariable("g:NERDTreeMapJumpPrevSibling", "<C-k>")
+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")
+
+"SECTION: Script level variable declaration{{{2
+if s:running_windows
+ let s:escape_chars = " `\|\"#%&,?()\*^<>"
+else
+ let s:escape_chars = " \\`\|\"#%&,?()\*^<>"
+endif
+let s:NERDTreeBufName = 'NERD_tree_'
+
+let s:tree_wid = 2
+let s:tree_markup_reg = '^[ `|▼▶]*[\-+~ ]*'
+let s:tree_up_dir_line = '.. (up a dir)'
+
+"the number to add to the nerd tree buffer name to make the buf name unique
+let s:next_buffer_number = 1
+
+" SECTION: Commands {{{1
+"============================================================
+"init the command that users start the nerd tree with
+command! -n=? -complete=dir -bar NERDTree :call s:initNerdTree('<args>')
+command! -n=? -complete=dir -bar NERDTreeToggle :call s:toggle('<args>')
+command! -n=0 -bar NERDTreeClose :call s:closeTreeIfOpen()
+command! -n=1 -complete=customlist,s:completeBookmarks -bar NERDTreeFromBookmark call s:initNerdTree('<args>')
+command! -n=0 -bar NERDTreeMirror call s:initNerdTreeMirror()
+command! -n=0 -bar NERDTreeFind call s:findAndRevealPath()
+" SECTION: Auto commands {{{1
+"============================================================
+augroup NERDTree
+ "Save the cursor position whenever we close the nerd tree
+ exec "autocmd BufWinLeave ". s:NERDTreeBufName ."* call <SID>saveScreenState()"
+
+ "disallow insert mode in the NERDTree
+ exec "autocmd BufEnter ". s:NERDTreeBufName ."* stopinsert"
+ "cache bookmarks when vim loads
+ autocmd VimEnter * call s:Bookmark.CacheBookmarks(0)
+
+ "load all nerdtree plugins after vim starts
+ autocmd VimEnter * runtime! nerdtree_plugin/**/*.vim
+augroup END
+
+if g:NERDTreeHijackNetrw
+ augroup NERDTreeHijackNetrw
+ autocmd VimEnter * silent! autocmd! FileExplorer
+ au BufEnter,VimEnter * call s:checkForBrowse(expand("<amatch>"))
+ augroup END
+endif
+
+"SECTION: Classes {{{1
+"============================================================
+"CLASS: Bookmark {{{2
+"============================================================
+let s:Bookmark = {}
+" FUNCTION: Bookmark.activate() {{{3
+function! s:Bookmark.activate()
+ if self.path.isDirectory
+ call self.toRoot()
+ else
+ if self.validate()
+ let n = s:TreeFileNode.New(self.path)
+ call n.open()
+ call s:closeTreeIfQuitOnOpen()
+ endif
+ endif
+endfunction
+" FUNCTION: Bookmark.AddBookmark(name, path) {{{3
+" 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))
+ call s:Bookmark.Sort()
+endfunction
+" Function: Bookmark.Bookmarks() {{{3
+" 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) {{{3
+" 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) {{{3
+" 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() {{{3
+" 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) {{{3
+" Class method to read all bookmarks from the bookmarks file intialize
+" 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, s:Path.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 s:echo(invalidBookmarksFound . " invalid bookmarks were read. See :help NERDTreeInvalidBookmarks for info.")
+ endif
+ endif
+ call s:Bookmark.Sort()
+ endif
+endfunction
+" FUNCTION: Bookmark.compareTo(otherbookmark) {{{3
+" Compare these two bookmarks for sorting purposes
+function! s:Bookmark.compareTo(otherbookmark)
+ return a:otherbookmark.name < self.name
+endfunction
+" FUNCTION: Bookmark.ClearAll() {{{3
+" 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() {{{3
+" 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) {{{3
+" 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 ? s:TreeDirNode.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) {{{3
+" 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() {{{3
+" 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() {{{3
+" 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() {{{3
+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) {{{3
+" 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.openInNewTab(options) {{{3
+" Create a new bookmark object with the given name and path object
+function! s:Bookmark.openInNewTab(options)
+ let currentTab = tabpagenr()
+ if self.path.isDirectory
+ tabnew
+ call s:initNerdTree(self.name)
+ else
+ exec "tabedit " . bookmark.path.str({'format': 'Edit'})
+ endif
+
+ if has_key(a:options, 'stayInCurrentTab')
+ exec "tabnext " . currentTab
+ endif
+endfunction
+" Function: Bookmark.setPath(path) {{{3
+" makes this bookmark point to the given path
+function! s:Bookmark.setPath(path)
+ let self.path = a:path
+endfunction
+" Function: Bookmark.Sort() {{{3
+" Class method that sorts all bookmarks
+function! s:Bookmark.Sort()
+ let CompareFunc = function("s:compareBookmarks")
+ call sort(s:Bookmark.Bookmarks(), CompareFunc)
+endfunction
+" Function: Bookmark.str() {{{3
+" Get the string that should be rendered in the view for this bookmark
+function! s:Bookmark.str()
+ let pathStrMaxLen = winwidth(s: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() {{{3
+" 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 = s:TreeFileNode.New(s:Bookmark.BookmarkFor(self.name).path)
+ endtry
+ call targetNode.makeRoot()
+ call s:renderView()
+ call targetNode.putCursorHere(0, 0)
+ endif
+endfunction
+" FUNCTION: Bookmark.ToRoot(name) {{{3
+" 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() {{{3
+function! s:Bookmark.validate()
+ if self.path.exists()
+ return 1
+ else
+ call s:Bookmark.CacheBookmarks(1)
+ call s:renderView()
+ call s:echo(self.name . "now points to an invalid location. See :help NERDTreeInvalidBookmarks for info.")
+ return 0
+ endif
+endfunction
+
+" Function: Bookmark.Write() {{{3
+" 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
+"CLASS: KeyMap {{{2
+"============================================================
+let s:KeyMap = {}
+"FUNCTION: KeyMap.All() {{{3
+function! s:KeyMap.All()
+ if !exists("s:keyMaps")
+ let s:keyMaps = []
+ endif
+ return s:keyMaps
+endfunction
+
+"FUNCTION: KeyMap.BindAll() {{{3
+function! s:KeyMap.BindAll()
+ for i in s:KeyMap.All()
+ call i.bind()
+ endfor
+endfunction
+
+"FUNCTION: KeyMap.bind() {{{3
+function! s:KeyMap.bind()
+ exec "nnoremap <silent> <buffer> ". self.key ." :call ". self.callback ."()<cr>"
+endfunction
+
+"FUNCTION: KeyMap.Create(options) {{{3
+function! s:KeyMap.Create(options)
+ let newKeyMap = copy(self)
+ let newKeyMap.key = a:options['key']
+ let newKeyMap.quickhelpText = a:options['quickhelpText']
+ let newKeyMap.callback = a:options['callback']
+ call add(s:KeyMap.All(), newKeyMap)
+endfunction
+"CLASS: MenuController {{{2
+"============================================================
+let s:MenuController = {}
+"FUNCTION: MenuController.New(menuItems) {{{3
+"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() {{{3
+"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() {{{3
+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) {{{3
+"get the MenuItem that is curently selected
+function! s:MenuController._current()
+ return self.menuItems[self.selection]
+endfunction
+
+"FUNCTION: MenuController._handleKeypress(key) {{{3
+"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) {{{3
+"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) {{{3
+"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() {{{3
+"sets &cmdheight to whatever is needed to display the menu
+function! s:MenuController._setCmdheight()
+ let &cmdheight = len(self.menuItems) + 3
+endfunction
+
+"FUNCTION: MenuController._saveOptions() {{{3
+"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() {{{3
+"restore the options we saved in _saveOptions()
+function! s:MenuController._restoreOptions()
+ let &cmdheight = self._oldCmdheight
+ let &lazyredraw = self._oldLazyredraw
+endfunction
+
+"FUNCTION: MenuController._cursorDown() {{{3
+"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() {{{3
+"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
+
+"CLASS: MenuItem {{{2
+"============================================================
+let s:MenuItem = {}
+"FUNCTION: MenuItem.All() {{{3
+"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() {{{3
+"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) {{{3
+"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) {{{3
+"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) {{{3
+"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() {{{3
+"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() {{{3
+"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 = s:MenuController.New(self.children)
+ call mc.showMenu()
+ else
+ if self.callback != -1
+ call {self.callback}()
+ endif
+ endif
+endfunction
+
+"FUNCTION: MenuItem.isSeparator() {{{3
+"return 1 if this menuitem is a separator
+function! s:MenuItem.isSeparator()
+ return self.callback == -1 && self.children == []
+endfunction
+
+"FUNCTION: MenuItem.isSubmenu() {{{3
+"return 1 if this menuitem is a submenu
+function! s:MenuItem.isSubmenu()
+ return self.callback == -1 && !empty(self.children)
+endfunction
+
+"CLASS: TreeFileNode {{{2
+"This class is the parent of the TreeDirNode class and constitures the
+"'Component' part of the composite design pattern between the treenode
+"classes.
+"============================================================
+let s:TreeFileNode = {}
+"FUNCTION: TreeFileNode.activate(forceKeepWinOpen) {{{3
+function! s:TreeFileNode.activate(forceKeepWinOpen)
+ call self.open()
+ if !a:forceKeepWinOpen
+ call s:closeTreeIfQuitOnOpen()
+ end
+endfunction
+"FUNCTION: TreeFileNode.bookmark(name) {{{3
+"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 = s:Bookmark.GetNodeForName(a:name, 1)
+ catch /^NERDTree.BookmarkNotFoundError/
+ catch /^NERDTree.BookmarkedNodeNotFoundError/
+ endtry
+
+ call s:Bookmark.AddBookmark(a:name, self.path)
+ call self.path.cacheDisplayString()
+ call s:Bookmark.Write()
+
+ if !empty(oldMarkedNode)
+ call oldMarkedNode.path.cacheDisplayString()
+ endif
+endfunction
+"FUNCTION: TreeFileNode.cacheParent() {{{3
+"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.compareNodes {{{3
+"This is supposed to be a class level method but i cant figure out how to
+"get func refs to work from a dict..
+"
+"A class level method that compares two nodes
+"
+"Args:
+"n1, n2: the 2 nodes to compare
+function! s:compareNodes(n1, n2)
+ return a:n1.path.compareTo(a:n2.path)
+endfunction
+
+"FUNCTION: TreeFileNode.clearBoomarks() {{{3
+function! s:TreeFileNode.clearBoomarks()
+ for i in s:Bookmark.Bookmarks()
+ if i.path.equals(self.path)
+ call i.delete()
+ end
+ endfor
+ call self.path.cacheDisplayString()
+endfunction
+"FUNCTION: TreeFileNode.copy(dest) {{{3
+function! s:TreeFileNode.copy(dest)
+ call self.path.copy(a:dest)
+ let newPath = s:Path.New(a:dest)
+ let parent = b:NERDTreeRoot.findNode(newPath.getParent())
+ if !empty(parent)
+ call parent.refresh()
+ endif
+ return parent.findNode(newPath)
+endfunction
+
+"FUNCTION: TreeFileNode.delete {{{3
+"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() {{{3
+"
+"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) {{{3
+"
+"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) {{{3
+"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) {{{3
+"
+"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) {{{3
+"
+"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.getLineNum(){{{3
+"returns the line number this node is rendered on, or -1 if it isnt rendered
+function! s:TreeFileNode.getLineNum()
+ "if the node is the root then return the root line no.
+ if self.isRoot()
+ return s:TreeFileNode.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 = self.path.str({'format': 'UI'})
+
+
+ let lnum = s:TreeFileNode.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 = s:indentLevelFor(curLine)
+ if indent ==# curPathComponent
+ let curLine = s: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: TreeFileNode.GetRootForTab(){{{3
+"get the root node for this tab
+function! s:TreeFileNode.GetRootForTab()
+ if s:treeExistsForTab()
+ return getbufvar(t:NERDTreeBufName, 'NERDTreeRoot')
+ end
+ return {}
+endfunction
+"FUNCTION: TreeFileNode.GetRootLineNum(){{{3
+"gets the line number of the root node
+function! s:TreeFileNode.GetRootLineNum()
+ let rootLine = 1
+ while getline(rootLine) !~ '^\(/\|<\)'
+ let rootLine = rootLine + 1
+ endwhile
+ return rootLine
+endfunction
+
+"FUNCTION: TreeFileNode.GetSelected() {{{3
+"gets the treenode that the cursor is currently over
+function! s:TreeFileNode.GetSelected()
+ try
+ let path = s:getPath(line("."))
+ if path ==# {}
+ return {}
+ endif
+ return b:NERDTreeRoot.findNode(path)
+ catch /NERDTree/
+ return {}
+ endtry
+endfunction
+"FUNCTION: TreeFileNode.isVisible() {{{3
+"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() {{{3
+"returns 1 if this node is b:NERDTreeRoot
+function! s:TreeFileNode.isRoot()
+ if !s:treeExistsForBuf()
+ throw "NERDTree.NoTreeError: No tree exists for the current buffer"
+ endif
+
+ return self.equals(b:NERDTreeRoot)
+endfunction
+
+"FUNCTION: TreeFileNode.makeRoot() {{{3
+"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
+endfunction
+"FUNCTION: TreeFileNode.New(path) {{{3
+"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 s:TreeDirNode.New(a:path)
+ else
+ let newTreeNode = copy(self)
+ let newTreeNode.path = a:path
+ let newTreeNode.parent = {}
+ return newTreeNode
+ endif
+endfunction
+
+"FUNCTION: TreeFileNode.open() {{{3
+"Open the file represented by the given node in the current window, splitting
+"the window if needed
+"
+"ARGS:
+"treenode: file node to open
+function! s:TreeFileNode.open()
+ if b:NERDTreeType ==# "secondary"
+ exec 'edit ' . self.path.str({'format': 'Edit'})
+ return
+ endif
+
+ "if the file is already open in this tab then just stick the cursor in it
+ let winnr = bufwinnr('^' . self.path.str() . '$')
+ if winnr != -1
+ call s:exec(winnr . "wincmd w")
+
+ else
+ if !s:isWindowUsable(winnr("#")) && s:firstUsableWindow() ==# -1
+ call self.openSplit()
+ else
+ try
+ if !s:isWindowUsable(winnr("#"))
+ call s:exec(s:firstUsableWindow() . "wincmd w")
+ else
+ call s:exec('wincmd p')
+ endif
+ exec ("edit " . self.path.str({'format': 'Edit'}))
+ catch /^Vim\%((\a\+)\)\=:E37/
+ call s:putCursorInTreeWin()
+ throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self.path.str() ." is already open and modified."
+ catch /^Vim\%((\a\+)\)\=:/
+ echo v:exception
+ endtry
+ endif
+ endif
+endfunction
+"FUNCTION: TreeFileNode.openSplit() {{{3
+"Open this node in a new window
+function! s:TreeFileNode.openSplit()
+
+ if b:NERDTreeType ==# "secondary"
+ exec "split " . self.path.str({'format': 'Edit'})
+ return
+ endif
+
+ " 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 s: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 " . self.path.str({'format': 'Edit'}))
+ catch /^Vim\%((\a\+)\)\=:E37/
+ call s: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 s:exec(there)
+ exec("silent ". splitMode ." resize ". size)
+ call s:exec('wincmd p')
+ endif
+
+ " Restore splitmode settings
+ let &splitbelow=savesplitbelow
+ let &splitright=savesplitright
+endfunction
+"FUNCTION: TreeFileNode.openVSplit() {{{3
+"Open this node in a new vertical window
+function! s:TreeFileNode.openVSplit()
+ if b:NERDTreeType ==# "secondary"
+ exec "vnew " . self.path.str({'format': 'Edit'})
+ return
+ endif
+
+ let winwidth = winwidth(".")
+ if winnr("$")==#1
+ let winwidth = g:NERDTreeWinSize
+ endif
+
+ call s:exec("wincmd p")
+ exec "vnew " . self.path.str({'format': 'Edit'})
+
+ "resize the nerd tree back to the original size
+ call s:putCursorInTreeWin()
+ exec("silent vertical resize ". winwidth)
+ call s:exec('wincmd p')
+endfunction
+"FUNCTION: TreeFileNode.openInNewTab(options) {{{3
+function! s:TreeFileNode.openInNewTab(options)
+ let currentTab = tabpagenr()
+
+ if !has_key(a:options, 'keepTreeOpen')
+ call s:closeTreeIfQuitOnOpen()
+ endif
+
+ exec "tabedit " . self.path.str({'format': 'Edit'})
+
+ if has_key(a:options, 'stayInCurrentTab') && a:options['stayInCurrentTab']
+ exec "tabnext " . currentTab
+ endif
+
+endfunction
+"FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{3
+"Places the cursor on the line number this node is rendered on
+"
+"Args:
+"isJump: 1 if this cursor movement should be counted as a jump by vim
+"recurseUpward: try to put the cursor on the parent if the this node isnt
+"visible
+function! s:TreeFileNode.putCursorHere(isJump, recurseUpward)
+ let ln = self.getLineNum()
+ if ln != -1
+ if a:isJump
+ mark '
+ endif
+ call cursor(ln, col("."))
+ else
+ if a:recurseUpward
+ let node = self
+ while node != {} && node.getLineNum() ==# -1
+ let node = node.parent
+ call node.open()
+ endwhile
+ call s:renderView()
+ call node.putCursorHere(a:isJump, 0)
+ endif
+ endif
+endfunction
+
+"FUNCTION: TreeFileNode.refresh() {{{3
+function! s:TreeFileNode.refresh()
+ call self.path.refresh()
+endfunction
+"FUNCTION: TreeFileNode.rename() {{{3
+"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 {{{3
+"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]
+ let treeParts = treeParts . ' '
+ endfor
+ endif
+
+ if self.path.isDirectory
+ if self.isOpen
+ let treeParts = treeParts . '▼ '
+ else
+ let treeParts = treeParts . '▶ '
+ endif
+ else
+ let treeParts = treeParts . ''
+ 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
+"CLASS: TreeDirNode {{{2
+"This class is a child of the TreeFileNode class and constitutes the
+"'Composite' part of the composite design pattern between the treenode
+"classes.
+"============================================================
+let s:TreeDirNode = copy(s:TreeFileNode)
+"FUNCTION: TreeDirNode.AbsoluteTreeRoot(){{{3
+"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(forceKeepWinOpen) {{{3
+unlet s:TreeDirNode.activate
+function! s:TreeDirNode.activate(forceKeepWinOpen)
+ call self.toggleOpen()
+ call s:renderView()
+ call self.putCursorHere(0, 0)
+endfunction
+"FUNCTION: TreeDirNode.addChild(treenode, inOrder) {{{3
+"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() {{{3
+"Closes this directory
+function! s:TreeDirNode.close()
+ let self.isOpen = 0
+endfunction
+
+"FUNCTION: TreeDirNode.closeChildren() {{{3
+"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) {{{3
+"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 = s:TreeFileNode.New(a:path)
+ call self.addChild(newTreeNode, a:inOrder)
+ return newTreeNode
+endfunction
+
+"FUNCTION: TreeDirNode.findNode(path) {{{3
+"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() {{{3
+"Returns the number of children this node has
+function! s:TreeDirNode.getChildCount()
+ return len(self.children)
+endfunction
+
+"FUNCTION: TreeDirNode.getChild(path) {{{3
+"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) {{{3
+"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) {{{3
+"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() {{{3
+"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 = s:TreeFileNode.GetSelected()
+ if currentDir != {} && !currentDir.isRoot()
+ if currentDir.path.isDirectory ==# 0
+ let currentDir = currentDir.parent
+ endif
+ endif
+ return currentDir
+endfunction
+"FUNCTION: TreeDirNode.getVisibleChildCount() {{{3
+"Returns the number of visible children this node has
+function! s:TreeDirNode.getVisibleChildCount()
+ return len(self.getVisibleChildren())
+endfunction
+
+"FUNCTION: TreeDirNode.getVisibleChildren() {{{3
+"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() {{{3
+"returns 1 if this node has any childre, 0 otherwise..
+function! s:TreeDirNode.hasVisibleChildren()
+ return self.getVisibleChildCount() != 0
+endfunction
+
+"FUNCTION: TreeDirNode._initChildren() {{{3
+"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'})
+ let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*')
+ let files = split(filesStr, "\n")
+
+ if !a:silent && len(files) > g:NERDTreeNotificationThreshold
+ call s: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 = s:Path.New(i)
+ call self.createChild(path, 0)
+ catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/
+ let invalidFilesFound += 1
+ endtry
+ endif
+ endfor
+
+ call self.sortChildren()
+
+ if !a:silent && len(files) > g:NERDTreeNotificationThreshold
+ call s:echo("Please wait, caching a large dir ... DONE (". self.getChildCount() ." nodes cached).")
+ endif
+
+ if invalidFilesFound
+ call s:echoWarning(invalidFilesFound . " file(s) could not be loaded into the NERD tree")
+ endif
+ return self.getChildCount()
+endfunction
+"FUNCTION: TreeDirNode.New(path) {{{3
+"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() {{{3
+"Reads in all this nodes children
+"
+"Return: the number of child nodes read
+unlet s:TreeDirNode.open
+function! s:TreeDirNode.open()
+ let self.isOpen = 1
+ if self.children ==# []
+ return self._initChildren(0)
+ else
+ return 0
+ endif
+endfunction
+
+" FUNCTION: TreeDirNode.openExplorer() {{{3
+" opens an explorer window for this node in the previous window (could be a
+" nerd tree or a netrw)
+function! s:TreeDirNode.openExplorer()
+ let oldwin = winnr()
+ call s:exec('wincmd p')
+ if oldwin ==# winnr() || (&modified && s:bufInWindows(winbufnr(winnr())) < 2)
+ call s:exec('wincmd p')
+ call self.openSplit()
+ else
+ exec ("silent edit " . self.path.str({'format': 'Edit'}))
+ endif
+endfunction
+"FUNCTION: TreeDirNode.openInNewTab(options) {{{3
+unlet s:TreeDirNode.openInNewTab
+function! s:TreeDirNode.openInNewTab(options)
+ let currentTab = tabpagenr()
+
+ if !has_key(a:options, 'keepTreeOpen') || !a:options['keepTreeOpen']
+ call s:closeTreeIfQuitOnOpen()
+ endif
+
+ tabnew
+ call s:initNerdTree(self.path.str())
+
+ if has_key(a:options, 'stayInCurrentTab') && a:options['stayInCurrentTab']
+ exec "tabnext " . currentTab
+ endif
+endfunction
+"FUNCTION: TreeDirNode.openRecursively() {{{3
+"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() {{{3
+"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() {{{3
+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 = s:Path.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 = s:TreeFileNode.New(path)
+ let newNode.parent = self
+ call add(newChildNodes, newNode)
+ endif
+
+
+ catch /^NERDTree.InvalidArgumentsError/
+ 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 s:echoWarning("some files could not be loaded into the NERD tree")
+ endif
+ endif
+endfunction
+
+"FUNCTION: TreeDirNode.reveal(path) {{{3
+"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 s:renderView()
+ 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) {{{3
+"
+"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() {{{3
+"
+"Sorts the children of this node according to alphabetical order and the
+"directory priority.
+"
+function! s:TreeDirNode.sortChildren()
+ let CompareFunc = function("s:compareNodes")
+ call sort(self.children, CompareFunc)
+endfunction
+
+"FUNCTION: TreeDirNode.toggleOpen() {{{3
+"Opens this directory if it is closed and vice versa
+function! s:TreeDirNode.toggleOpen()
+ if self.isOpen ==# 1
+ call self.close()
+ else
+ call self.open()
+ endif
+endfunction
+
+"FUNCTION: TreeDirNode.transplantChild(newNode) {{{3
+"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
+"============================================================
+"CLASS: Path {{{2
+"============================================================
+let s:Path = {}
+"FUNCTION: Path.AbsolutePathFor(str) {{{3
+function! s:Path.AbsolutePathFor(str)
+ let prependCWD = 0
+ if s:running_windows
+ let prependCWD = 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() {{{3
+function! s:Path.bookmarkNames()
+ if !exists("self._bookmarkNames")
+ call self.cacheDisplayString()
+ endif
+ return self._bookmarkNames
+endfunction
+"FUNCTION: Path.cacheDisplayString() {{{3
+function! s:Path.cacheDisplayString()
+ let self.cachedDisplayString = self.getLastPathComponent(1)
+
+ if self.isExecutable
+ let self.cachedDisplayString = self.cachedDisplayString . '*'
+ endif
+
+ let self._bookmarkNames = []
+ for i in s:Bookmark.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() {{{3
+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 s:echo("CWD is now: " . getcwd())
+ catch
+ throw "NERDTree.PathChangeError: cannot change CWD to " . dir
+ endtry
+endfunction
+
+"FUNCTION: Path.compareTo() {{{3
+"
+"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 the sort sequences are the same then compare the paths
+ "alphabetically
+ let pathCompare = g:NERDTreeCaseSensitiveSort ? thisPath <# thatPath : thisPath <? thatPath
+ if pathCompare
+ return -1
+ else
+ return 1
+ endif
+ endif
+endfunction
+
+"FUNCTION: Path.Create(fullpath) {{{3
+"
+"Factory method.
+"
+"Creates a path object with the given path. The path is also created on the
+"filesystem. If the path already exists, a NERDTree.Path.Exists exception is
+"thrown. If any other errors occur, a NERDTree.Path exception is thrown.
+"
+"Args:
+"fullpath: the full filesystem path to the file/dir to create
+function! s:Path.Create(fullpath)
+ "bail if the a:fullpath already exists
+ if isdirectory(a:fullpath) || filereadable(a:fullpath)
+ throw "NERDTree.CreatePathError: Directory Exists: '" . a:fullpath . "'"
+ endif
+
+ try
+
+ "if it ends with a slash, assume its a dir create it
+ if a:fullpath =~ '\(\\\|\/\)$'
+ "whack the trailing slash off the end if it exists
+ let fullpath = substitute(a:fullpath, '\(\\\|\/\)$', '', '')
+
+ call mkdir(fullpath, 'p')
+
+ "assume its a file and create
+ else
+ call writefile([], a:fullpath)
+ endif
+ catch
+ throw "NERDTree.CreatePathError: Could not create path: '" . a:fullpath . "'"
+ endtry
+
+ return s:Path.New(a:fullpath)
+endfunction
+
+"FUNCTION: Path.copy(dest) {{{3
+"
+"Copies the file/dir represented by this Path to the given location
+"
+"Args:
+"dest: the location to copy this dir/file to
+function! s:Path.copy(dest)
+ if !s:Path.CopyingSupported()
+ throw "NERDTree.CopyingNotSupportedError: Copying is not supported on this OS"
+ endif
+
+ let dest = s:Path.WinToUnixPath(a:dest)
+
+ let cmd = g:NERDTreeCopyCmd . " " . self.str() . " " . dest
+ let success = system(cmd)
+ if success != 0
+ throw "NERDTree.CopyError: Could not copy ''". self.str() ."'' to: '" . a:dest . "'"
+ endif
+endfunction
+
+"FUNCTION: Path.CopyingSupported() {{{3
+"
+"returns 1 if copying is supported for this OS
+function! s:Path.CopyingSupported()
+ return exists('g:NERDTreeCopyCmd')
+endfunction
+
+
+"FUNCTION: Path.copyingWillOverwrite(dest) {{{3
+"
+"returns 1 if copy this path to the given location will cause files to
+"overwritten
+"
+"Args:
+"dest: the location this path will be copied to
+function! s:Path.copyingWillOverwrite(dest)
+ if filereadable(a:dest)
+ return 1
+ endif
+
+ if isdirectory(a:dest)
+ let path = s:Path.JoinPathStrings(a:dest, self.getLastPathComponent(0))
+ if filereadable(path)
+ return 1
+ endif
+ endif
+endfunction
+
+"FUNCTION: Path.delete() {{{3
+"
+"Deletes the file represented by this path.
+"Deletion of directories is not supported
+"
+"Throws NERDTree.Path.Deletion exceptions
+function! s:Path.delete()
+ if self.isDirectory
+
+ let cmd = g:NERDTreeRemoveDirCmd . self.str({'escape': 1})
+ let success = system(cmd)
+
+ if v:shell_error != 0
+ throw "NERDTree.PathDeletionError: Could not delete directory: '" . self.str() . "'"
+ endif
+ else
+ let success = delete(self.str())
+ if success != 0
+ throw "NERDTree.PathDeletionError: Could not delete file: '" . self.str() . "'"
+ endif
+ endif
+
+ "delete all bookmarks for this path
+ for i in self.bookmarkNames()
+ let bookmark = s:Bookmark.BookmarkFor(i)
+ call bookmark.delete()
+ endfor
+endfunction
+
+"FUNCTION: Path.displayString() {{{3
+"
+"Returns a string that specifies how the path should be represented as a
+"string
+function! s:Path.displayString()
+ if self.cachedDisplayString ==# ""
+ call self.cacheDisplayString()
+ endif
+
+ return self.cachedDisplayString
+endfunction
+"FUNCTION: Path.extractDriveLetter(fullpath) {{{3
+"
+"If running windows, cache the drive letter for this path
+function! s:Path.extractDriveLetter(fullpath)
+ if s:running_windows
+ let self.drive = substitute(a:fullpath, '\(^[a-zA-Z]:\).*', '\1', '')
+ else
+ let self.drive = ''
+ endif
+
+endfunction
+"FUNCTION: Path.exists() {{{3
+"return 1 if this path points to a location that is readable or is a directory
+function! s:Path.exists()
+ let p = self.str()
+ return filereadable(p) || isdirectory(p)
+endfunction
+"FUNCTION: Path.getDir() {{{3
+"
+"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() {{{3
+"
+"Returns a new path object for this paths parent
+"
+"Return:
+"a new Path object
+function! s:Path.getParent()
+ if s:running_windows
+ 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) {{{3
+"
+"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() {{{3
+"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.ignore() {{{3
+"returns true if this path should be ignored
+function! s:Path.ignore()
+ let lastPathComponent = self.getLastPathComponent(0)
+
+ "filter out the user specified paths to ignore
+ if b:NERDTreeIgnoreEnabled
+ for i in g:NERDTreeIgnore
+ if lastPathComponent =~ i
+ return 1
+ endif
+ endfor
+ endif
+
+ "dont show hidden files unless instructed to
+ if b:NERDTreeShowHidden ==# 0 && lastPathComponent =~ '^\.'
+ return 1
+ endif
+
+ if b:NERDTreeShowFiles ==# 0 && self.isDirectory ==# 0
+ return 1
+ endif
+
+ return 0
+endfunction
+
+"FUNCTION: Path.isUnder(path) {{{3
+"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(...) {{{3
+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() {{{3
+"
+"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() {{{3
+"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 = ""
+
+ return newPath
+endfunction
+
+"FUNCTION: Path.Slash() {{{3
+"return the slash to use for the current OS
+function! s:Path.Slash()
+ return s:running_windows ? '\' : '/'
+endfunction
+
+"FUNCTION: Path.readInfoFromDisk(fullpath) {{{3
+"
+"
+"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 = resolve(self.strTrunk()) . '/' . lastPathComponent
+
+ "if the last part of the path is a symlink then flag it as such
+ let self.isSymLink = (resolve(hardPath) != hardPath)
+ if self.isSymLink
+ let self.symLinkDest = 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() {{{3
+function! s:Path.refresh()
+ call self.readInfoFromDisk(self.str())
+ call self.cacheDisplayString()
+endfunction
+
+"FUNCTION: Path.rename() {{{3
+"
+"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 = s:Bookmark.BookmarkFor(i)
+ call b.setPath(copy(self))
+ endfor
+ call s:Bookmark.Write()
+endfunction
+
+"FUNCTION: Path.str() {{{3
+"
+"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 has_key(options, 'escape') && 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() {{{3
+function! s:Path._strForUI()
+ let toReturn = '/' . join(self.pathSegments, '/')
+ if self.isDirectory && toReturn != '/'
+ let toReturn = toReturn . '/'
+ endif
+ return toReturn
+endfunction
+
+"FUNCTION: Path._strForCd() {{{3
+"
+" returns a string that can be used with :cd
+function! s:Path._strForCd()
+ return escape(self.str(), s:escape_chars)
+endfunction
+"FUNCTION: Path._strForEdit() {{{3
+"
+"Return: the string for this path that is suitable to be used with the :edit
+"command
+function! s:Path._strForEdit()
+ let p = self.str({'format': 'UI'})
+ let cwd = getcwd()
+
+ if s:running_windows
+ let p = tolower(self.str())
+ let cwd = tolower(getcwd())
+ endif
+
+ let p = escape(p, s:escape_chars)
+
+ let cwd = cwd . s:Path.Slash()
+
+ "return a relative path if we can
+ if stridx(p, cwd) ==# 0
+ let p = strpart(p, strlen(cwd))
+ endif
+
+ if p ==# ''
+ let p = '.'
+ endif
+
+ return p
+
+endfunction
+"FUNCTION: Path._strForGlob() {{{3
+function! s:Path._strForGlob()
+ let lead = s:Path.Slash()
+
+ "if we are running windows then slap a drive letter on the front
+ if s:running_windows
+ let lead = self.drive . '\'
+ endif
+
+ let toReturn = lead . join(self.pathSegments, s:Path.Slash())
+
+ if !s:running_windows
+ let toReturn = escape(toReturn, s:escape_chars)
+ endif
+ return toReturn
+endfunction
+"FUNCTION: Path._str() {{{3
+"
+"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 s:running_windows
+ let lead = self.drive . '\'
+ endif
+
+ return lead . join(self.pathSegments, s:Path.Slash())
+endfunction
+
+"FUNCTION: Path.strTrunk() {{{3
+"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.WinToUnixPath(pathstr){{{3
+"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 !s:running_windows
+ return a:pathstr
+ endif
+
+ let toReturn = a:pathstr
+
+ "remove the x:\ of the front
+ let toReturn = substitute(toReturn, '^.*:\(\\\|/\)\?', '/', "")
+
+ "convert all \ chars to /
+ let toReturn = substitute(toReturn, '\', '/', "g")
+
+ return toReturn
+endfunction
+
+" SECTION: General Functions {{{1
+"============================================================
+"FUNCTION: s:bufInWindows(bnum){{{2
+"[[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: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: s:checkForBrowse(dir) {{{2
+"inits a secondary nerd tree in the current buffer if appropriate
+function! s:checkForBrowse(dir)
+ if a:dir != '' && isdirectory(a:dir)
+ call s:initNerdTreeInPlace(a:dir)
+ endif
+endfunction
+"FUNCTION: s:compareBookmarks(first, second) {{{2
+"Compares two bookmarks
+function! s:compareBookmarks(first, second)
+ return a:first.compareTo(a:second)
+endfunction
+
+" FUNCTION: s:completeBookmarks(A,L,P) {{{2
+" completion function for the bookmark commands
+function! s:completeBookmarks(A,L,P)
+ return filter(s:Bookmark.BookmarkNames(), 'v:val =~ "^' . a:A . '"')
+endfunction
+" FUNCTION: s:exec(cmd) {{{2
+" same as :exec cmd but eventignore=all is set for the duration
+function! s:exec(cmd)
+ let old_ei = &ei
+ set ei=all
+ exec a:cmd
+ let &ei = old_ei
+endfunction
+" FUNCTION: s:findAndRevealPath() {{{2
+function! s:findAndRevealPath()
+ try
+ let p = s:Path.New(expand("%:p"))
+ catch /^NERDTree.InvalidArgumentsError/
+ call s:echo("no file for the current buffer")
+ return
+ endtry
+
+ if !s:treeExistsForTab()
+ call s:initNerdTree(p.getParent().str())
+ else
+ if !p.isUnder(s:TreeFileNode.GetRootForTab().path)
+ call s:initNerdTree(p.getParent().str())
+ else
+ if !s:isTreeOpen()
+ call s:toggle("")
+ endif
+ endif
+ endif
+ call s:putCursorInTreeWin()
+ call b:NERDTreeRoot.reveal(p)
+endfunction
+"FUNCTION: s:initNerdTree(name) {{{2
+"Initialise the nerd tree for this tab. The tree will start in either the
+"given directory, or the directory associated with the given bookmark
+"
+"Args:
+"name: the name of a bookmark or a directory
+function! s:initNerdTree(name)
+ let path = {}
+ if s:Bookmark.BookmarkExistsFor(a:name)
+ let path = s:Bookmark.BookmarkFor(a:name).path
+ else
+ let dir = a:name ==# '' ? getcwd() : a:name
+
+ "hack to get an absolute path if a relative path is given
+ if dir =~ '^\.'
+ let dir = getcwd() . s:Path.Slash() . dir
+ endif
+ let dir = resolve(dir)
+
+ try
+ let path = s:Path.New(dir)
+ catch /^NERDTree.InvalidArgumentsError/
+ call s:echo("No bookmark or directory found for: " . a:name)
+ return
+ endtry
+ endif
+ if !path.isDirectory
+ let path = path.getParent()
+ endif
+
+ "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 s:treeExistsForTab()
+ if s:isTreeOpen()
+ call s:closeTree()
+ endif
+ unlet t:NERDTreeBufName
+ endif
+
+ let newRoot = s:TreeDirNode.New(path)
+ call newRoot.open()
+
+ call s:createTreeWin()
+ let b:treeShowHelp = 0
+ let b:NERDTreeIgnoreEnabled = 1
+ let b:NERDTreeShowFiles = g:NERDTreeShowFiles
+ let b:NERDTreeShowHidden = g:NERDTreeShowHidden
+ let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks
+ let b:NERDTreeRoot = newRoot
+
+ let b:NERDTreeType = "primary"
+
+ call s:renderView()
+ call b:NERDTreeRoot.putCursorHere(0, 0)
+endfunction
+
+"FUNCTION: s:initNerdTreeInPlace(dir) {{{2
+function! s:initNerdTreeInPlace(dir)
+ try
+ let path = s:Path.New(a:dir)
+ catch /^NERDTree.InvalidArgumentsError/
+ call s: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 " . s:nextBufferName()
+
+ let b:NERDTreePreviousBuf = bufnr(previousBuf)
+
+ let b:NERDTreeRoot = s:TreeDirNode.New(path)
+ call b:NERDTreeRoot.open()
+
+ "throwaway buffer options
+ setlocal noswapfile
+ setlocal buftype=nofile
+ setlocal bufhidden=hide
+ setlocal nowrap
+ setlocal foldcolumn=0
+ setlocal nobuflisted
+ setlocal nospell
+ if g:NERDTreeShowLineNumbers
+ setlocal nu
+ else
+ setlocal nonu
+ endif
+
+ iabc <buffer>
+
+ if g:NERDTreeHighlightCursorline
+ setlocal cursorline
+ endif
+
+ call s:setupStatusline()
+
+ let b:treeShowHelp = 0
+ let b:NERDTreeIgnoreEnabled = 1
+ let b:NERDTreeShowFiles = g:NERDTreeShowFiles
+ let b:NERDTreeShowHidden = g:NERDTreeShowHidden
+ let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks
+
+ let b:NERDTreeType = "secondary"
+
+ call s:bindMappings()
+ setfiletype nerdtree
+ " syntax highlighting
+ if has("syntax") && exists("g:syntax_on")
+ call s:setupSyntaxHighlighting()
+ endif
+
+ call s:renderView()
+endfunction
+" FUNCTION: s:initNerdTreeMirror() {{{2
+function! s:initNerdTreeMirror()
+
+ "get the names off all the nerd tree buffers
+ let treeBufNames = []
+ for i in range(1, tabpagenr("$"))
+ let nextName = s:tabpagevar(i, 'NERDTreeBufName')
+ if nextName != -1 && (!exists("t:NERDTreeBufName") || nextName != t:NERDTreeBufName)
+ call add(treeBufNames, nextName)
+ endif
+ endfor
+ let treeBufNames = s:unique(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 s:echo("No trees to mirror")
+ return
+ endif
+
+ if s:treeExistsForTab() && s:isTreeOpen()
+ call s:closeTree()
+ endif
+
+ let t:NERDTreeBufName = bufferName
+ call s:createTreeWin()
+ exec 'buffer ' . bufferName
+ if !&hidden
+ call s:renderView()
+ endif
+endfunction
+" FUNCTION: s:nextBufferName() {{{2
+" returns the buffer name for the next nerd tree
+function! s:nextBufferName()
+ let name = s:NERDTreeBufName . s:next_buffer_number
+ let s:next_buffer_number += 1
+ return name
+endfunction
+" FUNCTION: s:tabpagevar(tabnr, var) {{{2
+function! s: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:treeExistsForBuffer() {{{2
+" Returns 1 if a nerd tree root exists in the current buffer
+function! s:treeExistsForBuf()
+ return exists("b:NERDTreeRoot")
+endfunction
+" Function: s:treeExistsForTab() {{{2
+" Returns 1 if a nerd tree root exists in the current tab
+function! s:treeExistsForTab()
+ return exists("t:NERDTreeBufName")
+endfunction
+" Function: s:unique(list) {{{2
+" returns a:list without duplicates
+function! s:unique(list)
+ let uniqlist = []
+ for elem in a:list
+ if index(uniqlist, elem) ==# -1
+ let uniqlist += [elem]
+ endif
+ endfor
+ return uniqlist
+endfunction
+" SECTION: Public API {{{1
+"============================================================
+let g:NERDTreePath = s:Path
+let g:NERDTreeDirNode = s:TreeDirNode
+let g:NERDTreeFileNode = s:TreeFileNode
+let g:NERDTreeBookmark = s:Bookmark
+
+function! NERDTreeAddMenuItem(options)
+ call s:MenuItem.Create(a:options)
+endfunction
+
+function! NERDTreeAddMenuSeparator(...)
+ let opts = a:0 ? a:1 : {}
+ call s:MenuItem.CreateSeparator(opts)
+endfunction
+
+function! NERDTreeAddSubmenu(options)
+ return s:MenuItem.Create(a:options)
+endfunction
+
+function! NERDTreeAddKeyMap(options)
+ call s:KeyMap.Create(a:options)
+endfunction
+
+function! NERDTreeRender()
+ call s:renderView()
+endfunction
+
+" SECTION: View Functions {{{1
+"============================================================
+"FUNCTION: s:centerView() {{{2
+"centers the nerd tree window around the cursor (provided the nerd tree
+"options permit)
+function! s:centerView()
+ if g:NERDTreeAutoCenter
+ let current_line = winline()
+ let lines_to_top = current_line
+ let lines_to_bottom = winheight(s:getTreeWinNum()) - current_line
+ if lines_to_top < g:NERDTreeAutoCenterThreshold || lines_to_bottom < g:NERDTreeAutoCenterThreshold
+ normal! zz
+ endif
+ endif
+endfunction
+"FUNCTION: s:closeTree() {{{2
+"Closes the primary NERD tree window for this tab
+function! s:closeTree()
+ if !s:isTreeOpen()
+ throw "NERDTree.NoTreeFoundError: no NERDTree is open"
+ endif
+
+ if winnr("$") != 1
+ if winnr() == s:getTreeWinNum()
+ wincmd p
+ let bufnr = bufnr("")
+ wincmd p
+ else
+ let bufnr = bufnr("")
+ endif
+
+ call s:exec(s:getTreeWinNum() . " wincmd w")
+ close
+ call s:exec(bufwinnr(bufnr) . " wincmd w")
+ else
+ close
+ endif
+endfunction
+
+"FUNCTION: s:closeTreeIfOpen() {{{2
+"Closes the NERD tree window if it is open
+function! s:closeTreeIfOpen()
+ if s:isTreeOpen()
+ call s:closeTree()
+ endif
+endfunction
+"FUNCTION: s:closeTreeIfQuitOnOpen() {{{2
+"Closes the NERD tree window if the close on open option is set
+function! s:closeTreeIfQuitOnOpen()
+ if g:NERDTreeQuitOnOpen && s:isTreeOpen()
+ call s:closeTree()
+ endif
+endfunction
+"FUNCTION: s:createTreeWin() {{{2
+"Inits the NERD tree window. ie. opens it, sizes it, sets all the local
+"options etc
+function! s:createTreeWin()
+ "create the nerd tree window
+ let splitLocation = g:NERDTreeWinPos ==# "left" ? "topleft " : "botright "
+ let splitSize = g:NERDTreeWinSize
+
+ if !exists('t:NERDTreeBufName')
+ let t:NERDTreeBufName = s: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
+
+ "throwaway buffer options
+ setlocal noswapfile
+ setlocal buftype=nofile
+ setlocal nowrap
+ setlocal foldcolumn=0
+ setlocal nobuflisted
+ setlocal nospell
+ if g:NERDTreeShowLineNumbers
+ setlocal nu
+ else
+ setlocal nonu
+ endif
+
+ iabc <buffer>
+
+ if g:NERDTreeHighlightCursorline
+ setlocal cursorline
+ endif
+
+ call s:setupStatusline()
+
+ call s:bindMappings()
+ setfiletype nerdtree
+ " syntax highlighting
+ if has("syntax") && exists("g:syntax_on")
+ call s:setupSyntaxHighlighting()
+ endif
+endfunction
+
+"FUNCTION: s:dumpHelp {{{2
+"prints out the quick help
+function! s:dumpHelp()
+ let old_h = @h
+ if b:treeShowHelp ==# 1
+ let @h= "\" NERD tree (" . s:NERD_tree_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."\" <CR>,\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."\"\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
+ if len(s:KeyMap.All())
+ let @h=@h."\"\n\" ----------------------------\n"
+ let @h=@h."\" Custom mappings~\n"
+ for i in s:KeyMap.All()
+ let @h=@h."\" ". i.key .": ". i.quickhelpText ."\n"
+ endfor
+ endif
+
+ 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 <name>\n"
+ let @h=@h."\" :BookmarkToRoot <name>\n"
+ let @h=@h."\" :RevealBookmark <name>\n"
+ let @h=@h."\" :OpenBookmark <name>\n"
+ let @h=@h."\" :ClearBookmarks [<names>]\n"
+ let @h=@h."\" :ClearAllBookmarks\n"
+ else
+ let @h="\" Press ". g:NERDTreeMapHelp ." for help\n"
+ endif
+
+ silent! put h
+
+ let @h = old_h
+endfunction
+"FUNCTION: s:echo {{{2
+"A wrapper for :echo. Appends 'NERDTree:' on the front of all messages
+"
+"Args:
+"msg: the message to echo
+function! s:echo(msg)
+ redraw
+ echomsg "NERDTree: " . a:msg
+endfunction
+"FUNCTION: s:echoWarning {{{2
+"Wrapper for s:echo, sets the message type to warningmsg for this message
+"Args:
+"msg: the message to echo
+function! s:echoWarning(msg)
+ echohl warningmsg
+ call s:echo(a:msg)
+ echohl normal
+endfunction
+"FUNCTION: s:echoError {{{2
+"Wrapper for s:echo, sets the message type to errormsg for this message
+"Args:
+"msg: the message to echo
+function! s:echoError(msg)
+ echohl errormsg
+ call s:echo(a:msg)
+ echohl normal
+endfunction
+"FUNCTION: s:firstUsableWindow(){{{2
+"find the window number of the first normal window
+function! s: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: s:getPath(ln) {{{2
+"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:getPath(ln)
+ let line = getline(a:ln)
+
+ let rootLine = s:TreeFileNode.GetRootLineNum()
+
+ "check to see if we have the root node
+ if a:ln == rootLine
+ return b:NERDTreeRoot.path
+ endif
+
+ " in case called from outside the tree
+ "if line !~ '^ *[|`▶▼ ]' || line =~ '^$'
+ "return {}
+ "endif
+
+ if line ==# s:tree_up_dir_line
+ return b:NERDTreeRoot.path.getParent()
+ endif
+
+ let indent = s:indentLevelFor(line)
+
+ "remove the tree parts and the leading space
+ let curFile = s: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 = s: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 = s: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 = s:Path.New(curFile)
+ return toReturn
+endfunction
+
+"FUNCTION: s:getTreeWinNum() {{{2
+"gets the nerd tree window number for this tab
+function! s:getTreeWinNum()
+ if exists("t:NERDTreeBufName")
+ return bufwinnr(t:NERDTreeBufName)
+ else
+ return -1
+ endif
+endfunction
+"FUNCTION: s:indentLevelFor(line) {{{2
+function! s:indentLevelFor(line)
+ return match(a:line, '[^ \-+~`|]') / s:tree_wid
+endfunction
+"FUNCTION: s:isTreeOpen() {{{2
+function! s:isTreeOpen()
+ return s:getTreeWinNum() != -1
+endfunction
+"FUNCTION: s:isWindowUsable(winnumber) {{{2
+"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:isWindowUsable(winnumber)
+ "gotta split if theres only one window (i.e. the NERD tree)
+ if winnr("$") ==# 1
+ return 0
+ endif
+
+ let oldwinnr = winnr()
+ call s:exec(a:winnumber . "wincmd p")
+ let specialWindow = getbufvar("%", '&buftype') != '' || getwinvar('%', '&previewwindow')
+ let modified = &modified
+ call s: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 || s:bufInWindows(winbufnr(a:winnumber)) >= 2
+endfunction
+
+" FUNCTION: s:jumpToChild(direction) {{{2
+" Args:
+" direction: 0 if going to first child, 1 if going to last
+function! s:jumpToChild(direction)
+ let currentNode = s:TreeFileNode.GetSelected()
+ if currentNode ==# {} || currentNode.isRoot()
+ call s:echo("cannot jump to " . (a:direction ? "last" : "first") . " child")
+ return
+ end
+ let dirNode = currentNode.parent
+ let childNodes = dirNode.getVisibleChildren()
+
+ let targetNode = childNodes[0]
+ if a:direction
+ let targetNode = childNodes[len(childNodes) - 1]
+ endif
+
+ if targetNode.equals(currentNode)
+ let siblingDir = 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 s:centerView()
+endfunction
+
+
+"FUNCTION: s:promptToDelBuffer(bufnum, msg){{{2
+"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 nr2char(getchar()) ==# 'y'
+ exec "silent bdelete! " . a:bufnum
+ endif
+endfunction
+
+"FUNCTION: s:putCursorOnBookmarkTable(){{{2
+"Places the cursor at the top of the bookmarks table
+function! s:putCursorOnBookmarkTable()
+ if !b:NERDTreeShowBookmarks
+ throw "NERDTree.IllegalOperationError: cant find bookmark table, bookmarks arent active"
+ endif
+
+ let rootNodeLine = s:TreeFileNode.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, 0)
+endfunction
+
+"FUNCTION: s:putCursorInTreeWin(){{{2
+"Places the cursor in the nerd tree window
+function! s:putCursorInTreeWin()
+ if !s:isTreeOpen()
+ throw "NERDTree.InvalidOperationError: cant put cursor in NERD tree window, no window exists"
+ endif
+
+ call s:exec(s:getTreeWinNum() . "wincmd w")
+endfunction
+
+"FUNCTION: s:renderBookmarks {{{2
+function! s:renderBookmarks()
+
+ call setline(line(".")+1, ">----------Bookmarks----------")
+ call cursor(line(".")+1, col("."))
+
+ for i in s:Bookmark.Bookmarks()
+ call setline(line(".")+1, i.str())
+ call cursor(line(".")+1, col("."))
+ endfor
+
+ call setline(line(".")+1, '')
+ call cursor(line(".")+1, col("."))
+endfunction
+"FUNCTION: s:renderView {{{2
+"The entry function for rendering the tree
+function! s:renderView()
+ 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 s:dumpHelp()
+
+ "delete the blank line before the help and add one after it
+ call setline(line(".")+1, "")
+ call cursor(line(".")+1, col("."))
+
+ if b:NERDTreeShowBookmarks
+ call s:renderBookmarks()
+ endif
+
+ "add the 'up a dir' line
+ call setline(line(".")+1, s:tree_up_dir_line)
+ call cursor(line(".")+1, col("."))
+
+ "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: s:renderViewSavingPosition {{{2
+"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:renderViewSavingPosition()
+ let currentNode = s:TreeFileNode.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 s:renderView()
+
+ if currentNode != {}
+ call currentNode.putCursorHere(0, 0)
+ endif
+endfunction
+"FUNCTION: s:restoreScreenState() {{{2
+"
+"Sets the screen state back to what it was when s:saveScreenState was last
+"called.
+"
+"Assumes the cursor is in the NERDTree window
+function! s:restoreScreenState()
+ if !exists("b:NERDTreeOldTopLine") || !exists("b:NERDTreeOldPos") || !exists("b:NERDTreeOldWindowSize")
+ return
+ endif
+ exec("silent vertical resize ".b:NERDTreeOldWindowSize)
+
+ let old_scrolloff=&scrolloff
+ let &scrolloff=0
+ call cursor(b:NERDTreeOldTopLine, 0)
+ normal! zt
+ call setpos(".", b:NERDTreeOldPos)
+ let &scrolloff=old_scrolloff
+endfunction
+
+"FUNCTION: s:saveScreenState() {{{2
+"Saves the current cursor position in the current buffer and the window
+"scroll position
+function! s:saveScreenState()
+ let win = winnr()
+ try
+ call s:putCursorInTreeWin()
+ let b:NERDTreeOldPos = getpos(".")
+ let b:NERDTreeOldTopLine = line("w0")
+ let b:NERDTreeOldWindowSize = winwidth("")
+ call s:exec(win . "wincmd w")
+ catch /^NERDTree.InvalidOperationError/
+ endtry
+endfunction
+
+"FUNCTION: s:setupStatusline() {{{2
+function! s:setupStatusline()
+ if g:NERDTreeStatusline != -1
+ let &l:statusline = g:NERDTreeStatusline
+ endif
+endfunction
+"FUNCTION: s:setupSyntaxHighlighting() {{{2
+function! s:setupSyntaxHighlighting()
+ "treeFlags are syntax items that should be invisible, but give clues as to
+ "how things should be highlighted
+ syn match treeFlag #\~#
+ syn match treeFlag #\[RO\]#
+
+ "highlighting for the .. (up dir) line at the top of the tree
+ execute "syn match treeUp #". s:tree_up_dir_line ."#"
+
+ "highlighting for the ~/+ symbols for the directory nodes
+ syn match treeClosable #\~\<#
+ syn match treeClosable #\~\.#
+ syn match treeOpenable #+\<#
+ syn match treeOpenable #+\.#he=e-1
+
+ "highlighting for the tree structural parts
+ syn match treePart #|#
+ syn match treePart #`#
+ syn match treePartFile #[|`]-#hs=s+1 contains=treePart
+
+ "quickhelp syntax elements
+ syn match treeHelpKey #" \{1,2\}[^ ]*:#hs=s+2,he=e-1
+ syn match treeHelpKey #" \{1,2\}[^ ]*,#hs=s+2,he=e-1
+ syn match treeHelpTitle #" .*\~#hs=s+2,he=e-1 contains=treeFlag
+ syn match treeToggleOn #".*(on)#hs=e-2,he=e-1 contains=treeHelpKey
+ syn match treeToggleOff #".*(off)#hs=e-3,he=e-1 contains=treeHelpKey
+ syn match treeHelpCommand #" :.\{-}\>#hs=s+3
+ syn match treeHelp #^".*# contains=treeHelpKey,treeHelpTitle,treeFlag,treeToggleOff,treeToggleOn,treeHelpCommand
+
+ "highlighting for readonly files
+ syn match treeRO #.*\[RO\]#hs=s+2 contains=treeFlag,treeBookmark,treePart,treePartFile
+
+ "highlighting for sym links
+ syn match treeLink #[^-| `].* -> # contains=treeBookmark,treeOpenable,treeClosable,treeDirSlash
+
+ "highlighing for directory nodes and file nodes
+ syn match treeDirSlash #/#
+ syn match treeDir #[^-| `].*/# contains=treeLink,treeDirSlash,treeOpenable,treeClosable
+ syn match treeExecFile #[|`]-.*\*\($\| \)# contains=treeLink,treePart,treeRO,treePartFile,treeBookmark
+ syn match treeFile #|-.*# contains=treeLink,treePart,treeRO,treePartFile,treeBookmark,treeExecFile
+ syn match treeFile #`-.*# contains=treeLink,treePart,treeRO,treePartFile,treeBookmark,treeExecFile
+ syn match treeCWD #^/.*$#
+
+ "highlighting for bookmarks
+ syn match treeBookmark # {.*}#hs=s+1
+
+ "highlighting for the bookmarks table
+ syn match treeBookmarksLeader #^>#
+ syn match treeBookmarksHeader #^>-\+Bookmarks-\+$# contains=treeBookmarksLeader
+ syn match treeBookmarkName #^>.\{-} #he=e-1 contains=treeBookmarksLeader
+ syn match treeBookmark #^>.*$# contains=treeBookmarksLeader,treeBookmarkName,treeBookmarksHeader
+
+ if g:NERDChristmasTree
+ hi def link treePart Special
+ hi def link treePartFile Type
+ hi def link treeFile Normal
+ hi def link treeExecFile Title
+ hi def link treeDirSlash Identifier
+ hi def link treeClosable Type
+ else
+ hi def link treePart Normal
+ hi def link treePartFile Normal
+ hi def link treeFile Normal
+ hi def link treeClosable Title
+ endif
+
+ hi def link treeBookmarksHeader statement
+ hi def link treeBookmarksLeader ignore
+ hi def link treeBookmarkName Identifier
+ hi def link treeBookmark normal
+
+ hi def link treeHelp String
+ hi def link treeHelpKey Identifier
+ hi def link treeHelpCommand Identifier
+ hi def link treeHelpTitle Macro
+ hi def link treeToggleOn Question
+ hi def link treeToggleOff WarningMsg
+
+ hi def link treeDir Directory
+ hi def link treeUp Directory
+ hi def link treeCWD Statement
+ hi def link treeLink Macro
+ hi def link treeOpenable Title
+ hi def link treeFlag ignore
+ hi def link treeRO WarningMsg
+ hi def link treeBookmark Statement
+
+ hi def link NERDTreeCurrentNode Search
+endfunction
+
+"FUNCTION: s: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! s:stripMarkupFromLine(line, removeLeadingSpaces)
+ let line = a:line
+ "remove the tree parts and the leading space
+ let line = substitute (line, s:tree_markup_reg,"","")
+
+ "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\($\| \)', "","")
+
+ 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
+
+"FUNCTION: s:toggle(dir) {{{2
+"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:toggle(dir)
+ if s:treeExistsForTab()
+ if !s:isTreeOpen()
+ call s:createTreeWin()
+ if !&hidden
+ call s:renderView()
+ endif
+ call s:restoreScreenState()
+ else
+ call s:closeTree()
+ endif
+ else
+ call s:initNerdTree(a:dir)
+ endif
+endfunction
+"SECTION: Interface bindings {{{1
+"============================================================
+"FUNCTION: s:activateNode(forceKeepWindowOpen) {{{2
+"If the current node is a file, open it in the previous window (or a new one
+"if the previous is modified). If it is a directory then it is opened.
+"
+"args:
+"forceKeepWindowOpen - dont close the window even if NERDTreeQuitOnOpen is set
+function! s:activateNode(forceKeepWindowOpen)
+ if getline(".") ==# s:tree_up_dir_line
+ return s:upDir(0)
+ endif
+
+ let treenode = s:TreeFileNode.GetSelected()
+ if treenode != {}
+ call treenode.activate(a:forceKeepWindowOpen)
+ else
+ let bookmark = s:Bookmark.GetSelected()
+ if !empty(bookmark)
+ call bookmark.activate()
+ endif
+ endif
+endfunction
+
+"FUNCTION: s:bindMappings() {{{2
+function! s:bindMappings()
+ " set up mappings and commands for this buffer
+ nnoremap <silent> <buffer> <middlerelease> :call <SID>handleMiddleMouse()<cr>
+ nnoremap <silent> <buffer> <leftrelease> <leftrelease>:call <SID>checkForActivate()<cr>
+ nnoremap <silent> <buffer> <2-leftmouse> :call <SID>activateNode(0)<cr>
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapActivateNode . " :call <SID>activateNode(0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenSplit ." :call <SID>openEntrySplit(0,0)<cr>"
+ exec "nnoremap <silent> <buffer> <cr> :call <SID>activateNode(0)<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapPreview ." :call <SID>previewNode(0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapPreviewSplit ." :call <SID>previewNode(1)<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenVSplit ." :call <SID>openEntrySplit(1,0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapPreviewVSplit ." :call <SID>previewNode(2)<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenRecursively ." :call <SID>openNodeRecursively()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapUpdirKeepOpen ." :call <SID>upDir(1)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapUpdir ." :call <SID>upDir(0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapChangeRoot ." :call <SID>chRoot()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapChdir ." :call <SID>chCwd()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapQuit ." :call <SID>closeTreeWindow()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapRefreshRoot ." :call <SID>refreshRoot()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapRefresh ." :call <SID>refreshCurrent()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapHelp ." :call <SID>displayHelp()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleZoom ." :call <SID>toggleZoom()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleHidden ." :call <SID>toggleShowHidden()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleFilters ." :call <SID>toggleIgnoreFilter()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleFiles ." :call <SID>toggleShowFiles()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleBookmarks ." :call <SID>toggleShowBookmarks()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapCloseDir ." :call <SID>closeCurrentDir()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapCloseChildren ." :call <SID>closeChildren()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapMenu ." :call <SID>showMenu()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpParent ." :call <SID>jumpToParent()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpNextSibling ." :call <SID>jumpToSibling(1)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpPrevSibling ." :call <SID>jumpToSibling(0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpFirstChild ." :call <SID>jumpToFirstChild()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpLastChild ." :call <SID>jumpToLastChild()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpRoot ." :call <SID>jumpToRoot()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenInTab ." :call <SID>openInNewTab(0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenInTabSilent ." :call <SID>openInNewTab(1)<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenExpl ." :call <SID>openExplorer()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapDeleteBookmark ." :call <SID>deleteBookmark()<cr>"
+
+ "bind all the user custom maps
+ call s:KeyMap.BindAll()
+
+ command! -buffer -nargs=1 Bookmark :call <SID>bookmarkNode('<args>')
+ command! -buffer -complete=customlist,s:completeBookmarks -nargs=1 RevealBookmark :call <SID>revealBookmark('<args>')
+ command! -buffer -complete=customlist,s:completeBookmarks -nargs=1 OpenBookmark :call <SID>openBookmark('<args>')
+ command! -buffer -complete=customlist,s:completeBookmarks -nargs=* ClearBookmarks call <SID>clearBookmarks('<args>')
+ command! -buffer -complete=customlist,s:completeBookmarks -nargs=+ BookmarkToRoot call s:Bookmark.ToRoot('<args>')
+ command! -buffer -nargs=0 ClearAllBookmarks call s:Bookmark.ClearAll() <bar> call <SID>renderView()
+ command! -buffer -nargs=0 ReadBookmarks call s:Bookmark.CacheBookmarks(0) <bar> call <SID>renderView()
+ command! -buffer -nargs=0 WriteBookmarks call s:Bookmark.Write()
+endfunction
+
+" FUNCTION: s:bookmarkNode(name) {{{2
+" Associate the current node with the given name
+function! s:bookmarkNode(name)
+ let currentNode = s:TreeFileNode.GetSelected()
+ if currentNode != {}
+ try
+ call currentNode.bookmark(a:name)
+ call s:renderView()
+ catch /^NERDTree.IllegalBookmarkNameError/
+ call s:echo("bookmark names must not contain spaces")
+ endtry
+ else
+ call s:echo("select a node first")
+ endif
+endfunction
+"FUNCTION: s:checkForActivate() {{{2
+"Checks if the click should open the current node, if so then activate() is
+"called (directories are automatically opened if the symbol beside them is
+"clicked)
+function! s:checkForActivate()
+ let currentNode = s:TreeFileNode.GetSelected()
+ if currentNode != {}
+ call s:activateNode(0)
+ return
+ endif
+endfunction
+
+" FUNCTION: s:chCwd() {{{2
+function! s:chCwd()
+ let treenode = s:TreeFileNode.GetSelected()
+ if treenode ==# {}
+ call s:echo("Select a node first")
+ return
+ endif
+
+ try
+ call treenode.path.changeToDir()
+ catch /^NERDTree.PathChangeError/
+ call s:echoWarning("could not change cwd")
+ endtry
+endfunction
+
+" FUNCTION: s:chRoot() {{{2
+" changes the current root to the selected one
+function! s:chRoot()
+ let treenode = s:TreeFileNode.GetSelected()
+ if treenode ==# {}
+ call s:echo("Select a node first")
+ return
+ endif
+
+ call treenode.makeRoot()
+ call s:renderView()
+ call b:NERDTreeRoot.putCursorHere(0, 0)
+endfunction
+
+" FUNCTION: s:clearBookmarks(bookmarks) {{{2
+function! s:clearBookmarks(bookmarks)
+ if a:bookmarks ==# ''
+ let currentNode = s:TreeFileNode.GetSelected()
+ if currentNode != {}
+ call currentNode.clearBoomarks()
+ endif
+ else
+ for name in split(a:bookmarks, ' ')
+ let bookmark = s:Bookmark.BookmarkFor(name)
+ call bookmark.delete()
+ endfor
+ endif
+ call s:renderView()
+endfunction
+" FUNCTION: s:closeChildren() {{{2
+" closes all childnodes of the current node
+function! s:closeChildren()
+ let currentNode = s:TreeDirNode.GetSelected()
+ if currentNode ==# {}
+ call s:echo("Select a node first")
+ return
+ endif
+
+ call currentNode.closeChildren()
+ call s:renderView()
+ call currentNode.putCursorHere(0, 0)
+endfunction
+" FUNCTION: s:closeCurrentDir() {{{2
+" closes the parent dir of the current node
+function! s:closeCurrentDir()
+ let treenode = s:TreeFileNode.GetSelected()
+ if treenode ==# {}
+ call s:echo("Select a node first")
+ return
+ endif
+
+ let parent = treenode.parent
+ if parent ==# {} || parent.isRoot()
+ call s:echo("cannot close tree root")
+ else
+ call treenode.parent.close()
+ call s:renderView()
+ call treenode.parent.putCursorHere(0, 0)
+ endif
+endfunction
+" FUNCTION: s:closeTreeWindow() {{{2
+" close the tree window
+function! s:closeTreeWindow()
+ if b:NERDTreeType ==# "secondary" && b:NERDTreePreviousBuf != -1
+ exec "buffer " . b:NERDTreePreviousBuf
+ else
+ if winnr("$") > 1
+ call s:closeTree()
+ else
+ call s:echo("Cannot close last window")
+ endif
+ endif
+endfunction
+" FUNCTION: s:deleteBookmark() {{{2
+" if the cursor is on a bookmark, prompt to delete
+function! s:deleteBookmark()
+ let bookmark = s:Bookmark.GetSelected()
+ if bookmark ==# {}
+ call s:echo("Put the cursor on a bookmark")
+ return
+ endif
+
+ echo "Are you sure you wish to delete the bookmark:\n\"" . bookmark.name . "\" (yN):"
+
+ if nr2char(getchar()) ==# 'y'
+ try
+ call bookmark.delete()
+ call s:renderView()
+ redraw
+ catch /^NERDTree/
+ call s:echoWarning("Could not remove bookmark")
+ endtry
+ else
+ call s:echo("delete aborted" )
+ endif
+
+endfunction
+
+" FUNCTION: s:displayHelp() {{{2
+" toggles the help display
+function! s:displayHelp()
+ let b:treeShowHelp = b:treeShowHelp ? 0 : 1
+ call s:renderView()
+ call s:centerView()
+endfunction
+
+" FUNCTION: s:handleMiddleMouse() {{{2
+function! s:handleMiddleMouse()
+ let curNode = s:TreeFileNode.GetSelected()
+ if curNode ==# {}
+ call s:echo("Put the cursor on a node first" )
+ return
+ endif
+
+ if curNode.path.isDirectory
+ call s:openExplorer()
+ else
+ call s:openEntrySplit(0,0)
+ endif
+endfunction
+
+
+" FUNCTION: s:jumpToFirstChild() {{{2
+" wrapper for the jump to child method
+function! s:jumpToFirstChild()
+ call s:jumpToChild(0)
+endfunction
+
+" FUNCTION: s:jumpToLastChild() {{{2
+" wrapper for the jump to child method
+function! s:jumpToLastChild()
+ call s:jumpToChild(1)
+endfunction
+
+" FUNCTION: s:jumpToParent() {{{2
+" moves the cursor to the parent of the current node
+function! s:jumpToParent()
+ let currentNode = s:TreeFileNode.GetSelected()
+ if !empty(currentNode)
+ if !empty(currentNode.parent)
+ call currentNode.parent.putCursorHere(1, 0)
+ call s:centerView()
+ else
+ call s:echo("cannot jump to parent")
+ endif
+ else
+ call s:echo("put the cursor on a node first")
+ endif
+endfunction
+
+" FUNCTION: s:jumpToRoot() {{{2
+" moves the cursor to the root node
+function! s:jumpToRoot()
+ call b:NERDTreeRoot.putCursorHere(1, 0)
+ call s:centerView()
+endfunction
+
+" FUNCTION: s:jumpToSibling() {{{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(forward)
+ let currentNode = s:TreeFileNode.GetSelected()
+ if !empty(currentNode)
+ let sibling = currentNode.findSibling(a:forward)
+
+ if !empty(sibling)
+ call sibling.putCursorHere(1, 0)
+ call s:centerView()
+ endif
+ else
+ call s:echo("put the cursor on a node first")
+ endif
+endfunction
+
+" FUNCTION: s:openBookmark(name) {{{2
+" put the cursor on the given bookmark and, if its a file, open it
+function! s:openBookmark(name)
+ try
+ let targetNode = s:Bookmark.GetNodeForName(a:name, 0)
+ call targetNode.putCursorHere(0, 1)
+ redraw!
+ catch /^NERDTree.BookmarkedNodeNotFoundError/
+ call s:echo("note - target node is not cached")
+ let bookmark = s:Bookmark.BookmarkFor(a:name)
+ let targetNode = s:TreeFileNode.New(bookmark.path)
+ endtry
+ if targetNode.path.isDirectory
+ call targetNode.openExplorer()
+ else
+ call targetNode.open()
+ endif
+endfunction
+" FUNCTION: s:openEntrySplit(vertical, forceKeepWindowOpen) {{{2
+"Opens the currently selected file from the explorer in a
+"new window
+"
+"args:
+"forceKeepWindowOpen - dont close the window even if NERDTreeQuitOnOpen is set
+function! s:openEntrySplit(vertical, forceKeepWindowOpen)
+ let treenode = s:TreeFileNode.GetSelected()
+ if treenode != {}
+ if a:vertical
+ call treenode.openVSplit()
+ else
+ call treenode.openSplit()
+ endif
+ if !a:forceKeepWindowOpen
+ call s:closeTreeIfQuitOnOpen()
+ endif
+ else
+ call s:echo("select a node first")
+ endif
+endfunction
+
+" FUNCTION: s:openExplorer() {{{2
+function! s:openExplorer()
+ let treenode = s:TreeDirNode.GetSelected()
+ if treenode != {}
+ call treenode.openExplorer()
+ else
+ call s:echo("select a node first")
+ endif
+endfunction
+
+" FUNCTION: s:openInNewTab(stayCurrentTab) {{{2
+" Opens the selected node or bookmark in a new tab
+" Args:
+" stayCurrentTab: if 1 then vim will stay in the current tab, if 0 then vim
+" will go to the tab where the new file is opened
+function! s:openInNewTab(stayCurrentTab)
+ let target = s:TreeFileNode.GetSelected()
+ if target == {}
+ let target = s:Bookmark.GetSelected()
+ endif
+
+ if target != {}
+ call target.openInNewTab({'stayInCurrentTab': a:stayCurrentTab})
+ endif
+endfunction
+
+" FUNCTION: s:openNodeRecursively() {{{2
+function! s:openNodeRecursively()
+ let treenode = s:TreeFileNode.GetSelected()
+ if treenode ==# {} || treenode.path.isDirectory ==# 0
+ call s:echo("Select a directory node first" )
+ else
+ call s:echo("Recursively opening node. Please wait...")
+ call treenode.openRecursively()
+ call s:renderView()
+ redraw
+ call s:echo("Recursively opening node. Please wait... DONE")
+ endif
+
+endfunction
+
+"FUNCTION: s:previewNode() {{{2
+"Args:
+" openNewWin: if 0, use the previous window, if 1 open in new split, if 2
+" open in a vsplit
+function! s:previewNode(openNewWin)
+ let currentBuf = bufnr("")
+ if a:openNewWin > 0
+ call s:openEntrySplit(a:openNewWin ==# 2,1)
+ else
+ call s:activateNode(1)
+ end
+ call s:exec(bufwinnr(currentBuf) . "wincmd w")
+endfunction
+
+" FUNCTION: s:revealBookmark(name) {{{2
+" put the cursor on the node associate with the given name
+function! s:revealBookmark(name)
+ try
+ let targetNode = s:Bookmark.GetNodeForName(a:name, 0)
+ call targetNode.putCursorHere(0, 1)
+ catch /^NERDTree.BookmarkNotFoundError/
+ call s:echo("Bookmark isnt cached under the current root")
+ endtry
+endfunction
+" FUNCTION: s:refreshRoot() {{{2
+" Reloads the current root. All nodes below this will be lost and the root dir
+" will be reloaded.
+function! s:refreshRoot()
+ call s:echo("Refreshing the root node. This could take a while...")
+ call b:NERDTreeRoot.refresh()
+ call s:renderView()
+ redraw
+ call s:echo("Refreshing the root node. This could take a while... DONE")
+endfunction
+
+" FUNCTION: s:refreshCurrent() {{{2
+" refreshes the root for the current node
+function! s:refreshCurrent()
+ let treenode = s:TreeDirNode.GetSelected()
+ if treenode ==# {}
+ call s:echo("Refresh failed. Select a node first")
+ return
+ endif
+
+ call s:echo("Refreshing node. This could take a while...")
+ call treenode.refresh()
+ call s:renderView()
+ redraw
+ call s:echo("Refreshing node. This could take a while... DONE")
+endfunction
+" FUNCTION: s:showMenu() {{{2
+function! s:showMenu()
+ let curNode = s:TreeFileNode.GetSelected()
+ if curNode ==# {}
+ call s:echo("Put the cursor on a node first" )
+ return
+ endif
+
+ let mc = s:MenuController.New(s:MenuItem.AllEnabled())
+ call mc.showMenu()
+endfunction
+
+" FUNCTION: s:toggleIgnoreFilter() {{{2
+" toggles the use of the NERDTreeIgnore option
+function! s:toggleIgnoreFilter()
+ let b:NERDTreeIgnoreEnabled = !b:NERDTreeIgnoreEnabled
+ call s:renderViewSavingPosition()
+ call s:centerView()
+endfunction
+
+" FUNCTION: s:toggleShowBookmarks() {{{2
+" toggles the display of bookmarks
+function! s:toggleShowBookmarks()
+ let b:NERDTreeShowBookmarks = !b:NERDTreeShowBookmarks
+ if b:NERDTreeShowBookmarks
+ call s:renderView()
+ call s:putCursorOnBookmarkTable()
+ else
+ call s:renderViewSavingPosition()
+ endif
+ call s:centerView()
+endfunction
+" FUNCTION: s:toggleShowFiles() {{{2
+" toggles the display of hidden files
+function! s:toggleShowFiles()
+ let b:NERDTreeShowFiles = !b:NERDTreeShowFiles
+ call s:renderViewSavingPosition()
+ call s:centerView()
+endfunction
+
+" FUNCTION: s:toggleShowHidden() {{{2
+" toggles the display of hidden files
+function! s:toggleShowHidden()
+ let b:NERDTreeShowHidden = !b:NERDTreeShowHidden
+ call s:renderViewSavingPosition()
+ call s:centerView()
+endfunction
+
+" FUNCTION: s:toggleZoom() {{2
+" zoom (maximize/minimize) the NERDTree window
+function! s: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
+
+"FUNCTION: s:upDir(keepState) {{{2
+"moves the tree up a level
+"
+"Args:
+"keepState: 1 if the current root should be left open when the tree is
+"re-rendered
+function! s:upDir(keepState)
+ let cwd = b:NERDTreeRoot.path.str({'format': 'UI'})
+ if cwd ==# "/" || cwd =~ '^[^/]..$'
+ call s: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 = s:TreeDirNode.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 s:renderView()
+ call oldRoot.putCursorHere(0, 0)
+ endif
+endfunction
+
+
+"reset &cpo back to users setting
+let &cpo = s:old_cpo
+
+" vim: set sw=4 sts=4 et fdm=marker:
diff --git a/vim/plugin/SearchComplete.vim b/vim/plugin/SearchComplete.vim
new file mode 100644
index 0000000..8e950c6
--- /dev/null
+++ b/vim/plugin/SearchComplete.vim
@@ -0,0 +1,100 @@
+" SearchComplete.vim
+" Author: Chris Russell
+" Version: 1.1
+" License: GPL v2.0
+"
+" Description:
+" This script defineds functions and key mappings for Tab completion in
+" searches.
+"
+" Help:
+" This script catches the <Tab> character when using the '/' search
+" command. Pressing Tab will expand the current partial word to the
+" next matching word starting with the partial word.
+"
+" If you want to match a tab, use the '\t' pattern.
+"
+" Installation:
+" Simply drop this file into your $HOME/.vim/plugin directory.
+"
+" Changelog:
+" 2002-11-08 v1.1
+" Convert to unix eol
+" 2002-11-05 v1.0
+" Initial release
+"
+" TODO:
+"
+
+
+"--------------------------------------------------
+" Avoid multiple sourcing
+"--------------------------------------------------
+if exists( "loaded_search_complete" )
+ finish
+endif
+let loaded_search_complete = 1
+
+
+"--------------------------------------------------
+" Key mappings
+"--------------------------------------------------
+noremap / :call SearchCompleteStart()<CR>/
+
+
+"--------------------------------------------------
+" Set mappings for search complete
+"--------------------------------------------------
+function! SearchCompleteStart()
+ cnoremap <Tab> <C-C>:call SearchComplete()<CR>/<C-R>s
+ cnoremap <silent> <CR> <CR>:call SearchCompleteStop()<CR>
+ cnoremap <silent> <Esc> <C-C>:call SearchCompleteStop()<CR>
+endfunction
+
+"--------------------------------------------------
+" Tab completion in / search
+"--------------------------------------------------
+function! SearchComplete()
+ " get current cursor position
+ let l:loc = col( "." ) - 1
+ " get partial search and delete
+ let l:search = histget( '/', -1 )
+ call histdel( '/', -1 )
+ " check if new search
+ if l:search == @s
+ " get root search string
+ let l:search = b:searchcomplete
+ " increase number of autocompletes
+ let b:searchcompletedepth = b:searchcompletedepth . "\<C-N>"
+ else
+ " one autocomplete
+ let b:searchcompletedepth = "\<C-N>"
+ endif
+ " store origional search parameter
+ let b:searchcomplete = l:search
+ " set paste option to disable indent options
+ let l:paste = &paste
+ setlocal paste
+ " on a temporary line put search string and use autocomplete
+ execute "normal! A\n" . l:search . b:searchcompletedepth
+ " get autocomplete result
+ let @s = getline( line( "." ) )
+ " undo and return to first char
+ execute "normal! u0"
+ " return to cursor position
+ if l:loc > 0
+ execute "normal! ". l:loc . "l"
+ endif
+ " reset paste option
+ let &paste = l:paste
+endfunction
+
+"--------------------------------------------------
+" Remove search complete mappings
+"--------------------------------------------------
+function! SearchCompleteStop()
+ cunmap <Tab>
+ cunmap <CR>
+ cunmap <Esc>
+endfunction
+
diff --git a/vim/plugin/ZoomWinPlugin.vim b/vim/plugin/ZoomWinPlugin.vim
new file mode 100644
index 0000000..3f24a7d
--- /dev/null
+++ b/vim/plugin/ZoomWinPlugin.vim
@@ -0,0 +1,49 @@
+" ZoomWin: Brief-like ability to zoom into/out-of a window
+" Author: Charles Campbell
+" original version by Ron Aaron
+" Date: Jan 16, 2009
+" Version: 23e ASTRO-ONLY
+" History: see :help zoomwin-history {{{1
+" GetLatestVimScripts: 508 1 :AutoInstall: ZoomWin.vim
+
+" ---------------------------------------------------------------------
+" Load Once: {{{1
+if &cp || exists("g:loaded_ZoomWinPlugin")
+ finish
+endif
+if v:version < 702
+ echohl WarningMsg
+ echo "***warning*** this version of ZoomWin needs vim 7.2"
+ echohl Normal
+ finish
+endif
+let s:keepcpo = &cpo
+let g:loaded_ZoomWinPlugin = "v23"
+set cpo&vim
+"DechoTabOn
+
+" ---------------------------------------------------------------------
+" Public Interface: {{{1
+if !hasmapto("<Plug>ZoomWin")
+ nmap <unique> <c-w>o <Plug>ZoomWin
+endif
+nnoremap <silent> <script> <Plug>ZoomWin :set lz<CR>:silent call ZoomWin#ZoomWin()<CR>:set nolz<CR>
+com! ZoomWin :set lz|silent call ZoomWin#ZoomWin()|set nolz
+
+au VimLeave * call ZoomWin#CleanupSessionFile()
+
+" ---------------------------------------------------------------------
+" ZoomWin: toggles between a single-window and a multi-window layout {{{1
+" The original version was by Ron Aaron.
+" This function provides compatibility with previous versions.
+fun! ZoomWin()
+ call ZoomWin#ZoomWin()
+endfun
+
+" ---------------------------------------------------------------------
+" Restore: {{{1
+let &cpo= s:keepcpo
+unlet s:keepcpo
+" ---------------------------------------------------------------------
+" Modelines: {{{1
+" vim: ts=4 fdm=marker
diff --git a/vim/plugin/ack.vim b/vim/plugin/ack.vim
new file mode 100644
index 0000000..8cc0d45
--- /dev/null
+++ b/vim/plugin/ack.vim
@@ -0,0 +1,79 @@
+" NOTE: You must, of course, install the ack script
+" in your path.
+" On Debian / Ubuntu:
+" sudo apt-get install ack-grep
+" On your vimrc:
+" let g:ackprg="ack-grep -H --nocolor --nogroup --column"
+"
+" With MacPorts:
+" sudo port install p5-app-ack
+
+" Location of the ack utility
+if !exists("g:ackprg")
+ let g:ackprg="ack -H --nocolor --nogroup --column"
+endif
+
+function! s:Ack(cmd, args)
+ redraw
+ echo "Searching ..."
+
+ " If no pattern is provided, search for the word under the cursor
+ if empty(a:args)
+ let l:grepargs = expand("<cword>")
+ else
+ let l:grepargs = a:args
+ end
+
+ " Format, used to manage column jump
+ if a:cmd =~# '-g$'
+ let g:ackformat="%f"
+ else
+ let g:ackformat="%f:%l:%c:%m"
+ end
+
+ let grepprg_bak=&grepprg
+ let grepformat_bak=&grepformat
+ try
+ let &grepprg=g:ackprg
+ let &grepformat=g:ackformat
+ silent execute a:cmd . " " . l:grepargs
+ finally
+ let &grepprg=grepprg_bak
+ let &grepformat=grepformat_bak
+ endtry
+
+ if a:cmd =~# '^l'
+ botright lopen
+ else
+ botright copen
+ endif
+
+ " TODO: Document this!
+ exec "nnoremap <silent> <buffer> q :ccl<CR>"
+ exec "nnoremap <silent> <buffer> t <C-W><CR><C-W>T"
+ exec "nnoremap <silent> <buffer> T <C-W><CR><C-W>TgT<C-W><C-W>"
+ exec "nnoremap <silent> <buffer> o <CR>"
+ exec "nnoremap <silent> <buffer> go <CR><C-W><C-W>"
+
+ " If highlighting is on, highlight the search keyword.
+ if exists("g:ackhighlight")
+ let @/=a:args
+ set hlsearch
+ end
+
+ redraw!
+endfunction
+
+function! s:AckFromSearch(cmd, args)
+ let search = getreg('/')
+ " translate vim regular expression to perl regular expression.
+ let search = substitute(search,'\(\\<\|\\>\)','\\b','g')
+ call s:Ack(a:cmd, '"' . search .'" '. a:args)
+endfunction
+
+command! -bang -nargs=* -complete=file Ack call s:Ack('grep<bang>',<q-args>)
+command! -bang -nargs=* -complete=file AckAdd call s:Ack('grepadd<bang>', <q-args>)
+command! -bang -nargs=* -complete=file AckFromSearch call s:AckFromSearch('grep<bang>', <q-args>)
+command! -bang -nargs=* -complete=file LAck call s:Ack('lgrep<bang>', <q-args>)
+command! -bang -nargs=* -complete=file LAckAdd call s:Ack('lgrepadd<bang>', <q-args>)
+command! -bang -nargs=* -complete=file AckFile call s:Ack('grep<bang> -g', <q-args>)
diff --git a/vim/plugin/cecutil.vim b/vim/plugin/cecutil.vim
new file mode 100644
index 0000000..0bf3434
--- /dev/null
+++ b/vim/plugin/cecutil.vim
@@ -0,0 +1,510 @@
+" cecutil.vim : save/restore window position
+" save/restore mark position
+" save/restore selected user maps
+" Author: Charles E. Campbell, Jr.
+" Version: 18b ASTRO-ONLY
+" Date: Aug 27, 2008
+"
+" Saving Restoring Destroying Marks: {{{1
+" call SaveMark(markname) let savemark= SaveMark(markname)
+" call RestoreMark(markname) call RestoreMark(savemark)
+" call DestroyMark(markname)
+" commands: SM RM DM
+"
+" Saving Restoring Destroying Window Position: {{{1
+" call SaveWinPosn() let winposn= SaveWinPosn()
+" call RestoreWinPosn() call RestoreWinPosn(winposn)
+" \swp : save current window/buffer's position
+" \rwp : restore current window/buffer's previous position
+" commands: SWP RWP
+"
+" Saving And Restoring User Maps: {{{1
+" call SaveUserMaps(mapmode,maplead,mapchx,suffix)
+" call RestoreUserMaps(suffix)
+"
+" GetLatestVimScripts: 1066 1 :AutoInstall: cecutil.vim
+"
+" You believe that God is one. You do well. The demons also {{{1
+" believe, and shudder. But do you want to know, vain man, that
+" faith apart from works is dead? (James 2:19,20 WEB)
+
+" ---------------------------------------------------------------------
+" Load Once: {{{1
+if &cp || exists("g:loaded_cecutil")
+ finish
+endif
+let g:loaded_cecutil = "v18b"
+let s:keepcpo = &cpo
+set cpo&vim
+"DechoTabOn
+
+" =======================
+" Public Interface: {{{1
+" =======================
+
+" ---------------------------------------------------------------------
+" Map Interface: {{{2
+if !hasmapto('<Plug>SaveWinPosn')
+ map <unique> <Leader>swp <Plug>SaveWinPosn
+endif
+if !hasmapto('<Plug>RestoreWinPosn')
+ map <unique> <Leader>rwp <Plug>RestoreWinPosn
+endif
+nmap <silent> <Plug>SaveWinPosn :call SaveWinPosn()<CR>
+nmap <silent> <Plug>RestoreWinPosn :call RestoreWinPosn()<CR>
+
+" ---------------------------------------------------------------------
+" Command Interface: {{{2
+com! -bar -nargs=0 SWP call SaveWinPosn()
+com! -bar -nargs=0 RWP call RestoreWinPosn()
+com! -bar -nargs=1 SM call SaveMark(<q-args>)
+com! -bar -nargs=1 RM call RestoreMark(<q-args>)
+com! -bar -nargs=1 DM call DestroyMark(<q-args>)
+
+if v:version < 630
+ let s:modifier= "sil "
+else
+ let s:modifier= "sil keepj "
+endif
+
+" ===============
+" Functions: {{{1
+" ===============
+
+" ---------------------------------------------------------------------
+" SaveWinPosn: {{{2
+" let winposn= SaveWinPosn() will save window position in winposn variable
+" call SaveWinPosn() will save window position in b:cecutil_winposn{b:cecutil_iwinposn}
+" let winposn= SaveWinPosn(0) will *only* save window position in winposn variable (no stacking done)
+fun! SaveWinPosn(...)
+" call Dfunc("SaveWinPosn() a:0=".a:0)
+ if line(".") == 1 && getline(1) == ""
+" call Dfunc("SaveWinPosn : empty buffer")
+ return ""
+ endif
+ let so_keep = &l:so
+ let siso_keep = &siso
+ let ss_keep = &l:ss
+ setlocal so=0 siso=0 ss=0
+
+ let swline = line(".")
+ let swcol = col(".")
+ let swwline = winline() - 1
+ let swwcol = virtcol(".") - wincol()
+ let savedposn = "call GoWinbufnr(".winbufnr(0).")|silent ".swline
+ let savedposn = savedposn."|".s:modifier."norm! 0z\<cr>"
+ if swwline > 0
+ let savedposn= savedposn.":".s:modifier."norm! ".swwline."\<c-y>\<cr>"
+ endif
+ if swwcol > 0
+ let savedposn= savedposn.":".s:modifier."norm! 0".swwcol."zl\<cr>"
+ endif
+ let savedposn = savedposn.":".s:modifier."call cursor(".swline.",".swcol.")\<cr>"
+
+ " save window position in
+ " b:cecutil_winposn_{iwinposn} (stack)
+ " only when SaveWinPosn() is used
+ if a:0 == 0
+ if !exists("b:cecutil_iwinposn")
+ let b:cecutil_iwinposn= 1
+ else
+ let b:cecutil_iwinposn= b:cecutil_iwinposn + 1
+ endif
+" call Decho("saving posn to SWP stack")
+ let b:cecutil_winposn{b:cecutil_iwinposn}= savedposn
+ endif
+
+ let &l:so = so_keep
+ let &siso = siso_keep
+ let &l:ss = ss_keep
+
+" if exists("b:cecutil_iwinposn") " Decho
+" call Decho("b:cecutil_winpos{".b:cecutil_iwinposn."}[".b:cecutil_winposn{b:cecutil_iwinposn}."]")
+" else " Decho
+" call Decho("b:cecutil_iwinposn doesn't exist")
+" endif " Decho
+" call Dret("SaveWinPosn [".savedposn."]")
+ return savedposn
+endfun
+
+" ---------------------------------------------------------------------
+" RestoreWinPosn: {{{2
+" call RestoreWinPosn()
+" call RestoreWinPosn(winposn)
+fun! RestoreWinPosn(...)
+" call Dfunc("RestoreWinPosn() a:0=".a:0)
+" call Decho("getline(1)<".getline(1).">")
+" call Decho("line(.)=".line("."))
+ if line(".") == 1 && getline(1) == ""
+" call Dfunc("RestoreWinPosn : empty buffer")
+ return ""
+ endif
+ let so_keep = &l:so
+ let siso_keep = &l:siso
+ let ss_keep = &l:ss
+ setlocal so=0 siso=0 ss=0
+
+ if a:0 == 0 || a:1 == ""
+ " use saved window position in b:cecutil_winposn{b:cecutil_iwinposn} if it exists
+ if exists("b:cecutil_iwinposn") && exists("b:cecutil_winposn{b:cecutil_iwinposn}")
+" call Decho("using stack b:cecutil_winposn{".b:cecutil_iwinposn."}<".b:cecutil_winposn{b:cecutil_iwinposn}.">")
+ try
+ exe "silent! ".b:cecutil_winposn{b:cecutil_iwinposn}
+ catch /^Vim\%((\a\+)\)\=:E749/
+ " ignore empty buffer error messages
+ endtry
+ " normally drop top-of-stack by one
+ " but while new top-of-stack doesn't exist
+ " drop top-of-stack index by one again
+ if b:cecutil_iwinposn >= 1
+ unlet b:cecutil_winposn{b:cecutil_iwinposn}
+ let b:cecutil_iwinposn= b:cecutil_iwinposn - 1
+ while b:cecutil_iwinposn >= 1 && !exists("b:cecutil_winposn{b:cecutil_iwinposn}")
+ let b:cecutil_iwinposn= b:cecutil_iwinposn - 1
+ endwhile
+ if b:cecutil_iwinposn < 1
+ unlet b:cecutil_iwinposn
+ endif
+ endif
+ else
+ echohl WarningMsg
+ echomsg "***warning*** need to SaveWinPosn first!"
+ echohl None
+ endif
+
+ else " handle input argument
+" call Decho("using input a:1<".a:1.">")
+ " use window position passed to this function
+ exe "silent ".a:1
+ " remove a:1 pattern from b:cecutil_winposn{b:cecutil_iwinposn} stack
+ if exists("b:cecutil_iwinposn")
+ let jwinposn= b:cecutil_iwinposn
+ while jwinposn >= 1 " search for a:1 in iwinposn..1
+ if exists("b:cecutil_winposn{jwinposn}") " if it exists
+ if a:1 == b:cecutil_winposn{jwinposn} " and the pattern matches
+ unlet b:cecutil_winposn{jwinposn} " unlet it
+ if jwinposn == b:cecutil_iwinposn " if at top-of-stack
+ let b:cecutil_iwinposn= b:cecutil_iwinposn - 1 " drop stacktop by one
+ endif
+ endif
+ endif
+ let jwinposn= jwinposn - 1
+ endwhile
+ endif
+ endif
+
+ " Seems to be something odd: vertical motions after RWP
+ " cause jump to first column. The following fixes that.
+ " Note: was using wincol()>1, but with signs, a cursor
+ " at column 1 yields wincol()==3. Beeping ensued.
+ if virtcol('.') > 1
+ silent norm! hl
+ elseif virtcol(".") < virtcol("$")
+ silent norm! lh
+ endif
+
+ let &l:so = so_keep
+ let &l:siso = siso_keep
+ let &l:ss = ss_keep
+
+" call Dret("RestoreWinPosn")
+endfun
+
+" ---------------------------------------------------------------------
+" GoWinbufnr: go to window holding given buffer (by number) {{{2
+" Prefers current window; if its buffer number doesn't match,
+" then will try from topleft to bottom right
+fun! GoWinbufnr(bufnum)
+" call Dfunc("GoWinbufnr(".a:bufnum.")")
+ if winbufnr(0) == a:bufnum
+" call Dret("GoWinbufnr : winbufnr(0)==a:bufnum")
+ return
+ endif
+ winc t
+ let first=1
+ while winbufnr(0) != a:bufnum && (first || winnr() != 1)
+ winc w
+ let first= 0
+ endwhile
+" call Dret("GoWinbufnr")
+endfun
+
+" ---------------------------------------------------------------------
+" SaveMark: sets up a string saving a mark position. {{{2
+" For example, SaveMark("a")
+" Also sets up a global variable, g:savemark_{markname}
+fun! SaveMark(markname)
+" call Dfunc("SaveMark(markname<".a:markname.">)")
+ let markname= a:markname
+ if strpart(markname,0,1) !~ '\a'
+ let markname= strpart(markname,1,1)
+ endif
+" call Decho("markname=".markname)
+
+ let lzkeep = &lz
+ set lz
+
+ if 1 <= line("'".markname) && line("'".markname) <= line("$")
+ let winposn = SaveWinPosn(0)
+ exe s:modifier."norm! `".markname
+ let savemark = SaveWinPosn(0)
+ let g:savemark_{markname} = savemark
+ let savemark = markname.savemark
+ call RestoreWinPosn(winposn)
+ else
+ let g:savemark_{markname} = ""
+ let savemark = ""
+ endif
+
+ let &lz= lzkeep
+
+" call Dret("SaveMark : savemark<".savemark.">")
+ return savemark
+endfun
+
+" ---------------------------------------------------------------------
+" RestoreMark: {{{2
+" call RestoreMark("a") -or- call RestoreMark(savemark)
+fun! RestoreMark(markname)
+" call Dfunc("RestoreMark(markname<".a:markname.">)")
+
+ if strlen(a:markname) <= 0
+" call Dret("RestoreMark : no such mark")
+ return
+ endif
+ let markname= strpart(a:markname,0,1)
+ if markname !~ '\a'
+ " handles 'a -> a styles
+ let markname= strpart(a:markname,1,1)
+ endif
+" call Decho("markname=".markname." strlen(a:markname)=".strlen(a:markname))
+
+ let lzkeep = &lz
+ set lz
+ let winposn = SaveWinPosn(0)
+
+ if strlen(a:markname) <= 2
+ if exists("g:savemark_{markname}") && strlen(g:savemark_{markname}) != 0
+ " use global variable g:savemark_{markname}
+" call Decho("use savemark list")
+ call RestoreWinPosn(g:savemark_{markname})
+ exe "norm! m".markname
+ endif
+ else
+ " markname is a savemark command (string)
+" call Decho("use savemark command")
+ let markcmd= strpart(a:markname,1)
+ call RestoreWinPosn(markcmd)
+ exe "norm! m".markname
+ endif
+
+ call RestoreWinPosn(winposn)
+ let &lz = lzkeep
+
+" call Dret("RestoreMark")
+endfun
+
+" ---------------------------------------------------------------------
+" DestroyMark: {{{2
+" call DestroyMark("a") -- destroys mark
+fun! DestroyMark(markname)
+" call Dfunc("DestroyMark(markname<".a:markname.">)")
+
+ " save options and set to standard values
+ let reportkeep= &report
+ let lzkeep = &lz
+ set lz report=10000
+
+ let markname= strpart(a:markname,0,1)
+ if markname !~ '\a'
+ " handles 'a -> a styles
+ let markname= strpart(a:markname,1,1)
+ endif
+" call Decho("markname=".markname)
+
+ let curmod = &mod
+ let winposn = SaveWinPosn(0)
+ 1
+ let lineone = getline(".")
+ exe "k".markname
+ d
+ put! =lineone
+ let &mod = curmod
+ call RestoreWinPosn(winposn)
+
+ " restore options to user settings
+ let &report = reportkeep
+ let &lz = lzkeep
+
+" call Dret("DestroyMark")
+endfun
+
+" ---------------------------------------------------------------------
+" QArgSplitter: to avoid \ processing by <f-args>, <q-args> is needed. {{{2
+" However, <q-args> doesn't split at all, so this one returns a list
+" with splits at all whitespace (only!), plus a leading length-of-list.
+" The resulting list: qarglist[0] corresponds to a:0
+" qarglist[i] corresponds to a:{i}
+fun! QArgSplitter(qarg)
+" call Dfunc("QArgSplitter(qarg<".a:qarg.">)")
+ let qarglist = split(a:qarg)
+ let qarglistlen = len(qarglist)
+ let qarglist = insert(qarglist,qarglistlen)
+" call Dret("QArgSplitter ".string(qarglist))
+ return qarglist
+endfun
+
+" ---------------------------------------------------------------------
+" ListWinPosn: {{{2
+"fun! ListWinPosn() " Decho
+" if !exists("b:cecutil_iwinposn") || b:cecutil_iwinposn == 0 " Decho
+" call Decho("nothing on SWP stack") " Decho
+" else " Decho
+" let jwinposn= b:cecutil_iwinposn " Decho
+" while jwinposn >= 1 " Decho
+" if exists("b:cecutil_winposn{jwinposn}") " Decho
+" call Decho("winposn{".jwinposn."}<".b:cecutil_winposn{jwinposn}.">") " Decho
+" else " Decho
+" call Decho("winposn{".jwinposn."} -- doesn't exist") " Decho
+" endif " Decho
+" let jwinposn= jwinposn - 1 " Decho
+" endwhile " Decho
+" endif " Decho
+"endfun " Decho
+"com! -nargs=0 LWP call ListWinPosn() " Decho
+
+" ---------------------------------------------------------------------
+" SaveUserMaps: this function sets up a script-variable (s:restoremap) {{{2
+" which can be used to restore user maps later with
+" call RestoreUserMaps()
+"
+" mapmode - see :help maparg for details (n v o i c l "")
+" ex. "n" = Normal
+" The letters "b" and "u" are optional prefixes;
+" The "u" means that the map will also be unmapped
+" The "b" means that the map has a <buffer> qualifier
+" ex. "un" = Normal + unmapping
+" ex. "bn" = Normal + <buffer>
+" ex. "bun" = Normal + <buffer> + unmapping
+" ex. "ubn" = Normal + <buffer> + unmapping
+" maplead - see mapchx
+" mapchx - "<something>" handled as a single map item.
+" ex. "<left>"
+" - "string" a string of single letters which are actually
+" multiple two-letter maps (using the maplead:
+" maplead . each_character_in_string)
+" ex. maplead="\" and mapchx="abc" saves user mappings for
+" \a, \b, and \c
+" Of course, if maplead is "", then for mapchx="abc",
+" mappings for a, b, and c are saved.
+" - :something handled as a single map item, w/o the ":"
+" ex. mapchx= ":abc" will save a mapping for "abc"
+" suffix - a string unique to your plugin
+" ex. suffix= "DrawIt"
+fun! SaveUserMaps(mapmode,maplead,mapchx,suffix)
+" call Dfunc("SaveUserMaps(mapmode<".a:mapmode."> maplead<".a:maplead."> mapchx<".a:mapchx."> suffix<".a:suffix.">)")
+
+ if !exists("s:restoremap_{a:suffix}")
+ " initialize restoremap_suffix to null string
+ let s:restoremap_{a:suffix}= ""
+ endif
+
+ " set up dounmap: if 1, then save and unmap (a:mapmode leads with a "u")
+ " if 0, save only
+ let mapmode = a:mapmode
+ let dounmap = 0
+ let dobuffer = ""
+ while mapmode =~ '^[bu]'
+ if mapmode =~ '^u'
+ let dounmap= 1
+ let mapmode= strpart(a:mapmode,1)
+ elseif mapmode =~ '^b'
+ let dobuffer= "<buffer> "
+ let mapmode= strpart(a:mapmode,1)
+ endif
+ endwhile
+" call Decho("dounmap=".dounmap." dobuffer<".dobuffer.">")
+
+ " save single map :...something...
+ if strpart(a:mapchx,0,1) == ':'
+" call Decho("save single map :...something...")
+ let amap= strpart(a:mapchx,1)
+ if amap == "|" || amap == "\<c-v>"
+ let amap= "\<c-v>".amap
+ endif
+ let amap = a:maplead.amap
+ let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|:silent! ".mapmode."unmap ".dobuffer.amap
+ if maparg(amap,mapmode) != ""
+ let maprhs = substitute(maparg(amap,mapmode),'|','<bar>','ge')
+ let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|:".mapmode."map ".dobuffer.amap." ".maprhs
+ endif
+ if dounmap
+ exe "silent! ".mapmode."unmap ".dobuffer.amap
+ endif
+
+ " save single map <something>
+ elseif strpart(a:mapchx,0,1) == '<'
+" call Decho("save single map <something>")
+ let amap = a:mapchx
+ if amap == "|" || amap == "\<c-v>"
+ let amap= "\<c-v>".amap
+" call Decho("amap[[".amap."]]")
+ endif
+ let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|silent! ".mapmode."unmap ".dobuffer.amap
+ if maparg(a:mapchx,mapmode) != ""
+ let maprhs = substitute(maparg(amap,mapmode),'|','<bar>','ge')
+ let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|".mapmode."map ".amap." ".dobuffer.maprhs
+ endif
+ if dounmap
+ exe "silent! ".mapmode."unmap ".dobuffer.amap
+ endif
+
+ " save multiple maps
+ else
+" call Decho("save multiple maps")
+ let i= 1
+ while i <= strlen(a:mapchx)
+ let amap= a:maplead.strpart(a:mapchx,i-1,1)
+ if amap == "|" || amap == "\<c-v>"
+ let amap= "\<c-v>".amap
+ endif
+ let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|silent! ".mapmode."unmap ".dobuffer.amap
+ if maparg(amap,mapmode) != ""
+ let maprhs = substitute(maparg(amap,mapmode),'|','<bar>','ge')
+ let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|".mapmode."map ".amap." ".dobuffer.maprhs
+ endif
+ if dounmap
+ exe "silent! ".mapmode."unmap ".dobuffer.amap
+ endif
+ let i= i + 1
+ endwhile
+ endif
+" call Dret("SaveUserMaps : restoremap_".a:suffix.": ".s:restoremap_{a:suffix})
+endfun
+
+" ---------------------------------------------------------------------
+" RestoreUserMaps: {{{2
+" Used to restore user maps saved by SaveUserMaps()
+fun! RestoreUserMaps(suffix)
+" call Dfunc("RestoreUserMaps(suffix<".a:suffix.">)")
+ if exists("s:restoremap_{a:suffix}")
+ let s:restoremap_{a:suffix}= substitute(s:restoremap_{a:suffix},'|\s*$','','e')
+ if s:restoremap_{a:suffix} != ""
+" call Decho("exe ".s:restoremap_{a:suffix})
+ exe "silent! ".s:restoremap_{a:suffix}
+ endif
+ unlet s:restoremap_{a:suffix}
+ endif
+" call Dret("RestoreUserMaps")
+endfun
+
+" ==============
+" Restore: {{{1
+" ==============
+let &cpo= s:keepcpo
+unlet s:keepcpo
+
+" ================
+" Modelines: {{{1
+" ================
+" vim: ts=4 fdm=marker
diff --git a/vim/plugin/color_sample_pack.vim b/vim/plugin/color_sample_pack.vim
new file mode 100644
index 0000000..00e8af2
--- /dev/null
+++ b/vim/plugin/color_sample_pack.vim
@@ -0,0 +1,164 @@
+" Maintainer: Robert Melton ( iam -at- robertmelton -dot- com)
+" Last Change: 2010 Jan 20th
+
+" default schemes
+amenu T&hemes.D&efault.Blue :colo blue<CR>
+amenu T&hemes.D&efault.DarkBlue :colo darkblue<CR>
+amenu T&hemes.D&efault.Default :colo default<CR>
+amenu T&hemes.D&efault.Delek :colo delek<CR>
+amenu T&hemes.D&efault.Desert :colo desert<CR>
+amenu T&hemes.D&efault.ElfLord :colo elflord<CR>
+amenu T&hemes.D&efault.Evening :colo evening<CR>
+amenu T&hemes.D&efault.Koehler :colo koehler<CR>
+amenu T&hemes.D&efault.Morning :colo morning<CR>
+amenu T&hemes.D&efault.Murphy :colo murphy<CR>
+amenu T&hemes.D&efault.Pablo :colo pablo<CR>
+amenu T&hemes.D&efault.PeachPuff :colo peachpuff<CR>
+amenu T&hemes.D&efault.Ron :colo ron<CR>
+amenu T&hemes.D&efault.Shine :colo shine<CR>
+amenu T&hemes.D&efault.Torte :colo torte<CR>
+amenu T&hemes.-s1- :
+
+" 37 new themes
+amenu T&hemes.&New.&Dark.Adaryn :colo adaryn<CR>
+amenu T&hemes.&New.&Dark.Adrian :colo adrian<CR>
+amenu T&hemes.&New.&Dark.Anotherdark :colo anotherdark<CR>
+amenu T&hemes.&New.&Dark.BlackSea :colo blacksea<CR>
+amenu T&hemes.&New.&Dark.Colorer :colo colorer<CR>
+amenu T&hemes.&New.&Dark.Darkbone :colo darkbone<CR>
+amenu T&hemes.&New.&Dark.DarkZ :colo darkz<CR>
+amenu T&hemes.&New.&Dark.Herald :colo herald<CR>
+amenu T&hemes.&New.&Dark.Jammy :colo jammy<CR>
+amenu T&hemes.&New.&Dark.Kellys :colo kellys<CR>
+amenu T&hemes.&New.&Dark.Lettuce :colo lettuce<CR>
+amenu T&hemes.&New.&Dark.Maroloccio :colo maroloccio<CR>
+amenu T&hemes.&New.&Dark.Molokai :colo molokai<CR>
+amenu T&hemes.&New.&Dark.Mustang :colo mustang<CR>
+amenu T&hemes.&New.&Dark.TIRBlack :colo tir_black<CR>
+amenu T&hemes.&New.&Dark.Twilight :colo twilight<CR>
+amenu T&hemes.&New.&Dark.Two2Tango :colo two2tango<CR>
+amenu T&hemes.&New.&Dark.Wuye :colo wuye<CR>
+amenu T&hemes.&New.&Dark.Zmrok :colo zmrok<CR>
+amenu T&hemes.&New.&Light.BClear :colo bclear<CR>
+amenu T&hemes.&New.&Light.Satori :colo satori<CR>
+amenu T&hemes.&New.&Light.Silent :colo silent<CR>
+amenu T&hemes.&New.&Light.SoSo :colo soso<CR>
+amenu T&hemes.&New.&Light.SummerFruit256 :colo summerfruit256<CR>
+amenu T&hemes.&New.&Light.TAqua :colo taqua<CR>
+amenu T&hemes.&New.&Light.TCSoft :colo tcsoft<CR>
+amenu T&hemes.&New.&Light.VYLight :colo vylight<CR>
+amenu T&hemes.&New.&Other.Aqua :colo aqua<CR>
+amenu T&hemes.&New.&Other.Clarity :colo clarity<CR>
+amenu T&hemes.&New.&Other.CleanPHP :colo cleanphp<CR>
+amenu T&hemes.&New.&Other.Denim :colo denim<CR>
+amenu T&hemes.&New.&Other.Guardian :colo guardian<CR>
+amenu T&hemes.&New.&Other.Moss :colo moss<CR>
+amenu T&hemes.&New.&Other.Nightshimmer :colo nightshimmer<CR>
+amenu T&hemes.&New.&Other.NoQuarter :colo no_quarter<CR>
+amenu T&hemes.&New.&Other.RobinHood :colo robinhood<CR>
+amenu T&hemes.&New.&Other.SoftBlue :colo softblue<CR>
+amenu T&hemes.&New.&Other.Wood :colo wood<CR>
+
+" 30 removed themes
+amenu T&hemes.De&precated.&Dark.DwBlue :colo dw_blue<CR>
+amenu T&hemes.De&precated.&Dark.DwCyan :colo dw_cyan<CR>
+amenu T&hemes.De&precated.&Dark.DwGreen :colo dw_green<CR>
+amenu T&hemes.De&precated.&Dark.DwOrange :colo dw_orange<CR>
+amenu T&hemes.De&precated.&Dark.DwPurple :colo dw_purple<CR>
+amenu T&hemes.De&precated.&Dark.DwRed :colo dw_red<CR>
+amenu T&hemes.De&precated.&Dark.DwYellow :colo dw_yellow<CR>
+amenu T&hemes.De&precated.&Dark.Fruity :colo fruity<CR>
+amenu T&hemes.De&precated.&Dark.Leo :colo leo<CR>
+amenu T&hemes.De&precated.&Dark.Matrix :colo matrix<CR>
+amenu T&hemes.De&precated.&Dark.Metacosm :colo metacosm<CR>
+amenu T&hemes.De&precated.&Dark.Northland :colo northland<CR>
+amenu T&hemes.De&precated.&Dark.Railscasts2 :colo railscasts2<CR>
+amenu T&hemes.De&precated.&Dark.Synic :colo synic<CR>
+amenu T&hemes.De&precated.&Dark.Wombat256 :colo wombat256<CR>
+amenu T&hemes.De&precated.&Dark.Xoria256 :colo xoria256<CR>
+amenu T&hemes.De&precated.&Light.Autumn2 :colo autumn2<CR>
+amenu T&hemes.De&precated.&Light.Buttercream :colo buttercream<CR>
+amenu T&hemes.De&precated.&Light.Fine_blue :colo fine_blue<CR>
+amenu T&hemes.De&precated.&Light.Impact :colo impact<CR>
+amenu T&hemes.De&precated.&Light.Oceanlight :colo oceanlight<CR>
+amenu T&hemes.De&precated.&Light.Print_bw :colo print_bw<CR>
+amenu T&hemes.De&precated.&Light.Pyte :colo pyte<CR>
+amenu T&hemes.De&precated.&Light.Spring :colo spring<CR>
+amenu T&hemes.De&precated.&Light.Winter :colo winter<CR>
+amenu T&hemes.De&precated.&Other.Astronaut :colo astronaut<CR>
+amenu T&hemes.De&precated.&Other.Bluegreen :colo bluegreen<CR>
+amenu T&hemes.De&precated.&Other.Navajo :colo navajo<CR>
+amenu T&hemes.De&precated.&Other.Olive :colo olive<CR>
+amenu T&hemes.De&precated.&Other.Tabula :colo tabula<CR>
+amenu T&hemes.De&precated.&Other.Xemacs :colo xemacs<CR>
+
+" Themepack Themes
+amenu T&hemes.&Dark.Asu1dark :colo asu1dark<CR>
+amenu T&hemes.&Dark.Brookstream :colo brookstream<CR>
+amenu T&hemes.&Dark.Calmar256-dark :colo calmar256-dark<CR>
+amenu T&hemes.&Dark.Camo :colo camo<CR>
+amenu T&hemes.&Dark.Candy :colo candy<CR>
+amenu T&hemes.&Dark.Candycode :colo candycode<CR>
+amenu T&hemes.&Dark.Dante :colo dante<CR>
+amenu T&hemes.&Dark.Darkspectrum :colo darkspectrum<CR>
+amenu T&hemes.&Dark.Desert256 :colo desert256<CR>
+amenu T&hemes.&Dark.DesertEx :colo desertEx<CR>
+amenu T&hemes.&Dark.Dusk :colo dusk<CR>
+amenu T&hemes.&Dark.Earendel :colo earendel<CR>
+amenu T&hemes.&Dark.Ekvoli :colo ekvoli<CR>
+amenu T&hemes.&Dark.Fnaqevan :colo fnaqevan<CR>
+amenu T&hemes.&Dark.Freya :colo freya<CR>
+amenu T&hemes.&Dark.Golden :colo golden<CR>
+amenu T&hemes.&Dark.Inkpot :colo inkpot<CR>
+amenu T&hemes.&Dark.Jellybeans :colo jellybeans<CR>
+amenu T&hemes.&Dark.Lucius :colo lucius<CR>
+amenu T&hemes.&Dark.Manxome :colo manxome<CR>
+amenu T&hemes.&Dark.Moria :colo moria<CR>
+amenu T&hemes.&Dark.Motus :colo motus<CR>
+amenu T&hemes.&Dark.Neon :colo neon<CR>
+amenu T&hemes.&Dark.Neverness :colo neverness<CR>
+amenu T&hemes.&Dark.Oceanblack :colo oceanblack<CR>
+amenu T&hemes.&Dark.Railscasts :colo railscasts<CR>
+amenu T&hemes.&Dark.Rdark :colo rdark<CR>
+amenu T&hemes.&Dark.Relaxedgreen :colo relaxedgreen<CR>
+amenu T&hemes.&Dark.Rootwater :colo rootwater<CR>
+amenu T&hemes.&Dark.Tango :colo tango<CR>
+amenu T&hemes.&Dark.Tango2 :colo tango2<CR>
+amenu T&hemes.&Dark.Vibrantink :colo vibrantink<CR>
+amenu T&hemes.&Dark.Vividchalk :colo vividchalk<CR>
+amenu T&hemes.&Dark.Wombat :colo wombat<CR>
+amenu T&hemes.&Dark.Zenburn :colo zenburn<CR>
+
+amenu T&hemes.&Light.Autumn :colo autumn<CR>
+amenu T&hemes.&Light.Autumnleaf :colo autumnleaf<CR>
+amenu T&hemes.&Light.Baycomb :colo baycomb<CR>
+amenu T&hemes.&Light.Biogoo :colo biogoo<CR>
+amenu T&hemes.&Light.Calmar256-light :colo calmar256-light<CR>
+amenu T&hemes.&Light.Chela_light :colo chela_light<CR>
+amenu T&hemes.&Light.Dawn :colo dawn<CR>
+amenu T&hemes.&Light.Eclipse :colo eclipse<CR>
+amenu T&hemes.&Light.Fog :colo fog<CR>
+amenu T&hemes.&Light.Fruit :colo fruit<CR>
+amenu T&hemes.&Light.Habilight :colo habilight<CR>
+amenu T&hemes.&Light.Ironman :colo ironman<CR>
+amenu T&hemes.&Light.Martin_krischik :colo martin_krischik<CR>
+amenu T&hemes.&Light.Nuvola :colo nuvola<CR>
+amenu T&hemes.&Light.PapayaWhip :colo PapayaWhip<CR>
+amenu T&hemes.&Light.Sienna :colo sienna<CR>
+amenu T&hemes.&Light.Simpleandfriendly :colo simpleandfriendly<CR>
+amenu T&hemes.&Light.Tolerable :colo tolerable<CR>
+amenu T&hemes.&Light.Vc :colo vc<CR>
+
+amenu T&hemes.&Other.Aiseered :colo aiseered<CR>
+amenu T&hemes.&Other.Borland :colo borland<CR>
+amenu T&hemes.&Other.Breeze :colo breeze<CR>
+amenu T&hemes.&Other.Chocolateliquor :colo chocolateliquor<CR>
+amenu T&hemes.&Other.Darkblue2 :colo darkblue2<CR>
+amenu T&hemes.&Other.Darkslategray :colo darkslategray<CR>
+amenu T&hemes.&Other.Marklar :colo marklar<CR>
+amenu T&hemes.&Other.Navajo-night :colo navajo-night<CR>
+amenu T&hemes.&Other.Night :colo night<CR>
+amenu T&hemes.&Other.Oceandeep :colo oceandeep<CR>
+amenu T&hemes.&Other.Peaksea :colo peaksea<CR>
+amenu T&hemes.&Other.Sea :colo sea<CR>
+amenu T&hemes.&Other.Settlemyer :colo settlemyer<CR>
diff --git a/vim/plugin/conque_term.vim b/vim/plugin/conque_term.vim
new file mode 100644
index 0000000..07f96e0
--- /dev/null
+++ b/vim/plugin/conque_term.vim
@@ -0,0 +1,93 @@
+" FILE: plugin/conque_term.vim {{{
+" AUTHOR: Nico Raffo <nicoraffo@gmail.com>
+" MODIFIED: 2010-05-27
+" VERSION: 1.1, for Vim 7.0
+" LICENSE:
+" Conque - pty interaction in Vim
+" Copyright (C) 2009-2010 Nico Raffo
+"
+" MIT License
+"
+" Permission is hereby granted, free of charge, to any person obtaining a copy
+" of this software and associated documentation files (the "Software"), to deal
+" in the Software without restriction, including without limitation the rights
+" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+" copies of the Software, and to permit persons to whom the Software is
+" furnished to do so, subject to the following conditions:
+"
+" The above copyright notice and this permission notice shall be included in
+" all copies or substantial portions of the Software.
+"
+" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+" THE SOFTWARE.
+" }}}
+
+" See docs/conque_term.txt for help or type :help conque_term
+
+if exists('g:ConqueTerm_Loaded') || v:version < 700
+ finish
+endif
+
+" **********************************************************************************************************
+" **** CONFIG **********************************************************************************************
+" **********************************************************************************************************
+
+" Choose key mapping to leave insert mode {{{
+" If you choose something other than '<Esc>', then <Esc> will be sent to terminal
+" Using a different key will usually fix Alt/Meta key issues
+if !exists('g:ConqueTerm_EscKey')
+ let g:ConqueTerm_EscKey = '<Esc>'
+endif " }}}
+
+" Enable color. {{{
+" If your apps use a lot of color it will slow down the shell.
+if !exists('g:ConqueTerm_Color')
+ let g:ConqueTerm_Color = 1
+endif " }}}
+
+" TERM environment setting {{{
+if !exists('g:ConqueTerm_TERM')
+ let g:ConqueTerm_TERM = 'vt100'
+endif " }}}
+
+" Syntax for your buffer {{{
+if !exists('g:ConqueTerm_Syntax')
+ let g:ConqueTerm_Syntax = 'conque_term'
+endif " }}}
+
+" Keep on updating the shell window after you've switched to another buffer {{{
+if !exists('g:ConqueTerm_ReadUnfocused')
+ let g:ConqueTerm_ReadUnfocused = 0
+endif " }}}
+
+" Use this regular expression to highlight prompt {{{
+if !exists('g:ConqueTerm_PromptRegex')
+ let g:ConqueTerm_PromptRegex = '^\w\+@[0-9A-Za-z_.-]\+:[0-9A-Za-z_./\~,:-]\+\$'
+endif " }}}
+
+" Allow user to use <C-w> keys to switch window in insert mode. {{{
+if !exists('g:ConqueTerm_CWInsert')
+ let g:ConqueTerm_CWInsert = 0
+endif " }}}
+
+" **********************************************************************************************************
+" **** Startup *********************************************************************************************
+" **********************************************************************************************************
+
+" Startup {{{
+
+let g:ConqueTerm_Loaded = 1
+let g:ConqueTerm_Idx = 1
+
+command! -nargs=+ -complete=shellcmd ConqueTerm call conque_term#open(<q-args>)
+command! -nargs=+ -complete=shellcmd ConqueTermSplit call conque_term#open(<q-args>, ['belowright split'])
+command! -nargs=+ -complete=shellcmd ConqueTermVSplit call conque_term#open(<q-args>, ['belowright vsplit'])
+command! -nargs=+ -complete=shellcmd ConqueTermTab call conque_term#open(<q-args>, ['tabnew'])
+
+" }}}
+
diff --git a/vim/plugin/delimitMate.vim b/vim/plugin/delimitMate.vim
new file mode 100644
index 0000000..95ebf19
--- /dev/null
+++ b/vim/plugin/delimitMate.vim
@@ -0,0 +1,434 @@
+" File: plugin/delimitMate.vim
+" Version: 2.6
+" Modified: 2011-01-14
+" Description: This plugin provides auto-completion for quotes, parens, etc.
+" Maintainer: Israel Chauca F. <israelchauca@gmail.com>
+" Manual: Read ":help delimitMate".
+" ============================================================================
+
+" Initialization: {{{
+
+if exists("g:loaded_delimitMate") || &cp
+ " User doesn't want this plugin or compatible is set, let's get out!
+ finish
+endif
+let g:loaded_delimitMate = 1
+
+if exists("s:loaded_delimitMate") && !exists("g:delimitMate_testing")
+ " Don't define the functions if they already exist: just do the work
+ " (unless we are testing):
+ call s:DelimitMateDo()
+ finish
+endif
+
+if v:version < 700
+ echoerr "delimitMate: this plugin requires vim >= 7!"
+ finish
+endif
+
+let s:loaded_delimitMate = 1
+let delimitMate_version = "2.6"
+
+function! s:option_init(name, default) "{{{
+ let b = exists("b:delimitMate_" . a:name)
+ let g = exists("g:delimitMate_" . a:name)
+ let prefix = "_l_delimitMate_"
+
+ if !b && !g
+ let sufix = a:default
+ elseif !b && g
+ exec "let sufix = g:delimitMate_" . a:name
+ else
+ exec "let sufix = b:delimitMate_" . a:name
+ endif
+ if exists("b:" . prefix . a:name)
+ exec "unlockvar! b:" . prefix . a:name
+ endif
+ exec "let b:" . prefix . a:name . " = " . string(sufix)
+ exec "lockvar! b:" . prefix . a:name
+endfunction "}}}
+
+function! s:init() "{{{
+" Initialize variables:
+
+ " autoclose
+ call s:option_init("autoclose", 1)
+
+ " matchpairs
+ call s:option_init("matchpairs", string(&matchpairs)[1:-2])
+ call s:option_init("matchpairs_list", split(b:_l_delimitMate_matchpairs, ','))
+ call s:option_init("left_delims", split(b:_l_delimitMate_matchpairs, ':.,\='))
+ call s:option_init("right_delims", split(b:_l_delimitMate_matchpairs, ',\=.:'))
+
+ " quotes
+ call s:option_init("quotes", "\" ' `")
+ call s:option_init("quotes_list", split(b:_l_delimitMate_quotes))
+
+ " nesting_quotes
+ call s:option_init("nesting_quotes", [])
+
+ " excluded_regions
+ call s:option_init("excluded_regions", "Comment")
+ call s:option_init("excluded_regions_list", split(b:_l_delimitMate_excluded_regions, ',\s*'))
+ let enabled = len(b:_l_delimitMate_excluded_regions_list) > 0
+ call s:option_init("excluded_regions_enabled", enabled)
+
+ " excluded filetypes
+ call s:option_init("excluded_ft", "")
+
+ " expand_space
+ if exists("b:delimitMate_expand_space") && type(b:delimitMate_expand_space) == type("")
+ echom "b:delimitMate_expand_space is '".b:delimitMate_expand_space."' but it must be either 1 or 0!"
+ echom "Read :help 'delimitMate_expand_space' for more details."
+ unlet b:delimitMate_expand_space
+ let b:delimitMate_expand_space = 1
+ endif
+ if exists("g:delimitMate_expand_space") && type(g:delimitMate_expand_space) == type("")
+ echom "delimitMate_expand_space is '".g:delimitMate_expand_space."' but it must be either 1 or 0!"
+ echom "Read :help 'delimitMate_expand_space' for more details."
+ unlet g:delimitMate_expand_space
+ let g:delimitMate_expand_space = 1
+ endif
+ call s:option_init("expand_space", 0)
+
+ " expand_cr
+ if exists("b:delimitMate_expand_cr") && type(b:delimitMate_expand_cr) == type("")
+ echom "b:delimitMate_expand_cr is '".b:delimitMate_expand_cr."' but it must be either 1 or 0!"
+ echom "Read :help 'delimitMate_expand_cr' for more details."
+ unlet b:delimitMate_expand_cr
+ let b:delimitMate_expand_cr = 1
+ endif
+ if exists("g:delimitMate_expand_cr") && type(g:delimitMate_expand_cr) == type("")
+ echom "delimitMate_expand_cr is '".g:delimitMate_expand_cr."' but it must be either 1 or 0!"
+ echom "Read :help 'delimitMate_expand_cr' for more details."
+ unlet g:delimitMate_expand_cr
+ let g:delimitMate_expand_cr = 1
+ endif
+ if ((&backspace !~ 'eol' || &backspace !~ 'start') && &backspace != 2) &&
+ \ ((exists('b:delimitMate_expand_cr') && b:delimitMate_expand_cr == 1) ||
+ \ (exists('g:delimitMate_expand_cr') && g:delimitMate_expand_cr == 1))
+ echom "delimitMate: There seems to be some incompatibility with your settings that may interfer with the expansion of <CR>. See :help 'delimitMate_expand_cr' for details."
+ endif
+ call s:option_init("expand_cr", 0)
+
+ " smart_matchpairs
+ call s:option_init("smart_matchpairs", '^\%(\w\|\!\|£\|\$\|_\|["'']\s*\S\)')
+
+ " smart_quotes
+ call s:option_init("smart_quotes", 1)
+
+ " apostrophes
+ call s:option_init("apostrophes", "")
+ call s:option_init("apostrophes_list", split(b:_l_delimitMate_apostrophes, ":\s*"))
+
+ " tab2exit
+ call s:option_init("tab2exit", 1)
+
+ " balance_matchpairs
+ call s:option_init("balance_matchpairs", 0)
+
+ let b:_l_delimitMate_buffer = []
+
+endfunction "}}} Init()
+
+"}}}
+
+" Functions: {{{
+
+function! s:Map() "{{{
+ " Set mappings:
+ try
+ let save_cpo = &cpo
+ let save_keymap = &keymap
+ let save_iminsert = &iminsert
+ let save_imsearch = &imsearch
+ set keymap=
+ set cpo&vim
+ if b:_l_delimitMate_autoclose
+ call s:AutoClose()
+ else
+ call s:NoAutoClose()
+ endif
+ call s:ExtraMappings()
+ finally
+ let &cpo = save_cpo
+ let &keymap = save_keymap
+ let &iminsert = save_iminsert
+ let &imsearch = save_imsearch
+ endtry
+
+ let b:delimitMate_enabled = 1
+
+endfunction "}}} Map()
+
+function! s:Unmap() " {{{
+ let imaps =
+ \ b:_l_delimitMate_right_delims +
+ \ b:_l_delimitMate_left_delims +
+ \ b:_l_delimitMate_quotes_list +
+ \ b:_l_delimitMate_apostrophes_list +
+ \ ['<BS>', '<S-BS>', '<Del>', '<CR>', '<Space>', '<S-Tab>', '<Esc>'] +
+ \ ['<Up>', '<Down>', '<Left>', '<Right>', '<LeftMouse>', '<RightMouse>'] +
+ \ ['<Home>', '<End>', '<PageUp>', '<PageDown>', '<S-Down>', '<S-Up>', '<C-G>g']
+
+ for map in imaps
+ if maparg(map, "i") =~? 'delimitMate'
+ if map == '|'
+ let map = '<Bar>'
+ endif
+ exec 'silent! iunmap <buffer> ' . map
+ endif
+ endfor
+
+ if !has('gui_running')
+ silent! iunmap <C-[>OC
+ endif
+
+ let b:delimitMate_enabled = 0
+endfunction " }}} s:Unmap()
+
+function! s:TestMappingsDo() "{{{
+ %d
+ if !exists("g:delimitMate_testing")
+ silent call delimitMate#TestMappings()
+ else
+ let temp_varsDM = [b:_l_delimitMate_expand_space, b:_l_delimitMate_expand_cr, b:_l_delimitMate_autoclose]
+ for i in [0,1]
+ let b:delimitMate_expand_space = i
+ let b:delimitMate_expand_cr = i
+ for a in [0,1]
+ let b:delimitMate_autoclose = a
+ call s:init()
+ call s:Unmap()
+ call s:Map()
+ call delimitMate#TestMappings()
+ call append(line('$'),'')
+ endfor
+ endfor
+ let b:delimitMate_expand_space = temp_varsDM[0]
+ let b:delimitMate_expand_cr = temp_varsDM[1]
+ let b:delimitMate_autoclose = temp_varsDM[2]
+ unlet temp_varsDM
+ endif
+ normal gg
+ g/\%^$/d
+endfunction "}}}
+
+function! s:DelimitMateDo(...) "{{{
+
+ " First, remove all magic, if needed:
+ if exists("b:delimitMate_enabled") && b:delimitMate_enabled == 1
+ call s:Unmap()
+ endif
+
+ " Check if this file type is excluded:
+ if exists("g:delimitMate_excluded_ft") &&
+ \ index(split(g:delimitMate_excluded_ft, ','), &filetype, 0, 1) >= 0
+
+ " Finish here:
+ return 1
+ endif
+
+ " Check if user tried to disable using b:loaded_delimitMate
+ if exists("b:loaded_delimitMate")
+ return 1
+ endif
+
+ " Initialize settings:
+ call s:init()
+
+ " Now, add magic:
+ call s:Map()
+
+ if a:0 > 0
+ echo "delimitMate has been reset."
+ endif
+endfunction "}}}
+
+function! s:DelimitMateSwitch() "{{{
+ if exists("b:delimitMate_enabled") && b:delimitMate_enabled
+ call s:Unmap()
+ echo "delimitMate has been disabled."
+ else
+ call s:Unmap()
+ call s:init()
+ call s:Map()
+ echo "delimitMate has been enabled."
+ endif
+endfunction "}}}
+
+function! s:Finish() " {{{
+ if exists('g:delimitMate_loaded')
+ return delimitMate#Finish(1)
+ endif
+ return ''
+endfunction " }}}
+
+function! s:FlushBuffer() " {{{
+ if exists('g:delimitMate_loaded')
+ return delimitMate#FlushBuffer()
+ endif
+ return ''
+endfunction " }}}
+
+"}}}
+
+" Mappers: {{{
+function! s:NoAutoClose() "{{{
+ " inoremap <buffer> ) <C-R>=delimitMate#SkipDelim('\)')<CR>
+ for delim in b:_l_delimitMate_right_delims + b:_l_delimitMate_quotes_list
+ if delim == '|'
+ let delim = '<Bar>'
+ endif
+ exec 'inoremap <silent> <Plug>delimitMate' . delim . ' <C-R>=delimitMate#SkipDelim("' . escape(delim,'"') . '")<CR>'
+ exec 'silent! imap <unique> <buffer> '.delim.' <Plug>delimitMate'.delim
+ endfor
+endfunction "}}}
+
+function! s:AutoClose() "{{{
+ " Add matching pair and jump to the midle:
+ " inoremap <silent> <buffer> ( ()<Left>
+ let i = 0
+ while i < len(b:_l_delimitMate_matchpairs_list)
+ let ld = b:_l_delimitMate_left_delims[i] == '|' ? '<bar>' : b:_l_delimitMate_left_delims[i]
+ let rd = b:_l_delimitMate_right_delims[i] == '|' ? '<bar>' : b:_l_delimitMate_right_delims[i]
+ exec 'inoremap <silent> <Plug>delimitMate' . ld . ' ' . ld . '<C-R>=delimitMate#ParenDelim("' . escape(rd, '|') . '")<CR>'
+ exec 'silent! imap <unique> <buffer> '.ld.' <Plug>delimitMate'.ld
+ let i += 1
+ endwhile
+
+ " Exit from inside the matching pair:
+ for delim in b:_l_delimitMate_right_delims
+ exec 'inoremap <silent> <Plug>delimitMate' . delim . ' <C-R>=delimitMate#JumpOut("\' . delim . '")<CR>'
+ exec 'silent! imap <unique> <buffer> ' . delim . ' <Plug>delimitMate'. delim
+ endfor
+
+ " Add matching quote and jump to the midle, or exit if inside a pair of matching quotes:
+ " inoremap <silent> <buffer> " <C-R>=delimitMate#QuoteDelim("\"")<CR>
+ for delim in b:_l_delimitMate_quotes_list
+ if delim == '|'
+ let delim = '<Bar>'
+ endif
+ exec 'inoremap <silent> <Plug>delimitMate' . delim . ' <C-R>=delimitMate#QuoteDelim("\' . delim . '")<CR>'
+ exec 'silent! imap <unique> <buffer> ' . delim . ' <Plug>delimitMate' . delim
+ endfor
+
+ " Try to fix the use of apostrophes (kept for backward compatibility):
+ " inoremap <silent> <buffer> n't n't
+ for map in b:_l_delimitMate_apostrophes_list
+ exec "inoremap <silent> " . map . " " . map
+ exec 'silent! imap <unique> <buffer> ' . map . ' <Plug>delimitMate' . map
+ endfor
+endfunction "}}}
+
+function! s:ExtraMappings() "{{{
+ " If pair is empty, delete both delimiters:
+ inoremap <silent> <Plug>delimitMateBS <C-R>=delimitMate#BS()<CR>
+ if !hasmapto('<Plug>delimitMateBS','i')
+ silent! imap <unique> <buffer> <BS> <Plug>delimitMateBS
+ endif
+ " If pair is empty, delete closing delimiter:
+ inoremap <silent> <expr> <Plug>delimitMateS-BS delimitMate#WithinEmptyPair() ? "\<C-R>=delimitMate#Del()\<CR>" : "\<S-BS>"
+ if !hasmapto('<Plug>delimitMateS-BS','i')
+ silent! imap <unique> <buffer> <S-BS> <Plug>delimitMateS-BS
+ endif
+ " Expand return if inside an empty pair:
+ inoremap <silent> <Plug>delimitMateCR <C-R>=delimitMate#ExpandReturn()<CR>
+ if b:_l_delimitMate_expand_cr != 0 && !hasmapto('<Plug>delimitMateCR', 'i')
+ silent! imap <unique> <buffer> <CR> <Plug>delimitMateCR
+ endif
+ " Expand space if inside an empty pair:
+ inoremap <silent> <Plug>delimitMateSpace <C-R>=delimitMate#ExpandSpace()<CR>
+ if b:_l_delimitMate_expand_space != 0 && !hasmapto('<Plug>delimitMateSpace', 'i')
+ silent! imap <unique> <buffer> <Space> <Plug>delimitMateSpace
+ endif
+ " Jump over any delimiter:
+ inoremap <silent> <Plug>delimitMateS-Tab <C-R>=delimitMate#JumpAny("\<S-Tab>")<CR>
+ if b:_l_delimitMate_tab2exit && !hasmapto('<Plug>delimitMateS-Tab', 'i')
+ silent! imap <unique> <buffer> <S-Tab> <Plug>delimitMateS-Tab
+ endif
+ " Change char buffer on Del:
+ inoremap <silent> <Plug>delimitMateDel <C-R>=delimitMate#Del()<CR>
+ if !hasmapto('<Plug>delimitMateDel', 'i')
+ silent! imap <unique> <buffer> <Del> <Plug>delimitMateDel
+ endif
+ " Flush the char buffer on movement keystrokes or when leaving insert mode:
+ for map in ['Esc', 'Left', 'Right', 'Home', 'End']
+ exec 'inoremap <silent> <Plug>delimitMate'.map.' <C-R>=<SID>Finish()<CR><'.map.'>'
+ if !hasmapto('<Plug>delimitMate'.map, 'i')
+ exec 'silent! imap <unique> <buffer> <'.map.'> <Plug>delimitMate'.map
+ endif
+ endfor
+ " Except when pop-up menu is active:
+ for map in ['Up', 'Down', 'PageUp', 'PageDown', 'S-Down', 'S-Up']
+ exec 'inoremap <silent> <expr> <Plug>delimitMate'.map.' pumvisible() ? "\<'.map.'>" : "\<C-R>=\<SID>Finish()\<CR>\<'.map.'>"'
+ if !hasmapto('<Plug>delimitMate'.map, 'i')
+ exec 'silent! imap <unique> <buffer> <'.map.'> <Plug>delimitMate'.map
+ endif
+ endfor
+ " Avoid ambiguous mappings:
+ for map in ['LeftMouse', 'RightMouse']
+ exec 'inoremap <silent> <Plug>delimitMateM'.map.' <C-R>=delimitMate#Finish(1)<CR><'.map.'>'
+ if !hasmapto('<Plug>delimitMate'.map, 'i')
+ exec 'silent! imap <unique> <buffer> <'.map.'> <Plug>delimitMateM'.map
+ endif
+ endfor
+
+ " Jump over next delimiters
+ inoremap <buffer> <Plug>delimitMateJumpMany <C-R>=len(b:_l_delimitMate_buffer) ? delimitMate#Finish(0) : delimitMate#JumpMany()<CR>
+ if !hasmapto('<Plug>delimitMateJumpMany')
+ imap <silent> <buffer> <C-G>g <Plug>delimitMateJumpMany
+ endif
+
+ " The following simply creates an ambiguous mapping so vim fully processes
+ " the escape sequence for terminal keys, see 'ttimeout' for a rough
+ " explanation, this just forces it to work
+ if !has('gui_running')
+ imap <silent> <C-[>OC <RIGHT>
+ endif
+endfunction "}}}
+
+"}}}
+
+" Commands: {{{
+
+call s:DelimitMateDo()
+
+" Let me refresh without re-loading the buffer:
+command! -bar DelimitMateReload call s:DelimitMateDo(1)
+
+" Quick test:
+command! -bar DelimitMateTest silent call s:TestMappingsDo()
+
+" Switch On/Off:
+command! -bar DelimitMateSwitch call s:DelimitMateSwitch()
+"}}}
+
+" Autocommands: {{{
+
+augroup delimitMate
+ au!
+ " Run on file type change.
+ "autocmd VimEnter * autocmd FileType * call <SID>DelimitMateDo()
+ autocmd FileType * call <SID>DelimitMateDo()
+
+ " Run on new buffers.
+ autocmd BufNewFile,BufRead,BufEnter *
+ \ if !exists('b:delimitMate_was_here') |
+ \ call <SID>DelimitMateDo() |
+ \ let b:delimitMate_was_here = 1 |
+ \ endif
+
+ " Flush the char buffer:
+ autocmd InsertEnter * call <SID>FlushBuffer()
+ autocmd BufEnter *
+ \ if mode() == 'i' |
+ \ call <SID>FlushBuffer() |
+ \ endif
+
+augroup END
+
+"}}}
+
+" GetLatestVimScripts: 2754 1 :AutoInstall: delimitMate.vim
+" vim:foldmethod=marker:foldcolumn=4
diff --git a/vim/plugin/endwise.vim b/vim/plugin/endwise.vim
new file mode 100644
index 0000000..dca90ff
--- /dev/null
+++ b/vim/plugin/endwise.vim
@@ -0,0 +1,134 @@
+" endwise.vim - EndWise
+" Author: Tim Pope <http://tpo.pe/>
+" Version: 1.0
+" License: Same as Vim itself. See :help license
+" GetLatestVimScripts: 2386 1 :AutoInstall: endwise.vim
+
+if exists("g:loaded_endwise") || &cp
+ finish
+endif
+let g:loaded_endwise = 1
+
+augroup endwise " {{{1
+ autocmd!
+ autocmd FileType lua
+ \ let b:endwise_addition = '\=submatch(0)=="{" ? "}" : "end"' |
+ \ let b:endwise_words = 'function,do,then' |
+ \ let b:endwise_pattern = '^\s*\zs\%(function\|do\|then\)\>\%(.*[^.:@$]\<end\>\)\@!\|\<then\|do\ze\%(\s*|.*|\)\=\s*$' |
+ \ let b:endwise_syngroups = 'luaFunction,luaStatement,luaCond'
+ autocmd FileType ruby
+ \ let b:endwise_addition = '\=submatch(0)=="{" ? "}" : "end"' |
+ \ let b:endwise_words = 'module,class,def,if,unless,case,while,until,begin,do' |
+ \ let b:endwise_pattern = '^\s*\zs\%(module\|class\|def\|if\|unless\|case\|while\|until\|for\|\|begin\)\>\%(.*[^.:@$]\<end\>\)\@!\|\<do\ze\%(\s*|.*|\)\=\s*$' |
+ \ let b:endwise_syngroups = 'rubyModule,rubyClass,rubyDefine,rubyControl,rubyConditional,rubyRepeat'
+ autocmd FileType sh,zsh
+ \ let b:endwise_addition = '\=submatch(0)=="if" ? "fi" : submatch(0)=="case" ? "esac" : "done"' |
+ \ let b:endwise_words = 'if,until,case,do' |
+ \ let b:endwise_pattern = '\%(^\s*\zs\%(if\|case\)\>\ze\|\zs\<do\ze$\|^\s*\zsdo\s*\ze$\)' |
+ \ let b:endwise_syngroups = 'shConditional,shLoop,shIf,shFor,shRepeat,shCaseEsac,zshConditional,zshRepeat,zshDelimiter'
+ autocmd FileType vb,vbnet,aspvbs
+ \ let b:endwise_addition = 'End &' |
+ \ let b:endwise_words = 'Function,Sub,Class,Module,Enum,Namespace' |
+ \ let b:endwise_pattern = '\%(\<End\>.*\)\@<!\<&\>' |
+ \ let b:endwise_syngroups = 'vbStatement,vbnetStorage,vbnetProcedure,vbnet.*Words,AspVBSStatement'
+ autocmd FileType vim
+ \ let b:endwise_addition = 'end&' |
+ \ let b:endwise_words = 'fu\%[nction],wh\%[ile],if,for,try' |
+ \ let b:endwise_syngroups = 'vimFuncKey,vimNotFunc,vimCommand'
+augroup END " }}}1
+
+" Maps {{{1
+
+if maparg("<Plug>DiscretionaryEnd") == ""
+ inoremap <silent> <SID>DiscretionaryEnd <C-R>=<SID>crend(0)<CR>
+ inoremap <silent> <SID>AlwaysEnd <C-R>=<SID>crend(1)<CR>
+ imap <script> <Plug>DiscretionaryEnd <SID>DiscretionaryEnd
+ imap <script> <Plug>AlwaysEnd <SID>AlwaysEnd
+endif
+if maparg('<CR>','i') =~# '<C-R>=.*crend(.)<CR>\|<\%(Plug\|SID\)>.*End'
+ " Already mapped
+elseif maparg('<CR>','i') =~ '<CR>'
+ exe "imap <script> <C-X><CR> ".maparg('<CR>','i')."<SID>AlwaysEnd"
+ exe "imap <script> <CR> ".maparg('<CR>','i')."<SID>DiscretionaryEnd"
+elseif maparg('<CR>','i') =~ '<Plug>delimitMateCR'
+ exe "imap <C-X><CR> ".maparg('<CR>', 'i')."<Plug>AlwaysEnd"
+ exe "imap <CR> ".maparg('<CR>', 'i')."<Plug>DiscretionaryEnd"
+else
+ imap <C-X><CR> <CR><Plug>AlwaysEnd
+ imap <CR> <CR><Plug>DiscretionaryEnd
+endif
+
+if maparg('<M-o>','i') == ''
+ inoremap <M-o> <C-O>o
+endif
+
+" }}}1
+
+" Code {{{1
+
+function! s:mysearchpair(beginpat,endpat,synpat)
+ let g:endwise_syntaxes = ""
+ let s:lastline = line('.')
+ call s:synname()
+ let line = searchpair(a:beginpat,'',a:endpat,'Wn','<SID>synname() !~# "^'.substitute(a:synpat,'\\','\\\\','g').'$"',line('.')+50)
+ return line
+endfunction
+
+function! s:crend(always)
+ let n = ""
+ if !exists("b:endwise_addition") || !exists("b:endwise_words") || !exists("b:endwise_syngroups")
+ return n
+ end
+ let synpat = '\%('.substitute(b:endwise_syngroups,',','\\|','g').'\)'
+ let wordchoice = '\%('.substitute(b:endwise_words,',','\\|','g').'\)'
+ if exists("b:endwise_pattern")
+ let beginpat = substitute(b:endwise_pattern,'&',substitute(wordchoice,'\\','\\&','g'),'g')
+ else
+ let beginpat = '\<'.wordchoice.'\>'
+ endif
+ let lnum = line('.') - 1
+ let space = matchstr(getline(lnum),'^\s*')
+ let col = match(getline(lnum),beginpat) + 1
+ let word = matchstr(getline(lnum),beginpat)
+ let endword = substitute(word,'.*',b:endwise_addition,'')
+ let y = n.endword."\<C-O>O"
+ let endpat = '\<'.endword.'\>'
+ if a:always
+ return y
+ elseif col <= 0 || synIDattr(synID(lnum,col,1),'name') !~ '^'.synpat.'$'
+ return n
+ elseif getline('.') !~ '^\s*#\=$'
+ return n
+ endif
+ let line = s:mysearchpair(beginpat,endpat,synpat)
+ " even is false if no end was found, or if the end found was less
+ " indented than the current line
+ let even = strlen(matchstr(getline(line),'^\s*')) >= strlen(space)
+ if line == 0
+ let even = 0
+ endif
+ if !even && line == line('.') + 1
+ return y
+ endif
+ if even
+ return n
+ endif
+ return y
+endfunction
+
+function! s:synname()
+ " Checking this helps to force things to stay in sync
+ while s:lastline < line('.')
+ let s = synIDattr(synID(s:lastline,indent(s:lastline)+1,1),'name')
+ let s:lastline = nextnonblank(s:lastline + 1)
+ endwhile
+
+ let s = synIDattr(synID(line('.'),col('.'),1),'name')
+ let g:endwise_syntaxes = g:endwise_syntaxes . line('.').','.col('.')."=".s."\n"
+ let s:lastline = line('.')
+ return s
+endfunction
+
+" }}}1
+
+" vim:set sw=2 sts=2:
diff --git a/vim/plugin/fugitive.vim b/vim/plugin/fugitive.vim
new file mode 100644
index 0000000..17d52fc
--- /dev/null
+++ b/vim/plugin/fugitive.vim
@@ -0,0 +1,2220 @@
+" fugitive.vim - A Git wrapper so awesome, it should be illegal
+" Maintainer: Tim Pope <http://tpo.pe/>
+" Version: 1.2
+" 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
+
+" Utility {{{1
+
+function! s:function(name) abort
+ return function(substitute(a:name,'^s:',matchstr(expand('<sfile>'), '<SNR>\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:shellesc(arg) abort
+ if a:arg =~ '^[A-Za-z0-9_/.-]\+$'
+ return a:arg
+ elseif &shell =~# 'cmd' && a:arg !~# '"'
+ return '"'.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)
+ echohl WarningMsg
+ echomsg a:str
+ echohl None
+ let v:warningmsg = a:str
+endfunction
+
+function! s:shellslash(path)
+ if exists('+shellslash') && !&shellslash
+ return s:gsub(a:path,'\\','/')
+ else
+ return a:path
+ endif
+endfunction
+
+function! s:recall()
+ let rev = s:buffer().rev()
+ if rev ==# ':'
+ return matchstr(getline('.'),'^#\t\%([[:alpha:] ]\+: *\)\=\zs.\{-\}\ze\%( (new commits)\)\=$\|^\d\{6} \x\{40\} \d\t\zs.*')
+ 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()
+ for command in s:commands
+ exe 'command! -buffer '.command
+ endfor
+endfunction
+
+function! s:compatibility_check()
+ if exists('b:git_dir') && exists('*GitBranchInfoCheckGitDir') && !exists('g:fugitive_did_compatibility_warning')
+ let g:fugitive_did_compatibility_warning = 1
+ call s:warn("See http://github.com/tpope/vim-fugitive/issues#issue/1 for why you should remove git-branch-info.vim")
+ endif
+endfunction
+
+augroup fugitive_utility
+ autocmd!
+ autocmd User Fugitive call s:define_commands()
+ autocmd VimEnter * call s:compatibility_check()
+augroup END
+
+let s:abstract_prototype = {}
+
+" }}}1
+" Initialization {{{1
+
+function! s:ExtractGitDir(path) abort
+ let path = s:shellslash(a:path)
+ if path =~? '^fugitive://.*//'
+ return matchstr(path,'fugitive://\zs.\{-\}\ze//')
+ endif
+ let fn = fnamemodify(path,':s?[\/]$??')
+ let ofn = ""
+ let nfn = fn
+ while fn != ofn
+ if filereadable(fn . '/.git/HEAD')
+ return s:sub(simplify(fnamemodify(fn . '/.git',':p')),'\W$','')
+ elseif fn =~ '\.git$' && filereadable(fn . '/HEAD')
+ return s:sub(simplify(fnamemodify(fn,':p')),'\W$','')
+ endif
+ let ofn = fn
+ let fn = fnamemodify(ofn,':h')
+ endwhile
+ return ''
+endfunction
+
+function! s:Detect(path)
+ if exists('b:git_dir') && b:git_dir ==# ''
+ unlet b:git_dir
+ endif
+ if !exists('b:git_dir')
+ let dir = s:ExtractGitDir(a:path)
+ if dir != ''
+ let b:git_dir = dir
+ endif
+ endif
+ if exists('b:git_dir')
+ silent doautocmd User Fugitive
+ cnoremap <expr> <buffer> <C-R><C-G> <SID>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.'/tags',', ')) == -1
+ call buffer.setvar('&tags',escape(b:git_dir.'/tags',', ').','.buffer.getvar('&tags'))
+ if &filetype != ''
+ call buffer.setvar('&tags',escape(b:git_dir.'/'.&filetype.'.tags',', ').','.buffer.getvar('&tags'))
+ endif
+ endif
+ endif
+endfunction
+
+augroup fugitive
+ autocmd!
+ autocmd BufNewFile,BufReadPost * call s:Detect(expand('<amatch>:p'))
+ autocmd FileType netrw call s:Detect(expand('<afile>:p'))
+ autocmd VimEnter * if expand('<amatch>')==''|call s:Detect(getcwd())|endif
+ autocmd BufWinLeave * execute getwinvar(+winnr(), 'fugitive_leave')
+augroup END
+
+" }}}1
+" Repository {{{1
+
+let s:repo_prototype = {}
+let s:repos = {}
+
+function! s:repo(...) abort
+ let dir = a:0 ? a:1 : (exists('b:git_dir') && b:git_dir !=# '' ? b:git_dir : s:ExtractGitDir(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! s:repo_dir(...) dict abort
+ return join([self.git_dir]+a:000,'/')
+endfunction
+
+function! s:repo_tree(...) dict abort
+ if !self.bare()
+ let dir = fnamemodify(self.git_dir,':h')
+ return join([dir]+a:000,'/')
+ endif
+ call s:throw('no work tree')
+endfunction
+
+function! s:repo_bare() dict abort
+ return self.dir() !~# '/\.git$'
+endfunction
+
+function! s:repo_translate(spec) dict abort
+ if a:spec ==# '.' || a:spec ==# '/.'
+ return self.bare() ? self.dir() : self.tree()
+ elseif a:spec =~# '^/'
+ return fnamemodify(self.dir(),':h').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(s:repo().dir())] ==# s:repo().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(s:repo().dir('refs/'.a:spec))
+ return self.dir('refs/'.a:spec)
+ elseif filereadable(s:repo().dir('refs/tags/'.a:spec))
+ return self.dir('refs/tags/'.a:spec)
+ elseif filereadable(s:repo().dir('refs/heads/'.a:spec))
+ return self.dir('refs/heads/'.a:spec)
+ elseif filereadable(s:repo().dir('refs/remotes/'.a:spec))
+ return self.dir('refs/remotes/'.a:spec)
+ elseif filereadable(s:repo().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
+
+call s:add_methods('repo',['dir','tree','bare','translate'])
+
+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(),"\\\"' ").' show'
+ if has('gui_running') && !has('win32')
+ return g:fugitive_git_executable . ' --no-pager' . args
+ else
+ return g:fugitive_git_executable . args
+ endif
+endfunction
+
+call s:add_methods('repo',['keywordprg'])
+
+" }}}1
+" Buffer {{{1
+
+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 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*','')
+ else
+ 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
+
+call s:add_methods('buffer',['getvar','setvar','getline','repo','type','spec','name','commit','path','rev','sha1','expand','containing_commit'])
+
+" }}}1
+" Git {{{1
+
+call s:command("-bang -nargs=? -complete=customlist,s:GitComplete Git :execute s:Git(<bang>0,<q-args>)")
+
+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,cmd) abort
+ if a:bang
+ return s:Edit('edit',1,a:cmd)
+ endif
+ let git = s:repo().git_command()
+ if has('gui_running') && !has('win32')
+ let git .= ' --no-pager'
+ endif
+ let cmd = matchstr(a:cmd,'\v\C.{-}%($|\\@<!%(\\\\)*\|)@=')
+ call s:ExecuteInTree('!'.git.' '.cmd)
+ call fugitive#reload_status()
+ return matchstr(a:cmd,'\v\C\\@<!%(\\\\)*\|\zs.*')
+endfunction
+
+function! s:GitComplete(A,L,P) abort
+ if !exists('s:exec_path')
+ let s:exec_path = s:sub(system(g:fugitive_git_executable.' --exec-path'),'\n$','')
+ endif
+ let cmds = map(split(glob(s:exec_path.'/git-*'),"\n"),'s:sub(v:val[strlen(s:exec_path)+5 : -1],"\\.exe$","")')
+ if a:L =~ ' [[:alnum:]-]\+ '
+ return s:repo().superglob(a:A)
+ elseif a:A == ''
+ return sort(cmds+keys(s:repo().aliases()))
+ else
+ return filter(sort(cmds+keys(s:repo().aliases())),'v:val[0:strlen(a:A)-1] ==# a:A')
+ endif
+endfunction
+
+" }}}1
+" Gcd, Glcd {{{1
+
+function! s:DirComplete(A,L,P) abort
+ let matches = s:repo().dirglob(a:A)
+ return matches
+endfunction
+
+call s:command("-bar -bang -nargs=? -complete=customlist,s:DirComplete Gcd :cd<bang> `=s:repo().bare() ? s:repo().dir(<q-args>) : s:repo().tree(<q-args>)`")
+call s:command("-bar -bang -nargs=? -complete=customlist,s:DirComplete Glcd :lcd<bang> `=s:repo().bare() ? s:repo().dir(<q-args>) : s:repo().tree(<q-args>)`")
+
+" }}}1
+" Gstatus {{{1
+
+call s:command("-bar Gstatus :execute s:Status()")
+
+function! s:Status() abort
+ try
+ Gpedit :
+ wincmd P
+ nnoremap <buffer> <silent> q :<C-U>bdelete<CR>
+ catch /^fugitive:/
+ return 'echoerr v:errmsg'
+ endtry
+ return ''
+endfunction
+
+function! fugitive#reload_status() abort
+ 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
+endfunction
+
+function! s:StageReloadSeek(target,lnum1,lnum2)
+ let jump = a:target
+ let f = matchstr(getline(a:lnum1-1),'^#\t\%([[:alpha:] ]\+: *\)\=\zs.*')
+ if f !=# '' | let jump = f | endif
+ let f = matchstr(getline(a:lnum2+1),'^#\t\%([[:alpha:] ]\+: *\)\=\zs.*')
+ if f !=# '' | let jump = f | endif
+ silent! edit!
+ 1
+ redraw
+ call search('^#\t\%([[:alpha:] ]\+: *\)\=\V'.jump.'\%( (new commits)\)\=\$','W')
+endfunction
+
+function! s:StageDiff(diff) abort
+ let section = getline(search('^# .*:$','bcnW'))
+ let line = getline('.')
+ let filename = matchstr(line,'^#\t\%([[:alpha:] ]\+: *\)\=\zs.\{-\}\ze\%( (new commits)\)\=$')
+ if filename ==# '' && section ==# '# Changes to be committed:'
+ return 'Git diff --cached'
+ elseif filename ==# ''
+ return 'Git diff'
+ elseif line =~# '^#\trenamed:' && filename =~# ' -> '
+ let [old, new] = split(filename,' -> ')
+ execute 'Gedit '.s:fnameescape(':0:'.new)
+ return a:diff.' HEAD:'.s:fnameescape(old)
+ elseif section ==# '# Changes to be committed:'
+ 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 section = getline(search('^# .*:$','bcnW'))
+ let line = getline('.')
+ let filename = matchstr(line,'^#\t\%([[:alpha:] ]\+: *\)\=\zs.\{-\}\ze\%( (new commits)\)\=$')
+ let arg = (filename ==# '' ? '.' : filename)
+ if section ==# '# Changes to be committed:'
+ return 'Git! diff --cached '.s:shellesc(arg)
+ elseif section ==# '# Untracked files:'
+ let repo = s:repo()
+ call repo.git_chomp_in_tree('add','--intent-to-add',arg)
+ if arg ==# '.'
+ silent! edit!
+ 1
+ if !search('^# Change\%(d but not updated\|s not staged for commit\):$','W')
+ call search('^# Change','W')
+ endif
+ else
+ call s:StageReloadSeek(arg,line('.'),line('.'))
+ endif
+ return ''
+ else
+ return 'Git! diff '.s:shellesc(arg)
+ endif
+endfunction
+
+function! s:StageToggle(lnum1,lnum2) abort
+ try
+ let output = ''
+ for lnum in range(a:lnum1,a:lnum2)
+ let line = getline(lnum)
+ let repo = s:repo()
+ if line ==# '# Changes to be committed:'
+ call repo.git_chomp_in_tree('reset','-q')
+ silent! edit!
+ 1
+ if !search('^# Untracked files:$','W')
+ call search('^# Change','W')
+ endif
+ return ''
+ elseif line =~# '^# Change\%(d but not updated\|s not staged for commit\):$'
+ call repo.git_chomp_in_tree('add','-u')
+ silent! edit!
+ 1
+ if !search('^# Untracked files:$','W')
+ call search('^# Change','W')
+ endif
+ return ''
+ elseif line ==# '# Untracked files:'
+ call repo.git_chomp_in_tree('add','.')
+ silent! edit!
+ 1
+ call search('^# Change','W')
+ return ''
+ endif
+ let filename = matchstr(line,'^#\t\%([[:alpha:] ]\+: *\)\=\zs.\{-\}\ze\%( (\a\+ [[:alpha:], ]\+)\)\=$')
+ if filename ==# ''
+ continue
+ endif
+ if !exists('first_filename')
+ let first_filename = filename
+ endif
+ execute lnum
+ let section = getline(search('^# .*:$','bnW'))
+ if line =~# '^#\trenamed:' && filename =~ ' -> '
+ let cmd = ['mv','--'] + reverse(split(filename,' -> '))
+ let filename = cmd[-1]
+ elseif section =~? ' to be '
+ let cmd = ['reset','-q','--',filename]
+ elseif line =~# '^#\tdeleted:'
+ let cmd = ['rm','--',filename]
+ else
+ let cmd = ['add','--',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 line = getline(lnum)
+ if line ==# '# Changes to be committed:'
+ return 'Git reset --patch'
+ elseif line =~# '^# Change\%(d but not updated\|s not staged for commit\):$'
+ return 'Git add --patch'
+ endif
+ let filename = matchstr(line,'^#\t\%([[:alpha:] ]\+: *\)\=\zs.\{-\}\ze\%( (new commits)\)\=$')
+ if filename ==# ''
+ continue
+ endif
+ if !exists('first_filename')
+ let first_filename = filename
+ endif
+ execute lnum
+ let section = getline(search('^# .*:$','bnW'))
+ if line =~# '^#\trenamed:' && filename =~ ' -> '
+ let reset += [split(filename,' -> ')[1]]
+ elseif section =~? ' to be '
+ let reset += [filename]
+ elseif line !~# '^#\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.'\%( (new commits)\)\=\$','W')
+ endif
+ catch /^fugitive:/
+ return 'echoerr v:errmsg'
+ endtry
+ return 'checktime'
+endfunction
+
+" }}}1
+" Gcommit {{{1
+
+call s:command("-nargs=? -complete=customlist,s:CommitComplete Gcommit :execute s:Commit(<q-args>)")
+
+function! s:Commit(args) abort
+ let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
+ let dir = getcwd()
+ let msgfile = s:repo().dir('COMMIT_EDITMSG')
+ let outfile = tempname()
+ let errorfile = tempname()
+ try
+ execute cd.'`=s:repo().tree()`'
+ if &shell =~# 'cmd'
+ let command = ''
+ let old_editor = $GIT_EDITOR
+ let $GIT_EDITOR = 'false'
+ else
+ let command = 'env GIT_EDITOR=false '
+ endif
+ let command .= s:repo().git_command('commit').' '.a:args
+ if &shell =~# 'csh'
+ silent execute '!('.command.' > '.outfile.') >& '.errorfile
+ elseif a:args =~# '\%(^\| \)--interactive\>'
+ execute '!'.command.' 2> '.errorfile
+ else
+ silent execute '!'.command.' > '.outfile.' 2> '.errorfile
+ endif
+ 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,'%(%(^| )-- )@<!%(^| )@<=%(-[se]|--edit|--interactive)%($| )','')
+ let args = s:gsub(args,'%(%(^| )-- )@<!%(^| )@<=%(-F|--file|-m|--message)%(\s+|\=)%(''[^'']*''|"%(\\.|[^"])*"|\\.|\S)*','')
+ let args = s:gsub(args,'%(^| )@<=[%#]%(:\w)*','\=expand(submatch(0))')
+ let args = '-F '.s:shellesc(msgfile).' '.args
+ if args !~# '\%(^\| \)--cleanup\>'
+ let args = '--cleanup=strip '.args
+ endif
+ if bufname('%') == '' && line('$') == 1 && getline(1) == '' && !&mod
+ keepalt edit `=msgfile`
+ elseif s:buffer().type() ==# 'index'
+ keepalt edit `=msgfile`
+ execute (search('^#','n')+1).'wincmd+'
+ setlocal nopreviewwindow
+ else
+ keepalt split `=msgfile`
+ endif
+ let b:fugitive_commit_arguments = args
+ setlocal bufhidden=delete 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)
+ execute cd.'`=dir`'
+ 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 -<Tab>
+ 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()
+ let args = getbufvar(+expand('<abuf>'),'fugitive_commit_arguments')
+ if !empty(args)
+ call setbufvar(+expand('<abuf>'),'fugitive_commit_arguments','')
+ return s:Commit(args)
+ endif
+ return ''
+endfunction
+
+augroup fugitive_commit
+ autocmd!
+ autocmd VimLeavePre,BufDelete *.git/COMMIT_EDITMSG execute s:sub(s:FinishCommit(), '^echoerr (.*)', 'echohl ErrorMsg|echo \1|echohl NONE')
+augroup END
+
+" }}}1
+" Ggrep, Glog {{{1
+
+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(<bang>0,<q-args>)")
+call s:command("-bar -bang -nargs=* -complete=customlist,s:EditComplete Glog :execute s:Log('grep<bang>',<f-args>)")
+
+function! s:Grep(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 'grep! '.escape(matchstr(a:arg,'\v\C.{-}%($|[''" ]\@=\|)@='),'|')
+ let list = getqflist()
+ for entry in list
+ if bufname(entry.bufnr) =~ ':'
+ let entry.filename = s:repo().translate(bufname(entry.bufnr))
+ unlet! entry.bufnr
+ elseif a:arg =~# '\%(^\| \)--cached\>'
+ let entry.filename = s:repo().translate(':0:'.bufname(entry.bufnr))
+ unlet! entry.bufnr
+ endif
+ endfor
+ call setqflist(list,'r')
+ if !a:bang && !empty(list)
+ return 'cfirst'.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,...)
+ let path = s:buffer().path('/')
+ if path =~# '^/\.git\%(/\|$\)' || index(a:000,'--') != -1
+ let path = ''
+ endif
+ let cmd = ['--no-pager', 'log', '--no-color']
+ let cmd += [escape('--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 =~# '/.'
+ let cmd += ['--',path[1:-1]]
+ 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 = call(s:repo().git_command,cmd,s:repo())
+ let &grepformat = '%f::%m'
+ exe a:cmd
+ finally
+ let &grepformat = grepformat
+ let &grepprg = grepprg
+ execute cd.'`=dir`'
+ endtry
+endfunction
+
+" }}}1
+" Gedit, Gpedit, Gsplit, Gvsplit, Gtabedit, Gread {{{1
+
+function! s:Edit(cmd,bang,...) abort
+ 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
+ wincmd p
+ endif
+ endfor
+ endif
+ endif
+ endif
+
+ if a:bang
+ let args = s:gsub(a:0 ? a:1 : '', '\\@<!%(\\\\)*\zs[%#]', '\=s:buffer().expand(submatch(0))')
+ if a:cmd =~# 'read'
+ let git = s:repo().git_command()
+ let last = line('$')
+ silent call s:ExecuteInTree((a:cmd ==# 'read' ? '$read' : a:cmd).'!'.git.' --no-pager '.args)
+ if a:cmd ==# 'read'
+ silent execute '1,'.last.'delete_'
+ endif
+ call fugitive#reload_status()
+ diffupdate
+ return 'redraw|echo '.string(':!'.git.' '.args)
+ else
+ let temp = tempname()
+ let s:temp_files[temp] = s:repo().dir()
+ silent execute a:cmd.' '.temp
+ if a:cmd =~# 'pedit'
+ wincmd P
+ endif
+ let echo = s:Edit('read',1,args)
+ silent write!
+ setlocal buftype=nowrite nomodified filetype=git foldmarker=<<<<<<<,>>>>>>>
+ 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 = s:buffer().expand(a:1)
+ elseif expand('%') ==# ''
+ let file = ':'
+ elseif s:buffer().commit() ==# '' && s:buffer().path('/') !~# '^/.git\>'
+ let file = s:buffer().path(':')
+ else
+ let file = s:buffer().path('/')
+ endif
+ try
+ let file = s: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 s:repo().superglob(a:A)
+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<bang>',0,<f-args>)")
+call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gedit :execute s:Edit('edit<bang>',0,<f-args>)")
+call s:command("-bar -bang -nargs=? -complete=customlist,s:EditRunComplete Gpedit :execute s:Edit('pedit',<bang>0,<f-args>)")
+call s:command("-bar -bang -nargs=? -complete=customlist,s:EditRunComplete Gsplit :execute s:Edit('split',<bang>0,<f-args>)")
+call s:command("-bar -bang -nargs=? -complete=customlist,s:EditRunComplete Gvsplit :execute s:Edit('vsplit',<bang>0,<f-args>)")
+call s:command("-bar -bang -nargs=? -complete=customlist,s:EditRunComplete Gtabedit :execute s:Edit('tabedit',<bang>0,<f-args>)")
+call s:command("-bar -bang -nargs=? -count -complete=customlist,s:EditRunComplete Gread :execute s:Edit((!<count> && <line1> ? '' : <count>).'read',<bang>0,<f-args>)")
+
+" }}}1
+" Gwrite, Gwq {{{1
+
+call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gwrite :execute s:Write(<bang>0,<f-args>)")
+call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gw :execute s:Write(<bang>0,<f-args>)")
+call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gwq :execute s:Wq(<bang>0,<f-args>)")
+
+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 ? a:1 : 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', file)
+ else
+ let error = s:repo().git_chomp_in_tree('add', file)
+ 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('$'))
+ if bufloaded(nr) && !getbufvar(nr,'&modified') && (bufname(nr) == one || bufname(nr) == two || bufname(nr) == 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 = bufname(bufnr)
+ 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 $read `=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
+
+" }}}1
+" Gdiff {{{1
+
+call s:command("-bang -bar -nargs=? -complete=customlist,s:EditComplete Gdiff :execute s:Diff(<bang>0,<f-args>)")
+call s:command("-bar -nargs=? -complete=customlist,s:EditComplete Gvdiff :execute s:Diff(0,<f-args>)")
+call s:command("-bar -nargs=? -complete=customlist,s:EditComplete Gsdiff :execute s:Diff(1,<f-args>)")
+
+augroup fugitive_diff
+ autocmd!
+ autocmd BufWinLeave * if s:diff_window_count() == 2 && &diff && getbufvar(+expand('<abuf>'), 'git_dir') !=# '' | call s:diffoff_all(getbufvar(+expand('<abuf>'), 'git_dir')) | endif
+ autocmd BufWinEnter * if s:diff_window_count() == 1 && &diff && getbufvar(+expand('<abuf>'), 'git_dir') !=# '' | call s:diffoff() | endif
+augroup END
+
+function! s:diff_window_count()
+ let c = 0
+ for nr in range(1,winnr('$'))
+ let c += getwinvar(nr,'&diff')
+ endfor
+ return c
+endfunction
+
+function! s:diffthis()
+ if !&diff
+ let w:fugitive_diff_restore = 'setlocal nodiff noscrollbind'
+ let w:fugitive_diff_restore .= ' scrollopt=' . &l:scrollopt
+ let w:fugitive_diff_restore .= &l:wrap ? ' wrap' : ' nowrap'
+ let w:fugitive_diff_restore .= ' foldmethod=' . &l:foldmethod
+ let w:fugitive_diff_restore .= ' foldcolumn=' . &l:foldcolumn
+ diffthis
+ endif
+endfunction
+
+function! s:diffoff()
+ 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)
+ 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
+ if exists('restorewinnr')
+ wincmd p
+ 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(bang,...) abort
+ let split = a:bang ? 'split' : 'vsplit'
+ 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 nr = bufnr('')
+ execute 'leftabove '.split.' `=fugitive#buffer().repo().translate(s:buffer().expand('':2''))`'
+ execute 'nnoremap <buffer> <silent> dp :diffput '.nr.'<Bar>diffupdate<CR>'
+ call s:diffthis()
+ wincmd p
+ execute 'rightbelow '.split.' `=fugitive#buffer().repo().translate(s:buffer().expand('':3''))`'
+ execute 'nnoremap <buffer> <silent> dp :diffput '.nr.'<Bar>diffupdate<CR>'
+ call s:diffthis()
+ wincmd p
+ call s:diffthis()
+ return ''
+ elseif a:0
+ if a:1 ==# ''
+ return ''
+ elseif a:1 ==# '/'
+ let file = s:buffer().path('/')
+ elseif a:1 ==# ':'
+ let file = s:buffer().path(':0:')
+ elseif a:1 =~# '^:/.'
+ try
+ let file = s:repo().rev_parse(a:1).s:buffer().path(':')
+ catch /^fugitive:/
+ return 'echoerr v:errmsg'
+ endtry
+ else
+ let file = s:buffer().expand(a:1)
+ 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\+')
+ if s:buffer().compare_age(commit) < 0
+ execute 'rightbelow '.split.' `=spec`'
+ else
+ execute 'leftabove '.split.' `=spec`'
+ endif
+ call s:diffthis()
+ wincmd p
+ call s:diffthis()
+ return ''
+ catch /^fugitive:/
+ return 'echoerr v:errmsg'
+ endtry
+endfunction
+
+" }}}1
+" Gmove, Gremove {{{1
+
+function! s:Move(force,destination)
+ if a:destination =~# '^/'
+ let destination = a:destination[1:-1]
+ else
+ let destination = 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().name())
+ " 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 'edit '.s:fnameescape(destination)
+ else
+ return 'saveas! '.s:fnameescape(destination)
+ endif
+ else
+ return 'file '.s:fnameescape(s:repo().translate(':0:'.destination)
+ endif
+endfunction
+
+function! s:MoveComplete(A,L,P)
+ 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)
+ 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(<bang>0,<q-args>)" |
+ \ exe "command! -buffer -bar -bang Gremove :execute s:Remove(<bang>0)" |
+ \ endif
+augroup END
+
+" }}}1
+" Gblame {{{1
+
+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(<bang>0,<line1>,<line2>,<count>,[<f-args>])" | endif
+augroup END
+
+function! s:Blame(bang,line1,line2,count,args) abort
+ try
+ if s:buffer().path() == ''
+ call s:throw('file or blob required')
+ endif
+ if filter(copy(a:args),'v:val !~# "^\\%(--root\|--show-name\\|-\\=\\%([ltwfs]\\|[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 basecmd = escape(call(s:repo().git_command,cmd+['--',s:buffer().path()],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 = 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
+ let bufnr = bufnr('')
+ let restore = 'call setwinvar(bufwinnr('.bufnr.'),"&scrollbind",0)'
+ if &l:wrap
+ let restore .= '|call setwinvar(bufwinnr('.bufnr.'),"&wrap",1)'
+ endif
+ if &l:foldenable
+ let restore .= '|call setwinvar(bufwinnr('.bufnr.'),"&foldenable",1)'
+ endif
+ let winnr = winnr()
+ windo set noscrollbind
+ exe winnr.'wincmd w'
+ setlocal scrollbind nowrap nofoldenable
+ let top = line('w0') + &scrolloff
+ let current = line('.')
+ let s:temp_files[temp] = s:repo().dir()
+ exe '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
+ execute "vertical resize ".(match(getline('.'),'\s\+\d\+)')+1)
+ setlocal nomodified nomodifiable nonumber scrollbind nowrap foldcolumn=0 nofoldenable filetype=fugitiveblame
+ if exists('+relativenumber')
+ setlocal norelativenumber
+ endif
+ nnoremap <buffer> <silent> <CR> :<C-U>exe <SID>BlameJump('')<CR>
+ nnoremap <buffer> <silent> P :<C-U>exe <SID>BlameJump('^'.v:count1)<CR>
+ nnoremap <buffer> <silent> ~ :<C-U>exe <SID>BlameJump('~'.v:count1)<CR>
+ nnoremap <buffer> <silent> o :<C-U>exe <SID>Edit((&splitbelow ? "botright" : "topleft")." split", 0, matchstr(getline('.'),'\x\+'))<CR>
+ nnoremap <buffer> <silent> O :<C-U>exe <SID>Edit("tabedit", 0, matchstr(getline('.'),'\x\+'))<CR>
+ syncbind
+ endif
+ finally
+ if exists('l:dir')
+ execute cd.'`=dir`'
+ endif
+ endtry
+ return ''
+ catch /^fugitive:/
+ return 'echoerr v:errmsg'
+ endtry
+endfunction
+
+function! s:BlameJump(suffix) abort
+ let commit = matchstr(getline('.'),'^\^\=\zs\x\+')
+ if commit =~# '^0\+$'
+ let commit = ':0'
+ endif
+ let lnum = matchstr(getline('.'),'\d\+\ze\s\+[([:digit:]]')
+ let path = matchstr(getline('.'),'^\^\=\zs\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)
+ if winnr > 0
+ exe bufnr.'bdelete'
+ endif
+ execute 'Gblame '.args
+ execute lnum
+ let delta = line('.') - line('w0') - offset
+ if delta > 0
+ execute 'norm! 'delta."\<C-E>"
+ elseif delta < 0
+ execute 'norm! '(-delta)."\<C-Y>"
+ endif
+ syncbind
+ return ''
+endfunction
+
+function! s:BlameSyntax() abort
+ let b:current_syntax = 'fugitiveblame'
+ 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
+ syn match FugitiveblameLineNumber " \@<=\d\+)\@=" contained containedin=FugitiveblameAnnotation
+ syn match FugitiveblameOriginalFile " \%(\f\+\D\@<=\|\D\@=\f\+\)\%(\%(\s\+\d\+\)\=\s\%((\|\s*\d\+)\)\)\@=" contained nextgroup=FugitiveblameOriginalLineNumber,FugitiveblameAnnotation skipwhite
+ syn match FugitiveblameOriginalLineNumber " \@<=\d\+\%(\s(\)\@=" contained nextgroup=FugitiveblameAnnotation skipwhite
+ syn match FugitiveblameOriginalLineNumber " \@<=\d\+\%(\s\+\d\+)\)\@=" contained nextgroup=FugitiveblameShort skipwhite
+ 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 Function
+ 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
+endfunction
+
+" }}}1
+" Gbrowse {{{1
+
+call s:command("-bar -bang -count=0 -nargs=? -complete=customlist,s:EditComplete Gbrowse :execute s:Browse(<bang>0,<line1>,<count>,<f-args>)")
+
+function! s:Browse(bang,line1,count,...) abort
+ try
+ let rev = a:0 ? substitute(a:1,'@[[: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 && a:1 =~# '@[[:alnum:]_-]*\%(://.\{-\}\)\=$'
+ let remote = matchstr(a:1,'@\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(),'\<refs/heads/\zs.*')
+ endif
+ if branch != ''
+ let remote = s:repo().git_chomp('config','branch.'.branch.'.remote')
+ if remote =~# '^\.\=$'
+ let remote = 'origin'
+ elseif rev[0:strlen(branch)-1] ==# branch && rev[strlen(branch)] =~# '[:^~@]'
+ let rev = s:repo().git_chomp('config','branch.'.branch.'.merge')[11:-1] . rev[strlen(branch):-1]
+ endif
+ endif
+ endif
+ endif
+
+ let raw = s:repo().git_chomp('config','remote.'.remote.'.url')
+ if raw ==# ''
+ let raw = remote
+ endif
+
+ let url = s:github_url(s:repo(),raw,rev,commit,path,type,a:line1,a:count)
+ if url == ''
+ let url = s:instaweb_url(s:repo(),rev,commit,path,type,a:count ? a:line1 : 0)
+ endif
+
+ if url == ''
+ call s:throw("Instaweb failed to start and '".remote."' is not a GitHub remote")
+ endif
+
+ if a:bang
+ let @* = url
+ return 'echomsg '.string(url)
+ else
+ return 'echomsg '.string(url).'|call fugitive#buffer().repo().git_chomp("web--browse",'.string(url).')'
+ endif
+ catch /^fugitive:/
+ return 'echoerr v:errmsg'
+ endtry
+endfunction
+
+function! s:github_url(repo,url,rev,commit,path,type,line1,line2) abort
+ let path = a:path
+ let repo_path = matchstr(a:url,'^\%(https\=://\|git://\|git@\)github\.com[/:]\zs.\{-\}\ze\%(\.git\)\=$')
+ if repo_path ==# ''
+ return ''
+ endif
+ let root = 'https://github.com/' . repo_path
+ if path =~# '^\.git/refs/heads/'
+ let branch = a: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:rev =~# '^[[:alnum:]._-]\+:'
+ let commit = matchstr(a:rev,'^[^:]*')
+ elseif a:commit =~# '^\d\=$'
+ let local = matchstr(a:repo.head_ref(),'\<refs/heads/\zs.*')
+ let commit = a:repo.git_chomp('config','branch.'.local.'.merge')[11:-1]
+ if commit ==# ''
+ let commit = local
+ endif
+ else
+ let commit = a:commit
+ endif
+ if a:type == 'tree'
+ let url = s:sub(root . '/tree/' . commit . '/' . path,'/$','')
+ elseif a:type == 'blob'
+ let url = root . '/blob/' . commit . '/' . path
+ if a:line2 && a:line1 == a:line2
+ let url .= '#L' . a:line1
+ elseif a:line2
+ let url .= '#L' . a:line1 . '-' . a:line2
+ endif
+ elseif a:type == 'tag'
+ let commit = matchstr(getline(3),'^tag \zs.*')
+ let url = root . '/tree/' . commit
+ else
+ let url = root . '/commit/' . commit
+ endif
+ return url
+endfunction
+
+function! s:instaweb_url(repo,rev,commit,path,type,...) abort
+ let output = a:repo.git_chomp('instaweb','-b','unknown')
+ if output =~# 'http://'
+ let root = matchstr(output,'http://.*').'/?p='.fnamemodify(a:repo.dir(),':t')
+ else
+ return ''
+ endif
+ if a:path =~# '^\.git/refs/.'
+ return root . ';a=shortlog;h=' . matchstr(a:path,'^\.git/\zs.*')
+ elseif a:path =~# '^\.git\>'
+ return root
+ endif
+ let url = root
+ if a:commit =~# '^\x\{40\}$'
+ if a:type ==# 'commit'
+ let url .= ';a=commit'
+ endif
+ let url .= ';h=' . a:repo.rev_parse(a:commit . (a:path == '' ? '' : ':' . a:path))
+ else
+ if a:type ==# 'blob'
+ let tmp = tempname()
+ silent execute 'write !'.a:repo.git_command('hash-object','-w','--stdin').' > '.tmp
+ let url .= ';h=' . readfile(tmp)[0]
+ else
+ try
+ let url .= ';h=' . a:repo.rev_parse((a:commit == '' ? 'HEAD' : ':' . a:commit) . ':' . a:path)
+ catch /^fugitive:/
+ call s:throw('fugitive: cannot browse uncommitted file')
+ endtry
+ endif
+ let root .= ';hb=' . matchstr(a:repo.head_ref(),'[^ ]\+$')
+ endif
+ if a:path !=# ''
+ let url .= ';f=' . a:path
+ endif
+ if a:0 && a:1
+ let url .= '#l' . a:1
+ endif
+ return url
+endfunction
+
+" }}}1
+" File access {{{1
+
+function! s:ReplaceCmd(cmd,...) abort
+ let fn = bufname('')
+ let tmp = tempname()
+ let prefix = ''
+ try
+ if a:0 && a:1 != ''
+ if &shell =~# 'cmd'
+ 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 &shell =~# 'cmd'
+ call system('cmd /c "'.prefix.a:cmd.' > '.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
+ silent edit!
+ silent exe 'keepalt file '.s:fnameescape(fn)
+ call delete(tmp)
+ if bufname('$') == tmp
+ silent execute 'bwipeout '.bufnr('$')
+ endif
+ silent exe 'doau BufReadPost '.s:fnameescape(fn)
+endfunction
+
+function! s:BufReadIndex()
+ 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
+ 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()
+ try
+ execute cd.'`=s:repo().tree()`'
+ call s:ReplaceCmd(s:repo().git_command('status'),index)
+ finally
+ execute cd.'`=dir`'
+ endtry
+ set ft=gitcommit
+ endif
+ setlocal ro noma nomod nomodeline bufhidden=wipe
+ call s:JumpInit()
+ nunmap <buffer> P
+ nunmap <buffer> ~
+ nnoremap <buffer> <silent> <C-N> :call search('^#\t.*','W')<Bar>.<CR>
+ nnoremap <buffer> <silent> <C-P> :call search('^#\t.*','Wbe')<Bar>.<CR>
+ nnoremap <buffer> <silent> - :<C-U>execute <SID>StageToggle(line('.'),line('.')+v:count1-1)<CR>
+ xnoremap <buffer> <silent> - :<C-U>execute <SID>StageToggle(line("'<"),line("'>"))<CR>
+ nnoremap <buffer> <silent> a :<C-U>let b:fugitive_display_format += 1<Bar>exe <SID>BufReadIndex()<CR>
+ nnoremap <buffer> <silent> i :<C-U>let b:fugitive_display_format -= 1<Bar>exe <SID>BufReadIndex()<CR>
+ nnoremap <buffer> <silent> C :<C-U>Gcommit<CR>
+ nnoremap <buffer> <silent> cA :<C-U>Gcommit --amend --reuse-message=HEAD<CR>
+ nnoremap <buffer> <silent> ca :<C-U>Gcommit --amend<CR>
+ nnoremap <buffer> <silent> cc :<C-U>Gcommit<CR>
+ nnoremap <buffer> <silent> D :<C-U>execute <SID>StageDiff('Gvdiff')<CR>
+ nnoremap <buffer> <silent> dd :<C-U>execute <SID>StageDiff('Gvdiff')<CR>
+ nnoremap <buffer> <silent> dh :<C-U>execute <SID>StageDiff('Gsdiff')<CR>
+ nnoremap <buffer> <silent> ds :<C-U>execute <SID>StageDiff('Gsdiff')<CR>
+ nnoremap <buffer> <silent> dp :<C-U>execute <SID>StageDiffEdit()<CR>
+ nnoremap <buffer> <silent> dv :<C-U>execute <SID>StageDiff('Gvdiff')<CR>
+ nnoremap <buffer> <silent> p :<C-U>execute <SID>StagePatch(line('.'),line('.')+v:count1-1)<CR>
+ xnoremap <buffer> <silent> p :<C-U>execute <SID>StagePatch(line("'<"),line("'>"))<CR>
+ nnoremap <buffer> <silent> q :<C-U>if bufnr('$') == 1<Bar>quit<Bar>else<Bar>bdelete<Bar>endif<CR>
+ nnoremap <buffer> <silent> R :<C-U>edit<CR>
+ catch /^fugitive:/
+ return 'echoerr v:errmsg'
+ endtry
+endfunction
+
+function! s:FileRead()
+ try
+ let repo = s:repo(s:ExtractGitDir(expand('<amatch>')))
+ let path = s:sub(s:sub(matchstr(expand('<amatch>'),'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()
+ try
+ let b:fugitive_type = 'blob'
+ let b:git_dir = s:repo().dir()
+ call s:ReplaceCmd(s:repo().git_command('cat-file','blob',s:buffer().sha1()))
+ if &bufhidden ==# ''
+ setlocal bufhidden=delete
+ endif
+ return ''
+ catch /^fugitive: rev-parse/
+ silent exe 'doau BufNewFile '.s:fnameescape(bufname(''))
+ return ''
+ catch /^fugitive:/
+ return 'echoerr v:errmsg'
+ endtry
+endfunction
+
+function! s:BufWriteIndexFile()
+ let tmp = tempname()
+ try
+ let path = matchstr(expand('<amatch>'),'//\d/\zs.*')
+ let stage = matchstr(expand('<amatch>'),'//\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 has('win32')
+ let error = system('type '.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()
+ 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
+
+ let pos = getpos('.')
+ silent %delete
+ setlocal endofline
+
+ 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))
+ call search('^parent ')
+ if getline('.') ==# 'parent '
+ silent delete_
+ else
+ silent s/\%(^parent\)\@<! /\rparent /ge
+ endif
+ if search('^encoding \%(<unknown>\)\=$','W',line('.')+3)
+ silent delete_
+ end
+ 1
+ endif
+ elseif b:fugitive_type ==# 'blob'
+ call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash))
+ endif
+ call setpos('.',pos)
+ setlocal ro noma nomod nomodeline
+ if &bufhidden ==# ''
+ setlocal bufhidden=delete
+ endif
+ if b:fugitive_type !=# 'blob'
+ set filetype=git
+ nnoremap <buffer> <silent> a :<C-U>let b:fugitive_display_format += v:count1<Bar>exe <SID>BufReadObject()<CR>
+ nnoremap <buffer> <silent> i :<C-U>let b:fugitive_display_format -= v:count1<Bar>exe <SID>BufReadObject()<CR>
+ else
+ call s:JumpInit()
+ endif
+
+ return ''
+ catch /^fugitive:/
+ return 'echoerr v:errmsg'
+ endtry
+endfunction
+
+augroup fugitive_files
+ autocmd!
+ autocmd BufReadCmd *.git/index exe s:BufReadIndex()
+ autocmd BufReadCmd *.git/*index*.lock exe s:BufReadIndex()
+ 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 call s:JumpInit()
+augroup END
+
+" }}}1
+" Temp files {{{1
+
+let s:temp_files = {}
+
+augroup fugitive_temp
+ autocmd!
+ autocmd BufNewFile,BufReadPost *
+ \ if has_key(s:temp_files,expand('<amatch>:p')) |
+ \ let b:git_dir = s:temp_files[expand('<amatch>:p')] |
+ \ let b:git_type = 'temp' |
+ \ call s:Detect(expand('<amatch>:p')) |
+ \ setlocal bufhidden=delete |
+ \ nnoremap <buffer> <silent> q :<C-U>bdelete<CR> |
+ \ endif
+augroup END
+
+" }}}1
+" Go to file {{{1
+
+function! s:JumpInit() abort
+ nnoremap <buffer> <silent> <CR> :<C-U>exe <SID>GF("edit")<CR>
+ if !&modifiable
+ nnoremap <buffer> <silent> o :<C-U>exe <SID>GF("split")<CR>
+ nnoremap <buffer> <silent> O :<C-U>exe <SID>GF("tabedit")<CR>
+ nnoremap <buffer> <silent> P :<C-U>exe <SID>Edit('edit',0,<SID>buffer().commit().'^'.v:count1.<SID>buffer().path(':'))<CR>
+ nnoremap <buffer> <silent> ~ :<C-U>exe <SID>Edit('edit',0,<SID>buffer().commit().'~'.v:count1.<SID>buffer().path(':'))<CR>
+ nnoremap <buffer> <silent> C :<C-U>exe <SID>Edit('edit',0,<SID>buffer().containing_commit())<CR>
+ nnoremap <buffer> <silent> cc :<C-U>exe <SID>Edit('edit',0,<SID>buffer().containing_commit())<CR>
+ nnoremap <buffer> <silent> co :<C-U>exe <SID>Edit('split',0,<SID>buffer().containing_commit())<CR>
+ nnoremap <buffer> <silent> cO :<C-U>exe <SID>Edit('tabedit',0,<SID>buffer().containing_commit())<CR>
+ nnoremap <buffer> <silent> cp :<C-U>exe <SID>Edit('pedit',0,<SID>buffer().containing_commit())<CR>
+ 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("<cfile>")
+ 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\%( (new commits)\)\=$')
+ 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('.') =~# '^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('.')
+ 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
+
+" }}}1
+" Statusline {{{1
+
+function! s:repo_head_ref() dict abort
+ return readfile(s:repo().dir('HEAD'))[0]
+endfunction
+
+call s:add_methods('repo',['head_ref'])
+
+function! fugitive#statusline(...)
+ if !exists('b:git_dir')
+ return ''
+ endif
+ let status = ''
+ if s:buffer().commit() != ''
+ let status .= ':' . s:buffer().commit()[0:7]
+ endif
+ let head = s:repo().head_ref()
+ if head =~# '^ref: '
+ let status .= s:sub(head,'^ref: %(refs/%(heads/|remotes/|tags/)=)=','(').')'
+ elseif head =~# '^\x\{40\}$'
+ let status .= '('.head[0:7].')'
+ endif
+ if &statusline =~# '%[MRHWY]' && &statusline !~# '%[mrhwy]'
+ return ',GIT'.status
+ else
+ return '[Git'.status.']'
+ endif
+endfunction
+
+" }}}1
+
+" vim:set ft=vim ts=8 sw=2 sts=2:
diff --git a/vim/plugin/gist.vim b/vim/plugin/gist.vim
new file mode 100644
index 0000000..9081d00
--- /dev/null
+++ b/vim/plugin/gist.vim
@@ -0,0 +1,826 @@
+"=============================================================================
+" File: gist.vim
+" Author: Yasuhiro Matsumoto <mattn.jp@gmail.com>
+" Last Change: 20-Aug-2011.
+" Version: 5.0
+" WebPage: http://github.com/mattn/gist-vim
+" License: BSD
+" Usage:
+"
+" :Gist
+" post current buffer to gist, using default privicy option
+" (see g:gist_private)
+"
+" :'<,'>Gist
+" post selected text to gist., using default privicy option
+" This applies to all permutations listed below (except multi)
+" (see g:gist_private)
+"
+" :Gist -p
+" create a private gist
+"
+" :Gist -P
+" create a public gist
+" (only relevant if you've set gists to be private by default)
+"
+" :Gist -P
+" post whole text to gist as public
+" This is only relevant if you've set gists to be private by default
+" :Gist -a
+" create a gist anonymously
+"
+" :Gist -m
+" create a gist with all open buffers
+"
+" :Gist -e
+" edit the gist. (you need to have opend the gist buffer first)
+" you can update the gist with :w command on gist buffer
+"
+" :Gist -d
+" delete the gist. (you need to have opend the gist buffer first)
+" password authentication is needed
+"
+" :Gist -f
+" fork the gist. (you need to have opend the gist buffer first)
+" password authentication is needed
+"
+" :Gist -e foo.js
+" edit the gist with name 'foo.js'. (you need to have opend the gist buffer first)
+"
+" :Gist XXXXX
+" get gist XXXXX
+"
+" :Gist -c XXXXX
+" get gist XXXXX and add to clipboard
+"
+" :Gist -l
+" list your public gists
+"
+" :Gist -l mattn
+" list gists from mattn
+"
+" :Gist -la
+" list all your (public and private) gists
+"
+" Tips:
+" * if set g:gist_clip_command, gist.vim will copy the gist code
+" with option '-c'.
+"
+" # mac
+" let g:gist_clip_command = 'pbcopy'
+"
+" # linux
+" let g:gist_clip_command = 'xclip -selection clipboard'
+"
+" # others(cygwin?)
+" let g:gist_clip_command = 'putclip'
+"
+" * if you want to detect filetype from gist's filename...
+"
+" # detect filetype if vim failed auto-detection.
+" let g:gist_detect_filetype = 1
+"
+" # detect filetype always.
+" let g:gist_detect_filetype = 2
+"
+" * if you want to open browser after the post...
+"
+" let g:gist_open_browser_after_post = 1
+"
+" * if you want to change the browser...
+"
+" let g:gist_browser_command = 'w3m %URL%'
+"
+" or
+"
+" let g:gist_browser_command = 'opera %URL% &'
+"
+" on windows, should work with original setting.
+"
+" * if you want to show your private gists with ':Gist -l'
+"
+" let g:gist_show_privates = 1
+"
+" * if don't you want to copy URL of the post...
+"
+" let g:gist_put_url_to_clipboard_after_post = 0
+"
+" or if you want to copy URL and add linefeed at the last of URL,
+"
+" let g:gist_put_url_to_clipboard_after_post = 2
+"
+" default value is 1.
+"
+" Thanks:
+" MATSUU Takuto:
+" removed carriage return
+" gist_browser_command enhancement
+" edit support
+"
+" GetLatestVimScripts: 2423 1 :AutoInstall: gist.vim
+" script type: plugin
+
+if &cp || (exists('g:loaded_gist_vim') && g:loaded_gist_vim)
+ finish
+endif
+let g:loaded_gist_vim = 1
+
+if (!exists('g:github_user') || !exists('g:github_token')) && !executable('git')
+ echohl ErrorMsg | echomsg "Gist: require 'git' command" | echohl None
+ finish
+endif
+
+if !executable('curl')
+ echohl ErrorMsg | echomsg "Gist: require 'curl' command" | echohl None
+ finish
+endif
+
+if !exists('g:gist_open_browser_after_post')
+ let g:gist_open_browser_after_post = 0
+endif
+
+if !exists('g:gist_put_url_to_clipboard_after_post')
+ let g:gist_put_url_to_clipboard_after_post = 1
+endif
+
+if !exists('g:gist_curl_options')
+ let g:gist_curl_options = ""
+endif
+
+if !exists('g:gist_browser_command')
+ if has('win32') || has('win64')
+ let g:gist_browser_command = "!start rundll32 url.dll,FileProtocolHandler %URL%"
+ elseif has('mac')
+ let g:gist_browser_command = "open %URL%"
+ elseif executable('xdg-open')
+ let g:gist_browser_command = "xdg-open %URL%"
+ else
+ let g:gist_browser_command = "firefox %URL% &"
+ endif
+endif
+
+if !exists('g:gist_detect_filetype')
+ let g:gist_detect_filetype = 0
+endif
+
+if !exists('g:gist_private')
+ let g:gist_private = 0
+endif
+
+if !exists('g:gist_show_privates')
+ let g:gist_show_privates = 0
+endif
+
+if !exists('g:gist_cookie_dir')
+ let g:gist_cookie_dir = substitute(expand('<sfile>:p:h'), '[/\\]plugin$', '', '').'/cookies'
+endif
+
+function! s:nr2hex(nr)
+ let n = a:nr
+ let r = ""
+ while n
+ let r = '0123456789ABCDEF'[n % 16] . r
+ let n = n / 16
+ endwhile
+ return r
+endfunction
+
+function! s:encodeURIComponent(instr)
+ let instr = iconv(a:instr, &enc, "utf-8")
+ let len = strlen(instr)
+ let i = 0
+ let outstr = ''
+ while i < len
+ let ch = instr[i]
+ if ch =~# '[0-9A-Za-z-._~!''()*]'
+ let outstr = outstr . ch
+ elseif ch == ' '
+ let outstr = outstr . '+'
+ else
+ let outstr = outstr . '%' . substitute('0' . s:nr2hex(char2nr(ch)), '^.*\(..\)$', '\1', '')
+ endif
+ let i = i + 1
+ endwhile
+ return outstr
+endfunction
+
+" Note: A colon in the file name has side effects on Windows due to NTFS Alternate Data Streams; avoid it.
+let s:bufprefix = 'gist' . (has('unix') ? ':' : '_')
+function! s:GistList(user, token, gistls, page)
+ if a:gistls == '-all'
+ let url = 'https://gist.github.com/gists'
+ elseif g:gist_show_privates && a:gistls == a:user
+ let url = 'https://gist.github.com/mine'
+ else
+ let url = 'https://gist.github.com/'.a:gistls
+ endif
+ let winnum = bufwinnr(bufnr(s:bufprefix.a:gistls))
+ if winnum != -1
+ if winnum != bufwinnr('%')
+ exe winnum 'wincmd w'
+ endif
+ setlocal modifiable
+ else
+ exec 'silent split' s:bufprefix.a:gistls
+ endif
+ if a:page > 1
+ let oldlines = getline(0, line('$'))
+ let url = url . '?page=' . a:page
+ endif
+
+ setlocal foldmethod=manual
+ let oldlines = []
+ if g:gist_show_privates
+ echon 'Login to gist... '
+ silent %d _
+ let res = s:GistGetPage(url, a:user, '', '-L')
+ silent put =res.content
+ else
+ silent %d _
+ exec 'silent r! curl -s' g:gist_curl_options url
+ endif
+
+ 1delete _
+ silent! %s/>/>\r/g
+ silent! %s/</\r</g
+ silent! %g/<pre/,/<\/pre/join!
+ silent! %g/<span class="date"/,/<\/span/join
+ silent! %g/^<span class="date"/s/> */>/g
+ silent! %v/^\(gist:\|<pre>\|<span class="date">\)/d _
+ silent! %s/<div[^>]*>/\r /g
+ silent! %s/<\/pre>/\r/g
+ silent! %g/^gist:/,/<span class="date"/join
+ silent! %s/<[^>]\+>//g
+ silent! %s/\r//g
+ silent! %s/&nbsp;/ /g
+ silent! %s/&quot;/"/g
+ silent! %s/&amp;/\&/g
+ silent! %s/&gt;/>/g
+ silent! %s/&lt;/</g
+ silent! %s/&#\(\d\d\);/\=nr2char(submatch(1))/g
+ silent! %g/^gist: /s/ //g
+
+ call append(0, oldlines)
+ $put='more...'
+
+ let b:user = a:user
+ let b:token = a:token
+ let b:gistls = a:gistls
+ let b:page = a:page
+ setlocal buftype=nofile bufhidden=hide noswapfile
+ setlocal nomodified
+ syntax match SpecialKey /^gist:/he=e-1
+ nnoremap <silent> <buffer> <cr> :call <SID>GistListAction()<cr>
+
+ cal cursor(1+len(oldlines),1)
+ setlocal foldmethod=expr
+ setlocal foldexpr=getline(v:lnum)=~'^\\(gist:\\\|more\\)'?'>1':'='
+ setlocal foldtext=getline(v:foldstart)
+endfunction
+
+function! s:GistGetFileName(gistid)
+ let url = 'https://gist.github.com/'.a:gistid
+ let res = system('curl -s '.g:gist_curl_options.' '.url)
+ let res = substitute(res, '^.*<a href="/raw/[^"]\+/\([^"]\+\)".*$', '\1', '')
+ if res =~ '/'
+ return ''
+ else
+ return res
+ endif
+endfunction
+
+function! s:GistDetectFiletype(gistid)
+ let url = 'https://gist.github.com/'.a:gistid
+ let mx = '^.*<div class=".\{-}type-\([^"]\+\)">.*$'
+ let res = system('curl -s '.g:gist_curl_options.' '.url)
+ let res = substitute(matchstr(res, mx), mx, '\1', '')
+ let res = substitute(res, '.*\(\.[^\.]\+\)$', '\1', '')
+ let res = substitute(res, '-', '', 'g')
+ " TODO: more filetype detection that is specified in html.
+ if res == 'bat' | let res = 'dosbatch' | endif
+ if res == 'as' | let res = 'actionscript' | endif
+ if res == 'bash' | let res = 'sh' | endif
+ if res == 'cl' | let res = 'lisp' | endif
+ if res == 'rb' | let res = 'ruby' | endif
+ if res == 'viml' | let res = 'vim' | endif
+ if res == 'plain' || res == 'text' | let res = '' | endif
+
+ if res =~ '^\.'
+ silent! exec "doau BufRead *".res
+ else
+ silent! exec "setlocal ft=".tolower(res)
+ endif
+endfunction
+
+function! s:GistWrite(fname)
+ if substitute(a:fname, '\\', '/', 'g') == expand("%:p:gs@\\@/@")
+ Gist -e
+ else
+ exe "w".(v:cmdbang ? "!" : "") fnameescape(v:cmdarg) fnameescape(a:fname)
+ silent! exe "file" fnameescape(a:fname)
+ silent! au! BufWriteCmd <buffer>
+ endif
+endfunction
+
+function! s:GistGet(user, token, gistid, clipboard)
+ let url = 'https://raw.github.com/gist/'.a:gistid
+ let winnum = bufwinnr(bufnr(s:bufprefix.a:gistid))
+ if winnum != -1
+ if winnum != bufwinnr('%')
+ exe winnum 'wincmd w'
+ endif
+ setlocal modifiable
+ else
+ exec 'silent split' s:bufprefix.a:gistid
+ endif
+ filetype detect
+ silent %d _
+ exec 'silent 0r! curl -s' g:gist_curl_options url
+ $delete _
+ setlocal buftype=acwrite bufhidden=delete noswapfile
+ setlocal nomodified
+ doau StdinReadPost <buffer>
+ if (&ft == '' && g:gist_detect_filetype == 1) || g:gist_detect_filetype == 2
+ call s:GistDetectFiletype(a:gistid)
+ endif
+ if a:clipboard
+ if exists('g:gist_clip_command')
+ exec 'silent w !'.g:gist_clip_command
+ else
+ %yank +
+ endif
+ endif
+ 1
+ au! BufWriteCmd <buffer> call s:GistWrite(expand("<amatch>"))
+endfunction
+
+function! s:GistListAction()
+ let line = getline('.')
+ let mx = '^gist:\(\w\+\).*'
+ if line =~# mx
+ let gistid = substitute(line, mx, '\1', '')
+ call s:GistGet(g:github_user, g:github_token, gistid, 0)
+ return
+ endif
+ if line =~# '^more\.\.\.$'
+ delete
+ call s:GistList(b:user, b:token, b:gistls, b:page+1)
+ return
+ endif
+endfunction
+
+function! s:GistUpdate(user, token, content, gistid, gistnm)
+ if len(a:gistnm) == 0
+ let name = s:GistGetFileName(a:gistid)
+ else
+ let name = a:gistnm
+ endif
+ let namemx = '^[^.]\+\(.\+\)$'
+ let ext = ''
+ if name =~ namemx
+ let ext = substitute(name, namemx, '\1', '')
+ endif
+ let query = [
+ \ '_method=put',
+ \ 'file_ext[gistfile1%s]=%s',
+ \ 'file_name[gistfile1%s]=%s',
+ \ 'file_contents[gistfile1%s]=%s',
+ \ 'login=%s',
+ \ 'token=%s',
+ \ ]
+ let squery = printf(join(query, '&'),
+ \ s:encodeURIComponent(ext), s:encodeURIComponent(ext),
+ \ s:encodeURIComponent(ext), s:encodeURIComponent(name),
+ \ s:encodeURIComponent(ext), s:encodeURIComponent(a:content),
+ \ s:encodeURIComponent(a:user),
+ \ s:encodeURIComponent(a:token))
+ unlet query
+
+ let file = tempname()
+ call writefile([squery], file)
+ echon 'Updating it to gist... '
+ let quote = &shellxquote == '"' ? "'" : '"'
+ let url = 'https://gist.github.com/gists/'.a:gistid
+ let res = system('curl -i '.g:gist_curl_options.' -d @'.quote.file.quote.' '.url)
+ call delete(file)
+ let headers = split(res, '\(\r\?\n\|\r\n\?\)')
+ let location = matchstr(headers, '^Location: ')
+ let location = substitute(location, '^[^:]\+: ', '', '')
+ if len(location) > 0 && location =~ '^\(http\|https\):\/\/gist\.github\.com\/'
+ setlocal nomodified
+ redraw
+ echo 'Done: '.location
+ else
+ let message = matchstr(headers, '^Status: ')
+ let message = substitute(message, '^[^:]\+: [0-9]\+ ', '', '')
+ echohl ErrorMsg | echomsg 'Edit failed: '.message | echohl None
+ endif
+ return location
+endfunction
+
+function! s:GistGetPage(url, user, param, opt)
+ if !isdirectory(g:gist_cookie_dir)
+ call mkdir(g:gist_cookie_dir, 'p')
+ endif
+ let cookie_file = g:gist_cookie_dir.'/github'
+
+ if len(a:url) == 0
+ call delete(cookie_file)
+ return
+ endif
+
+ let quote = &shellxquote == '"' ? "'" : '"'
+ if !filereadable(cookie_file)
+ let password = inputsecret('Password:')
+ if len(password) == 0
+ echo 'Canceled'
+ return
+ endif
+ let url = 'https://gist.github.com/login?return_to=gist'
+ let res = system('curl -L -s '.g:gist_curl_options.' -c '.quote.cookie_file.quote.' '.quote.url.quote)
+ let token = substitute(res, '^.* name="authenticity_token" type="hidden" value="\([^"]\+\)".*$', '\1', '')
+
+ let query = [
+ \ 'authenticity_token=%s',
+ \ 'login=%s',
+ \ 'password=%s',
+ \ 'return_to=gist',
+ \ 'commit=Log+in',
+ \ ]
+ let squery = printf(join(query, '&'),
+ \ s:encodeURIComponent(token),
+ \ s:encodeURIComponent(a:user),
+ \ s:encodeURIComponent(password))
+ unlet query
+
+ let file = tempname()
+ let command = 'curl -s '.g:gist_curl_options.' -i'
+ let command .= ' -b '.quote.cookie_file.quote
+ let command .= ' -c '.quote.cookie_file.quote
+ let command .= ' '.quote.'https://gist.github.com/session'.quote
+ let command .= ' -d @' . quote.file.quote
+ call writefile([squery], file)
+ let res = system(command)
+ call delete(file)
+ let res = matchstr(split(res, '\(\r\?\n\|\r\n\?\)'), '^Location: ')
+ let res = substitute(res, '^[^:]\+: ', '', '')
+ if len(res) == 0
+ call delete(cookie_file)
+ return ''
+ endif
+ endif
+ let command = 'curl -s '.g:gist_curl_options.' -i '.a:opt
+ if len(a:param)
+ let command .= ' -d '.quote.a:param.quote
+ endif
+ let command .= ' -b '.quote.cookie_file.quote
+ let command .= ' '.quote.a:url.quote
+ let res = iconv(system(command), "utf-8", &encoding)
+ let pos = stridx(res, "\r\n\r\n")
+ if pos != -1
+ let content = res[pos+4:]
+ else
+ let pos = stridx(res, "\n\n")
+ let content = res[pos+2:]
+ endif
+ return {
+ \ "header" : split(res[0:pos], '\r\?\n'),
+ \ "content" : content
+ \}
+endfunction
+
+function! s:GistDelete(user, token, gistid)
+ echon 'Deleting gist... '
+ let res = s:GistGetPage('https://gist.github.com/'.a:gistid, a:user, '', '')
+ if (!len(res))
+ echohl ErrorMsg | echomsg 'Wrong password? no response received from github trying to delete ' . a:gistid | echohl None
+ return
+ endif
+ let mx = '^.* name="authenticity_token" type="hidden" value="\([^"]\+\)".*$'
+ let token = substitute(matchstr(res.content, mx), mx, '\1', '')
+ if len(token) > 0
+ let res = s:GistGetPage('https://gist.github.com/delete/'.a:gistid, a:user, '_method=delete&authenticity_token='.token, '')
+ if len(res.content) > 0
+ redraw
+ echo 'Done: '
+ else
+ let message = matchstr(res.header, '^Status: ')
+ let message = substitute(message, '^[^:]\+: [0-9]\+ ', '', '')
+ echohl ErrorMsg | echomsg 'Delete failed: '.message | echohl None
+ endif
+ else
+ echohl ErrorMsg | echomsg 'Delete failed' | echohl None
+ endif
+endfunction
+
+
+" GistPost function:
+" Post new gist to github
+"
+" if there is an embedded gist url or gist id in your file,
+" it will just update it.
+" -- by c9s
+"
+" embedded gist url format:
+"
+" Gist: https://gist.github.com/123123
+"
+" embedded gist id format:
+"
+" GistID: 123123
+"
+function! s:GistPost(user, token, content, private)
+
+ " find GistID: in content, then we should just update
+ for l in split(a:content, "\n")
+ if l =~ '\<GistID:'
+ let gistid = matchstr(l, 'GistID:\s*[0-9a-z]\+')
+
+ if strlen(gistid) == 0
+ echohl WarningMsg | echo "GistID error" | echohl None
+ return
+ endif
+ echo "Found GistID: " . gistid
+
+ cal s:GistUpdate(a:user, a:token, a:content, gistid, '')
+ return
+ elseif l =~ '\<Gist:'
+ let gistid = matchstr(l, 'Gist:\s*https://gist.github.com/[0-9a-z]\+')
+
+ if strlen(gistid) == 0
+ echohl WarningMsg | echo "GistID error" | echohl None
+ return
+ endif
+ echo "Found GistID: " . gistid
+
+ cal s:GistUpdate(a:user, a:token, a:content, gistid, '')
+ return
+ endif
+ endfor
+
+ let ext = expand('%:e')
+ let ext = len(ext) ? '.'.ext : ''
+ let name = expand('%:t')
+
+ let query = [
+ \ 'file_ext[gistfile1]=%s',
+ \ 'file_name[gistfile1]=%s',
+ \ 'file_contents[gistfile1]=%s',
+ \ ]
+
+ if len(a:user) > 0 && len(a:token) > 0
+ call add(query, 'login=%s')
+ call add(query, 'token=%s')
+ else
+ call add(query, '%.0s%.0s')
+ endif
+
+ if a:private
+ call add(query, 'action_button=private')
+ endif
+ let squery = printf(join(query, '&'),
+ \ s:encodeURIComponent(ext),
+ \ s:encodeURIComponent(name),
+ \ s:encodeURIComponent(a:content),
+ \ s:encodeURIComponent(a:user),
+ \ s:encodeURIComponent(a:token))
+ unlet query
+
+ let file = tempname()
+ call writefile([squery], file)
+ echon 'Posting it to gist... '
+ let quote = &shellxquote == '"' ? "'" : '"'
+ let url = 'https://gist.github.com/gists'
+ let res = system('curl -i '.g:gist_curl_options.' -d @'.quote.file.quote.' '.url)
+ call delete(file)
+ let headers = split(res, '\(\r\?\n\|\r\n\?\)')
+ let location = matchstr(headers, '^Location: ')
+ let location = substitute(location, '^[^:]\+: ', '', '')
+ if len(location) > 0 && location =~ '^\(http\|https\):\/\/gist\.github\.com\/'
+ redraw
+ echo 'Done: '.location
+ else
+ let message = matchstr(headers, '^Status: ')
+ let message = substitute(message, '^[^:]\+: [0-9]\+ ', '', '')
+ echohl ErrorMsg | echomsg 'Post failed: '.message | echohl None
+ endif
+ return location
+endfunction
+
+function! s:GistPostBuffers(user, token, private)
+ let bufnrs = range(1, bufnr("$"))
+ let bn = bufnr('%')
+ let query = []
+ if len(a:user) > 0 && len(a:token) > 0
+ call add(query, 'login=%s')
+ call add(query, 'token=%s')
+ else
+ call add(query, '%.0s%.0s')
+ endif
+ if a:private
+ call add(query, 'action_button=private')
+ endif
+ let squery = printf(join(query, "&"),
+ \ s:encodeURIComponent(a:user),
+ \ s:encodeURIComponent(a:token)) . '&'
+
+ let query = [
+ \ 'file_ext[gistfile]=%s',
+ \ 'file_name[gistfile]=%s',
+ \ 'file_contents[gistfile]=%s',
+ \ ]
+ let format = join(query, "&") . '&'
+
+ let index = 1
+ for bufnr in bufnrs
+ if !bufexists(bufnr) || buflisted(bufnr) == 0
+ continue
+ endif
+ echo "Creating gist content".index."... "
+ silent! exec "buffer!" bufnr
+ let content = join(getline(1, line('$')), "\n")
+ let ext = expand('%:e')
+ let ext = len(ext) ? '.'.ext : ''
+ let name = expand('%:t')
+ let squery .= printf(substitute(format, 'gistfile', 'gistfile'.index, 'g'),
+ \ s:encodeURIComponent(ext),
+ \ s:encodeURIComponent(name),
+ \ s:encodeURIComponent(content))
+ let index = index + 1
+ endfor
+ silent! exec "buffer!" bn
+
+ let file = tempname()
+ call writefile([squery], file)
+ echo "Posting it to gist... "
+ let quote = &shellxquote == '"' ? "'" : '"'
+ let url = 'https://gist.github.com/gists'
+ let res = system('curl -i '.g:gist_curl_options.' -d @'.quote.file.quote.' '.url)
+ call delete(file)
+ let res = matchstr(split(res, '\(\r\?\n\|\r\n\?\)'), '^Location: ')
+ let res = substitute(res, '^.*: ', '', '')
+ if len(res) > 0 && res =~ '^\(http\|https\):\/\/gist\.github\.com\/'
+ redraw
+ echo 'Done: '.res
+ else
+ echohl ErrorMsg | echomsg 'Post failed' | echohl None
+ endif
+ return res
+endfunction
+
+function! Gist(line1, line2, ...)
+ if !exists('g:github_user')
+ let g:github_user = substitute(system('git config --global github.user'), "\n", '', '')
+ if strlen(g:github_user) == 0
+ let g:github_user = $GITHUB_USER
+ end
+ endif
+ if !exists('g:github_token')
+ let g:github_token = substitute(system('git config --global github.token'), "\n", '', '')
+ if strlen(g:github_token) == 0
+ let g:github_token = $GITHUB_TOKEN
+ end
+ endif
+ if strlen(g:github_user) == 0 || strlen(g:github_token) == 0
+ echohl ErrorMsg
+ echomsg "You have no setting for github."
+ echohl WarningMsg
+ echo "git config --global github.user your-name"
+ echo "git config --global github.token your-token"
+ echo "or set g:github_user and g:github_token in your vimrc"
+ echo "or set shell env vars GITHUB_USER and GITHUB_TOKEN"
+ echohl None
+ return 0
+ end
+
+ let bufname = bufname("%")
+ let user = g:github_user
+ let token = g:github_token
+ let gistid = ''
+ let gistls = ''
+ let gistnm = ''
+ let private = g:gist_private
+ let multibuffer = 0
+ let clipboard = 0
+ let deletepost = 0
+ let editpost = 0
+ let listmx = '^\(-l\|--list\)\s*\([^\s]\+\)\?$'
+ let bufnamemx = '^' . s:bufprefix .'\([0-9a-f]\+\)$'
+
+ let args = (a:0 > 0) ? split(a:1, ' ') : []
+ for arg in args
+ if arg =~ '^\(-la\|--listall\)$\C'
+ let gistls = '-all'
+ elseif arg =~ '^\(-l\|--list\)$\C'
+ if g:gist_show_privates
+ let gistls = 'mine'
+ else
+ let gistls = g:github_user
+ endif
+ elseif arg == '--abandon\C'
+ call s:GistGetPage('', '', '', '')
+ return
+ elseif arg =~ '^\(-m\|--multibuffer\)$\C'
+ let multibuffer = 1
+ elseif arg =~ '^\(-p\|--private\)$\C'
+ let private = 1
+ elseif arg =~ '^\(-P\|--public\)$\C'
+ let private = 0
+ elseif arg =~ '^\(-a\|--anonymous\)$\C'
+ let user = ''
+ let token = ''
+ elseif arg =~ '^\(-c\|--clipboard\)$\C'
+ let clipboard = 1
+ elseif arg =~ '^\(-d\|--delete\)$\C' && bufname =~ bufnamemx
+ let deletepost = 1
+ let gistid = substitute(bufname, bufnamemx, '\1', '')
+ elseif arg =~ '^\(-e\|--edit\)$\C' && bufname =~ bufnamemx
+ let editpost = 1
+ let gistid = substitute(bufname, bufnamemx, '\1', '')
+ elseif arg =~ '^\(-f\|--fork\)$\C' && bufname =~ bufnamemx
+ let gistid = substitute(bufname, bufnamemx, '\1', '')
+ let res = s:GistGetPage("https://gist.github.com/fork/".gistid, g:github_user, '', '')
+ let loc = filter(res.header, 'v:val =~ "^Location:"')[0]
+ let loc = substitute(loc, '^[^:]\+: ', '', '')
+ let mx = '^https://gist.github.com/\([0-9a-z]\+\)$'
+ if loc =~ mx
+ let gistid = substitute(loc, mx, '\1', '')
+ else
+ echohl ErrorMsg | echomsg 'Fork failed' | echohl None
+ return
+ endif
+ elseif arg !~ '^-' && len(gistnm) == 0
+ if editpost == 1 || deletepost == 1
+ let gistnm = arg
+ elseif len(gistls) > 0 && arg != '^\w\+$\C'
+ let gistls = arg
+ elseif arg =~ '^[0-9a-z]\+$\C'
+ let gistid = arg
+ else
+ echohl ErrorMsg | echomsg 'Invalid arguments' | echohl None
+ unlet args
+ return 0
+ endif
+ elseif len(arg) > 0
+ echohl ErrorMsg | echomsg 'Invalid arguments' | echohl None
+ unlet args
+ return 0
+ endif
+ endfor
+ unlet args
+ "echo "gistid=".gistid
+ "echo "gistls=".gistls
+ "echo "gistnm=".gistnm
+ "echo "private=".private
+ "echo "clipboard=".clipboard
+ "echo "editpost=".editpost
+ "echo "deletepost=".deletepost
+
+ if len(gistls) > 0
+ call s:GistList(user, token, gistls, 1)
+ elseif len(gistid) > 0 && editpost == 0 && deletepost == 0
+ call s:GistGet(user, token, gistid, clipboard)
+ else
+ let url = ''
+ if multibuffer == 1
+ let url = s:GistPostBuffers(user, token, private)
+ else
+ let content = join(getline(a:line1, a:line2), "\n")
+ if editpost == 1
+ let url = s:GistUpdate(user, token, content, gistid, gistnm)
+ elseif deletepost == 1
+ call s:GistDelete(user, token, gistid)
+ else
+ let url = s:GistPost(user, token, content, private)
+ endif
+ endif
+ if len(url) > 0
+ if g:gist_open_browser_after_post
+ let cmd = substitute(g:gist_browser_command, '%URL%', url, 'g')
+ if cmd =~ '^!'
+ silent! exec cmd
+ elseif cmd =~ '^:[A-Z]'
+ exec cmd
+ else
+ call system(cmd)
+ endif
+ endif
+ if g:gist_put_url_to_clipboard_after_post > 0
+ if g:gist_put_url_to_clipboard_after_post == 2
+ let url = url . "\n"
+ endif
+ if exists('g:gist_clip_command')
+ call system(g:gist_clip_command, url)
+ elseif has('unix') && !has('xterm_clipboard')
+ let @" = url
+ else
+ let @+ = url
+ endif
+ endif
+ endif
+ endif
+ return 1
+endfunction
+
+command! -nargs=? -range=% Gist :call Gist(<line1>, <line2>, <f-args>)
+" vim:set et:
diff --git a/vim/plugin/indent-object.vim b/vim/plugin/indent-object.vim
new file mode 100644
index 0000000..afb8edd
--- /dev/null
+++ b/vim/plugin/indent-object.vim
@@ -0,0 +1,224 @@
+"--------------------------------------------------------------------------------
+"
+" Copyright (c) 2010 Michael Smith <msmith@msmith.id.au>
+"
+" http://github.com/michaeljsmith/vim-indent-object
+"
+" Permission is hereby granted, free of charge, to any person obtaining a copy
+" of this software and associated documentation files (the "Software"), to
+" deal in the Software without restriction, including without limitation the
+" rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+" sell copies of the Software, and to permit persons to whom the Software is
+" furnished to do so, subject to the following conditions:
+"
+" The above copyright notice and this permission notice shall be included in
+" all copies or substantial portions of the Software.
+"
+" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+" FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+" IN THE SOFTWARE.
+"
+"--------------------------------------------------------------------------------
+
+" Mappings excluding line below.
+onoremap <silent>ai :<C-u>cal <Sid>HandleTextObjectMapping(0, 0, 0, [line("."), line("."), col("."), col(".")])<CR>
+onoremap <silent>ii :<C-u>cal <Sid>HandleTextObjectMapping(1, 0, 0, [line("."), line("."), col("."), col(".")])<CR>
+vnoremap <silent>ai :<C-u>cal <Sid>HandleTextObjectMapping(0, 0, 1, [line("'<"), line("'>"), col("'<"), col("'>")])<CR><Esc>gv
+vnoremap <silent>ii :<C-u>cal <Sid>HandleTextObjectMapping(1, 0, 1, [line("'<"), line("'>"), col("'<"), col("'>")])<CR><Esc>gv
+
+" Mappings including line below.
+onoremap <silent>aI :<C-u>cal <Sid>HandleTextObjectMapping(0, 1, 0, [line("."), line("."), col("."), col(".")])<CR>
+onoremap <silent>iI :<C-u>cal <Sid>HandleTextObjectMapping(1, 1, 0, [line("."), line("."), col("."), col(".")])<CR>
+vnoremap <silent>aI :<C-u>cal <Sid>HandleTextObjectMapping(0, 1, 1, [line("'<"), line("'>"), col("'<"), col("'>")])<CR><Esc>gv
+vnoremap <silent>iI :<C-u>cal <Sid>HandleTextObjectMapping(1, 1, 1, [line("'<"), line("'>"), col("'<"), col("'>")])<CR><Esc>gv
+
+let s:l0 = -1
+let s:l1 = -1
+let s:c0 = -1
+let s:c1 = -1
+
+function! <Sid>TextObject(inner, incbelow, vis, range, count)
+
+ " Record the current state of the visual region.
+ let vismode = "V"
+
+ " Detect if this is a completely new visual selction session.
+ let new_vis = 0
+ let new_vis = new_vis || s:l0 != a:range[0]
+ let new_vis = new_vis || s:l1 != a:range[1]
+ let new_vis = new_vis || s:c0 != a:range[2]
+ let new_vis = new_vis || s:c1 != a:range[3]
+
+ let s:l0 = a:range[0]
+ let s:l1 = a:range[1]
+ let s:c0 = a:range[2]
+ let s:c1 = a:range[3]
+
+ " Repeatedly increase the scope of the selection.
+ let itr_cnt = 0
+ let cnt = a:count
+ while cnt > 0
+
+ " Look for the minimum indentation in the current visual region.
+ let l = s:l0
+ let idnt_invalid = 1000
+ let idnt = idnt_invalid
+ while l <= s:l1
+ if !(getline(l) =~ "^\\s*$")
+ let idnt = min([idnt, indent(l)])
+ endif
+ let l += 1
+ endwhile
+
+ " Keep track of where the range should be expanded to.
+ let l_1 = s:l0
+ let l_1o = l_1
+ let l2 = s:l1
+ let l2o = l2
+
+ " If we are highlighting only blank lines, we may not have found a
+ " valid indent. In this case we need to look for the next and previous
+ " non blank lines and check which of those has the largest indent.
+ if idnt == idnt_invalid
+ let idnt = 0
+ let pnb = prevnonblank(s:l0)
+ if pnb
+ let idnt = max([idnt, indent(pnb)])
+ let l_1 = pnb
+ endif
+ let nnb = nextnonblank(s:l0)
+ if nnb
+ let idnt = max([idnt, indent(nnb)])
+ endif
+
+ " If we are in whitespace at the beginning of a block, skip over
+ " it when we are selecting the range. Similarly, if we are in
+ " whitespace at the end, ignore it.
+ if idnt > indent(pnb)
+ let l_1 = nnb
+ endif
+ if idnt > indent(nnb)
+ let l2 = pnb
+ endif
+ endif
+
+ " Search backward for the first line with less indent than the target
+ " indent (skipping blank lines).
+ let blnk = getline(l_1) =~ "^\\s*$"
+ while l_1 > 0 && ((idnt == 0 && !blnk) || (idnt != 0 && (blnk || indent(l_1) >= idnt)))
+ if !blnk || !a:inner
+ let l_1o = l_1
+ endif
+ let l_1 -= 1
+ let blnk = getline(l_1) =~ "^\\s*$"
+ endwhile
+
+ " Search forward for the first line with more indent than the target
+ " indent (skipping blank lines).
+ let line_cnt = line("$")
+ let blnk = getline(l2) =~ "^\\s*$"
+ while l2 <= line_cnt && ((idnt == 0 && !blnk) || (idnt != 0 && (blnk || indent(l2) >= idnt)))
+ if !blnk || !a:inner
+ let l2o = l2
+ endif
+ let l2 += 1
+ let blnk = getline(l2) =~ "^\\s*$"
+ endwhile
+
+ " Determine which of these extensions to include. Include neither if
+ " we are selecting an 'inner' object. Exclude the bottom unless are
+ " told to include it.
+ let idnt2 = max([indent(l_1), indent(l2)])
+ if indent(l_1) < idnt2 || a:inner
+ let l_1 = l_1o
+ endif
+ if indent(l2) < idnt2 || a:inner || !a:incbelow
+ let l2 = l2o
+ endif
+ let l_1 = max([l_1, 1])
+ let l2 = min([l2, line("$")])
+
+ " Extend the columns to the start and end.
+ " If inner is selected, set the final cursor pos to the start
+ " of the text in the line.
+ let c_1 = 1
+ if a:inner
+ let c_1 = match(getline(l_1), "\\c\\S") + 1
+ endif
+ let c2 = len(getline(l2))
+ if !a:inner
+ let c2 += 1
+ endif
+
+ " Make sure there's no change if we haven't really made a
+ " significant change in linewise mode - this makes sure that
+ " we can iteratively increase selection in linewise mode.
+ if itr_cnt == 0 && vismode ==# 'V' && s:l0 == l_1 && s:l1 == l2
+ let c_1 = s:c0
+ let c2 = s:c1
+ endif
+
+ " Check whether the visual region has changed.
+ let chg = 0
+ let chg = chg || s:l0 != l_1
+ let chg = chg || s:l1 != l2
+ let chg = chg || s:c0 != c_1
+ let chg = chg || s:c1 != c2
+
+ if vismode ==# 'V' && new_vis
+ let chg = 1
+ endif
+
+ " Update the vars.
+ let s:l0 = l_1
+ let s:l1 = l2
+ let s:c0 = c_1
+ let s:c1 = c2
+
+ " If there was no change, then don't decrement the count (it didn't
+ " count because it didn't do anything).
+ if chg
+ let cnt = cnt - 1
+ else
+ " Since this didn't work, push the selection back one char. This
+ " will have the effect of getting the enclosing block. Do it at
+ " the beginning rather than the end - the beginning is very likely
+ " to be only one indentation level different.
+ if s:l0 == 0
+ return
+ endif
+ let s:l0 -= 1
+ let s:c0 = len(getline(s:l0))
+ endif
+
+ let itr_cnt += 1
+
+ endwhile
+
+ " Apply the range we have found. Make sure to use the current visual mode.
+ call cursor(s:l0, s:c0)
+ exe "normal! " . vismode
+ call cursor(s:l1, s:c1)
+ normal! o
+
+ " Update these static variables - we need to keep these up-to-date between
+ " invocations because it's the only way we can detect whether it's a new
+ " visual mode. We need to know if it's a new visual mode because otherwise
+ " if there's a single line block in visual line mode and we select it with
+ " "V", we can't tell whether it's already been selected using Vii.
+ exe "normal! \<Esc>"
+ let s:l0 = line("'<")
+ let s:l1 = line("'>")
+ let s:c0 = col("'<")
+ let s:c1 = col("'>")
+ normal gv
+
+endfunction
+
+function! <Sid>HandleTextObjectMapping(inner, incbelow, vis, range)
+ call <Sid>TextObject(a:inner, a:incbelow, a:vis, a:range, v:count1)
+endfunction
diff --git a/vim/plugin/rails.vim b/vim/plugin/rails.vim
new file mode 100644
index 0000000..2dd17f7
--- /dev/null
+++ b/vim/plugin/rails.vim
@@ -0,0 +1,339 @@
+" rails.vim - Detect a rails application
+" Author: Tim Pope <http://tpo.pe/>
+" GetLatestVimScripts: 1567 1 :AutoInstall: rails.vim
+
+" Install this file as plugin/rails.vim. See doc/rails.txt for details. (Grab
+" it from the URL above if you don't have it.) To access it from Vim, see
+" :help add-local-help (hint: :helptags ~/.vim/doc) Afterwards, you should be
+" able to do :help rails
+
+if exists('g:loaded_rails') || &cp || v:version < 700
+ finish
+endif
+let g:loaded_rails = 1
+
+" Utility Functions {{{1
+
+function! s:error(str)
+ echohl ErrorMsg
+ echomsg a:str
+ echohl None
+ let v:errmsg = a:str
+endfunction
+
+function! s:autoload(...)
+ if !exists("g:autoloaded_rails") && v:version >= 700
+ runtime! autoload/rails.vim
+ endif
+ if exists("g:autoloaded_rails")
+ if a:0
+ exe a:1
+ endif
+ return 1
+ endif
+ if !exists("g:rails_no_autoload_warning")
+ let g:rails_no_autoload_warning = 1
+ if v:version >= 700
+ call s:error("Disabling rails.vim: autoload/rails.vim is missing")
+ else
+ call s:error("Disabling rails.vim: Vim version 7 or higher required")
+ endif
+ endif
+ return ""
+endfunction
+
+" }}}1
+" Configuration {{{
+
+function! s:SetOptDefault(opt,val)
+ if !exists("g:".a:opt)
+ let g:{a:opt} = a:val
+ endif
+endfunction
+
+call s:SetOptDefault("rails_statusline",1)
+call s:SetOptDefault("rails_syntax",1)
+call s:SetOptDefault("rails_mappings",1)
+call s:SetOptDefault("rails_abbreviations",1)
+call s:SetOptDefault("rails_ctags_arguments","--languages=-javascript")
+call s:SetOptDefault("rails_default_file","README")
+call s:SetOptDefault("rails_root_url",'http://localhost:3000/')
+call s:SetOptDefault("rails_modelines",0)
+call s:SetOptDefault("rails_menu",0)
+call s:SetOptDefault("rails_gnu_screen",1)
+call s:SetOptDefault("rails_history_size",5)
+call s:SetOptDefault("rails_generators","controller\ngenerator\nhelper\nintegration_test\nmailer\nmetal\nmigration\nmodel\nobserver\nperformance_test\nplugin\nresource\nscaffold\nscaffold_controller\nsession_migration\nstylesheets")
+if exists("g:loaded_dbext") && executable("sqlite3") && ! executable("sqlite")
+ " Since dbext can't find it by itself
+ call s:SetOptDefault("dbext_default_SQLITE_bin","sqlite3")
+endif
+
+" }}}1
+" Detection {{{1
+
+function! s:escvar(r)
+ let r = fnamemodify(a:r,':~')
+ let r = substitute(r,'\W','\="_".char2nr(submatch(0))."_"','g')
+ let r = substitute(r,'^\d','_&','')
+ return r
+endfunction
+
+function! s:Detect(filename)
+ let fn = substitute(fnamemodify(a:filename,":p"),'\c^file://','','')
+ let sep = matchstr(fn,'^[^\\/]\{3,\}\zs[\\/]')
+ if sep != ""
+ let fn = getcwd().sep.fn
+ endif
+ if fn =~ '[\/]config[\/]environment\.rb$'
+ return s:BufInit(strpart(fn,0,strlen(fn)-22))
+ endif
+ if isdirectory(fn)
+ let fn = fnamemodify(fn,':s?[\/]$??')
+ else
+ let fn = fnamemodify(fn,':s?\(.*\)[\/][^\/]*$?\1?')
+ endif
+ let ofn = ""
+ let nfn = fn
+ while nfn != ofn && nfn != ""
+ if exists("s:_".s:escvar(nfn))
+ return s:BufInit(nfn)
+ endif
+ let ofn = nfn
+ let nfn = fnamemodify(nfn,':h')
+ endwhile
+ let ofn = ""
+ while fn != ofn
+ if filereadable(fn . "/config/environment.rb")
+ return s:BufInit(fn)
+ endif
+ let ofn = fn
+ let fn = fnamemodify(ofn,':s?\(.*\)[\/]\(app\|config\|db\|doc\|features\|lib\|log\|public\|script\|spec\|stories\|test\|tmp\|vendor\)\($\|[\/].*$\)?\1?')
+ endwhile
+ return 0
+endfunction
+
+function! s:BufInit(path)
+ let s:_{s:escvar(a:path)} = 1
+ if s:autoload()
+ return RailsBufInit(a:path)
+ endif
+endfunction
+
+" }}}1
+" Initialization {{{1
+
+augroup railsPluginDetect
+ autocmd!
+ autocmd BufNewFile,BufRead * call s:Detect(expand("<afile>:p"))
+ autocmd VimEnter * if expand("<amatch>") == "" && !exists("b:rails_root") | call s:Detect(getcwd()) | endif | if exists("b:rails_root") | silent doau User BufEnterRails | endif
+ autocmd FileType netrw if !exists("b:rails_root") | call s:Detect(expand("<afile>:p")) | endif | if exists("b:rails_root") | silent doau User BufEnterRails | endif
+ autocmd BufEnter * if exists("b:rails_root")|silent doau User BufEnterRails|endif
+ autocmd BufLeave * if exists("b:rails_root")|silent doau User BufLeaveRails|endif
+ autocmd Syntax railslog if s:autoload()|call rails#log_syntax()|endif
+augroup END
+
+command! -bar -bang -nargs=* -complete=dir Rails :if s:autoload()|call rails#new_app_command(<bang>0,<f-args>)|endif
+
+" }}}1
+" abolish.vim support {{{1
+
+function! s:function(name)
+ return function(substitute(a:name,'^s:',matchstr(expand('<sfile>'), '<SNR>\d\+_'),''))
+endfunction
+
+augroup railsPluginAbolish
+ autocmd!
+ autocmd VimEnter * call s:abolish_setup()
+augroup END
+
+function! s:abolish_setup()
+ if exists('g:Abolish') && has_key(g:Abolish,'Coercions')
+ if !has_key(g:Abolish.Coercions,'l')
+ let g:Abolish.Coercions.l = s:function('s:abolish_l')
+ endif
+ if !has_key(g:Abolish.Coercions,'t')
+ let g:Abolish.Coercions.t = s:function('s:abolish_t')
+ endif
+ endif
+endfunction
+
+function! s:abolish_l(word)
+ let singular = rails#singularize(a:word)
+ return a:word ==? singular ? rails#pluralize(a:word) : singular
+endfunction
+
+function! s:abolish_t(word)
+ if a:word =~# '\u'
+ return rails#pluralize(rails#underscore(a:word))
+ else
+ return rails#singularize(rails#camelize(a:word))
+ endif
+endfunction
+
+" }}}1
+" Menus {{{1
+
+if !(g:rails_menu && has("menu"))
+ finish
+endif
+
+function! s:sub(str,pat,rep)
+ return substitute(a:str,'\v\C'.a:pat,a:rep,'')
+endfunction
+
+function! s:gsub(str,pat,rep)
+ return substitute(a:str,'\v\C'.a:pat,a:rep,'g')
+endfunction
+
+function! s:menucmd(priority)
+ return 'anoremenu <script> '.(exists("$CREAM") ? 87 : '').s:gsub(g:rails_installed_menu,'[^.]','').'.'.a:priority.' '
+endfunction
+
+function! s:CreateMenus() abort
+ if exists("g:rails_installed_menu") && g:rails_installed_menu != ""
+ exe "aunmenu ".s:gsub(g:rails_installed_menu,'\&','')
+ unlet g:rails_installed_menu
+ endif
+ if has("menu") && (exists("g:did_install_default_menus") || exists("$CREAM")) && g:rails_menu
+ if g:rails_menu > 1
+ let g:rails_installed_menu = '&Rails'
+ else
+ let g:rails_installed_menu = '&Plugin.&Rails'
+ endif
+ let dots = s:gsub(g:rails_installed_menu,'[^.]','')
+ let menucmd = s:menucmd(200)
+ if exists("$CREAM")
+ exe menucmd.g:rails_installed_menu.'.-PSep- :'
+ exe menucmd.g:rails_installed_menu.'.&Related\ file\ :R\ /\ Alt+] :R<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Alternate\ file\ :A\ /\ Alt+[ :A<CR>'
+ exe menucmd.g:rails_installed_menu.'.&File\ under\ cursor\ Ctrl+Enter :Rfind<CR>'
+ else
+ exe menucmd.g:rails_installed_menu.'.-PSep- :'
+ exe menucmd.g:rails_installed_menu.'.&Related\ file\ :R\ /\ ]f :R<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Alternate\ file\ :A\ /\ [f :A<CR>'
+ exe menucmd.g:rails_installed_menu.'.&File\ under\ cursor\ gf :Rfind<CR>'
+ endif
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.Application\ &Controller :Rcontroller application<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.Application\ &Helper :Rhelper application<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.Application\ &Javascript :Rjavascript application<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.Application\ &Layout :Rlayout application<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.Application\ &README :R doc/README_FOR_APP<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.&Environment :Renvironment<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.&Database\ Configuration :R config/database.yml<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.Database\ &Schema :Rmigration 0<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.R&outes :Rinitializer<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.&Test\ Helper :Rintegrationtest<CR>'
+ exe menucmd.g:rails_installed_menu.'.-FSep- :'
+ exe menucmd.g:rails_installed_menu.'.Ra&ke\ :Rake :Rake<CR>'
+ let menucmd = substitute(menucmd,'200 $','500 ','')
+ exe menucmd.g:rails_installed_menu.'.&Server\ :Rserver.&Start\ :Rserver :Rserver<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Server\ :Rserver.&Force\ start\ :Rserver! :Rserver!<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Server\ :Rserver.&Kill\ :Rserver!\ - :Rserver! -<CR>'
+ exe substitute(menucmd,'<script>','<script> <silent>','').g:rails_installed_menu.'.&Evaluate\ Ruby\.\.\.\ :Rp :call <SID>menuprompt("Rp","Code to execute and output: ")<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Console\ :Rscript :Rscript console<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Preview\ :Rpreview :Rpreview<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Log\ file\ :Rlog :Rlog<CR>'
+ exe substitute(s:sub(menucmd,'anoremenu','vnoremenu'),'<script>','<script> <silent>','').g:rails_installed_menu.'.E&xtract\ as\ partial\ :Rextract :call <SID>menuprompt("'."'".'<,'."'".'>Rextract","Partial name (e.g., template or /controller/template): ")<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Migration\ writer\ :Rinvert :Rinvert<CR>'
+ exe menucmd.' '.g:rails_installed_menu.'.-HSep- :'
+ exe substitute(menucmd,'<script>','<script> <silent>','').g:rails_installed_menu.'.&Help\ :help\ rails :if <SID>autoload()<Bar>exe RailsHelpCommand("")<Bar>endif<CR>'
+ exe substitute(menucmd,'<script>','<script> <silent>','').g:rails_installed_menu.'.Abo&ut\ :if <SID>autoload()<Bar>exe RailsHelpCommand("about")<Bar>endif<CR>'
+ let g:rails_did_menus = 1
+ call s:ProjectMenu()
+ call s:menuBufLeave()
+ if exists("b:rails_root")
+ call s:menuBufEnter()
+ endif
+ endif
+endfunction
+
+function! s:ProjectMenu()
+ if exists("g:rails_did_menus") && g:rails_history_size > 0
+ if !exists("g:RAILS_HISTORY")
+ let g:RAILS_HISTORY = ""
+ endif
+ let history = g:RAILS_HISTORY
+ let menu = s:gsub(g:rails_installed_menu,'\&','')
+ silent! exe "aunmenu <script> ".menu.".Projects"
+ let dots = s:gsub(menu,'[^.]','')
+ exe 'anoremenu <script> <silent> '.(exists("$CREAM") ? '87' : '').dots.'.100 '.menu.'.Pro&jects.&New\.\.\.\ :Rails :call <SID>menuprompt("Rails","New application path and additional arguments: ")<CR>'
+ exe 'anoremenu <script> '.menu.'.Pro&jects.-FSep- :'
+ while history =~ '\n'
+ let proj = matchstr(history,'^.\{-\}\ze\n')
+ let history = s:sub(history,'^.{-}\n','')
+ exe 'anoremenu <script> '.menu.'.Pro&jects.'.s:gsub(proj,'[.\\ ]','\\&').' :e '.s:gsub(proj."/".g:rails_default_file,'[ !%#]','\\&')."<CR>"
+ endwhile
+ endif
+endfunction
+
+function! s:menuBufEnter()
+ if exists("g:rails_installed_menu") && g:rails_installed_menu != ""
+ let menu = s:gsub(g:rails_installed_menu,'\&','')
+ exe 'amenu enable '.menu.'.*'
+ if RailsFileType() !~ '^view\>'
+ exe 'vmenu disable '.menu.'.Extract\ as\ partial'
+ endif
+ if RailsFileType() !~ '^\%(db-\)\=migration$' || RailsFilePath() =~ '\<db/schema\.rb$'
+ exe 'amenu disable '.menu.'.Migration\ writer'
+ endif
+ call s:ProjectMenu()
+ silent! exe 'aunmenu '.menu.'.Rake\ tasks'
+ silent! exe 'aunmenu '.menu.'.Generate'
+ silent! exe 'aunmenu '.menu.'.Destroy'
+ if rails#app().cache.needs('rake_tasks') || empty(rails#app().rake_tasks())
+ exe substitute(s:menucmd(300),'<script>','<script> <silent>','').g:rails_installed_menu.'.Rake\ &tasks\ :Rake.Fill\ this\ menu :call rails#app().rake_tasks()<Bar>call <SID>menuBufLeave()<Bar>call <SID>menuBufEnter()<CR>'
+ else
+ let i = 0
+ while i < len(rails#app().rake_tasks())
+ let task = rails#app().rake_tasks()[i]
+ exe s:menucmd(300).g:rails_installed_menu.'.Rake\ &tasks\ :Rake.'.s:sub(task,':',':.').' :Rake '.task.'<CR>'
+ let i += 1
+ endwhile
+ endif
+ let i = 0
+ let menucmd = substitute(s:menucmd(400),'<script>','<script> <silent>','').g:rails_installed_menu
+ while i < len(rails#app().generators())
+ let generator = rails#app().generators()[i]
+ exe menucmd.'.&Generate\ :Rgen.'.s:gsub(generator,'_','\\ ').' :call <SID>menuprompt("Rgenerate '.generator.'","Arguments for script/generate '.generator.': ")<CR>'
+ exe menucmd.'.&Destroy\ :Rdestroy.'.s:gsub(generator,'_','\\ ').' :call <SID>menuprompt("Rdestroy '.generator.'","Arguments for script/destroy '.generator.': ")<CR>'
+ let i += 1
+ endwhile
+ endif
+endfunction
+
+function! s:menuBufLeave()
+ if exists("g:rails_installed_menu") && g:rails_installed_menu != ""
+ let menu = s:gsub(g:rails_installed_menu,'\&','')
+ exe 'amenu disable '.menu.'.*'
+ exe 'amenu enable '.menu.'.Help\ '
+ exe 'amenu enable '.menu.'.About\ '
+ exe 'amenu enable '.menu.'.Projects'
+ silent! exe 'aunmenu '.menu.'.Rake\ tasks'
+ silent! exe 'aunmenu '.menu.'.Generate'
+ silent! exe 'aunmenu '.menu.'.Destroy'
+ exe s:menucmd(300).g:rails_installed_menu.'.Rake\ tasks\ :Rake.-TSep- :'
+ exe s:menucmd(400).g:rails_installed_menu.'.&Generate\ :Rgen.-GSep- :'
+ exe s:menucmd(400).g:rails_installed_menu.'.&Destroy\ :Rdestroy.-DSep- :'
+ endif
+endfunction
+
+function! s:menuprompt(vimcmd,prompt)
+ let res = inputdialog(a:prompt,'','!!!')
+ if res == '!!!'
+ return ""
+ endif
+ exe a:vimcmd." ".res
+endfunction
+
+call s:CreateMenus()
+
+augroup railsPluginMenu
+ autocmd!
+ autocmd User BufEnterRails call s:menuBufEnter()
+ autocmd User BufLeaveRails call s:menuBufLeave()
+ " g:RAILS_HISTORY hasn't been set when s:InitPlugin() is called.
+ autocmd VimEnter * call s:ProjectMenu()
+augroup END
+
+" }}}1
+" vim:set sw=2 sts=2:
diff --git a/vim/plugin/searchfold_0.9.vim b/vim/plugin/searchfold_0.9.vim
new file mode 100644
index 0000000..1fb9ba8
--- /dev/null
+++ b/vim/plugin/searchfold_0.9.vim
@@ -0,0 +1,319 @@
+" Vim global plugin -- create folds based on last search pattern
+" General: {{{1
+" File: searchfold.vim
+" Created: 2008 Jan 19
+" Last Change: 2011 May 24
+" Rev Days: 18
+" Author: Andy Wokula <anwoku@yahoo.de>
+" Credits: Antonio Colombo's f.vim (Vimscript #318, 2005 May 10)
+" Vim Version: Vim 7.0
+" Version: 0.9
+
+" Description:
+" Provide mappings to fold away lines not matching the last search pattern
+" and to restore old fold settings afterwards. Uses manual fold method,
+" which allows for nested folds to hide or show more context. Doesn't
+" preserve the user's manual folds.
+
+" Usage:
+" <Leader>z fold away lines not matching the last search pattern.
+"
+" With [count], change the initial foldlevel to ([count] minus
+" one). The setting will be stored in g:searchfold_foldlevel
+" and will be reused when [count] is omitted.
+"
+" <Leader>iz fold away lines that do match the last search pattern
+" (inverse folding), also with [count].
+"
+" <Leader>Z restore the previous fold settings.
+"
+" Minor Extra: If already in restored state, show a dialog to
+" revert all involved local fold options to the global
+" defaults. The "(s)how" just prints info.
+
+" Customization:
+" :let g:searchfold_maxdepth = 7
+" (number)
+" maximum fold depth
+"
+" :let g:searchfold_usestep = 1
+" (boolean)
+" Controls how folds are organized: If 1 (default), each "zr"
+" (after "\z") unfolds the same amount of lines above and
+" below a match. If 0, only one more line is unfolded above a
+" match. This applies for next "\z" or "\iz".
+"
+" :let g:searchfold_postZ_do_zv = 1
+" (boolean)
+" If 1, execute "zv" (view cursor line) after <Leader>Z.
+"
+" :let g:searchfold_foldlevel = 0
+" (number)
+" Initial 'foldlevel' to set for <Leader>z and <Leader>iz.
+"
+" :let g:searchfold_do_maps = 1
+" (boolean)
+" Whether to map the default keys or not.
+"
+" Hint: For boolean options, 1 actually means any non-zero number.
+
+" Related: Vimscript #158 (foldutil.vim) ... still to be checked out
+" http://www.noah.org/wiki/Vim#Folding
+" Vimscript #2302 (foldsearch.vim)
+" Vimscript #578 (allfold.tar.gz)
+"
+" Changes:
+" v0.9 redraw removed, plug map renamed, comments (usestep ...)
+" v0.8 added inverse folding (<Leader>iz), g:searchfold_foldlevel,
+" count for <Leader>z, <Plug> mappings, disabled F(), (fixes)
+" v0.7 b:searchfold fallback, s:foldtext check
+" v0.6 (after v0.4) added customization vars (usestep, maxdepth, Zpost)
+" reverting global fold settings adds to cmd-history
+" v0.4 decreasing fold step always 1
+" maxdepth 7 (before: 6)
+" v0.3 (after v0.1) added a modified F() from f.vim
+" functions now with return values
+" v0.2 (skipped)
+
+" Init Folklore: {{{1
+if exists("loaded_searchfold")
+ finish
+endif
+let loaded_searchfold = 1
+
+if v:version<700
+ echo "Searchfold: you need at least Vim 7.0"
+ finish
+endif
+
+" Customization: {{{1
+if !exists("g:searchfold_maxdepth")
+ let g:searchfold_maxdepth = 7
+endif
+if !exists("g:searchfold_usestep")
+ let g:searchfold_usestep = 1
+endif
+if !exists("g:searchfold_postZ_do_zv")
+ let g:searchfold_postZ_do_zv = 1
+endif
+if !exists("g:searchfold_foldlevel")
+ let g:searchfold_foldlevel = 0
+endif
+if !exists("g:searchfold_do_maps")
+ let g:searchfold_do_maps = 1
+endif
+
+" s:variables {{{1
+let s:foldtext = "(v:folddashes.'').((v:foldend)-(v:foldstart)+(1))"
+" use unique notation of 'foldtext' to identify active searchfold in a
+" window
+
+func! s:FoldNested(from, to) " {{{1
+ " create one fold from line a:from to line a:to, with more nested folds
+ " return 1 if folds were created
+ " return 0 if from > to
+ let nlines = a:to - a:from
+ if nlines < 0
+ return 0
+ elseif nlines < 3
+ " range of 1 line possible
+ exec a:from.",".a:to. "fold"
+ return 1
+ endif
+
+ " calc folds, start with most outer fold
+ " - range of inner folds at least 2 lines (from<to)
+ " - limit nesting (depth)
+ " - snap folds at start and end of file
+ " - at greater "depth" (here depth->0), don't create folds with few
+ " lines only (check to-from>step)
+ if g:searchfold_maxdepth < 1 || g:searchfold_maxdepth > 12
+ let g:searchfold_maxdepth = 7
+ endif
+ let depth = g:searchfold_maxdepth
+ let step = 1 " decstep:''
+ let step1 = 1 " (const) decstep:'1'
+ let from = a:from
+ let to = a:to
+ " let decstep = exists("g:searchfold_usestep") && g:searchfold_usestep ? "" : "1"
+ let decstep = g:searchfold_usestep ? "" : "1"
+ let foldranges = []
+ let lined = line("$")
+ while depth>0 && from<to && to-from>step
+ call insert(foldranges, from.",".to)
+ let from += from>1 ? step : 0
+ " let to -= to<lined ? 1 : 0
+ let to -= to<lined ? step{decstep} : 0
+ let step += step " arbitrary
+ let depth -= 1
+ endwhile
+
+ " create folds, start with most inner fold
+ for range in foldranges
+ exec range. "fold"
+ endfor
+
+ return 1
+endfunc
+
+func! s:CreateFolds(inverse) " {{{1
+ " create search folds for the whole buffer based on last search pattern
+ let sav_cur = getpos(".")
+
+ let matches = [] " list of lnums
+ if !a:inverse
+ global//call add(matches, line("."))
+ else
+ vglobal//call add(matches, line("."))
+ endif
+
+ let nmatches = len(matches)
+ if nmatches > 0
+ call s:FoldNested(1, matches[0]-1)
+ let imax = nmatches - 1
+ let i = 0
+ while i < imax
+ if matches[i]+1 < matches[i+1]
+ call s:FoldNested(matches[i]+1, matches[i+1]-1)
+ endif
+ let i += 1
+ endwhile
+ call s:FoldNested(matches[imax]+1, line("$"))
+ endif
+
+ let &l:foldlevel = g:searchfold_foldlevel
+ call cursor(sav_cur[1:])
+
+ return nmatches
+endfunc
+
+func! <sid>SearchFoldEnable(inverse) "{{{1
+ " return number of matches
+ if !search("", "n")
+ " last search pattern not found, do nothing
+ return 0
+ endif
+ if (!exists("w:searchfold") || w:searchfold.bufnr != bufnr(""))
+ \ && &fdt != s:foldtext
+ " remember settings
+ let w:searchfold = { "bufnr": bufnr(""),
+ \ "fdm": &fdm,
+ \ "fdl": &fdl,
+ \ "fdt": &fdt,
+ \ "fen": &fen,
+ \ "fml": &fml }
+ " else: do not remember settings if already enabled
+ endif
+ setlocal foldmethod=manual
+ setlocal foldlevel=0
+ let &l:foldtext=s:foldtext
+ setlocal foldenable
+ setlocal foldminlines=0
+ normal! zE
+ if exists("w:searchfold")
+ let b:searchfold = w:searchfold
+ endif
+ return s:CreateFolds(a:inverse)
+endfunc
+func! SearchFoldRestore() "{{{1
+ " turn off
+ if exists("w:searchfold") && w:searchfold.bufnr == bufnr("")
+ " restore settings; var has the right settings if exists, but
+ " doesn't survive window split or win close/restore
+ let &l:fdm = w:searchfold.fdm
+ let &l:fdl = w:searchfold.fdl
+ let &l:fdt = w:searchfold.fdt
+ let &l:fen = w:searchfold.fen
+ let &l:fml = w:searchfold.fml
+ if &fdm == "manual"
+ " remove all search folds (old folds are lost anyway):
+ normal! zE
+ endif
+ unlet w:searchfold
+ elseif exists("b:searchfold") && &fdt == s:foldtext
+ " fallback only, may have wrong settings if overwritten
+ let &l:fdm = b:searchfold.fdm
+ let &l:fdl = b:searchfold.fdl
+ let &l:fdt = b:searchfold.fdt
+ let &l:fen = b:searchfold.fen
+ let &l:fml = b:searchfold.fml
+ if &fdm == "manual"
+ normal! zE
+ endif
+ else
+ let choice = input("Revert to global fold settings? (y/[n]/(s)how):")[0]
+ let setargs = 'fdm< fdl< fdt< fen< fml<'
+ if choice == "y"
+ let cmd = 'setlocal '. setargs
+ echo ':'. cmd
+ exec cmd
+ " call histadd(':', cmd)
+ elseif choice == "s"
+ let setargs = tr(setargs, "<","?")
+ let cmd = 'setglobal '. setargs
+ echo ':'. cmd
+ exec cmd
+ let cmd = 'setlocal '. setargs
+ echo ':'. cmd
+ exec cmd
+ endif
+ return
+ endif
+ if g:searchfold_postZ_do_zv
+ normal! zv
+ endif
+endfunc
+
+"" func! F() range "{{{1
+" " commented out 2010 Jun 01
+" " range arg: ignore range given by accident
+" let pat = input("Which regexp? ", @/)
+" if pat == ""
+" if exists("w:searchfold")
+" call SearchFoldRestore()
+" endif
+" return
+" endif
+" let @/ = pat
+" call histadd("search", @/)
+" call SearchFold()
+" endfunc
+
+" :call F() only for backwards compatibility
+
+func! SearchFold(...) "{{{1
+ let inverse = a:0>=1 && a:1
+ if v:count >= 1
+ let g:searchfold_foldlevel = v:count - 1
+ endif
+ let nmatches = <sid>SearchFoldEnable(inverse)
+ " at most one match per line counted
+ if nmatches == 0
+ echohl ErrorMsg
+ echomsg "Searchfold: Pattern not found:" @/
+ echohl none
+ elseif nmatches == line("$")
+ echomsg "Searchfold: Pattern found in every line:" @/
+ elseif nmatches == 1
+ echo "Searchfold: 1 line found"
+ else
+ echo "Searchfold:" nmatches "lines found"
+ endif
+ " 2011 Feb 06 commented out:
+ " let &hls = &hls
+ " redraw
+endfunc
+
+" Mappings: {{{1
+nn <silent> <Plug>SearchFoldNormal :<C-U>call SearchFold(0)<CR>
+nn <silent> <Plug>SearchFoldInverse :<C-U>call SearchFold(1)<CR>
+nn <silent> <Plug>SearchFoldRestore :<C-U>call SearchFoldRestore()<CR>
+
+if g:searchfold_do_maps
+ nmap <Leader>z <Plug>SearchFoldNormal
+ nmap <Leader>iz <Plug>SearchFoldInverse
+ nmap <Leader>Z <Plug>SearchFoldRestore
+endif
+
+" Modeline: {{{1
+" vim:set fdm=marker ts=8 sts=4 sw=4 noet:
diff --git a/vim/plugin/showmarks.vim b/vim/plugin/showmarks.vim
new file mode 100644
index 0000000..c6931c2
--- /dev/null
+++ b/vim/plugin/showmarks.vim
@@ -0,0 +1,507 @@
+" ==============================================================================
+" Name: ShowMarks
+" Description: Visually displays the location of marks.
+" Authors: Anthony Kruize <trandor@labyrinth.net.au>
+" Michael Geddes <michaelrgeddes@optushome.com.au>
+" Version: 2.2
+" Modified: 17 August 2004
+" License: Released into the public domain.
+" ChangeLog: See :help showmarks-changelog
+"
+" Usage: Copy this file into the plugins directory so it will be
+" automatically sourced.
+"
+" Default keymappings are:
+" <Leader>mt - Toggles ShowMarks on and off.
+" <Leader>mo - Turns ShowMarks on, and displays marks.
+" <Leader>mh - Clears a mark.
+" <Leader>ma - Clears all marks.
+" <Leader>mm - Places the next available mark.
+"
+" Hiding a mark doesn't actually remove it, it simply moves it
+" to line 1 and hides it visually.
+"
+" Configuration: ***********************************************************
+" * PLEASE read the included help file(showmarks.txt) for a *
+" * more thorough explanation of how to use ShowMarks. *
+" ***********************************************************
+" The following options can be used to customize the behavior
+" of ShowMarks. Simply include them in your vimrc file with
+" the desired settings.
+"
+" showmarks_enable (Default: 1)
+" Defines whether ShowMarks is enabled by default.
+" Example: let g:showmarks_enable=0
+" showmarks_include (Default: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'`^<>[]{}()\"")
+" Defines all marks, in precedence order (only the highest
+" precence will show on lines having more than one mark).
+" Can be buffer-specific (set b:showmarks_include)
+" showmarks_ignore_type (Default: "hq")
+" Defines the buffer types to be ignored.
+" Valid types are:
+" h - Help p - preview
+" q - quickfix r - readonly
+" m - non-modifiable
+" showmarks_textlower (Default: ">")
+" Defines how the mark is to be displayed.
+" A maximum of two characters can be displayed. To include
+" the mark in the text use a tab(\t) character. A single
+" character will display as the mark with the character
+" suffixed (same as "\t<character>")
+" Examples:
+" To display the mark with a > suffixed:
+" let g:showmarks_textlower="\t>"
+" or
+" let g:showmarks_textlower=">"
+" To display the mark with a ( prefixed:
+" let g:showmarks_textlower="(\t"
+" To display two > characters:
+" let g:showmarks_textlower=">>"
+" showmarks_textupper (Default: ">")
+" Same as above but for the marks A-Z.
+" Example: let g:showmarks_textupper="**"
+" showmarks_textother (Default: ">")
+" Same as above but for all other marks.
+" Example: let g:showmarks_textother="--"
+" showmarks_hlline_lower (Default: 0)
+" showmarks_hlline_upper (Default: 0)
+" showmarks_hlline_other (Default: 0)
+" Defines whether the entire line for a particular mark
+" should be highlighted.
+" Example: let g:showmarks_hlline_lower=1
+"
+" Setting Highlighting Colours
+" ShowMarks uses the following highlighting groups:
+" ShowMarksHLl - For marks a-z
+" ShowMarksHLu - For marks A-Z
+" ShowMarksHLo - For all other marks
+" ShowMarksHLm - For multiple marks on the same line.
+" (Highest precendece mark is shown)
+"
+" By default they are set to a bold blue on light blue.
+" Defining a highlight for each of these groups will
+" override the default highlighting.
+" See the VIM help for more information about highlighting.
+" ==============================================================================
+
+" Check if we should continue loading
+if exists( "loaded_showmarks" )
+ finish
+endif
+let loaded_showmarks = 1
+
+" Bail if Vim isn't compiled with signs support.
+if has( "signs" ) == 0
+ echohl ErrorMsg
+ echo "ShowMarks requires Vim to have +signs support."
+ echohl None
+ finish
+endif
+
+" Options: Set up some nice defaults
+if !exists('g:showmarks_enable' ) | let g:showmarks_enable = 1 | endif
+if !exists('g:showmarks_textlower' ) | let g:showmarks_textlower = ">" | endif
+if !exists('g:showmarks_textupper' ) | let g:showmarks_textupper = ">" | endif
+if !exists('g:showmarks_textother' ) | let g:showmarks_textother = ">" | endif
+if !exists('g:showmarks_ignore_type' ) | let g:showmarks_ignore_type = "hq" | endif
+if !exists('g:showmarks_ignore_name' ) | let g:showmarks_ignore_name = "" | endif
+if !exists('g:showmarks_hlline_lower') | let g:showmarks_hlline_lower = "0" | endif
+if !exists('g:showmarks_hlline_upper') | let g:showmarks_hlline_upper = "0" | endif
+if !exists('g:showmarks_hlline_other') | let g:showmarks_hlline_other = "0" | endif
+
+" This is the default, and used in ShowMarksSetup to set up info for any
+" possible mark (not just those specified in the possibly user-supplied list
+" of marks to show -- it can be changed on-the-fly).
+let s:all_marks = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'`^<>[]{}()\""
+
+" Commands
+com! -nargs=0 ShowMarksToggle :call <sid>ShowMarksToggle()
+com! -nargs=0 ShowMarksOn :call <sid>ShowMarksOn()
+com! -nargs=0 ShowMarksClearMark :call <sid>ShowMarksClearMark()
+com! -nargs=0 ShowMarksClearAll :call <sid>ShowMarksClearAll()
+com! -nargs=0 ShowMarksPlaceMark :call <sid>ShowMarksPlaceMark()
+
+" Mappings (NOTE: Leave the '|'s immediately following the '<cr>' so the mapping does not contain any trailing spaces!)
+if !hasmapto( '<Plug>ShowmarksShowMarksToggle' ) | map <silent> <unique> <leader>mt :ShowMarksToggle<cr>| endif
+if !hasmapto( '<Plug>ShowmarksShowMarksOn' ) | map <silent> <unique> <leader>mo :ShowMarksOn<cr>| endif
+if !hasmapto( '<Plug>ShowmarksClearMark' ) | map <silent> <unique> <leader>mh :ShowMarksClearMark<cr>| endif
+if !hasmapto( '<Plug>ShowmarksClearAll' ) | map <silent> <unique> <leader>ma :ShowMarksClearAll<cr>| endif
+if !hasmapto( '<Plug>ShowmarksPlaceMark' ) | map <silent> <unique> <leader>mm :ShowMarksPlaceMark<cr>| endif
+noremap <unique> <script> \sm m
+noremap <silent> m :exe 'norm \sm'.nr2char(getchar())<bar>call <sid>ShowMarks()<CR>
+
+" AutoCommands: Only if ShowMarks is enabled
+if g:showmarks_enable == 1
+ aug ShowMarks
+ au!
+ autocmd CursorHold * call s:ShowMarks()
+ aug END
+endif
+
+" Highlighting: Setup some nice colours to show the mark positions.
+hi default ShowMarksHLl ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold
+hi default ShowMarksHLu ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold
+hi default ShowMarksHLo ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold
+hi default ShowMarksHLm ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold
+
+" Function: IncludeMarks()
+" Description: This function returns the list of marks (in priority order) to
+" show in this buffer. Each buffer, if not already set, inherits the global
+" setting; if the global include marks have not been set; that is set to the
+" default value.
+fun! s:IncludeMarks()
+ if exists('b:showmarks_include') && exists('b:showmarks_previous_include') && b:showmarks_include != b:showmarks_previous_include
+ " The user changed the marks to include; hide all marks; change the
+ " included mark list, then show all marks. Prevent infinite
+ " recursion during this switch.
+ if exists('s:use_previous_include')
+ " Recursive call from ShowMarksHideAll()
+ return b:showmarks_previous_include
+ elseif exists('s:use_new_include')
+ " Recursive call from ShowMarks()
+ return b:showmarks_include
+ else
+ let s:use_previous_include = 1
+ call <sid>ShowMarksHideAll()
+ unlet s:use_previous_include
+ let s:use_new_include = 1
+ call <sid>ShowMarks()
+ unlet s:use_new_include
+ endif
+ endif
+
+ if !exists('g:showmarks_include')
+ let g:showmarks_include = s:all_marks
+ endif
+ if !exists('b:showmarks_include')
+ let b:showmarks_include = g:showmarks_include
+ endif
+
+ " Save this include setting so we can detect if it was changed.
+ let b:showmarks_previous_include = b:showmarks_include
+
+ return b:showmarks_include
+endf
+
+" Function: NameOfMark()
+" Paramaters: mark - Specifies the mark to find the name of.
+" Description: Convert marks that cannot be used as part of a variable name to
+" something that can be. i.e. We cannot use [ as a variable-name suffix (as
+" in 'placed_['; this function will return something like 63, so the variable
+" will be something like 'placed_63').
+" 10 is added to the mark's index to avoid colliding with the numeric marks
+" 0-9 (since a non-word mark could be listed in showmarks_include in the
+" first 10 characters if the user overrides the default).
+" Returns: The name of the requested mark.
+fun! s:NameOfMark(mark)
+ let name = a:mark
+ if a:mark =~# '\W'
+ let name = stridx(s:all_marks, a:mark) + 10
+ endif
+ return name
+endf
+
+" Function: VerifyText()
+" Paramaters: which - Specifies the variable to verify.
+" Description: Verify the validity of a showmarks_text{upper,lower,other} setup variable.
+" Default to ">" if it is found to be invalid.
+fun! s:VerifyText(which)
+ if strlen(g:showmarks_text{a:which}) == 0 || strlen(g:showmarks_text{a:which}) > 2
+ echohl ErrorMsg
+ echo "ShowMarks: text".a:which." must contain only 1 or 2 characters."
+ echohl None
+ let g:showmarks_text{a:which}=">"
+ endif
+endf
+
+" Function: ShowMarksSetup()
+" Description: This function sets up the sign definitions for each mark.
+" It uses the showmarks_textlower, showmarks_textupper and showmarks_textother
+" variables to determine how to draw the mark.
+fun! s:ShowMarksSetup()
+ " Make sure the textlower, textupper, and textother options are valid.
+ call s:VerifyText('lower')
+ call s:VerifyText('upper')
+ call s:VerifyText('other')
+
+ let n = 0
+ let s:maxmarks = strlen(s:all_marks)
+ while n < s:maxmarks
+ let c = strpart(s:all_marks, n, 1)
+ let nm = s:NameOfMark(c)
+ let text = '>'.c
+ let lhltext = ''
+ if c =~# '[a-z]'
+ if strlen(g:showmarks_textlower) == 1
+ let text=c.g:showmarks_textlower
+ elseif strlen(g:showmarks_textlower) == 2
+ let t1 = strpart(g:showmarks_textlower,0,1)
+ let t2 = strpart(g:showmarks_textlower,1,1)
+ if t1 == "\t"
+ let text=c.t2
+ elseif t2 == "\t"
+ let text=t1.c
+ else
+ let text=g:showmarks_textlower
+ endif
+ endif
+ let s:ShowMarksDLink{nm} = 'ShowMarksHLl'
+ if g:showmarks_hlline_lower == 1
+ let lhltext = 'linehl='.s:ShowMarksDLink{nm}.nm
+ endif
+ elseif c =~# '[A-Z]'
+ if strlen(g:showmarks_textupper) == 1
+ let text=c.g:showmarks_textupper
+ elseif strlen(g:showmarks_textupper) == 2
+ let t1 = strpart(g:showmarks_textupper,0,1)
+ let t2 = strpart(g:showmarks_textupper,1,1)
+ if t1 == "\t"
+ let text=c.t2
+ elseif t2 == "\t"
+ let text=t1.c
+ else
+ let text=g:showmarks_textupper
+ endif
+ endif
+ let s:ShowMarksDLink{nm} = 'ShowMarksHLu'
+ if g:showmarks_hlline_upper == 1
+ let lhltext = 'linehl='.s:ShowMarksDLink{nm}.nm
+ endif
+ else " Other signs, like ', ., etc.
+ if strlen(g:showmarks_textother) == 1
+ let text=c.g:showmarks_textother
+ elseif strlen(g:showmarks_textother) == 2
+ let t1 = strpart(g:showmarks_textother,0,1)
+ let t2 = strpart(g:showmarks_textother,1,1)
+ if t1 == "\t"
+ let text=c.t2
+ elseif t2 == "\t"
+ let text=t1.c
+ else
+ let text=g:showmarks_textother
+ endif
+ endif
+ let s:ShowMarksDLink{nm} = 'ShowMarksHLo'
+ if g:showmarks_hlline_other == 1
+ let lhltext = 'linehl='.s:ShowMarksDLink{nm}.nm
+ endif
+ endif
+
+ " Define the sign with a unique highlight which will be linked when placed.
+ exe 'sign define ShowMark'.nm.' '.lhltext.' text='.text.' texthl='.s:ShowMarksDLink{nm}.nm
+ let b:ShowMarksLink{nm} = ''
+ let n = n + 1
+ endw
+endf
+
+" Set things up
+call s:ShowMarksSetup()
+
+" Function: ShowMarksOn
+" Description: Enable showmarks, and show them now.
+fun! s:ShowMarksOn()
+ if g:showmarks_enable == 0
+ call <sid>ShowMarksToggle()
+ else
+ call <sid>ShowMarks()
+ endif
+endf
+
+" Function: ShowMarksToggle()
+" Description: This function toggles whether marks are displayed or not.
+fun! s:ShowMarksToggle()
+ if g:showmarks_enable == 0
+ let g:showmarks_enable = 1
+ call <sid>ShowMarks()
+ aug ShowMarks
+ au!
+ autocmd CursorHold * call s:ShowMarks()
+ aug END
+ else
+ let g:showmarks_enable = 0
+ call <sid>ShowMarksHideAll()
+ aug ShowMarks
+ au!
+ autocmd BufEnter * call s:ShowMarksHideAll()
+ aug END
+ endif
+endf
+
+" Function: ShowMarks()
+" Description: This function runs through all the marks and displays or
+" removes signs as appropriate. It is called on the CursorHold autocommand.
+" We use the marked_{ln} variables (containing a timestamp) to track what marks
+" we've shown (placed) in this call to ShowMarks; to only actually place the
+" first mark on any particular line -- this forces only the first mark
+" (according to the order of showmarks_include) to be shown (i.e., letters
+" take precedence over marks like paragraph and sentence.)
+fun! s:ShowMarks()
+ if g:showmarks_enable == 0
+ return
+ endif
+
+ if ((match(g:showmarks_ignore_type, "[Hh]") > -1) && (&buftype == "help" ))
+ \ || ((match(g:showmarks_ignore_type, "[Qq]") > -1) && (&buftype == "quickfix"))
+ \ || ((match(g:showmarks_ignore_type, "[Pp]") > -1) && (&pvw == 1 ))
+ \ || ((match(g:showmarks_ignore_type, "[Rr]") > -1) && (&readonly == 1 ))
+ \ || ((match(g:showmarks_ignore_type, "[Mm]") > -1) && (&modifiable == 0 ))
+ return
+ endif
+
+ let n = 0
+ let s:maxmarks = strlen(s:IncludeMarks())
+ while n < s:maxmarks
+ let c = strpart(s:IncludeMarks(), n, 1)
+ let nm = s:NameOfMark(c)
+ let id = n + (s:maxmarks * winbufnr(0))
+ let ln = line("'".c)
+
+ if ln == 0 && (exists('b:placed_'.nm) && b:placed_{nm} != ln)
+ exe 'sign unplace '.id.' buffer='.winbufnr(0)
+ elseif ln > 1 || c !~ '[a-zA-Z]'
+ " Have we already placed a mark here in this call to ShowMarks?
+ if exists('mark_at'.ln)
+ " Already placed a mark, set the highlight to multiple
+ if c =~# '[a-zA-Z]' && b:ShowMarksLink{mark_at{ln}} != 'ShowMarksHLm'
+ let b:ShowMarksLink{mark_at{ln}} = 'ShowMarksHLm'
+ exe 'hi link '.s:ShowMarksDLink{mark_at{ln}}.mark_at{ln}.' '.b:ShowMarksLink{mark_at{ln}}
+ endif
+ else
+ if !exists('b:ShowMarksLink'.nm) || b:ShowMarksLink{nm} != s:ShowMarksDLink{nm}
+ let b:ShowMarksLink{nm} = s:ShowMarksDLink{nm}
+ exe 'hi link '.s:ShowMarksDLink{nm}.nm.' '.b:ShowMarksLink{nm}
+ endif
+ let mark_at{ln} = nm
+ if !exists('b:placed_'.nm) || b:placed_{nm} != ln
+ exe 'sign unplace '.id.' buffer='.winbufnr(0)
+ exe 'sign place '.id.' name=ShowMark'.nm.' line='.ln.' buffer='.winbufnr(0)
+ let b:placed_{nm} = ln
+ endif
+ endif
+ endif
+ let n = n + 1
+ endw
+endf
+
+" Function: ShowMarksClearMark()
+" Description: This function hides the mark at the current line.
+" It simply moves the mark to line 1 and removes the sign.
+" Only marks a-z and A-Z are supported.
+fun! s:ShowMarksClearMark()
+ let ln = line(".")
+ let n = 0
+ let s:maxmarks = strlen(s:IncludeMarks())
+ while n < s:maxmarks
+ let c = strpart(s:IncludeMarks(), n, 1)
+ if c =~# '[a-zA-Z]' && ln == line("'".c)
+ let nm = s:NameOfMark(c)
+ let id = n + (s:maxmarks * winbufnr(0))
+ exe 'sign unplace '.id.' buffer='.winbufnr(0)
+ exe '1 mark '.c
+ let b:placed_{nm} = 1
+ endif
+ let n = n + 1
+ endw
+endf
+
+" Function: ShowMarksClearAll()
+" Description: This function clears all marks in the buffer.
+" It simply moves the marks to line 1 and removes the signs.
+" Only marks a-z and A-Z are supported.
+fun! s:ShowMarksClearAll()
+ let n = 0
+ let s:maxmarks = strlen(s:IncludeMarks())
+ while n < s:maxmarks
+ let c = strpart(s:IncludeMarks(), n, 1)
+ if c =~# '[a-zA-Z]'
+ let nm = s:NameOfMark(c)
+ let id = n + (s:maxmarks * winbufnr(0))
+ exe 'sign unplace '.id.' buffer='.winbufnr(0)
+ exe '1 mark '.c
+ let b:placed_{nm} = 1
+ endif
+ let n = n + 1
+ endw
+endf
+
+" Function: ShowMarksHideAll()
+" Description: This function hides all marks in the buffer.
+" It simply removes the signs.
+fun! s:ShowMarksHideAll()
+ let n = 0
+ let s:maxmarks = strlen(s:IncludeMarks())
+ while n < s:maxmarks
+ let c = strpart(s:IncludeMarks(), n, 1)
+ let nm = s:NameOfMark(c)
+ if exists('b:placed_'.nm)
+ let id = n + (s:maxmarks * winbufnr(0))
+ exe 'sign unplace '.id.' buffer='.winbufnr(0)
+ unlet b:placed_{nm}
+ endif
+ let n = n + 1
+ endw
+endf
+
+" Function: ShowMarksPlaceMark()
+" Description: This function will place the next unplaced mark (in priority
+" order) to the current location. The idea here is to automate the placement
+" of marks so the user doesn't have to remember which marks are placed or not.
+" Hidden marks are considered to be unplaced.
+" Only marks a-z are supported.
+fun! s:ShowMarksPlaceMark()
+ " Find the first, next, and last [a-z] mark in showmarks_include (i.e.
+ " priority order), so we know where to "wrap".
+ let first_alpha_mark = -1
+ let last_alpha_mark = -1
+ let next_mark = -1
+
+ if !exists('b:previous_auto_mark')
+ let b:previous_auto_mark = -1
+ endif
+
+ " Find the next unused [a-z] mark (in priority order); if they're all
+ " used, find the next one after the previously auto-assigned mark.
+ let n = 0
+ let s:maxmarks = strlen(s:IncludeMarks())
+ while n < s:maxmarks
+ let c = strpart(s:IncludeMarks(), n, 1)
+ if c =~# '[a-z]'
+ if line("'".c) <= 1
+ " Found an unused [a-z] mark; we're done.
+ let next_mark = n
+ break
+ endif
+
+ if first_alpha_mark < 0
+ let first_alpha_mark = n
+ endif
+ let last_alpha_mark = n
+ if n > b:previous_auto_mark && next_mark == -1
+ let next_mark = n
+ endif
+ endif
+ let n = n + 1
+ endw
+
+ if next_mark == -1 && (b:previous_auto_mark == -1 || b:previous_auto_mark == last_alpha_mark)
+ " Didn't find an unused mark, and haven't placed any auto-chosen marks yet,
+ " or the previously placed auto-chosen mark was the last alpha mark --
+ " use the first alpha mark this time.
+ let next_mark = first_alpha_mark
+ endif
+
+ if (next_mark == -1)
+ echohl WarningMsg
+ echo 'No marks in [a-z] included! (No "next mark" to choose from)'
+ echohl None
+ return
+ endif
+
+ let c = strpart(s:IncludeMarks(), next_mark, 1)
+ let b:previous_auto_mark = next_mark
+ exe 'mark '.c
+ call <sid>ShowMarks()
+endf
+
+" -----------------------------------------------------------------------------
+" vim:ts=4:sw=4:noet
diff --git a/vim/plugin/snipMate.vim b/vim/plugin/snipMate.vim
new file mode 100644
index 0000000..ef03b12
--- /dev/null
+++ b/vim/plugin/snipMate.vim
@@ -0,0 +1,271 @@
+" File: snipMate.vim
+" Author: Michael Sanders
+" Version: 0.84
+" Description: snipMate.vim implements some of TextMate's snippets features in
+" Vim. A snippet is a piece of often-typed text that you can
+" insert into your document using a trigger word followed by a "<tab>".
+"
+" For more help see snipMate.txt; you can do this by using:
+" :helptags ~/.vim/doc
+" :h snipMate.txt
+
+if exists('loaded_snips') || &cp || version < 700
+ finish
+endif
+let loaded_snips = 1
+if !exists('snips_author') | let snips_author = 'Me' | endif
+
+au BufRead,BufNewFile *.snippets\= set ft=snippet
+au FileType snippet setl noet fdm=indent
+
+let s:snippets = {} | let s:multi_snips = {}
+
+if !exists('snippets_dir')
+ let snippets_dir = substitute(globpath(&rtp, 'snippets/'), "\n", ',', 'g')
+endif
+
+fun! MakeSnip(scope, trigger, content, ...)
+ let multisnip = a:0 && a:1 != ''
+ let var = multisnip ? 's:multi_snips' : 's:snippets'
+ if !has_key({var}, a:scope) | let {var}[a:scope] = {} | endif
+ if !has_key({var}[a:scope], a:trigger)
+ let {var}[a:scope][a:trigger] = multisnip ? [[a:1, a:content]] : a:content
+ elseif multisnip | let {var}[a:scope][a:trigger] += [[a:1, a:content]]
+ else
+ echom 'Warning in snipMate.vim: Snippet '.a:trigger.' is already defined.'
+ \ .' See :h multi_snip for help on snippets with multiple matches.'
+ endif
+endf
+
+fun! ExtractSnips(dir, ft)
+ for path in split(globpath(a:dir, '*'), "\n")
+ if isdirectory(path)
+ let pathname = fnamemodify(path, ':t')
+ for snipFile in split(globpath(path, '*.snippet'), "\n")
+ call s:ProcessFile(snipFile, a:ft, pathname)
+ endfor
+ elseif fnamemodify(path, ':e') == 'snippet'
+ call s:ProcessFile(path, a:ft)
+ endif
+ endfor
+endf
+
+" Processes a single-snippet file; optionally add the name of the parent
+" directory for a snippet with multiple matches.
+fun s:ProcessFile(file, ft, ...)
+ let keyword = fnamemodify(a:file, ':t:r')
+ if keyword == '' | return | endif
+ try
+ let text = join(readfile(a:file), "\n")
+ catch /E484/
+ echom "Error in snipMate.vim: couldn't read file: ".a:file
+ endtry
+ return a:0 ? MakeSnip(a:ft, a:1, text, keyword)
+ \ : MakeSnip(a:ft, keyword, text)
+endf
+
+fun! ExtractSnipsFile(file, ft)
+ if !filereadable(a:file) | return | endif
+ let text = readfile(a:file)
+ let inSnip = 0
+ for line in text + ["\n"]
+ if inSnip && (line[0] == "\t" || line == '')
+ let content .= strpart(line, 1)."\n"
+ continue
+ elseif inSnip
+ call MakeSnip(a:ft, trigger, content[:-2], name)
+ let inSnip = 0
+ endif
+
+ if line[:6] == 'snippet'
+ let inSnip = 1
+ let trigger = strpart(line, 8)
+ let name = ''
+ let space = stridx(trigger, ' ') + 1
+ if space " Process multi snip
+ let name = strpart(trigger, space)
+ let trigger = strpart(trigger, 0, space - 1)
+ endif
+ let content = ''
+ endif
+ endfor
+endf
+
+" Reset snippets for filetype.
+fun! ResetSnippets(ft)
+ let ft = a:ft == '' ? '_' : a:ft
+ for dict in [s:snippets, s:multi_snips, g:did_ft]
+ if has_key(dict, ft)
+ unlet dict[ft]
+ endif
+ endfor
+endf
+
+" Reset snippets for all filetypes.
+fun! ResetAllSnippets()
+ let s:snippets = {} | let s:multi_snips = {} | let g:did_ft = {}
+endf
+
+" Reload snippets for filetype.
+fun! ReloadSnippets(ft)
+ let ft = a:ft == '' ? '_' : a:ft
+ call ResetSnippets(ft)
+ call GetSnippets(g:snippets_dir, ft)
+endf
+
+" Reload snippets for all filetypes.
+fun! ReloadAllSnippets()
+ for ft in keys(g:did_ft)
+ call ReloadSnippets(ft)
+ endfor
+endf
+
+let g:did_ft = {}
+fun! GetSnippets(dir, filetypes)
+ for ft in split(a:filetypes, '\.')
+ if has_key(g:did_ft, ft) | continue | endif
+ call s:DefineSnips(a:dir, ft, ft)
+ if ft == 'objc' || ft == 'cpp' || ft == 'cs'
+ call s:DefineSnips(a:dir, 'c', ft)
+ elseif ft == 'xhtml'
+ call s:DefineSnips(a:dir, 'html', 'xhtml')
+ endif
+ let g:did_ft[ft] = 1
+ endfor
+endf
+
+" Define "aliasft" snippets for the filetype "realft".
+fun s:DefineSnips(dir, aliasft, realft)
+ for path in split(globpath(a:dir, a:aliasft.'/')."\n".
+ \ globpath(a:dir, a:aliasft.'-*/'), "\n")
+ call ExtractSnips(path, a:realft)
+ endfor
+ for path in split(globpath(a:dir, a:aliasft.'.snippets')."\n".
+ \ globpath(a:dir, a:aliasft.'-*.snippets'), "\n")
+ call ExtractSnipsFile(path, a:realft)
+ endfor
+endf
+
+fun! TriggerSnippet()
+ if exists('g:SuperTabMappingForward')
+ if g:SuperTabMappingForward == "<tab>"
+ let SuperTabKey = "\<c-n>"
+ elseif g:SuperTabMappingBackward == "<tab>"
+ let SuperTabKey = "\<c-p>"
+ endif
+ endif
+
+ if pumvisible() " Update snippet if completion is used, or deal with supertab
+ if exists('SuperTabKey')
+ call feedkeys(SuperTabKey) | return ''
+ endif
+ call feedkeys("\<esc>a", 'n') " Close completion menu
+ call feedkeys("\<tab>") | return ''
+ endif
+
+ if exists('g:snipPos') | return snipMate#jumpTabStop(0) | endif
+
+ let word = matchstr(getline('.'), '\S\+\%'.col('.').'c')
+ for scope in [bufnr('%')] + split(&ft, '\.') + ['_']
+ let [trigger, snippet] = s:GetSnippet(word, scope)
+ " If word is a trigger for a snippet, delete the trigger & expand
+ " the snippet.
+ if snippet != ''
+ let col = col('.') - len(trigger)
+ sil exe 's/\V'.escape(trigger, '/\.').'\%#//'
+ return snipMate#expandSnip(snippet, col)
+ endif
+ endfor
+
+ if exists('SuperTabKey')
+ call feedkeys(SuperTabKey)
+ return ''
+ endif
+ return "\<tab>"
+endf
+
+fun! BackwardsSnippet()
+ if exists('g:snipPos') | return snipMate#jumpTabStop(1) | endif
+
+ if exists('g:SuperTabMappingForward')
+ if g:SuperTabMappingBackward == "<s-tab>"
+ let SuperTabKey = "\<c-p>"
+ elseif g:SuperTabMappingForward == "<s-tab>"
+ let SuperTabKey = "\<c-n>"
+ endif
+ endif
+ if exists('SuperTabKey')
+ call feedkeys(SuperTabKey)
+ return ''
+ endif
+ return "\<s-tab>"
+endf
+
+" Check if word under cursor is snippet trigger; if it isn't, try checking if
+" the text after non-word characters is (e.g. check for "foo" in "bar.foo")
+fun s:GetSnippet(word, scope)
+ let word = a:word | let snippet = ''
+ while snippet == ''
+ if exists('s:snippets["'.a:scope.'"]["'.escape(word, '\"').'"]')
+ let snippet = s:snippets[a:scope][word]
+ elseif exists('s:multi_snips["'.a:scope.'"]["'.escape(word, '\"').'"]')
+ let snippet = s:ChooseSnippet(a:scope, word)
+ if snippet == '' | break | endif
+ else
+ if match(word, '\W') == -1 | break | endif
+ let word = substitute(word, '.\{-}\W', '', '')
+ endif
+ endw
+ if word == '' && a:word != '.' && stridx(a:word, '.') != -1
+ let [word, snippet] = s:GetSnippet('.', a:scope)
+ endif
+ return [word, snippet]
+endf
+
+fun s:ChooseSnippet(scope, trigger)
+ let snippet = []
+ let i = 1
+ for snip in s:multi_snips[a:scope][a:trigger]
+ let snippet += [i.'. '.snip[0]]
+ let i += 1
+ endfor
+ if i == 2 | return s:multi_snips[a:scope][a:trigger][0][1] | endif
+ let num = inputlist(snippet) - 1
+ return num == -1 ? '' : s:multi_snips[a:scope][a:trigger][num][1]
+endf
+
+fun! ShowAvailableSnips()
+ let line = getline('.')
+ let col = col('.')
+ let word = matchstr(getline('.'), '\S\+\%'.col.'c')
+ let words = [word]
+ if stridx(word, '.')
+ let words += split(word, '\.', 1)
+ endif
+ let matchlen = 0
+ let matches = []
+ for scope in [bufnr('%')] + split(&ft, '\.') + ['_']
+ let triggers = has_key(s:snippets, scope) ? keys(s:snippets[scope]) : []
+ if has_key(s:multi_snips, scope)
+ let triggers += keys(s:multi_snips[scope])
+ endif
+ for trigger in triggers
+ for word in words
+ if word == ''
+ let matches += [trigger] " Show all matches if word is empty
+ elseif trigger =~ '^'.word
+ let matches += [trigger]
+ let len = len(word)
+ if len > matchlen | let matchlen = len | endif
+ endif
+ endfor
+ endfor
+ endfor
+
+ " This is to avoid a bug with Vim when using complete(col - matchlen, matches)
+ " (Issue#46 on the Google Code snipMate issue tracker).
+ call setline(line('.'), substitute(line, repeat('.', matchlen).'\%'.col.'c', '', ''))
+ call complete(col, matches)
+ return ''
+endf
+" vim:noet:sw=4:ts=4:ft=vim
diff --git a/vim/plugin/supertab.vim b/vim/plugin/supertab.vim
new file mode 100644
index 0000000..67f8c5c
--- /dev/null
+++ b/vim/plugin/supertab.vim
@@ -0,0 +1,737 @@
+" Author:
+" Original: Gergely Kontra <kgergely@mcl.hu>
+" Current: Eric Van Dewoestine <ervandew@gmail.com> (as of version 0.4)
+" Please direct all correspondence to Eric.
+" Version: 1.6
+" GetLatestVimScripts: 1643 1 :AutoInstall: supertab.vim
+"
+" Description: {{{
+" Use your tab key to do all your completion in insert mode!
+" You can cycle forward and backward with the <Tab> and <S-Tab> keys
+" Note: you must press <Tab> once to be able to cycle back
+"
+" http://www.vim.org/scripts/script.php?script_id=1643
+" }}}
+"
+" License: {{{
+" Copyright (c) 2002 - 2011
+" All rights reserved.
+"
+" Redistribution and use of this software in source and binary forms, with
+" or without modification, are permitted provided that the following
+" conditions are met:
+"
+" * Redistributions of source code must retain the above
+" copyright notice, this list of conditions and the
+" following disclaimer.
+"
+" * Redistributions in binary form must reproduce the above
+" copyright notice, this list of conditions and the
+" following disclaimer in the documentation and/or other
+" materials provided with the distribution.
+"
+" * Neither the name of Gergely Kontra or Eric Van Dewoestine nor the names
+" of its contributors may be used to endorse or promote products derived
+" from this software without specific prior written permission of Gergely
+" Kontra or Eric Van Dewoestine.
+"
+" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+" IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+" THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+" PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+" }}}
+"
+" Testing Info: {{{
+" Running vim + supertab with the absolute bar minimum settings:
+" $ vim -u NONE -U NONE -c "set nocp | runtime plugin/supertab.vim"
+" }}}
+
+if v:version < 700
+ finish
+endif
+
+if exists('complType') " Integration with other completion functions.
+ finish
+endif
+
+let s:save_cpo=&cpo
+set cpo&vim
+
+" Global Variables {{{
+
+ if !exists("g:SuperTabDefaultCompletionType")
+ let g:SuperTabDefaultCompletionType = "<c-p>"
+ endif
+
+ if !exists("g:SuperTabContextDefaultCompletionType")
+ let g:SuperTabContextDefaultCompletionType = "<c-p>"
+ endif
+
+ if !exists("g:SuperTabCompletionContexts")
+ let g:SuperTabCompletionContexts = ['s:ContextText']
+ endif
+
+ if !exists("g:SuperTabRetainCompletionDuration")
+ let g:SuperTabRetainCompletionDuration = 'insert'
+ endif
+
+ if !exists("g:SuperTabNoCompleteBefore")
+ " retain backwards compatability
+ if exists("g:SuperTabMidWordCompletion") && !g:SuperTabMidWordCompletion
+ let g:SuperTabNoCompleteBefore = ['\k']
+ else
+ let g:SuperTabNoCompleteBefore = []
+ endif
+ endif
+
+ if !exists("g:SuperTabNoCompleteAfter")
+ " retain backwards compatability
+ if exists("g:SuperTabLeadingSpaceCompletion") && g:SuperTabLeadingSpaceCompletion
+ let g:SuperTabNoCompleteAfter = []
+ else
+ let g:SuperTabNoCompleteAfter = ['\s']
+ endif
+ endif
+
+ if !exists("g:SuperTabMappingForward")
+ let g:SuperTabMappingForward = '<tab>'
+ endif
+ if !exists("g:SuperTabMappingBackward")
+ let g:SuperTabMappingBackward = '<s-tab>'
+ endif
+
+ if !exists("g:SuperTabMappingTabLiteral")
+ let g:SuperTabMappingTabLiteral = '<c-tab>'
+ endif
+
+ if !exists("g:SuperTabLongestEnhanced")
+ let g:SuperTabLongestEnhanced = 0
+ endif
+
+ if !exists("g:SuperTabLongestHighlight")
+ let g:SuperTabLongestHighlight = 0
+ endif
+
+ if !exists("g:SuperTabCrMapping")
+ let g:SuperTabCrMapping = 1
+ endif
+
+" }}}
+
+" Script Variables {{{
+
+ " construct the help text.
+ let s:tabHelp =
+ \ "Hit <CR> or CTRL-] on the completion type you wish to switch to.\n" .
+ \ "Use :help ins-completion for more information.\n" .
+ \ "\n" .
+ \ "|<c-n>| - Keywords in 'complete' searching down.\n" .
+ \ "|<c-p>| - Keywords in 'complete' searching up (SuperTab default).\n" .
+ \ "|<c-x><c-l>| - Whole lines.\n" .
+ \ "|<c-x><c-n>| - Keywords in current file.\n" .
+ \ "|<c-x><c-k>| - Keywords in 'dictionary'.\n" .
+ \ "|<c-x><c-t>| - Keywords in 'thesaurus', thesaurus-style.\n" .
+ \ "|<c-x><c-i>| - Keywords in the current and included files.\n" .
+ \ "|<c-x><c-]>| - Tags.\n" .
+ \ "|<c-x><c-f>| - File names.\n" .
+ \ "|<c-x><c-d>| - Definitions or macros.\n" .
+ \ "|<c-x><c-v>| - Vim command-line.\n" .
+ \ "|<c-x><c-u>| - User defined completion.\n" .
+ \ "|<c-x><c-o>| - Omni completion.\n" .
+ \ "|<c-x>s| - Spelling suggestions."
+
+ " set the available completion types and modes.
+ let s:types =
+ \ "\<c-e>\<c-y>\<c-l>\<c-n>\<c-k>\<c-t>\<c-i>\<c-]>" .
+ \ "\<c-f>\<c-d>\<c-v>\<c-n>\<c-p>\<c-u>\<c-o>\<c-n>\<c-p>s"
+ let s:modes = '/^E/^Y/^L/^N/^K/^T/^I/^]/^F/^D/^V/^P/^U/^O/s'
+ let s:types = s:types . "np"
+ let s:modes = s:modes . '/n/p'
+
+" }}}
+
+" SuperTabSetDefaultCompletionType(type) {{{
+" Globally available function that users can use to set the default
+" completion type for the current buffer, like in an ftplugin.
+function! SuperTabSetDefaultCompletionType(type)
+ " init hack for <c-x><c-v> workaround.
+ let b:complCommandLine = 0
+
+ let b:SuperTabDefaultCompletionType = a:type
+
+ " set the current completion type to the default
+ call SuperTabSetCompletionType(b:SuperTabDefaultCompletionType)
+endfunction " }}}
+
+" SuperTabSetCompletionType(type) {{{
+" Globally available function that users can use to create mappings to quickly
+" switch completion modes. Useful when a user wants to restore the default or
+" switch to another mode without having to kick off a completion of that type
+" or use SuperTabHelp. Note, this function only changes the current
+" completion type, not the default, meaning that the default will still be
+" restored once the configured retension duration has been met (see
+" g:SuperTabRetainCompletionDuration). To change the default for the current
+" buffer, use SuperTabDefaultCompletionType(type) instead. Example mapping to
+" restore SuperTab default:
+" nmap <F6> :call SetSuperTabCompletionType("<c-p>")<cr>
+function! SuperTabSetCompletionType(type)
+ call s:InitBuffer()
+ exec "let b:complType = \"" . escape(a:type, '<') . "\""
+endfunction " }}}
+
+" SuperTabAlternateCompletion(type) {{{
+" Function which can be mapped to a key to kick off an alternate completion
+" other than the default. For instance, if you have 'context' as the default
+" and want to map ctrl+space to issue keyword completion.
+" Note: due to the way vim expands ctrl characters in mappings, you cannot
+" create the alternate mapping like so:
+" imap <c-space> <c-r>=SuperTabAlternateCompletion("<c-p>")<cr>
+" instead, you have to use \<lt> to prevent vim from expanding the key
+" when creating the mapping.
+" gvim:
+" imap <c-space> <c-r>=SuperTabAlternateCompletion("\<lt>c-p>")<cr>
+" console:
+" imap <nul> <c-r>=SuperTabAlternateCompletion("\<lt>c-p>")<cr>
+function! SuperTabAlternateCompletion(type)
+ call SuperTabSetCompletionType(a:type)
+ " end any current completion before attempting to start the new one.
+ " use feedkeys to prevent possible remapping of <c-e> from causing issues.
+ "call feedkeys("\<c-e>", 'n')
+ " ^ since we can't detect completion mode vs regular insert mode, we force
+ " vim into keyword completion mode and end that mode to prevent the regular
+ " insert behavior of <c-e> from occurring.
+ call feedkeys("\<c-x>\<c-p>\<c-e>", 'n')
+ call feedkeys(b:complType, 'n')
+ return ''
+endfunction " }}}
+
+" SuperTabLongestHighlight(dir) {{{
+" When longest highlight is enabled, this function is used to do the actual
+" selection of the completion popup entry.
+function! SuperTabLongestHighlight(dir)
+ if !pumvisible()
+ return ''
+ endif
+ return a:dir == -1 ? "\<up>" : "\<down>"
+endfunction " }}}
+
+" s:Init {{{
+" Global initilization when supertab is loaded.
+function! s:Init()
+ " Setup mechanism to restore original completion type upon leaving insert
+ " mode if configured to do so
+ if g:SuperTabRetainCompletionDuration == 'insert'
+ augroup supertab_retain
+ autocmd!
+ autocmd InsertLeave * call s:SetDefaultCompletionType()
+ augroup END
+ endif
+endfunction " }}}
+
+" s:InitBuffer {{{
+" Per buffer initilization.
+function! s:InitBuffer()
+ if exists('b:SuperTabNoCompleteBefore')
+ return
+ endif
+
+ let b:complReset = 0
+ let b:complTypeManual = !exists('b:complTypeManual') ? '' : b:complTypeManual
+ let b:complTypeContext = ''
+
+ " init hack for <c-x><c-v> workaround.
+ let b:complCommandLine = 0
+
+ if !exists('b:SuperTabNoCompleteBefore')
+ let b:SuperTabNoCompleteBefore = g:SuperTabNoCompleteBefore
+ endif
+ if !exists('b:SuperTabNoCompleteAfter')
+ let b:SuperTabNoCompleteAfter = g:SuperTabNoCompleteAfter
+ endif
+
+ let b:SuperTabDefaultCompletionType = g:SuperTabDefaultCompletionType
+
+ " set the current completion type to the default
+ call SuperTabSetCompletionType(b:SuperTabDefaultCompletionType)
+endfunction " }}}
+
+" s:ManualCompletionEnter() {{{
+" Handles manual entrance into completion mode.
+function! s:ManualCompletionEnter()
+ if &smd
+ echo '' | echohl ModeMsg | echo '-- ^X++ mode (' . s:modes . ')' | echohl None
+ endif
+ let complType = nr2char(getchar())
+ if stridx(s:types, complType) != -1
+ if stridx("\<c-e>\<c-y>", complType) != -1 " no memory, just scroll...
+ return "\<c-x>" . complType
+ elseif stridx('np', complType) != -1
+ let complType = nr2char(char2nr(complType) - 96)
+ else
+ let complType = "\<c-x>" . complType
+ endif
+
+ let b:complTypeManual = complType
+
+ if index(['insert', 'session'], g:SuperTabRetainCompletionDuration) != -1
+ let b:complType = complType
+ endif
+
+ " Hack to workaround bug when invoking command line completion via <c-r>=
+ if complType == "\<c-x>\<c-v>"
+ return s:CommandLineCompletion()
+ endif
+
+ " optionally enable enhanced longest completion
+ if g:SuperTabLongestEnhanced && &completeopt =~ 'longest'
+ call s:EnableLongestEnhancement()
+ endif
+
+ if g:SuperTabLongestHighlight &&
+ \ &completeopt =~ 'longest' &&
+ \ &completeopt =~ 'menu' &&
+ \ !pumvisible()
+ let dir = (complType == "\<c-x>\<c-p>") ? -1 : 1
+ call feedkeys("\<c-r>=SuperTabLongestHighlight(" . dir . ")\<cr>", 'n')
+ endif
+
+ return complType
+ endif
+
+ echohl "Unknown mode"
+ return complType
+endfunction " }}}
+
+" s:SetCompletionType() {{{
+" Sets the completion type based on what the user has chosen from the help
+" buffer.
+function! s:SetCompletionType()
+ let chosen = substitute(getline('.'), '.*|\(.*\)|.*', '\1', '')
+ if chosen != getline('.')
+ let winnr = b:winnr
+ close
+ exec winnr . 'winc w'
+ call SuperTabSetCompletionType(chosen)
+ endif
+endfunction " }}}
+
+" s:SetDefaultCompletionType() {{{
+function! s:SetDefaultCompletionType()
+ if exists('b:SuperTabDefaultCompletionType') &&
+ \ (!exists('b:complCommandLine') || !b:complCommandLine)
+ call SuperTabSetCompletionType(b:SuperTabDefaultCompletionType)
+ endif
+endfunction " }}}
+
+" s:SuperTab(command) {{{
+" Used to perform proper cycle navigation as the user requests the next or
+" previous entry in a completion list, and determines whether or not to simply
+" retain the normal usage of <tab> based on the cursor position.
+function! s:SuperTab(command)
+ if exists('b:SuperTabDisabled') && b:SuperTabDisabled
+ return "\<tab>"
+ endif
+
+ call s:InitBuffer()
+
+ if s:WillComplete()
+ " optionally enable enhanced longest completion
+ if g:SuperTabLongestEnhanced && &completeopt =~ 'longest'
+ call s:EnableLongestEnhancement()
+ endif
+
+ if !pumvisible()
+ let b:complTypeManual = ''
+ endif
+
+ " exception: if in <c-p> mode, then <c-n> should move up the list, and
+ " <c-p> down the list.
+ if a:command == 'p' && !b:complReset &&
+ \ (b:complType == "\<c-p>" ||
+ \ (b:complType == 'context' &&
+ \ b:complTypeManual == '' &&
+ \ b:complTypeContext == "\<c-p>"))
+ return "\<c-n>"
+
+ elseif a:command == 'p' && !b:complReset &&
+ \ (b:complType == "\<c-n>" ||
+ \ (b:complType == 'context' &&
+ \ b:complTypeManual == '' &&
+ \ b:complTypeContext == "\<c-n>"))
+ return "\<c-p>"
+
+ " already in completion mode and not resetting for longest enhancement, so
+ " just scroll to next/previous
+ elseif pumvisible() && !b:complReset
+ let type = b:complType == 'context' ? b:complTypeContext : b:complType
+ if a:command == 'n'
+ return type == "\<c-p>" ? "\<c-p>" : "\<c-n>"
+ endif
+ return type == "\<c-p>" ? "\<c-n>" : "\<c-p>"
+ endif
+
+ " handle 'context' completion.
+ if b:complType == 'context'
+ let complType = s:ContextCompletion()
+ if complType == ''
+ exec "let complType = \"" .
+ \ escape(g:SuperTabContextDefaultCompletionType, '<') . "\""
+ endif
+ let b:complTypeContext = complType
+
+ " Hack to workaround bug when invoking command line completion via <c-r>=
+ elseif b:complType == "\<c-x>\<c-v>"
+ let complType = s:CommandLineCompletion()
+ else
+ let complType = b:complType
+ endif
+
+ " highlight first result if longest enabled
+ if g:SuperTabLongestHighlight &&
+ \ &completeopt =~ 'longest' &&
+ \ &completeopt =~ 'menu' &&
+ \ (!pumvisible() || b:complReset)
+ let dir = (complType == "\<c-p>") ? -1 : 1
+ call feedkeys("\<c-r>=SuperTabLongestHighlight(" . dir . ")\<cr>", 'n')
+ endif
+
+ if b:complReset
+ let b:complReset = 0
+ " not an accurate condition for everyone, but better than sending <c-e>
+ " at the wrong time.
+ if pumvisible()
+ return "\<c-e>" . complType
+ endif
+ endif
+
+ return complType
+ endif
+
+ return "\<tab>"
+endfunction " }}}
+
+" s:SuperTabHelp() {{{
+" Opens a help window where the user can choose a completion type to enter.
+function! s:SuperTabHelp()
+ let winnr = winnr()
+ if bufwinnr("SuperTabHelp") == -1
+ botright split SuperTabHelp
+
+ setlocal noswapfile
+ setlocal buftype=nowrite
+ setlocal bufhidden=delete
+
+ let saved = @"
+ let @" = s:tabHelp
+ silent put
+ call cursor(1, 1)
+ silent 1,delete
+ call cursor(4, 1)
+ let @" = saved
+ exec "resize " . line('$')
+
+ syntax match Special "|.\{-}|"
+
+ setlocal readonly
+ setlocal nomodifiable
+
+ nmap <silent> <buffer> <cr> :call <SID>SetCompletionType()<cr>
+ nmap <silent> <buffer> <c-]> :call <SID>SetCompletionType()<cr>
+ else
+ exec bufwinnr("SuperTabHelp") . "winc w"
+ endif
+ let b:winnr = winnr
+endfunction " }}}
+
+" s:WillComplete() {{{
+" Determines if completion should be kicked off at the current location.
+function! s:WillComplete()
+ if pumvisible()
+ return 1
+ endif
+
+ let line = getline('.')
+ let cnum = col('.')
+
+ " Start of line.
+ if line =~ '^\s*\%' . cnum . 'c'
+ return 0
+ endif
+
+ " honor SuperTabNoCompleteAfter
+ let pre = line[:cnum - 2]
+ for pattern in b:SuperTabNoCompleteAfter
+ if pre =~ pattern . '$'
+ return 0
+ endif
+ endfor
+
+ " honor SuperTabNoCompleteBefore
+ " Within a word, but user does not have mid word completion enabled.
+ let post = line[cnum - 1:]
+ for pattern in b:SuperTabNoCompleteBefore
+ if post =~ '^' . pattern
+ return 0
+ endif
+ endfor
+
+ return 1
+endfunction " }}}
+
+" s:EnableLongestEnhancement() {{{
+function! s:EnableLongestEnhancement()
+ augroup supertab_reset
+ autocmd!
+ autocmd InsertLeave,CursorMovedI <buffer>
+ \ call s:ReleaseKeyPresses() | autocmd! supertab_reset
+ augroup END
+ call s:CaptureKeyPresses()
+endfunction " }}}
+
+" s:CompletionReset(char) {{{
+function! s:CompletionReset(char)
+ let b:complReset = 1
+ return a:char
+endfunction " }}}
+
+" s:CaptureKeyPresses() {{{
+function! s:CaptureKeyPresses()
+ if !exists('b:capturing') || !b:capturing
+ let b:capturing = 1
+ " save any previous mappings
+ " TODO: capture additional info provided by vim 7.3.032 and up.
+ let b:captured = {
+ \ '<bs>': maparg('<bs>', 'i'),
+ \ '<c-h>': maparg('<c-h>', 'i'),
+ \ }
+ " TODO: use &keyword to get an accurate list of chars to map
+ for c in split('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_', '.\zs')
+ exec 'imap <buffer> ' . c . ' <c-r>=<SID>CompletionReset("' . c . '")<cr>'
+ endfor
+ imap <buffer> <bs> <c-r>=<SID>CompletionReset("\<lt>bs>")<cr>
+ imap <buffer> <c-h> <c-r>=<SID>CompletionReset("\<lt>c-h>")<cr>
+ endif
+endfunction " }}}
+
+" s:ReleaseKeyPresses() {{{
+function! s:ReleaseKeyPresses()
+ if exists('b:capturing') && b:capturing
+ let b:capturing = 0
+ for c in split('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_', '.\zs')
+ exec 'iunmap <buffer> ' . c
+ endfor
+
+ iunmap <buffer> <bs>
+ iunmap <buffer> <c-h>
+
+ " restore any previous mappings
+ for [key, rhs] in items(b:captured)
+ if rhs != ''
+ let args = substitute(rhs, '.*\(".\{-}"\).*', '\1', '')
+ if args != rhs
+ let args = substitute(args, '<', '<lt>', 'g')
+ let expr = substitute(rhs, '\(.*\)".\{-}"\(.*\)', '\1%s\2', '')
+ let rhs = printf(expr, args)
+ endif
+ exec printf("imap <silent> %s %s", key, rhs)
+ endif
+ endfor
+ unlet b:captured
+
+ if mode() == 'i' && &completeopt =~ 'menu'
+ " force full exit from completion mode (don't exit insert mode since
+ " that will break repeating with '.')
+ call feedkeys("\<space>\<bs>", 'n')
+ endif
+ endif
+endfunction " }}}
+
+" s:CommandLineCompletion() {{{
+" Hack needed to account for apparent bug in vim command line mode completion
+" when invoked via <c-r>=
+function! s:CommandLineCompletion()
+ " This hack will trigger InsertLeave which will then invoke
+ " s:SetDefaultCompletionType. To prevent default completion from being
+ " restored prematurely, set an internal flag for s:SetDefaultCompletionType
+ " to check for.
+ let b:complCommandLine = 1
+ return "\<c-\>\<c-o>:call feedkeys('\<c-x>\<c-v>\<c-v>', 'n') | " .
+ \ "let b:complCommandLine = 0\<cr>"
+endfunction " }}}
+
+" s:ContextCompletion() {{{
+function! s:ContextCompletion()
+ let contexts = exists('b:SuperTabCompletionContexts') ?
+ \ b:SuperTabCompletionContexts : g:SuperTabCompletionContexts
+
+ for context in contexts
+ try
+ let Context = function(context)
+ let complType = Context()
+ unlet Context
+ if type(complType) == 1 && complType != ''
+ return complType
+ endif
+ catch /E700/
+ echohl Error
+ echom 'supertab: no context function "' . context . '" found.'
+ echohl None
+ endtry
+ endfor
+ return ''
+endfunction " }}}
+
+" s:ContextDiscover() {{{
+function! s:ContextDiscover()
+ let discovery = exists('g:SuperTabContextDiscoverDiscovery') ?
+ \ g:SuperTabContextDiscoverDiscovery : []
+
+ " loop through discovery list to find the default
+ if !empty(discovery)
+ for pair in discovery
+ let var = substitute(pair, '\(.*\):.*', '\1', '')
+ let type = substitute(pair, '.*:\(.*\)', '\1', '')
+ exec 'let value = ' . var
+ if value !~ '^\s*$' && value != '0'
+ exec "let complType = \"" . escape(type, '<') . "\""
+ return complType
+ endif
+ endfor
+ endif
+endfunction " }}}
+
+" s:ContextText() {{{
+function! s:ContextText()
+ let exclusions = exists('g:SuperTabContextTextFileTypeExclusions') ?
+ \ g:SuperTabContextTextFileTypeExclusions : []
+
+ if index(exclusions, &ft) == -1
+ let curline = getline('.')
+ let cnum = col('.')
+ let synname = synIDattr(synID(line('.'), cnum - 1, 1), 'name')
+ if curline =~ '.*/\w*\%' . cnum . 'c' ||
+ \ ((has('win32') || has('win64')) && curline =~ '.*\\\w*\%' . cnum . 'c')
+ return "\<c-x>\<c-f>"
+
+ elseif curline =~ '.*\(\w\|[\])]\)\(\.\|::\|->\)\w*\%' . cnum . 'c' &&
+ \ synname !~ '\(String\|Comment\)'
+ let omniPrecedence = exists('g:SuperTabContextTextOmniPrecedence') ?
+ \ g:SuperTabContextTextOmniPrecedence : ['&completefunc', '&omnifunc']
+
+ for omniFunc in omniPrecedence
+ if omniFunc !~ '^&'
+ let omniFunc = '&' . omniFunc
+ endif
+ if getbufvar(bufnr('%'), omniFunc) != ''
+ return omniFunc == '&omnifunc' ? "\<c-x>\<c-o>" : "\<c-x>\<c-u>"
+ endif
+ endfor
+ endif
+ endif
+endfunction " }}}
+
+" s:ExpandMap(map) {{{
+function! s:ExpandMap(map)
+ let map = a:map
+ if map =~ '<Plug>'
+ let plug = substitute(map, '.\{-}\(<Plug>\w\+\).*', '\1', '')
+ let plug_map = maparg(plug, 'i')
+ let map = substitute(map, '.\{-}\(<Plug>\w\+\).*', plug_map, '')
+ endif
+ return map
+endfunction " }}}
+
+" Key Mappings {{{
+ " map a regular tab to ctrl-tab (note: doesn't work in console vim)
+ exec 'inoremap ' . g:SuperTabMappingTabLiteral . ' <tab>'
+
+ imap <c-x> <c-r>=<SID>ManualCompletionEnter()<cr>
+
+ imap <script> <Plug>SuperTabForward <c-r>=<SID>SuperTab('n')<cr>
+ imap <script> <Plug>SuperTabBackward <c-r>=<SID>SuperTab('p')<cr>
+
+ exec 'imap ' . g:SuperTabMappingForward . ' <Plug>SuperTabForward'
+ exec 'imap ' . g:SuperTabMappingBackward . ' <Plug>SuperTabBackward'
+
+ " After hitting <Tab>, hitting it once more will go to next match
+ " (because in XIM mode <c-n> and <c-p> mappings are ignored)
+ " and wont start a brand new completion
+ " The side effect, that in the beginning of line <c-n> and <c-p> inserts a
+ " <Tab>, but I hope it may not be a problem...
+ let ctrl_n = maparg('<c-n>', 'i')
+ if ctrl_n != ''
+ let ctrl_n = substitute(ctrl_n, '<', '<lt>', 'g')
+ exec 'imap <c-n> <c-r>=<SID>ForwardBack("n", "' . ctrl_n . '")<cr>'
+ else
+ imap <c-n> <Plug>SuperTabForward
+ endif
+ let ctrl_p = maparg('<c-p>', 'i')
+ if ctrl_p != ''
+ let ctrl_p = substitute(ctrl_p, '<', '<lt>', 'g')
+ exec 'imap <c-p> <c-r>=<SID>ForwardBack("p", "' . ctrl_p . '")<cr>'
+ else
+ imap <c-p> <Plug>SuperTabBackward
+ endif
+ function! s:ForwardBack(command, map)
+ exec "let map = \"" . escape(a:map, '<') . "\""
+ return pumvisible() ? s:SuperTab(a:command) : map
+ endfunction
+
+ if g:SuperTabCrMapping
+ if maparg('<CR>','i') =~ '<CR>'
+ let map = maparg('<cr>', 'i')
+ let cr = (map =~? '\(^\|[^)]\)<cr>')
+ let map = s:ExpandMap(map)
+ exec "inoremap <script> <cr> <c-r>=<SID>SelectCompletion(" . cr . ")<cr>" . map
+ else
+ inoremap <cr> <c-r>=<SID>SelectCompletion(1)<cr>
+ endif
+ function! s:SelectCompletion(cr)
+ " selecting a completion
+ if pumvisible()
+ " ugly hack to let other <cr> mappings for other plugins cooperate
+ " with supertab
+ let b:supertab_pumwasvisible = 1
+ return "\<c-y>"
+ endif
+
+ " only needed when chained with other mappings and one of them will
+ " issue a <cr>.
+ if exists('b:supertab_pumwasvisible') && !a:cr
+ unlet b:supertab_pumwasvisible
+ return ''
+ endif
+
+ " not so pleasant hack to keep <cr> working for abbreviations
+ let word = substitute(getline('.'), '^.*\s\+\(.*\%' . col('.') . 'c\).*', '\1', '')
+ if maparg(word, 'i', 1) != ''
+ call feedkeys("\<c-]>", 't')
+ call feedkeys("\<cr>", 'n')
+ return ''
+ endif
+
+ " only return a cr if nothing else is mapped to it since we don't want
+ " to duplicate a cr returned by another mapping.
+ return a:cr ? "\<cr>" : ""
+ endfunction
+ endif
+" }}}
+
+" Command Mappings {{{
+ if !exists(":SuperTabHelp")
+ command SuperTabHelp :call <SID>SuperTabHelp()
+ endif
+" }}}
+
+call s:Init()
+
+let &cpo = s:save_cpo
+
+" vim:ft=vim:fdm=marker
diff --git a/vim/plugin/surround.vim b/vim/plugin/surround.vim
new file mode 100644
index 0000000..ea28c02
--- /dev/null
+++ b/vim/plugin/surround.vim
@@ -0,0 +1,625 @@
+" surround.vim - Surroundings
+" Author: Tim Pope <vimNOSPAM@tpope.org>
+" Version: 1.90
+" GetLatestVimScripts: 1697 1 :AutoInstall: surround.vim
+"
+" See surround.txt for help. This can be accessed by doing
+"
+" :helptags ~/.vim/doc
+" :help surround
+"
+" Licensed under the same terms as Vim itself.
+
+" ============================================================================
+
+" Exit quickly when:
+" - this plugin was already loaded or disabled
+" - when 'compatible' is set
+if (exists("g:loaded_surround") && g:loaded_surround) || &cp
+ finish
+endif
+let g:loaded_surround = 1
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" 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 = c . s:getchar()
+ endwhile
+ if c == " "
+ let c = c . s:getchar()
+ endif
+ if c =~ "\<Esc>\|\<C-C>\|\0"
+ return ""
+ else
+ return c
+ endif
+endfunction
+
+function! s:inputreplacement()
+ "echo '-- SURROUND --'
+ let c = s:getchar()
+ if c == " "
+ let c = c . s:getchar()
+ endif
+ if c =~ "\<Esc>" || c =~ "\<C-C>"
+ return ""
+ else
+ return c
+ endif
+endfunction
+
+function! s:beep()
+ exe "norm! \<Esc>"
+ 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:repeat(str,count)
+ let cnt = a:count
+ let str = ""
+ while cnt > 0
+ let str = str . a:str
+ let cnt = cnt - 1
+ endwhile
+ return str
+endfunction
+
+function! s:fixindent(str,spc)
+ let str = substitute(a:str,'\t',s:repeat(' ',&sw),'g')
+ let spc = substitute(a:spc,'\t',s: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
+ while i < 7
+ let i = i + 1
+ 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
+ endwhile
+ 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 = 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 = s . insertion
+ let i = next
+ endif
+ else
+ let s = s . char
+ endif
+ let i = i + 1
+ endwhile
+ return s
+endfunction
+
+function! s:wrap(string,char,type,...)
+ let keeper = a:string
+ let newchar = a:char
+ 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
+ " Duplicate b's are just placeholders (removed)
+ 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 =~# "[tT\<C-T><,]"
+ let dounmapp = 0
+ let dounmapb = 0
+ if !maparg(">","c")
+ let dounmapb= 1
+ " Hide from AsNeeded
+ exe "cn"."oremap > <CR>"
+ 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
+ if tag != ""
+ let tag = substitute(tag,'>*$','','')
+ let before = '<'.tag.'>'
+ if tag =~ '/$'
+ let after = ''
+ else
+ let after = '</'.substitute(tag,' .*','','').'>'
+ endif
+ if newchar == "\<C-T>" || newchar == ","
+ if type ==# "v" || type ==# "V"
+ let before = 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 = env . s:closematch(env)
+ echo '\begin'.env
+ if env != ""
+ let before = '\begin'.env
+ let after = '\end'.matchstr(env,'[^}]*').'}'
+ endif
+ "if type ==# 'v' || type ==# 'V'
+ "let before = before ."\n\t"
+ "endif
+ "if type ==# 'v'
+ "let after = "\n".initspaces.after
+ "endif
+ elseif newchar ==# 'f' || newchar ==# 'F'
+ let fnc = input('function: ')
+ if fnc != ""
+ let before = substitute(fnc,'($','','').'('
+ let after = ')'
+ if newchar ==# 'F'
+ let before = before . ' '
+ let after = ' ' . after
+ endif
+ endif
+ 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 == "\<C-[>" || newchar == "\<C-]>"
+ let before = "{\n\t"
+ let after = "\n}"
+ elseif newchar !~ '\a'
+ let before = newchar
+ let after = newchar
+ else
+ let before = ''
+ let after = ''
+ endif
+ "let before = substitute(before,'\n','\n'.initspaces,'g')
+ let after = substitute(after ,'\n','\n'.initspaces,'g')
+ "let after = substitute(after,"\n\\s*\<C-U>\\s*",'\n','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 = keeper . "\n"
+ elseif keeper =~ '\n$' && after =~ '^\n'
+ let after = strpart(after,1)
+ endif
+ if before !~ '\n\s*$'
+ let before = before . "\n"
+ if special
+ let before = 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 =~ "^\<C-V>"
+ " 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
+ "call inputsave()
+ let linemode = a:0 ? a:1 : 0
+ let char = s:inputreplacement()
+ while char == "\<CR>" || char == "\<C-S>"
+ " TODO: use total count for additional blank lines
+ let linemode = linemode + 1
+ let char = s:inputreplacement()
+ endwhile
+ "call inputrestore()
+ if char == ""
+ return ""
+ endif
+ "call inputsave()
+ let cb_save = &clipboard
+ set clipboard-=unnamed
+ 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 linemode
+ "call setreg('"',substitute(getreg('"'),'^\s\+','',''),'c')
+ "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 "\<Del>"
+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 == "\<Esc>" || newchar == "\<C-C>" || newchar == ""
+ return s:beep()
+ endif
+ endif
+ let cb_save = &clipboard
+ set clipboard-=unnamed
+ let append = ""
+ let original = getreg('"')
+ let otype = getregtype('"')
+ call setreg('"',"")
+ let strcount = (scount == 1 ? "" : scount)
+ if char == '/'
+ exe 'norm! '.strcount.'[/d'.strcount.']/'
+ 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 \<Esc>d2i".char
+ call setreg('"',substitute(getreg('"'),' ','',''))
+ elseif char == '/'
+ norm! "_x
+ call setreg('"','/**/',"c")
+ let keeper = substitute(substitute(keeper,'^/\*\s\=','',''),'\s\=\*$','','')
+ else
+ " One character backwards
+ call search('.','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 =~# '[\[({<T]' || spc
+ let keeper = substitute(keeper,'^\s\+','','')
+ let keeper = substitute(keeper,'\s\+$','','')
+ endif
+ if col("']") == col("$") && col('.') + 1 == col('$')
+ if oldhead =~# '^\s*$' && a:0 < 2
+ let keeper = substitute(keeper,'\%^\n'.oldhead.'\(\s*.\{-\}\)\n\s*\%$','\1','')
+ endif
+ let pcmd = "p"
+ else
+ let pcmd = "P"
+ endif
+ if line('.') < oldlnum && regtype ==# "V"
+ let pcmd = "p"
+ endif
+ call setreg('"',keeper,regtype)
+ if newchar != ""
+ call s:wrapreg('"',newchar)
+ endif
+ silent exe 'norm! ""'.pcmd.'`['
+ if removed =~ '\n' || okeeper =~ '\n' || getreg('"') =~ '\n'
+ call s:reindent()
+ endif
+ if getline('.') =~ '^\s\+$' && keeper =~ '^\s*\n'
+ silent norm! cc
+ endif
+ call setreg('"',removed,regtype)
+ let s:lastdel = removed
+ let &clipboard = cb_save
+ if newchar == ""
+ silent! call repeat#set("\<Plug>Dsurround".char,scount)
+ else
+ silent! call repeat#set("\<Plug>Csurround".char.newchar,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
+ let reg_save = getreg(reg)
+ let reg_type = getregtype(reg)
+ "call setreg(reg,"\n","c")
+ 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 ==# "\<C-V>"
+ 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\@<!\s*$')
+ let keeper = substitute(keeper,'\_s\@<!\s*$','','')
+ endif
+ call setreg(reg,keeper,type)
+ call s:wrapreg(reg,char,a:0 && a:1)
+ if type ==# "v" && a:type !=# "v" && append != ""
+ call setreg(reg,append,"ac")
+ endif
+ silent exe 'norm! gv'.(reg == '"' ? '' : '"' . reg).'p`['
+ if type ==# 'V' || (getreg(reg) =~ '\n' && type ==# 'v')
+ call s:reindent()
+ endif
+ call setreg(reg,reg_save,reg_type)
+ let &selection = sel_save
+ let &clipboard = cb_save
+ if a:type =~ '^\d\+$'
+ silent! call repeat#set("\<Plug>Y".(a:0 && a:1 ? "S" : "s")."surround".char,a:type)
+ 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 <silent> <Plug>Dsurround :<C-U>call <SID>dosurround(<SID>inputtarget())<CR>
+nnoremap <silent> <Plug>Csurround :<C-U>call <SID>changesurround()<CR>
+nnoremap <silent> <Plug>Yssurround :<C-U>call <SID>opfunc(v:count1)<CR>
+nnoremap <silent> <Plug>YSsurround :<C-U>call <SID>opfunc2(v:count1)<CR>
+" <C-U> discards the numerical argument but there's not much we can do with it
+nnoremap <silent> <Plug>Ysurround :<C-U>set opfunc=<SID>opfunc<CR>g@
+nnoremap <silent> <Plug>YSurround :<C-U>set opfunc=<SID>opfunc2<CR>g@
+vnoremap <silent> <Plug>Vsurround :<C-U>call <SID>opfunc(visualmode())<CR>
+vnoremap <silent> <Plug>VSurround :<C-U>call <SID>opfunc(visualmode(),visualmode() ==# 'V' ? 1 : 0)<CR>
+vnoremap <silent> <Plug>VgSurround :<C-U>call <SID>opfunc(visualmode(),visualmode() ==# 'V' ? 0 : 1)<CR>
+inoremap <silent> <Plug>Isurround <C-R>=<SID>insert()<CR>
+inoremap <silent> <Plug>ISurround <C-R>=<SID>insert(1)<CR>
+
+if !exists("g:surround_no_mappings") || ! g:surround_no_mappings
+ nmap ds <Plug>Dsurround
+ nmap cs <Plug>Csurround
+ nmap ys <Plug>Ysurround
+ nmap yS <Plug>YSurround
+ nmap yss <Plug>Yssurround
+ nmap ySs <Plug>YSsurround
+ nmap ySS <Plug>YSsurround
+ if !hasmapto("<Plug>Vsurround","v") && !hasmapto("<Plug>VSurround","v")
+ if exists(":xmap")
+ xmap s <Plug>Vsurround
+ else
+ vmap s <Plug>Vsurround
+ endif
+ endif
+ if !hasmapto("<Plug>VSurround","v")
+ if exists(":xmap")
+ xmap S <Plug>VSurround
+ else
+ vmap S <Plug>VSurround
+ endif
+ endif
+ if exists(":xmap")
+ xmap gS <Plug>VgSurround
+ else
+ vmap gS <Plug>VgSurround
+ endif
+ if !hasmapto("<Plug>Isurround","i") && "" == mapcheck("<C-S>","i")
+ imap <C-S> <Plug>Isurround
+ endif
+ imap <C-G>s <Plug>Isurround
+ imap <C-G>S <Plug>ISurround
+ "Implemented internally instead
+ "imap <C-S><C-S> <Plug>ISurround
+endif
+
+let &cpo = s:cpo_save
+
+" vim:set ft=vim sw=2 sts=2 et:
diff --git a/vim/plugin/syntastic.vim b/vim/plugin/syntastic.vim
new file mode 100644
index 0000000..0eb657a
--- /dev/null
+++ b/vim/plugin/syntastic.vim
@@ -0,0 +1,614 @@
+"============================================================================
+"File: syntastic.vim
+"Description: vim plugin for on the fly syntax checking
+"Maintainer: Martin Grenfell <martin.grenfell at gmail dot com>
+"Version: 2.3.0
+"Last Change: 16 Feb, 2012
+"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_syntastic_plugin")
+ finish
+endif
+let g:loaded_syntastic_plugin = 1
+
+let s:running_windows = has("win16") || has("win32") || has("win64")
+
+if !s:running_windows
+ let s:uname = system('uname')
+endif
+
+if !exists("g:syntastic_enable_signs")
+ let g:syntastic_enable_signs = 1
+endif
+if !has('signs')
+ let g:syntastic_enable_signs = 0
+endif
+
+if !exists("g:syntastic_enable_balloons")
+ let g:syntastic_enable_balloons = 1
+endif
+if !has('balloon_eval')
+ let g:syntastic_enable_balloons = 0
+endif
+
+if !exists("g:syntastic_enable_highlighting")
+ let g:syntastic_enable_highlighting = 1
+endif
+
+if !exists("g:syntastic_echo_current_error")
+ let g:syntastic_echo_current_error = 1
+endif
+
+if !exists("g:syntastic_auto_loc_list")
+ let g:syntastic_auto_loc_list = 2
+endif
+
+if !exists("g:syntastic_auto_jump")
+ let syntastic_auto_jump=0
+endif
+
+if !exists("g:syntastic_quiet_warnings")
+ let g:syntastic_quiet_warnings = 0
+endif
+
+if !exists("g:syntastic_stl_format")
+ let g:syntastic_stl_format = '[Syntax: line:%F (%t)]'
+endif
+
+if !exists("g:syntastic_mode_map")
+ let g:syntastic_mode_map = {}
+endif
+
+if !has_key(g:syntastic_mode_map, "mode")
+ let g:syntastic_mode_map['mode'] = 'active'
+endif
+
+if !has_key(g:syntastic_mode_map, "active_filetypes")
+ let g:syntastic_mode_map['active_filetypes'] = []
+endif
+
+if !has_key(g:syntastic_mode_map, "passive_filetypes")
+ let g:syntastic_mode_map['passive_filetypes'] = []
+endif
+
+if !exists("g:syntastic_check_on_open")
+ let g:syntastic_check_on_open = 0
+endif
+
+if !exists("g:syntastic_loc_list_height")
+ let g:syntastic_loc_list_height = 10
+endif
+
+command! SyntasticToggleMode call s:ToggleMode()
+command! SyntasticCheck call s:UpdateErrors(0) <bar> redraw!
+command! Errors call s:ShowLocList()
+
+highlight link SyntasticError SpellBad
+highlight link SyntasticWarning SpellCap
+
+augroup syntastic
+ if g:syntastic_echo_current_error
+ autocmd cursormoved * call s:EchoCurrentError()
+ endif
+
+ autocmd BufReadPost * if g:syntastic_check_on_open | call s:UpdateErrors(1) | endif
+ autocmd BufWritePost * call s:UpdateErrors(1)
+
+ autocmd BufWinEnter * if empty(&bt) | call s:AutoToggleLocList() | endif
+ autocmd BufWinLeave * if empty(&bt) | lclose | endif
+augroup END
+
+
+"refresh and redraw all the error info for this buf when saving or reading
+function! s:UpdateErrors(auto_invoked)
+ if !empty(&buftype)
+ return
+ endif
+
+ if !a:auto_invoked || s:ModeMapAllowsAutoChecking()
+ call s:CacheErrors()
+ end
+
+ if s:BufHasErrorsOrWarningsToDisplay()
+ call setloclist(0, s:LocList())
+ endif
+
+ if g:syntastic_enable_balloons
+ call s:RefreshBalloons()
+ endif
+
+ if g:syntastic_enable_signs
+ call s:RefreshSigns()
+ endif
+
+ if g:syntastic_auto_jump && s:BufHasErrorsOrWarningsToDisplay()
+ silent! ll
+ endif
+
+ call s:AutoToggleLocList()
+endfunction
+
+"automatically open/close the location list window depending on the users
+"config and buffer error state
+function! s:AutoToggleLocList()
+ if s:BufHasErrorsOrWarningsToDisplay()
+ if g:syntastic_auto_loc_list == 1
+ call s:ShowLocList()
+ endif
+ else
+ if g:syntastic_auto_loc_list > 0
+
+ "TODO: this will close the loc list window if one was opened by
+ "something other than syntastic
+ lclose
+ endif
+ endif
+endfunction
+
+"lazy init the loc list for the current buffer
+function! s:LocList()
+ if !exists("b:syntastic_loclist")
+ let b:syntastic_loclist = []
+ endif
+ return b:syntastic_loclist
+endfunction
+
+"clear the loc list for the buffer
+function! s:ClearLocList()
+ let b:syntastic_loclist = []
+endfunction
+
+"detect and cache all syntax errors in this buffer
+"
+"depends on a function called SyntaxCheckers_{&ft}_GetLocList() existing
+"elsewhere
+function! s:CacheErrors()
+ call s:ClearLocList()
+
+ if filereadable(expand("%"))
+
+ "sub - for _ in filetypes otherwise we cant name syntax checker
+ "functions legally for filetypes like "gentoo-metadata"
+ let fts = substitute(&ft, '-', '_', 'g')
+ for ft in split(fts, '\.')
+ if s:Checkable(ft)
+ let errors = SyntaxCheckers_{ft}_GetLocList()
+ "make errors have type "E" by default
+ call SyntasticAddToErrors(errors, {'type': 'E'})
+ call extend(s:LocList(), errors)
+ endif
+ endfor
+ endif
+endfunction
+
+"toggle the g:syntastic_mode_map['mode']
+function! s:ToggleMode()
+ if g:syntastic_mode_map['mode'] == "active"
+ let g:syntastic_mode_map['mode'] = "passive"
+ else
+ let g:syntastic_mode_map['mode'] = "active"
+ endif
+
+ call s:ClearLocList()
+ call s:UpdateErrors(1)
+
+ echo "Syntastic: " . g:syntastic_mode_map['mode'] . " mode enabled"
+endfunction
+
+"check the current filetypes against g:syntastic_mode_map to determine whether
+"active mode syntax checking should be done
+function! s:ModeMapAllowsAutoChecking()
+ let fts = split(&ft, '\.')
+
+ if g:syntastic_mode_map['mode'] == 'passive'
+ "check at least one filetype is active
+ let actives = g:syntastic_mode_map["active_filetypes"]
+ return !empty(filter(fts, 'index(actives, v:val) != -1'))
+ else
+ "check no filetypes are passive
+ let passives = g:syntastic_mode_map["passive_filetypes"]
+ return empty(filter(fts, 'index(passives, v:val) != -1'))
+ endif
+endfunction
+
+"return true if there are cached errors/warnings for this buf
+function! s:BufHasErrorsOrWarnings()
+ return !empty(s:LocList())
+endfunction
+
+"return true if there are cached errors for this buf
+function! s:BufHasErrors()
+ return len(s:ErrorsForType('E')) > 0
+endfunction
+
+function! s:BufHasErrorsOrWarningsToDisplay()
+ return s:BufHasErrors() || (!g:syntastic_quiet_warnings && s:BufHasErrorsOrWarnings())
+endfunction
+
+function! s:ErrorsForType(type)
+ return s:FilterLocList({'type': a:type})
+endfunction
+
+function! s:Errors()
+ return s:ErrorsForType("E")
+endfunction
+
+function! s:Warnings()
+ return s:ErrorsForType("W")
+endfunction
+
+"Filter a loc list (defaults to s:LocList()) by a:filters
+"e.g.
+" s:FilterLocList({'bufnr': 10, 'type': 'e'})
+"
+"would return all errors in s:LocList() for buffer 10.
+"
+"Note that all comparisons are done with ==?
+function! s:FilterLocList(filters, ...)
+ let llist = a:0 ? a:1 : s:LocList()
+
+ let rv = deepcopy(llist)
+ for error in llist
+ for key in keys(a:filters)
+ let rhs = a:filters[key]
+ if type(rhs) == 1 "string
+ let rhs = '"' . rhs . '"'
+ endif
+
+ call filter(rv, "v:val['".key."'] ==? " . rhs)
+ endfor
+ endfor
+ return rv
+endfunction
+
+if g:syntastic_enable_signs
+ "define the signs used to display syntax and style errors/warns
+ sign define SyntasticError text=>> texthl=error
+ sign define SyntasticWarning text=>> texthl=todo
+ sign define SyntasticStyleError text=S> texthl=error
+ sign define SyntasticStyleWarning text=S> texthl=todo
+endif
+
+"start counting sign ids at 5000, start here to hopefully avoid conflicting
+"with any other code that places signs (not sure if this precaution is
+"actually needed)
+let s:first_sign_id = 5000
+let s:next_sign_id = s:first_sign_id
+
+"place signs by all syntax errs in the buffer
+function! s:SignErrors()
+ if s:BufHasErrorsOrWarningsToDisplay()
+
+ let errors = s:FilterLocList({'bufnr': bufnr('')})
+ for i in errors
+ let sign_severity = 'Error'
+ let sign_subtype = ''
+ if has_key(i,'subtype')
+ let sign_subtype = i['subtype']
+ endif
+ if i['type'] ==? 'w'
+ let sign_severity = 'Warning'
+ endif
+ let sign_type = 'Syntastic' . sign_subtype . sign_severity
+
+ if !s:WarningMasksError(i, errors)
+ exec "sign place ". s:next_sign_id ." line=". i['lnum'] ." name=". sign_type ." file=". expand("%:p")
+ call add(s:BufSignIds(), s:next_sign_id)
+ let s:next_sign_id += 1
+ endif
+ endfor
+ endif
+endfunction
+
+"return true if the given error item is a warning that, if signed, would
+"potentially mask an error if displayed at the same time
+function! s:WarningMasksError(error, llist)
+ if a:error['type'] !=? 'w'
+ return 0
+ endif
+
+ return len(s:FilterLocList({ 'type': "E", 'lnum': a:error['lnum'] }, a:llist)) > 0
+endfunction
+
+"remove the signs with the given ids from this buffer
+function! s:RemoveSigns(ids)
+ for i in a:ids
+ exec "sign unplace " . i
+ call remove(s:BufSignIds(), index(s:BufSignIds(), i))
+ endfor
+endfunction
+
+"get all the ids of the SyntaxError signs in the buffer
+function! s:BufSignIds()
+ if !exists("b:syntastic_sign_ids")
+ let b:syntastic_sign_ids = []
+ endif
+ return b:syntastic_sign_ids
+endfunction
+
+"update the error signs
+function! s:RefreshSigns()
+ let old_signs = copy(s:BufSignIds())
+ call s:SignErrors()
+ call s:RemoveSigns(old_signs)
+ let s:first_sign_id = s:next_sign_id
+endfunction
+
+"display the cached errors for this buf in the location list
+function! s:ShowLocList()
+ if !empty(s:LocList())
+ let num = winnr()
+ exec "lopen " . g:syntastic_loc_list_height
+ if num != winnr()
+ wincmd p
+ endif
+ endif
+endfunction
+
+"remove all error highlights from the window
+function! s:ClearErrorHighlights()
+ for match in getmatches()
+ if stridx(match['group'], 'Syntastic') == 0
+ call matchdelete(match['id'])
+ endif
+ endfor
+endfunction
+
+"check if a syntax checker exists for the given filetype - and attempt to
+"load one
+function! s:Checkable(ft)
+ if !exists("g:loaded_" . a:ft . "_syntax_checker")
+ exec "runtime syntax_checkers/" . a:ft . ".vim"
+ endif
+
+ return exists("*SyntaxCheckers_". a:ft ."_GetLocList")
+endfunction
+
+"set up error ballons for the current set of errors
+function! s:RefreshBalloons()
+ let b:syntastic_balloons = {}
+ if s:BufHasErrorsOrWarningsToDisplay()
+ for i in s:LocList()
+ let b:syntastic_balloons[i['lnum']] = i['text']
+ endfor
+ set beval bexpr=SyntasticErrorBalloonExpr()
+ endif
+endfunction
+
+"print as much of a:msg as possible without "Press Enter" prompt appearing
+function! s:WideMsg(msg)
+ let old_ruler = &ruler
+ let old_showcmd = &showcmd
+
+ let msg = strpart(a:msg, 0, winwidth(0)-1)
+
+ "This is here because it is possible for some error messages to begin with
+ "\n which will cause a "press enter" prompt. I have noticed this in the
+ "javascript:jshint checker and have been unable to figure out why it
+ "happens
+ let msg = substitute(msg, "\n", "", "g")
+
+ set noruler noshowcmd
+ redraw
+
+ echo msg
+
+ let &ruler=old_ruler
+ let &showcmd=old_showcmd
+endfunction
+
+"echo out the first error we find for the current line in the cmd window
+function! s:EchoCurrentError()
+ "If we have an error or warning at the current line, show it
+ let errors = s:FilterLocList({'lnum': line("."), "type": 'e'})
+ let warnings = s:FilterLocList({'lnum': line("."), "type": 'w'})
+
+ let b:syntastic_echoing_error = len(errors) || len(warnings)
+ if len(errors)
+ return s:WideMsg(errors[0]['text'])
+ endif
+ if len(warnings)
+ return s:WideMsg(warnings[0]['text'])
+ endif
+
+ "Otherwise, clear the status line
+ if b:syntastic_echoing_error
+ echo
+ let b:syntastic_echoing_error = 0
+ endif
+endfunction
+
+"load the chosen checker for the current filetype - useful for filetypes like
+"javascript that have more than one syntax checker
+function! s:LoadChecker(checker)
+ exec "runtime syntax_checkers/" . &ft . "/" . a:checker . ".vim"
+endfunction
+
+"return a string representing the state of buffer according to
+"g:syntastic_stl_format
+"
+"return '' if no errors are cached for the buffer
+function! SyntasticStatuslineFlag()
+ if s:BufHasErrorsOrWarningsToDisplay()
+ let errors = s:Errors()
+ let warnings = s:Warnings()
+
+ let output = g:syntastic_stl_format
+
+ "hide stuff wrapped in %E(...) unless there are errors
+ let output = substitute(output, '\C%E{\([^}]*\)}', len(errors) ? '\1' : '' , 'g')
+
+ "hide stuff wrapped in %W(...) unless there are warnings
+ let output = substitute(output, '\C%W{\([^}]*\)}', len(warnings) ? '\1' : '' , 'g')
+
+ "hide stuff wrapped in %B(...) unless there are both errors and warnings
+ let output = substitute(output, '\C%B{\([^}]*\)}', (len(warnings) && len(errors)) ? '\1' : '' , 'g')
+
+ "sub in the total errors/warnings/both
+ let output = substitute(output, '\C%w', len(warnings), 'g')
+ let output = substitute(output, '\C%e', len(errors), 'g')
+ let output = substitute(output, '\C%t', len(s:LocList()), 'g')
+
+ "first error/warning line num
+ let output = substitute(output, '\C%F', s:LocList()[0]['lnum'], 'g')
+
+ "first error line num
+ let output = substitute(output, '\C%fe', len(errors) ? errors[0]['lnum'] : '', 'g')
+
+ "first warning line num
+ let output = substitute(output, '\C%fw', len(warnings) ? warnings[0]['lnum'] : '', 'g')
+
+ return output
+ else
+ return ''
+ endif
+endfunction
+
+"A wrapper for the :lmake command. Sets up the make environment according to
+"the options given, runs make, resets the environment, returns the location
+"list
+"
+"a:options can contain the following keys:
+" 'makeprg'
+" 'errorformat'
+"
+"The corresponding options are set for the duration of the function call. They
+"are set with :let, so dont escape spaces.
+"
+"a:options may also contain:
+" 'defaults' - a dict containing default values for the returned errors
+" 'subtype' - all errors will be assigned the given subtype
+function! SyntasticMake(options)
+ let old_loclist = getloclist(0)
+ let old_makeprg = &makeprg
+ let old_shellpipe = &shellpipe
+ let old_shell = &shell
+ let old_errorformat = &errorformat
+
+ if !s:running_windows && (s:uname !~ "FreeBSD")
+ "this is a hack to stop the screen needing to be ':redraw'n when
+ "when :lmake is run. Otherwise the screen flickers annoyingly
+ let &shellpipe='&>'
+ let &shell = '/bin/bash'
+ endif
+
+ if has_key(a:options, 'makeprg')
+ let &makeprg = a:options['makeprg']
+ endif
+
+ if has_key(a:options, 'errorformat')
+ let &errorformat = a:options['errorformat']
+ endif
+
+ silent lmake!
+ let errors = getloclist(0)
+
+ call setloclist(0, old_loclist)
+ let &makeprg = old_makeprg
+ let &errorformat = old_errorformat
+ let &shellpipe=old_shellpipe
+ let &shell=old_shell
+
+ if !s:running_windows && s:uname =~ "FreeBSD"
+ redraw!
+ endif
+
+ if has_key(a:options, 'defaults')
+ call SyntasticAddToErrors(errors, a:options['defaults'])
+ endif
+
+ " Add subtype info if present.
+ if has_key(a:options, 'subtype')
+ call SyntasticAddToErrors(errors, {'subtype': a:options['subtype']})
+ endif
+
+ return errors
+endfunction
+
+"get the error balloon for the current mouse position
+function! SyntasticErrorBalloonExpr()
+ if !exists('b:syntastic_balloons')
+ return ''
+ endif
+ return get(b:syntastic_balloons, v:beval_lnum, '')
+endfunction
+
+"highlight the list of errors (a:errors) using matchadd()
+"
+"a:termfunc is provided to highlight errors that do not have a 'col' key (and
+"hence cant be done automatically). This function must take one arg (an error
+"item) and return a regex to match that item in the buffer.
+"
+"an optional boolean third argument can be provided to force a:termfunc to be
+"used regardless of whether a 'col' key is present for the error
+function! SyntasticHighlightErrors(errors, termfunc, ...)
+ if !g:syntastic_enable_highlighting
+ return
+ endif
+
+ call s:ClearErrorHighlights()
+
+ let force_callback = a:0 && a:1
+ for item in a:errors
+ let group = item['type'] == 'E' ? 'SyntasticError' : 'SyntasticWarning'
+ if item['col'] && !force_callback
+ let lastcol = col([item['lnum'], '$'])
+ let lcol = min([lastcol, item['col']])
+ call matchadd(group, '\%'.item['lnum'].'l\%'.lcol.'c')
+ else
+ let term = a:termfunc(item)
+ if len(term) > 0
+ call matchadd(group, '\%' . item['lnum'] . 'l' . term)
+ endif
+ endif
+ endfor
+endfunction
+
+"take a list of errors and add default values to them from a:options
+function! SyntasticAddToErrors(errors, options)
+ for i in range(0, len(a:errors)-1)
+ for key in keys(a:options)
+ if !has_key(a:errors[i], key) || empty(a:errors[i][key])
+ let a:errors[i][key] = a:options[key]
+ endif
+ endfor
+ endfor
+ return a:errors
+endfunction
+
+"take a list of syntax checkers for the current filetype and load the right
+"one based on the global settings and checker executable availabity
+"
+"a:checkers should be a list of syntax checker names. These names are assumed
+"to be the names of the vim syntax checker files that should be sourced, as
+"well as the names of the actual syntax checker executables. The checkers
+"should be listed in order of default preference.
+"
+"if a option called 'g:syntastic_[filetype]_checker' exists then attempt to
+"load the checker that it points to
+function! SyntasticLoadChecker(checkers)
+ let opt_name = "g:syntastic_" . &ft . "_checker"
+
+ if exists(opt_name)
+ let opt_val = {opt_name}
+ if index(a:checkers, opt_val) != -1 && executable(opt_val)
+ call s:LoadChecker(opt_val)
+ else
+ echoerr &ft . " syntax not supported or not installed."
+ endif
+ else
+ for checker in a:checkers
+ if executable(checker)
+ return s:LoadChecker(checker)
+ endif
+ endfor
+ endif
+endfunction
+
+" vim: set et sts=4 sw=4:
diff --git a/vim/plugin/tagbar.vim b/vim/plugin/tagbar.vim
new file mode 100644
index 0000000..a078a18
--- /dev/null
+++ b/vim/plugin/tagbar.vim
@@ -0,0 +1,118 @@
+" ============================================================================
+" File: tagbar.vim
+" Description: List the current file's tags in a sidebar, ordered by class etc
+" Author: Jan Larres <jan@majutsushi.net>
+" Licence: Vim licence
+" Website: http://majutsushi.github.com/tagbar/
+" Version: 2.3
+" Note: This plugin was heavily inspired by the 'Taglist' plugin by
+" Yegappan Lakshmanan and uses a small amount of code from it.
+"
+" Original taglist copyright notice:
+" Permission is hereby granted to use and distribute this code,
+" with or without modifications, provided that this copyright
+" notice is copied with it. Like anything else that's free,
+" taglist.vim is provided *as is* and comes with no warranty of
+" any kind, either expressed or implied. In no event will the
+" copyright holder be liable for any damamges resulting from the
+" use of this software.
+" ============================================================================
+
+scriptencoding utf-8
+
+if &cp || exists('g:loaded_tagbar')
+ finish
+endif
+
+" Basic init {{{1
+
+if v:version < 700
+ echohl WarningMsg
+ echomsg 'Tagbar: Vim version is too old, Tagbar requires at least 7.0'
+ echohl None
+ finish
+endif
+
+if v:version == 700 && !has('patch167')
+ echohl WarningMsg
+ echomsg 'Tagbar: Vim versions lower than 7.0.167 have a bug'
+ \ 'that prevents this version of Tagbar from working.'
+ \ 'Please use the alternate version posted on the website.'
+ echohl None
+ finish
+endif
+
+if !exists('g:tagbar_left')
+ let g:tagbar_left = 0
+endif
+
+if !exists('g:tagbar_width')
+ let g:tagbar_width = 40
+endif
+
+if !exists('g:tagbar_autoclose')
+ let g:tagbar_autoclose = 0
+endif
+
+if !exists('g:tagbar_autofocus')
+ let g:tagbar_autofocus = 0
+endif
+
+if !exists('g:tagbar_sort')
+ let g:tagbar_sort = 1
+endif
+
+if !exists('g:tagbar_compact')
+ let g:tagbar_compact = 0
+endif
+
+if !exists('g:tagbar_expand')
+ let g:tagbar_expand = 0
+endif
+
+if !exists('g:tagbar_singleclick')
+ let g:tagbar_singleclick = 0
+endif
+
+if !exists('g:tagbar_foldlevel')
+ let g:tagbar_foldlevel = 99
+endif
+
+if !exists('g:tagbar_iconchars')
+ if has('multi_byte') && has('unix') && &encoding == 'utf-8' &&
+ \ (empty(&termencoding) || &termencoding == 'utf-8')
+ let g:tagbar_iconchars = ['▶', '▼']
+ else
+ let g:tagbar_iconchars = ['+', '-']
+ endif
+endif
+
+if !exists('g:tagbar_autoshowtag')
+ let g:tagbar_autoshowtag = 0
+endif
+
+if !exists('g:tagbar_updateonsave_maxlines')
+ let g:tagbar_updateonsave_maxlines = 5000
+endif
+
+if !exists('g:tagbar_systemenc')
+ let g:tagbar_systemenc = &encoding
+endif
+
+augroup TagbarSession
+ autocmd!
+ autocmd SessionLoadPost * nested call tagbar#RestoreSession()
+augroup END
+
+" Commands {{{1
+command! -nargs=0 TagbarToggle call tagbar#ToggleWindow()
+command! -nargs=? TagbarOpen call tagbar#OpenWindow(<f-args>)
+command! -nargs=0 TagbarOpenAutoClose call tagbar#OpenWindow('fc')
+command! -nargs=0 TagbarClose call tagbar#CloseWindow()
+command! -nargs=1 TagbarSetFoldlevel call tagbar#SetFoldLevel(<args>)
+command! -nargs=0 TagbarShowTag call tagbar#OpenParents()
+command! -nargs=? TagbarDebug call tagbar#StartDebug(<f-args>)
+command! -nargs=0 TagbarDebugEnd call tagbar#StopDebug()
+
+" Modeline {{{1
+" vim: ts=8 sw=4 sts=4 et foldenable foldmethod=marker foldcolumn=1
diff --git a/vim/plugin/taglist.vim b/vim/plugin/taglist.vim
new file mode 100644
index 0000000..59901f6
--- /dev/null
+++ b/vim/plugin/taglist.vim
@@ -0,0 +1,4546 @@
+" File: taglist.vim
+" Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
+" Version: 4.5
+" Last Modified: September 21, 2007
+" Copyright: Copyright (C) 2002-2007 Yegappan Lakshmanan
+" Permission is hereby granted to use and distribute this code,
+" with or without modifications, provided that this copyright
+" notice is copied with it. Like anything else that's free,
+" taglist.vim is provided *as is* and comes with no warranty of any
+" kind, either expressed or implied. In no event will the copyright
+" holder be liable for any damamges resulting from the use of this
+" software.
+"
+" The "Tag List" plugin is a source code browser plugin for Vim and provides
+" an overview of the structure of the programming language files and allows
+" you to efficiently browse through source code files for different
+" programming languages. You can visit the taglist plugin home page for more
+" information:
+"
+" http://vim-taglist.sourceforge.net
+"
+" You can subscribe to the taglist mailing list to post your questions
+" or suggestions for improvement or to report bugs. Visit the following
+" page for subscribing to the mailing list:
+"
+" http://groups.yahoo.com/group/taglist/
+"
+" For more information about using this plugin, after installing the
+" taglist plugin, use the ":help taglist" command.
+"
+" Installation
+" ------------
+" 1. Download the taglist.zip file and unzip the files to the $HOME/.vim
+" or the $HOME/vimfiles or the $VIM/vimfiles directory. This should
+" unzip the following two files (the directory structure should be
+" preserved):
+"
+" plugin/taglist.vim - main taglist plugin file
+" doc/taglist.txt - documentation (help) file
+"
+" Refer to the 'add-plugin', 'add-global-plugin' and 'runtimepath'
+" Vim help pages for more details about installing Vim plugins.
+" 2. Change to the $HOME/.vim/doc or $HOME/vimfiles/doc or
+" $VIM/vimfiles/doc directory, start Vim and run the ":helptags ."
+" command to process the taglist help file.
+" 3. If the exuberant ctags utility is not present in your PATH, then set the
+" Tlist_Ctags_Cmd variable to point to the location of the exuberant ctags
+" utility (not to the directory) in the .vimrc file.
+" 4. If you are running a terminal/console version of Vim and the
+" terminal doesn't support changing the window width then set the
+" 'Tlist_Inc_Winwidth' variable to 0 in the .vimrc file.
+" 5. Restart Vim.
+" 6. You can now use the ":TlistToggle" command to open/close the taglist
+" window. You can use the ":help taglist" command to get more
+" information about using the taglist plugin.
+"
+" ****************** Do not modify after this line ************************
+
+" Line continuation used here
+let s:cpo_save = &cpo
+set cpo&vim
+
+if !exists('loaded_taglist')
+ " First time loading the taglist plugin
+ "
+ " To speed up the loading of Vim, the taglist plugin uses autoload
+ " mechanism to load the taglist functions.
+ " Only define the configuration variables, user commands and some
+ " auto-commands and finish sourcing the file
+
+ " The taglist plugin requires the built-in Vim system() function. If this
+ " function is not available, then don't load the plugin.
+ if !exists('*system')
+ echomsg 'Taglist: Vim system() built-in function is not available. ' .
+ \ 'Plugin is not loaded.'
+ let loaded_taglist = 'no'
+ let &cpo = s:cpo_save
+ finish
+ endif
+
+ " Location of the exuberant ctags tool
+ if !exists('Tlist_Ctags_Cmd')
+ if executable('exuberant-ctags')
+ " On Debian Linux, exuberant ctags is installed
+ " as exuberant-ctags
+ let Tlist_Ctags_Cmd = 'exuberant-ctags'
+ elseif executable('exctags')
+ " On Free-BSD, exuberant ctags is installed as exctags
+ let Tlist_Ctags_Cmd = 'exctags'
+ elseif executable('ctags')
+ let Tlist_Ctags_Cmd = 'ctags'
+ elseif executable('ctags.exe')
+ let Tlist_Ctags_Cmd = 'ctags.exe'
+ elseif executable('tags')
+ let Tlist_Ctags_Cmd = 'tags'
+ else
+ echomsg 'Taglist: Exuberant ctags (http://ctags.sf.net) ' .
+ \ 'not found in PATH. Plugin is not loaded.'
+ " Skip loading the plugin
+ let loaded_taglist = 'no'
+ let &cpo = s:cpo_save
+ finish
+ endif
+ endif
+
+
+ " Automatically open the taglist window on Vim startup
+ if !exists('Tlist_Auto_Open')
+ let Tlist_Auto_Open = 0
+ endif
+
+ " When the taglist window is toggle opened, move the cursor to the
+ " taglist window
+ if !exists('Tlist_GainFocus_On_ToggleOpen')
+ let Tlist_GainFocus_On_ToggleOpen = 0
+ endif
+
+ " Process files even when the taglist window is not open
+ if !exists('Tlist_Process_File_Always')
+ let Tlist_Process_File_Always = 0
+ endif
+
+ if !exists('Tlist_Show_Menu')
+ let Tlist_Show_Menu = 0
+ endif
+
+ " Tag listing sort type - 'name' or 'order'
+ if !exists('Tlist_Sort_Type')
+ let Tlist_Sort_Type = 'order'
+ endif
+
+ " Tag listing window split (horizontal/vertical) control
+ if !exists('Tlist_Use_Horiz_Window')
+ let Tlist_Use_Horiz_Window = 0
+ endif
+
+ " Open the vertically split taglist window on the left or on the right
+ " side. This setting is relevant only if Tlist_Use_Horiz_Window is set to
+ " zero (i.e. only for vertically split windows)
+ if !exists('Tlist_Use_Right_Window')
+ let Tlist_Use_Right_Window = 0
+ endif
+
+ " Increase Vim window width to display vertically split taglist window.
+ " For MS-Windows version of Vim running in a MS-DOS window, this must be
+ " set to 0 otherwise the system may hang due to a Vim limitation.
+ if !exists('Tlist_Inc_Winwidth')
+ if (has('win16') || has('win95')) && !has('gui_running')
+ let Tlist_Inc_Winwidth = 0
+ else
+ let Tlist_Inc_Winwidth = 1
+ endif
+ endif
+
+ " Vertically split taglist window width setting
+ if !exists('Tlist_WinWidth')
+ let Tlist_WinWidth = 30
+ endif
+
+ " Horizontally split taglist window height setting
+ if !exists('Tlist_WinHeight')
+ let Tlist_WinHeight = 10
+ endif
+
+ " Display tag prototypes or tag names in the taglist window
+ if !exists('Tlist_Display_Prototype')
+ let Tlist_Display_Prototype = 0
+ endif
+
+ " Display tag scopes in the taglist window
+ if !exists('Tlist_Display_Tag_Scope')
+ let Tlist_Display_Tag_Scope = 1
+ endif
+
+ " Use single left mouse click to jump to a tag. By default this is disabled.
+ " Only double click using the mouse will be processed.
+ if !exists('Tlist_Use_SingleClick')
+ let Tlist_Use_SingleClick = 0
+ endif
+
+ " Control whether additional help is displayed as part of the taglist or
+ " not. Also, controls whether empty lines are used to separate the tag
+ " tree.
+ if !exists('Tlist_Compact_Format')
+ let Tlist_Compact_Format = 0
+ endif
+
+ " Exit Vim if only the taglist window is currently open. By default, this is
+ " set to zero.
+ if !exists('Tlist_Exit_OnlyWindow')
+ let Tlist_Exit_OnlyWindow = 0
+ endif
+
+ " Automatically close the folds for the non-active files in the taglist
+ " window
+ if !exists('Tlist_File_Fold_Auto_Close')
+ let Tlist_File_Fold_Auto_Close = 0
+ endif
+
+ " Close the taglist window when a tag is selected
+ if !exists('Tlist_Close_On_Select')
+ let Tlist_Close_On_Select = 0
+ endif
+
+ " Automatically update the taglist window to display tags for newly
+ " edited files
+ if !exists('Tlist_Auto_Update')
+ let Tlist_Auto_Update = 1
+ endif
+
+ " Automatically highlight the current tag
+ if !exists('Tlist_Auto_Highlight_Tag')
+ let Tlist_Auto_Highlight_Tag = 1
+ endif
+
+ " Automatically highlight the current tag on entering a buffer
+ if !exists('Tlist_Highlight_Tag_On_BufEnter')
+ let Tlist_Highlight_Tag_On_BufEnter = 1
+ endif
+
+ " Enable fold column to display the folding for the tag tree
+ if !exists('Tlist_Enable_Fold_Column')
+ let Tlist_Enable_Fold_Column = 1
+ endif
+
+ " Display the tags for only one file in the taglist window
+ if !exists('Tlist_Show_One_File')
+ let Tlist_Show_One_File = 0
+ endif
+
+ if !exists('Tlist_Max_Submenu_Items')
+ let Tlist_Max_Submenu_Items = 20
+ endif
+
+ if !exists('Tlist_Max_Tag_Length')
+ let Tlist_Max_Tag_Length = 10
+ endif
+
+ " Do not change the name of the taglist title variable. The winmanager
+ " plugin relies on this name to determine the title for the taglist
+ " plugin.
+ let TagList_title = "__Tag_List__"
+
+ " Taglist debug messages
+ let s:tlist_msg = ''
+
+ " Define the taglist autocommand to automatically open the taglist window
+ " on Vim startup
+ if g:Tlist_Auto_Open
+ autocmd VimEnter * nested call s:Tlist_Window_Check_Auto_Open()
+ endif
+
+ " Refresh the taglist
+ if g:Tlist_Process_File_Always
+ autocmd BufEnter * call s:Tlist_Refresh()
+ endif
+
+ if g:Tlist_Show_Menu
+ autocmd GUIEnter * call s:Tlist_Menu_Init()
+ endif
+
+ " When the taglist buffer is created when loading a Vim session file,
+ " the taglist buffer needs to be initialized. The BufFilePost event
+ " is used to handle this case.
+ autocmd BufFilePost __Tag_List__ call s:Tlist_Vim_Session_Load()
+
+ " Define the user commands to manage the taglist window
+ command! -nargs=0 -bar TlistToggle call s:Tlist_Window_Toggle()
+ command! -nargs=0 -bar TlistOpen call s:Tlist_Window_Open()
+ " For backwards compatiblity define the Tlist command
+ command! -nargs=0 -bar Tlist TlistToggle
+ command! -nargs=+ -complete=file TlistAddFiles
+ \ call s:Tlist_Add_Files(<f-args>)
+ command! -nargs=+ -complete=dir TlistAddFilesRecursive
+ \ call s:Tlist_Add_Files_Recursive(<f-args>)
+ command! -nargs=0 -bar TlistClose call s:Tlist_Window_Close()
+ command! -nargs=0 -bar TlistUpdate call s:Tlist_Update_Current_File()
+ command! -nargs=0 -bar TlistHighlightTag call s:Tlist_Window_Highlight_Tag(
+ \ fnamemodify(bufname('%'), ':p'), line('.'), 2, 1)
+ " For backwards compatiblity define the TlistSync command
+ command! -nargs=0 -bar TlistSync TlistHighlightTag
+ command! -nargs=* -complete=buffer TlistShowPrototype
+ \ echo Tlist_Get_Tag_Prototype_By_Line(<f-args>)
+ command! -nargs=* -complete=buffer TlistShowTag
+ \ echo Tlist_Get_Tagname_By_Line(<f-args>)
+ command! -nargs=* -complete=file TlistSessionLoad
+ \ call s:Tlist_Session_Load(<q-args>)
+ command! -nargs=* -complete=file TlistSessionSave
+ \ call s:Tlist_Session_Save(<q-args>)
+ command! -bar TlistLock let Tlist_Auto_Update=0
+ command! -bar TlistUnlock let Tlist_Auto_Update=1
+
+ " Commands for enabling/disabling debug and to display debug messages
+ command! -nargs=? -complete=file -bar TlistDebug
+ \ call s:Tlist_Debug_Enable(<q-args>)
+ command! -nargs=0 -bar TlistUndebug call s:Tlist_Debug_Disable()
+ command! -nargs=0 -bar TlistMessages call s:Tlist_Debug_Show()
+
+ " Define autocommands to autoload the taglist plugin when needed.
+
+ " Trick to get the current script ID
+ map <SID>xx <SID>xx
+ let s:tlist_sid = substitute(maparg('<SID>xx'), '<SNR>\(\d\+_\)xx$',
+ \ '\1', '')
+ unmap <SID>xx
+
+ exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+ exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Window_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+ exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Menu_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+ exe 'autocmd FuncUndefined Tlist_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+ exe 'autocmd FuncUndefined TagList_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+
+ let loaded_taglist = 'fast_load_done'
+
+ if g:Tlist_Show_Menu && has('gui_running')
+ call s:Tlist_Menu_Init()
+ endif
+
+ " restore 'cpo'
+ let &cpo = s:cpo_save
+ finish
+endif
+
+if !exists('s:tlist_sid')
+ " Two or more versions of taglist plugin are installed. Don't
+ " load this version of the plugin.
+ finish
+endif
+
+unlet! s:tlist_sid
+
+if loaded_taglist != 'fast_load_done'
+ " restore 'cpo'
+ let &cpo = s:cpo_save
+ finish
+endif
+
+" Taglist plugin functionality is available
+let loaded_taglist = 'available'
+
+"------------------- end of user configurable options --------------------
+
+" Default language specific settings for supported file types and tag types
+"
+" Variable name format:
+"
+" s:tlist_def_{vim_ftype}_settings
+"
+" vim_ftype - Filetype detected by Vim
+"
+" Value format:
+"
+" <ctags_ftype>;<flag>:<name>;<flag>:<name>;...
+"
+" ctags_ftype - File type supported by exuberant ctags
+" flag - Flag supported by exuberant ctags to generate a tag type
+" name - Name of the tag type used in the taglist window to display the
+" tags of this type
+"
+
+" assembly language
+let s:tlist_def_asm_settings = 'asm;d:define;l:label;m:macro;t:type'
+
+" aspperl language
+let s:tlist_def_aspperl_settings = 'asp;f:function;s:sub;v:variable'
+
+" aspvbs language
+let s:tlist_def_aspvbs_settings = 'asp;f:function;s:sub;v:variable'
+
+" awk language
+let s:tlist_def_awk_settings = 'awk;f:function'
+
+" beta language
+let s:tlist_def_beta_settings = 'beta;f:fragment;s:slot;v:pattern'
+
+" c language
+let s:tlist_def_c_settings = 'c;d:macro;g:enum;s:struct;u:union;t:typedef;' .
+ \ 'v:variable;f:function'
+
+" c++ language
+let s:tlist_def_cpp_settings = 'c++;n:namespace;v:variable;d:macro;t:typedef;' .
+ \ 'c:class;g:enum;s:struct;u:union;f:function'
+
+" c# language
+let s:tlist_def_cs_settings = 'c#;d:macro;t:typedef;n:namespace;c:class;' .
+ \ 'E:event;g:enum;s:struct;i:interface;' .
+ \ 'p:properties;m:method'
+
+" cobol language
+let s:tlist_def_cobol_settings = 'cobol;d:data;f:file;g:group;p:paragraph;' .
+ \ 'P:program;s:section'
+
+" eiffel language
+let s:tlist_def_eiffel_settings = 'eiffel;c:class;f:feature'
+
+" erlang language
+let s:tlist_def_erlang_settings = 'erlang;d:macro;r:record;m:module;f:function'
+
+" expect (same as tcl) language
+let s:tlist_def_expect_settings = 'tcl;c:class;f:method;p:procedure'
+
+" fortran language
+let s:tlist_def_fortran_settings = 'fortran;p:program;b:block data;' .
+ \ 'c:common;e:entry;i:interface;k:type;l:label;m:module;' .
+ \ 'n:namelist;t:derived;v:variable;f:function;s:subroutine'
+
+" HTML language
+let s:tlist_def_html_settings = 'html;a:anchor;f:javascript function'
+
+" java language
+let s:tlist_def_java_settings = 'java;p:package;c:class;i:interface;' .
+ \ 'f:field;m:method'
+
+" javascript language
+let s:tlist_def_javascript_settings = 'javascript;f:function'
+
+" lisp language
+let s:tlist_def_lisp_settings = 'lisp;f:function'
+
+" lua language
+let s:tlist_def_lua_settings = 'lua;f:function'
+
+" makefiles
+let s:tlist_def_make_settings = 'make;m:macro'
+
+" pascal language
+let s:tlist_def_pascal_settings = 'pascal;f:function;p:procedure'
+
+" perl language
+let s:tlist_def_perl_settings = 'perl;c:constant;l:label;p:package;s:subroutine'
+
+" php language
+let s:tlist_def_php_settings = 'php;c:class;d:constant;v:variable;f:function'
+
+" python language
+let s:tlist_def_python_settings = 'python;c:class;m:member;f:function'
+
+" rexx language
+let s:tlist_def_rexx_settings = 'rexx;s:subroutine'
+
+" ruby language
+let s:tlist_def_ruby_settings = 'ruby;c:class;f:method;F:function;' .
+ \ 'm:singleton method'
+
+" scheme language
+let s:tlist_def_scheme_settings = 'scheme;s:set;f:function'
+
+" shell language
+let s:tlist_def_sh_settings = 'sh;f:function'
+
+" C shell language
+let s:tlist_def_csh_settings = 'sh;f:function'
+
+" Z shell language
+let s:tlist_def_zsh_settings = 'sh;f:function'
+
+" slang language
+let s:tlist_def_slang_settings = 'slang;n:namespace;f:function'
+
+" sml language
+let s:tlist_def_sml_settings = 'sml;e:exception;c:functor;s:signature;' .
+ \ 'r:structure;t:type;v:value;f:function'
+
+" sql language
+let s:tlist_def_sql_settings = 'sql;c:cursor;F:field;P:package;r:record;' .
+ \ 's:subtype;t:table;T:trigger;v:variable;f:function;p:procedure'
+
+" tcl language
+let s:tlist_def_tcl_settings = 'tcl;c:class;f:method;m:method;p:procedure'
+
+" vera language
+let s:tlist_def_vera_settings = 'vera;c:class;d:macro;e:enumerator;' .
+ \ 'f:function;g:enum;m:member;p:program;' .
+ \ 'P:prototype;t:task;T:typedef;v:variable;' .
+ \ 'x:externvar'
+
+"verilog language
+let s:tlist_def_verilog_settings = 'verilog;m:module;c:constant;P:parameter;' .
+ \ 'e:event;r:register;t:task;w:write;p:port;v:variable;f:function'
+
+" vim language
+let s:tlist_def_vim_settings = 'vim;a:autocmds;v:variable;f:function'
+
+" yacc language
+let s:tlist_def_yacc_settings = 'yacc;l:label'
+
+"------------------- end of language specific options --------------------
+
+" Vim window size is changed by the taglist plugin or not
+let s:tlist_winsize_chgd = -1
+" Taglist window is maximized or not
+let s:tlist_win_maximized = 0
+" Name of files in the taglist
+let s:tlist_file_names=''
+" Number of files in the taglist
+let s:tlist_file_count = 0
+" Number of filetypes supported by taglist
+let s:tlist_ftype_count = 0
+" Is taglist part of other plugins like winmanager or cream?
+let s:tlist_app_name = "none"
+" Are we displaying brief help text
+let s:tlist_brief_help = 1
+" List of files removed on user request
+let s:tlist_removed_flist = ""
+" Index of current file displayed in the taglist window
+let s:tlist_cur_file_idx = -1
+" Taglist menu is empty or not
+let s:tlist_menu_empty = 1
+
+" An autocommand is used to refresh the taglist window when entering any
+" buffer. We don't want to refresh the taglist window if we are entering the
+" file window from one of the taglist functions. The 'Tlist_Skip_Refresh'
+" variable is used to skip the refresh of the taglist window and is set
+" and cleared appropriately.
+let s:Tlist_Skip_Refresh = 0
+
+" Tlist_Window_Display_Help()
+function! s:Tlist_Window_Display_Help()
+ if s:tlist_app_name == "winmanager"
+ " To handle a bug in the winmanager plugin, add a space at the
+ " last line
+ call setline('$', ' ')
+ endif
+
+ if s:tlist_brief_help
+ " Add the brief help
+ call append(0, '" Press <F1> to display help text')
+ else
+ " Add the extensive help
+ call append(0, '" <enter> : Jump to tag definition')
+ call append(1, '" o : Jump to tag definition in new window')
+ call append(2, '" p : Preview the tag definition')
+ call append(3, '" <space> : Display tag prototype')
+ call append(4, '" u : Update tag list')
+ call append(5, '" s : Select sort field')
+ call append(6, '" d : Remove file from taglist')
+ call append(7, '" x : Zoom-out/Zoom-in taglist window')
+ call append(8, '" + : Open a fold')
+ call append(9, '" - : Close a fold')
+ call append(10, '" * : Open all folds')
+ call append(11, '" = : Close all folds')
+ call append(12, '" [[ : Move to the start of previous file')
+ call append(13, '" ]] : Move to the start of next file')
+ call append(14, '" q : Close the taglist window')
+ call append(15, '" <F1> : Remove help text')
+ endif
+endfunction
+
+" Tlist_Window_Toggle_Help_Text()
+" Toggle taglist plugin help text between the full version and the brief
+" version
+function! s:Tlist_Window_Toggle_Help_Text()
+ if g:Tlist_Compact_Format
+ " In compact display mode, do not display help
+ return
+ endif
+
+ " Include the empty line displayed after the help text
+ let brief_help_size = 1
+ let full_help_size = 16
+
+ setlocal modifiable
+
+ " Set report option to a huge value to prevent informational messages
+ " while deleting the lines
+ let old_report = &report
+ set report=99999
+
+ " Remove the currently highlighted tag. Otherwise, the help text
+ " might be highlighted by mistake
+ match none
+
+ " Toggle between brief and full help text
+ if s:tlist_brief_help
+ let s:tlist_brief_help = 0
+
+ " Remove the previous help
+ exe '1,' . brief_help_size . ' delete _'
+
+ " Adjust the start/end line numbers for the files
+ call s:Tlist_Window_Update_Line_Offsets(0, 1, full_help_size - brief_help_size)
+ else
+ let s:tlist_brief_help = 1
+
+ " Remove the previous help
+ exe '1,' . full_help_size . ' delete _'
+
+ " Adjust the start/end line numbers for the files
+ call s:Tlist_Window_Update_Line_Offsets(0, 0, full_help_size - brief_help_size)
+ endif
+
+ call s:Tlist_Window_Display_Help()
+
+ " Restore the report option
+ let &report = old_report
+
+ setlocal nomodifiable
+endfunction
+
+" Taglist debug support
+let s:tlist_debug = 0
+
+" File for storing the debug messages
+let s:tlist_debug_file = ''
+
+" Tlist_Debug_Enable
+" Enable logging of taglist debug messages.
+function! s:Tlist_Debug_Enable(...)
+ let s:tlist_debug = 1
+
+ " Check whether a valid file name is supplied.
+ if a:1 != ''
+ let s:tlist_debug_file = fnamemodify(a:1, ':p')
+
+ " Empty the log file
+ exe 'redir! > ' . s:tlist_debug_file
+ redir END
+
+ " Check whether the log file is present/created
+ if !filewritable(s:tlist_debug_file)
+ call s:Tlist_Warning_Msg('Taglist: Unable to create log file '
+ \ . s:tlist_debug_file)
+ let s:tlist_debug_file = ''
+ endif
+ endif
+endfunction
+
+" Tlist_Debug_Disable
+" Disable logging of taglist debug messages.
+function! s:Tlist_Debug_Disable(...)
+ let s:tlist_debug = 0
+ let s:tlist_debug_file = ''
+endfunction
+
+" Tlist_Debug_Show
+" Display the taglist debug messages in a new window
+function! s:Tlist_Debug_Show()
+ if s:tlist_msg == ''
+ call s:Tlist_Warning_Msg('Taglist: No debug messages')
+ return
+ endif
+
+ " Open a new window to display the taglist debug messages
+ new taglist_debug.txt
+ " Delete all the lines (if the buffer already exists)
+ silent! %delete _
+ " Add the messages
+ silent! put =s:tlist_msg
+ " Move the cursor to the first line
+ normal! gg
+endfunction
+
+" Tlist_Log_Msg
+" Log the supplied debug message along with the time
+function! s:Tlist_Log_Msg(msg)
+ if s:tlist_debug
+ if s:tlist_debug_file != ''
+ exe 'redir >> ' . s:tlist_debug_file
+ silent echon strftime('%H:%M:%S') . ': ' . a:msg . "\n"
+ redir END
+ else
+ " Log the message into a variable
+ " Retain only the last 3000 characters
+ let len = strlen(s:tlist_msg)
+ if len > 3000
+ let s:tlist_msg = strpart(s:tlist_msg, len - 3000)
+ endif
+ let s:tlist_msg = s:tlist_msg . strftime('%H:%M:%S') . ': ' .
+ \ a:msg . "\n"
+ endif
+ endif
+endfunction
+
+" Tlist_Warning_Msg()
+" Display a message using WarningMsg highlight group
+function! s:Tlist_Warning_Msg(msg)
+ echohl WarningMsg
+ echomsg a:msg
+ echohl None
+endfunction
+
+" Last returned file index for file name lookup.
+" Used to speed up file lookup
+let s:tlist_file_name_idx_cache = -1
+
+" Tlist_Get_File_Index()
+" Return the index of the specified filename
+function! s:Tlist_Get_File_Index(fname)
+ if s:tlist_file_count == 0 || a:fname == ''
+ return -1
+ endif
+
+ " If the new filename is same as the last accessed filename, then
+ " return that index
+ if s:tlist_file_name_idx_cache != -1 &&
+ \ s:tlist_file_name_idx_cache < s:tlist_file_count
+ if s:tlist_{s:tlist_file_name_idx_cache}_filename == a:fname
+ " Same as the last accessed file
+ return s:tlist_file_name_idx_cache
+ endif
+ endif
+
+ " First, check whether the filename is present
+ let s_fname = a:fname . "\n"
+ let i = stridx(s:tlist_file_names, s_fname)
+ if i == -1
+ let s:tlist_file_name_idx_cache = -1
+ return -1
+ endif
+
+ " Second, compute the file name index
+ let nl_txt = substitute(strpart(s:tlist_file_names, 0, i), "[^\n]", '', 'g')
+ let s:tlist_file_name_idx_cache = strlen(nl_txt)
+ return s:tlist_file_name_idx_cache
+endfunction
+
+" Last returned file index for line number lookup.
+" Used to speed up file lookup
+let s:tlist_file_lnum_idx_cache = -1
+
+" Tlist_Window_Get_File_Index_By_Linenum()
+" Return the index of the filename present in the specified line number
+" Line number refers to the line number in the taglist window
+function! s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
+ call s:Tlist_Log_Msg('Tlist_Window_Get_File_Index_By_Linenum (' . a:lnum . ')')
+
+ " First try to see whether the new line number is within the range
+ " of the last returned file
+ if s:tlist_file_lnum_idx_cache != -1 &&
+ \ s:tlist_file_lnum_idx_cache < s:tlist_file_count
+ if a:lnum >= s:tlist_{s:tlist_file_lnum_idx_cache}_start &&
+ \ a:lnum <= s:tlist_{s:tlist_file_lnum_idx_cache}_end
+ return s:tlist_file_lnum_idx_cache
+ endif
+ endif
+
+ let fidx = -1
+
+ if g:Tlist_Show_One_File
+ " Displaying only one file in the taglist window. Check whether
+ " the line is within the tags displayed for that file
+ if s:tlist_cur_file_idx != -1
+ if a:lnum >= s:tlist_{s:tlist_cur_file_idx}_start
+ \ && a:lnum <= s:tlist_{s:tlist_cur_file_idx}_end
+ let fidx = s:tlist_cur_file_idx
+ endif
+
+ endif
+ else
+ " Do a binary search in the taglist
+ let left = 0
+ let right = s:tlist_file_count - 1
+
+ while left < right
+ let mid = (left + right) / 2
+
+ if a:lnum >= s:tlist_{mid}_start && a:lnum <= s:tlist_{mid}_end
+ let s:tlist_file_lnum_idx_cache = mid
+ return mid
+ endif
+
+ if a:lnum < s:tlist_{mid}_start
+ let right = mid - 1
+ else
+ let left = mid + 1
+ endif
+ endwhile
+
+ if left >= 0 && left < s:tlist_file_count
+ \ && a:lnum >= s:tlist_{left}_start
+ \ && a:lnum <= s:tlist_{left}_end
+ let fidx = left
+ endif
+ endif
+
+ let s:tlist_file_lnum_idx_cache = fidx
+
+ return fidx
+endfunction
+
+" Tlist_Exe_Cmd_No_Acmds
+" Execute the specified Ex command after disabling autocommands
+function! s:Tlist_Exe_Cmd_No_Acmds(cmd)
+ let old_eventignore = &eventignore
+ set eventignore=all
+ exe a:cmd
+ let &eventignore = old_eventignore
+endfunction
+
+" Tlist_Skip_File()
+" Check whether tag listing is supported for the specified file
+function! s:Tlist_Skip_File(filename, ftype)
+ " Skip buffers with no names and buffers with filetype not set
+ if a:filename == '' || a:ftype == ''
+ return 1
+ endif
+
+ " Skip files which are not supported by exuberant ctags
+ " First check whether default settings for this filetype are available.
+ " If it is not available, then check whether user specified settings are
+ " available. If both are not available, then don't list the tags for this
+ " filetype
+ let var = 's:tlist_def_' . a:ftype . '_settings'
+ if !exists(var)
+ let var = 'g:tlist_' . a:ftype . '_settings'
+ if !exists(var)
+ return 1
+ endif
+ endif
+
+ " Skip files which are not readable or files which are not yet stored
+ " to the disk
+ if !filereadable(a:filename)
+ return 1
+ endif
+
+ return 0
+endfunction
+
+" Tlist_User_Removed_File
+" Returns 1 if a file is removed by a user from the taglist
+function! s:Tlist_User_Removed_File(filename)
+ return stridx(s:tlist_removed_flist, a:filename . "\n") != -1
+endfunction
+
+" Tlist_Update_Remove_List
+" Update the list of user removed files from the taglist
+" add == 1, add the file to the removed list
+" add == 0, delete the file from the removed list
+function! s:Tlist_Update_Remove_List(filename, add)
+ if a:add
+ let s:tlist_removed_flist = s:tlist_removed_flist . a:filename . "\n"
+ else
+ let idx = stridx(s:tlist_removed_flist, a:filename . "\n")
+ let text_before = strpart(s:tlist_removed_flist, 0, idx)
+ let rem_text = strpart(s:tlist_removed_flist, idx)
+ let next_idx = stridx(rem_text, "\n")
+ let text_after = strpart(rem_text, next_idx + 1)
+
+ let s:tlist_removed_flist = text_before . text_after
+ endif
+endfunction
+
+" Tlist_FileType_Init
+" Initialize the ctags arguments and tag variable for the specified
+" file type
+function! s:Tlist_FileType_Init(ftype)
+ call s:Tlist_Log_Msg('Tlist_FileType_Init (' . a:ftype . ')')
+ " If the user didn't specify any settings, then use the default
+ " ctags args. Otherwise, use the settings specified by the user
+ let var = 'g:tlist_' . a:ftype . '_settings'
+ if exists(var)
+ " User specified ctags arguments
+ let settings = {var} . ';'
+ else
+ " Default ctags arguments
+ let var = 's:tlist_def_' . a:ftype . '_settings'
+ if !exists(var)
+ " No default settings for this file type. This filetype is
+ " not supported
+ return 0
+ endif
+ let settings = s:tlist_def_{a:ftype}_settings . ';'
+ endif
+
+ let msg = 'Taglist: Invalid ctags option setting - ' . settings
+
+ " Format of the option that specifies the filetype and ctags arugments:
+ "
+ " <language_name>;flag1:name1;flag2:name2;flag3:name3
+ "
+
+ " Extract the file type to pass to ctags. This may be different from the
+ " file type detected by Vim
+ let pos = stridx(settings, ';')
+ if pos == -1
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+ let ctags_ftype = strpart(settings, 0, pos)
+ if ctags_ftype == ''
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+ " Make sure a valid filetype is supplied. If the user didn't specify a
+ " valid filetype, then the ctags option settings may be treated as the
+ " filetype
+ if ctags_ftype =~ ':'
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+
+ " Remove the file type from settings
+ let settings = strpart(settings, pos + 1)
+ if settings == ''
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+
+ " Process all the specified ctags flags. The format is
+ " flag1:name1;flag2:name2;flag3:name3
+ let ctags_flags = ''
+ let cnt = 0
+ while settings != ''
+ " Extract the flag
+ let pos = stridx(settings, ':')
+ if pos == -1
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+ let flag = strpart(settings, 0, pos)
+ if flag == ''
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+ " Remove the flag from settings
+ let settings = strpart(settings, pos + 1)
+
+ " Extract the tag type name
+ let pos = stridx(settings, ';')
+ if pos == -1
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+ let name = strpart(settings, 0, pos)
+ if name == ''
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+ let settings = strpart(settings, pos + 1)
+
+ let cnt = cnt + 1
+
+ let s:tlist_{a:ftype}_{cnt}_name = flag
+ let s:tlist_{a:ftype}_{cnt}_fullname = name
+ let ctags_flags = ctags_flags . flag
+ endwhile
+
+ let s:tlist_{a:ftype}_ctags_args = '--language-force=' . ctags_ftype .
+ \ ' --' . ctags_ftype . '-types=' . ctags_flags
+ let s:tlist_{a:ftype}_count = cnt
+ let s:tlist_{a:ftype}_ctags_flags = ctags_flags
+
+ " Save the filetype name
+ let s:tlist_ftype_{s:tlist_ftype_count}_name = a:ftype
+ let s:tlist_ftype_count = s:tlist_ftype_count + 1
+
+ return 1
+endfunction
+
+" Tlist_Detect_Filetype
+" Determine the filetype for the specified file using the filetypedetect
+" autocmd.
+function! s:Tlist_Detect_Filetype(fname)
+ " Ignore the filetype autocommands
+ let old_eventignore = &eventignore
+ set eventignore=FileType
+
+ " Save the 'filetype', as this will be changed temporarily
+ let old_filetype = &filetype
+
+ " Run the filetypedetect group of autocommands to determine
+ " the filetype
+ exe 'doautocmd filetypedetect BufRead ' . a:fname
+
+ " Save the detected filetype
+ let ftype = &filetype
+
+ " Restore the previous state
+ let &filetype = old_filetype
+ let &eventignore = old_eventignore
+
+ return ftype
+endfunction
+
+" Tlist_Get_Buffer_Filetype
+" Get the filetype for the specified buffer
+function! s:Tlist_Get_Buffer_Filetype(bnum)
+ let buf_ft = getbufvar(a:bnum, '&filetype')
+
+ if bufloaded(a:bnum)
+ " For loaded buffers, the 'filetype' is already determined
+ return buf_ft
+ endif
+
+ " For unloaded buffers, if the 'filetype' option is set, return it
+ if buf_ft != ''
+ return buf_ft
+ endif
+
+ " Skip non-existent buffers
+ if !bufexists(a:bnum)
+ return ''
+ endif
+
+ " For buffers whose filetype is not yet determined, try to determine
+ " the filetype
+ let bname = bufname(a:bnum)
+
+ return s:Tlist_Detect_Filetype(bname)
+endfunction
+
+" Tlist_Discard_TagInfo
+" Discard the stored tag information for a file
+function! s:Tlist_Discard_TagInfo(fidx)
+ call s:Tlist_Log_Msg('Tlist_Discard_TagInfo (' .
+ \ s:tlist_{a:fidx}_filename . ')')
+ let ftype = s:tlist_{a:fidx}_filetype
+
+ " Discard information about the tags defined in the file
+ let i = 1
+ while i <= s:tlist_{a:fidx}_tag_count
+ let fidx_i = 's:tlist_' . a:fidx . '_' . i
+ unlet! {fidx_i}_tag
+ unlet! {fidx_i}_tag_name
+ unlet! {fidx_i}_tag_type
+ unlet! {fidx_i}_ttype_idx
+ unlet! {fidx_i}_tag_proto
+ unlet! {fidx_i}_tag_searchpat
+ unlet! {fidx_i}_tag_linenum
+ let i = i + 1
+ endwhile
+
+ let s:tlist_{a:fidx}_tag_count = 0
+
+ " Discard information about tag type groups
+ let i = 1
+ while i <= s:tlist_{ftype}_count
+ let ttype = s:tlist_{ftype}_{i}_name
+ if s:tlist_{a:fidx}_{ttype} != ''
+ let fidx_ttype = 's:tlist_' . a:fidx . '_' . ttype
+ let {fidx_ttype} = ''
+ let {fidx_ttype}_offset = 0
+ let cnt = {fidx_ttype}_count
+ let {fidx_ttype}_count = 0
+ let j = 1
+ while j <= cnt
+ unlet! {fidx_ttype}_{j}
+ let j = j + 1
+ endwhile
+ endif
+ let i = i + 1
+ endwhile
+
+ " Discard the stored menu command also
+ let s:tlist_{a:fidx}_menu_cmd = ''
+endfunction
+
+" Tlist_Window_Update_Line_Offsets
+" Update the line offsets for tags for files starting from start_idx
+" and displayed in the taglist window by the specified offset
+function! s:Tlist_Window_Update_Line_Offsets(start_idx, increment, offset)
+ let i = a:start_idx
+
+ while i < s:tlist_file_count
+ if s:tlist_{i}_visible
+ " Update the start/end line number only if the file is visible
+ if a:increment
+ let s:tlist_{i}_start = s:tlist_{i}_start + a:offset
+ let s:tlist_{i}_end = s:tlist_{i}_end + a:offset
+ else
+ let s:tlist_{i}_start = s:tlist_{i}_start - a:offset
+ let s:tlist_{i}_end = s:tlist_{i}_end - a:offset
+ endif
+ endif
+ let i = i + 1
+ endwhile
+endfunction
+
+" Tlist_Discard_FileInfo
+" Discard the stored information for a file
+function! s:Tlist_Discard_FileInfo(fidx)
+ call s:Tlist_Log_Msg('Tlist_Discard_FileInfo (' .
+ \ s:tlist_{a:fidx}_filename . ')')
+ call s:Tlist_Discard_TagInfo(a:fidx)
+
+ let ftype = s:tlist_{a:fidx}_filetype
+
+ let i = 1
+ while i <= s:tlist_{ftype}_count
+ let ttype = s:tlist_{ftype}_{i}_name
+ unlet! s:tlist_{a:fidx}_{ttype}
+ unlet! s:tlist_{a:fidx}_{ttype}_offset
+ unlet! s:tlist_{a:fidx}_{ttype}_count
+ let i = i + 1
+ endwhile
+
+ unlet! s:tlist_{a:fidx}_filename
+ unlet! s:tlist_{a:fidx}_sort_type
+ unlet! s:tlist_{a:fidx}_filetype
+ unlet! s:tlist_{a:fidx}_mtime
+ unlet! s:tlist_{a:fidx}_start
+ unlet! s:tlist_{a:fidx}_end
+ unlet! s:tlist_{a:fidx}_valid
+ unlet! s:tlist_{a:fidx}_visible
+ unlet! s:tlist_{a:fidx}_tag_count
+ unlet! s:tlist_{a:fidx}_menu_cmd
+endfunction
+
+" Tlist_Window_Remove_File_From_Display
+" Remove the specified file from display
+function! s:Tlist_Window_Remove_File_From_Display(fidx)
+ call s:Tlist_Log_Msg('Tlist_Window_Remove_File_From_Display (' .
+ \ s:tlist_{a:fidx}_filename . ')')
+ " If the file is not visible then no need to remove it
+ if !s:tlist_{a:fidx}_visible
+ return
+ endif
+
+ " Remove the tags displayed for the specified file from the window
+ let start = s:tlist_{a:fidx}_start
+ " Include the empty line after the last line also
+ if g:Tlist_Compact_Format
+ let end = s:tlist_{a:fidx}_end
+ else
+ let end = s:tlist_{a:fidx}_end + 1
+ endif
+
+ setlocal modifiable
+ exe 'silent! ' . start . ',' . end . 'delete _'
+ setlocal nomodifiable
+
+ " Correct the start and end line offsets for all the files following
+ " this file, as the tags for this file are removed
+ call s:Tlist_Window_Update_Line_Offsets(a:fidx + 1, 0, end - start + 1)
+endfunction
+
+" Tlist_Remove_File
+" Remove the file under the cursor or the specified file index
+" user_request - User requested to remove the file from taglist
+function! s:Tlist_Remove_File(file_idx, user_request)
+ let fidx = a:file_idx
+
+ if fidx == -1
+ let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
+ if fidx == -1
+ return
+ endif
+ endif
+ call s:Tlist_Log_Msg('Tlist_Remove_File (' .
+ \ s:tlist_{fidx}_filename . ', ' . a:user_request . ')')
+
+ let save_winnr = winnr()
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum != -1
+ " Taglist window is open, remove the file from display
+
+ if save_winnr != winnum
+ let old_eventignore = &eventignore
+ set eventignore=all
+ exe winnum . 'wincmd w'
+ endif
+
+ call s:Tlist_Window_Remove_File_From_Display(fidx)
+
+ if save_winnr != winnum
+ exe save_winnr . 'wincmd w'
+ let &eventignore = old_eventignore
+ endif
+ endif
+
+ let fname = s:tlist_{fidx}_filename
+
+ if a:user_request
+ " As the user requested to remove the file from taglist,
+ " add it to the removed list
+ call s:Tlist_Update_Remove_List(fname, 1)
+ endif
+
+ " Remove the file name from the taglist list of filenames
+ let idx = stridx(s:tlist_file_names, fname . "\n")
+ let text_before = strpart(s:tlist_file_names, 0, idx)
+ let rem_text = strpart(s:tlist_file_names, idx)
+ let next_idx = stridx(rem_text, "\n")
+ let text_after = strpart(rem_text, next_idx + 1)
+ let s:tlist_file_names = text_before . text_after
+
+ call s:Tlist_Discard_FileInfo(fidx)
+
+ " Shift all the file variables by one index
+ let i = fidx + 1
+
+ while i < s:tlist_file_count
+ let j = i - 1
+
+ let s:tlist_{j}_filename = s:tlist_{i}_filename
+ let s:tlist_{j}_sort_type = s:tlist_{i}_sort_type
+ let s:tlist_{j}_filetype = s:tlist_{i}_filetype
+ let s:tlist_{j}_mtime = s:tlist_{i}_mtime
+ let s:tlist_{j}_start = s:tlist_{i}_start
+ let s:tlist_{j}_end = s:tlist_{i}_end
+ let s:tlist_{j}_valid = s:tlist_{i}_valid
+ let s:tlist_{j}_visible = s:tlist_{i}_visible
+ let s:tlist_{j}_tag_count = s:tlist_{i}_tag_count
+ let s:tlist_{j}_menu_cmd = s:tlist_{i}_menu_cmd
+
+ let k = 1
+ while k <= s:tlist_{j}_tag_count
+ let s:tlist_{j}_{k}_tag = s:tlist_{i}_{k}_tag
+ let s:tlist_{j}_{k}_tag_name = s:tlist_{i}_{k}_tag_name
+ let s:tlist_{j}_{k}_tag_type = s:Tlist_Get_Tag_Type_By_Tag(i, k)
+ let s:tlist_{j}_{k}_ttype_idx = s:tlist_{i}_{k}_ttype_idx
+ let s:tlist_{j}_{k}_tag_proto = s:Tlist_Get_Tag_Prototype(i, k)
+ let s:tlist_{j}_{k}_tag_searchpat = s:Tlist_Get_Tag_SearchPat(i, k)
+ let s:tlist_{j}_{k}_tag_linenum = s:Tlist_Get_Tag_Linenum(i, k)
+ let k = k + 1
+ endwhile
+
+ let ftype = s:tlist_{i}_filetype
+
+ let k = 1
+ while k <= s:tlist_{ftype}_count
+ let ttype = s:tlist_{ftype}_{k}_name
+ let s:tlist_{j}_{ttype} = s:tlist_{i}_{ttype}
+ let s:tlist_{j}_{ttype}_offset = s:tlist_{i}_{ttype}_offset
+ let s:tlist_{j}_{ttype}_count = s:tlist_{i}_{ttype}_count
+ if s:tlist_{j}_{ttype} != ''
+ let l = 1
+ while l <= s:tlist_{j}_{ttype}_count
+ let s:tlist_{j}_{ttype}_{l} = s:tlist_{i}_{ttype}_{l}
+ let l = l + 1
+ endwhile
+ endif
+ let k = k + 1
+ endwhile
+
+ " As the file and tag information is copied to the new index,
+ " discard the previous information
+ call s:Tlist_Discard_FileInfo(i)
+
+ let i = i + 1
+ endwhile
+
+ " Reduce the number of files displayed
+ let s:tlist_file_count = s:tlist_file_count - 1
+
+ if g:Tlist_Show_One_File
+ " If the tags for only one file is displayed and if we just
+ " now removed that file, then invalidate the current file idx
+ if s:tlist_cur_file_idx == fidx
+ let s:tlist_cur_file_idx = -1
+ endif
+ endif
+endfunction
+
+" Tlist_Window_Goto_Window
+" Goto the taglist window
+function! s:Tlist_Window_Goto_Window()
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum != -1
+ if winnr() != winnum
+ call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w')
+ endif
+ endif
+endfunction
+
+" Tlist_Window_Create
+" Create a new taglist window. If it is already open, jump to it
+function! s:Tlist_Window_Create()
+ call s:Tlist_Log_Msg('Tlist_Window_Create()')
+ " If the window is open, jump to it
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum != -1
+ " Jump to the existing window
+ if winnr() != winnum
+ exe winnum . 'wincmd w'
+ endif
+ return
+ endif
+
+ " If used with winmanager don't open windows. Winmanager will handle
+ " the window/buffer management
+ if s:tlist_app_name == "winmanager"
+ return
+ endif
+
+ " Create a new window. If user prefers a horizontal window, then open
+ " a horizontally split window. Otherwise open a vertically split
+ " window
+ if g:Tlist_Use_Horiz_Window
+ " Open a horizontally split window
+ let win_dir = 'botright'
+ " Horizontal window height
+ let win_size = g:Tlist_WinHeight
+ else
+ if s:tlist_winsize_chgd == -1
+ " Open a vertically split window. Increase the window size, if
+ " needed, to accomodate the new window
+ if g:Tlist_Inc_Winwidth &&
+ \ &columns < (80 + g:Tlist_WinWidth)
+ " Save the original window position
+ let s:tlist_pre_winx = getwinposx()
+ let s:tlist_pre_winy = getwinposy()
+
+ " one extra column is needed to include the vertical split
+ let &columns= &columns + g:Tlist_WinWidth + 1
+
+ let s:tlist_winsize_chgd = 1
+ else
+ let s:tlist_winsize_chgd = 0
+ endif
+ endif
+
+ if g:Tlist_Use_Right_Window
+ " Open the window at the rightmost place
+ let win_dir = 'botright vertical'
+ else
+ " Open the window at the leftmost place
+ let win_dir = 'topleft vertical'
+ endif
+ let win_size = g:Tlist_WinWidth
+ endif
+
+ " If the tag listing temporary buffer already exists, then reuse it.
+ " Otherwise create a new buffer
+ let bufnum = bufnr(g:TagList_title)
+ if bufnum == -1
+ " Create a new buffer
+ let wcmd = g:TagList_title
+ else
+ " Edit the existing buffer
+ let wcmd = '+buffer' . bufnum
+ endif
+
+ " Create the taglist window
+ exe 'silent! ' . win_dir . ' ' . win_size . 'split ' . wcmd
+
+ " Save the new window position
+ let s:tlist_winx = getwinposx()
+ let s:tlist_winy = getwinposy()
+
+ " Initialize the taglist window
+ call s:Tlist_Window_Init()
+endfunction
+
+" Tlist_Window_Zoom
+" Zoom (maximize/minimize) the taglist window
+function! s:Tlist_Window_Zoom()
+ if s:tlist_win_maximized
+ " Restore the window back to the previous size
+ if g:Tlist_Use_Horiz_Window
+ exe 'resize ' . g:Tlist_WinHeight
+ else
+ exe 'vert resize ' . g:Tlist_WinWidth
+ endif
+ let s:tlist_win_maximized = 0
+ else
+ " Set the window size to the maximum possible without closing other
+ " windows
+ if g:Tlist_Use_Horiz_Window
+ resize
+ else
+ vert resize
+ endif
+ let s:tlist_win_maximized = 1
+ endif
+endfunction
+
+" Tlist_Ballon_Expr
+" When the mouse cursor is over a tag in the taglist window, display the
+" tag prototype (balloon)
+function! Tlist_Ballon_Expr()
+ " Get the file index
+ let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(v:beval_lnum)
+ if fidx == -1
+ return ''
+ endif
+
+ " Get the tag output line for the current tag
+ let tidx = s:Tlist_Window_Get_Tag_Index(fidx, v:beval_lnum)
+ if tidx == 0
+ return ''
+ endif
+
+ " Get the tag search pattern and display it
+ return s:Tlist_Get_Tag_Prototype(fidx, tidx)
+endfunction
+
+" Tlist_Window_Check_Width
+" Check the width of the taglist window. For horizontally split windows, the
+" 'winfixheight' option is used to fix the height of the window. For
+" vertically split windows, Vim doesn't support the 'winfixwidth' option. So
+" need to handle window width changes from this function.
+function! s:Tlist_Window_Check_Width()
+ let tlist_winnr = bufwinnr(g:TagList_title)
+ if tlist_winnr == -1
+ return
+ endif
+
+ let width = winwidth(tlist_winnr)
+ if width != g:Tlist_WinWidth
+ call s:Tlist_Log_Msg("Tlist_Window_Check_Width: Changing window " .
+ \ "width from " . width . " to " . g:Tlist_WinWidth)
+ let save_winnr = winnr()
+ if save_winnr != tlist_winnr
+ call s:Tlist_Exe_Cmd_No_Acmds(tlist_winnr . 'wincmd w')
+ endif
+ exe 'vert resize ' . g:Tlist_WinWidth
+ if save_winnr != tlist_winnr
+ call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
+ endif
+ endif
+endfunction
+
+" Tlist_Window_Exit_Only_Window
+" If the 'Tlist_Exit_OnlyWindow' option is set, then exit Vim if only the
+" taglist window is present.
+function! s:Tlist_Window_Exit_Only_Window()
+ " Before quitting Vim, delete the taglist buffer so that
+ " the '0 mark is correctly set to the previous buffer.
+ if v:version < 700
+ if winbufnr(2) == -1
+ bdelete
+ quit
+ endif
+ else
+ if winbufnr(2) == -1
+ if tabpagenr('$') == 1
+ " Only one tag page is present
+ bdelete
+ quit
+ else
+ " More than one tab page is present. Close only the current
+ " tab page
+ close
+ endif
+ endif
+ endif
+endfunction
+
+" Tlist_Window_Init
+" Set the default options for the taglist window
+function! s:Tlist_Window_Init()
+ call s:Tlist_Log_Msg('Tlist_Window_Init()')
+
+ " The 'readonly' option should not be set for the taglist buffer.
+ " If Vim is started as "view/gview" or if the ":view" command is
+ " used, then the 'readonly' option is set for all the buffers.
+ " Unset it for the taglist buffer
+ setlocal noreadonly
+
+ " Set the taglist buffer filetype to taglist
+ setlocal filetype=taglist
+
+ " Define taglist window element highlighting
+ syntax match TagListComment '^" .*'
+ syntax match TagListFileName '^[^" ].*$'
+ syntax match TagListTitle '^ \S.*$'
+ syntax match TagListTagScope '\s\[.\{-\}\]$'
+
+ " Define the highlighting only if colors are supported
+ if has('gui_running') || &t_Co > 2
+ " Colors to highlight various taglist window elements
+ " If user defined highlighting group exists, then use them.
+ " Otherwise, use default highlight groups.
+ if hlexists('MyTagListTagName')
+ highlight link TagListTagName MyTagListTagName
+ else
+ highlight default link TagListTagName Search
+ endif
+ " Colors to highlight comments and titles
+ if hlexists('MyTagListComment')
+ highlight link TagListComment MyTagListComment
+ else
+ highlight clear TagListComment
+ highlight default link TagListComment Comment
+ endif
+ if hlexists('MyTagListTitle')
+ highlight link TagListTitle MyTagListTitle
+ else
+ highlight clear TagListTitle
+ highlight default link TagListTitle Title
+ endif
+ if hlexists('MyTagListFileName')
+ highlight link TagListFileName MyTagListFileName
+ else
+ highlight clear TagListFileName
+ highlight default TagListFileName guibg=Grey ctermbg=darkgray
+ \ guifg=white ctermfg=white
+ endif
+ if hlexists('MyTagListTagScope')
+ highlight link TagListTagScope MyTagListTagScope
+ else
+ highlight clear TagListTagScope
+ highlight default link TagListTagScope Identifier
+ endif
+ else
+ highlight default TagListTagName term=reverse cterm=reverse
+ endif
+
+ " Folding related settings
+ setlocal foldenable
+ setlocal foldminlines=0
+ setlocal foldmethod=manual
+ setlocal foldlevel=9999
+ if g:Tlist_Enable_Fold_Column
+ setlocal foldcolumn=3
+ else
+ setlocal foldcolumn=0
+ endif
+ setlocal foldtext=v:folddashes.getline(v:foldstart)
+
+ if s:tlist_app_name != "winmanager"
+ " Mark buffer as scratch
+ silent! setlocal buftype=nofile
+ if s:tlist_app_name == "none"
+ silent! setlocal bufhidden=delete
+ endif
+ silent! setlocal noswapfile
+ " Due to a bug in Vim 6.0, the winbufnr() function fails for unlisted
+ " buffers. So if the taglist buffer is unlisted, multiple taglist
+ " windows will be opened. This bug is fixed in Vim 6.1 and above
+ if v:version >= 601
+ silent! setlocal nobuflisted
+ endif
+ endif
+
+ silent! setlocal nowrap
+
+ " If the 'number' option is set in the source window, it will affect the
+ " taglist window. So forcefully disable 'number' option for the taglist
+ " window
+ silent! setlocal nonumber
+
+ " Use fixed height when horizontally split window is used
+ if g:Tlist_Use_Horiz_Window
+ if v:version >= 602
+ set winfixheight
+ endif
+ endif
+ if !g:Tlist_Use_Horiz_Window && v:version >= 700
+ set winfixwidth
+ endif
+
+ " Setup balloon evaluation to display tag prototype
+ if v:version >= 700 && has('balloon_eval')
+ setlocal balloonexpr=Tlist_Ballon_Expr()
+ set ballooneval
+ endif
+
+ " Setup the cpoptions properly for the maps to work
+ let old_cpoptions = &cpoptions
+ set cpoptions&vim
+
+ " Create buffer local mappings for jumping to the tags and sorting the list
+ nnoremap <buffer> <silent> <CR>
+ \ :call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ nnoremap <buffer> <silent> o
+ \ :call <SID>Tlist_Window_Jump_To_Tag('newwin')<CR>
+ nnoremap <buffer> <silent> p
+ \ :call <SID>Tlist_Window_Jump_To_Tag('preview')<CR>
+ nnoremap <buffer> <silent> P
+ \ :call <SID>Tlist_Window_Jump_To_Tag('prevwin')<CR>
+ if v:version >= 700
+ nnoremap <buffer> <silent> t
+ \ :call <SID>Tlist_Window_Jump_To_Tag('checktab')<CR>
+ nnoremap <buffer> <silent> <C-t>
+ \ :call <SID>Tlist_Window_Jump_To_Tag('newtab')<CR>
+ endif
+ nnoremap <buffer> <silent> <2-LeftMouse>
+ \ :call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ nnoremap <buffer> <silent> s
+ \ :call <SID>Tlist_Change_Sort('cmd', 'toggle', '')<CR>
+ nnoremap <buffer> <silent> + :silent! foldopen<CR>
+ nnoremap <buffer> <silent> - :silent! foldclose<CR>
+ nnoremap <buffer> <silent> * :silent! %foldopen!<CR>
+ nnoremap <buffer> <silent> = :silent! %foldclose<CR>
+ nnoremap <buffer> <silent> <kPlus> :silent! foldopen<CR>
+ nnoremap <buffer> <silent> <kMinus> :silent! foldclose<CR>
+ nnoremap <buffer> <silent> <kMultiply> :silent! %foldopen!<CR>
+ nnoremap <buffer> <silent> <Space> :call <SID>Tlist_Window_Show_Info()<CR>
+ nnoremap <buffer> <silent> u :call <SID>Tlist_Window_Update_File()<CR>
+ nnoremap <buffer> <silent> d :call <SID>Tlist_Remove_File(-1, 1)<CR>
+ nnoremap <buffer> <silent> x :call <SID>Tlist_Window_Zoom()<CR>
+ nnoremap <buffer> <silent> [[ :call <SID>Tlist_Window_Move_To_File(-1)<CR>
+ nnoremap <buffer> <silent> <BS> :call <SID>Tlist_Window_Move_To_File(-1)<CR>
+ nnoremap <buffer> <silent> ]] :call <SID>Tlist_Window_Move_To_File(1)<CR>
+ nnoremap <buffer> <silent> <Tab> :call <SID>Tlist_Window_Move_To_File(1)<CR>
+ nnoremap <buffer> <silent> <F1> :call <SID>Tlist_Window_Toggle_Help_Text()<CR>
+ nnoremap <buffer> <silent> q :close<CR>
+
+ " Insert mode mappings
+ inoremap <buffer> <silent> <CR>
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ " Windows needs return
+ inoremap <buffer> <silent> <Return>
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ inoremap <buffer> <silent> o
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('newwin')<CR>
+ inoremap <buffer> <silent> p
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('preview')<CR>
+ inoremap <buffer> <silent> P
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('prevwin')<CR>
+ if v:version >= 700
+ inoremap <buffer> <silent> t
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('checktab')<CR>
+ inoremap <buffer> <silent> <C-t>
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('newtab')<CR>
+ endif
+ inoremap <buffer> <silent> <2-LeftMouse>
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ inoremap <buffer> <silent> s
+ \ <C-o>:call <SID>Tlist_Change_Sort('cmd', 'toggle', '')<CR>
+ inoremap <buffer> <silent> + <C-o>:silent! foldopen<CR>
+ inoremap <buffer> <silent> - <C-o>:silent! foldclose<CR>
+ inoremap <buffer> <silent> * <C-o>:silent! %foldopen!<CR>
+ inoremap <buffer> <silent> = <C-o>:silent! %foldclose<CR>
+ inoremap <buffer> <silent> <kPlus> <C-o>:silent! foldopen<CR>
+ inoremap <buffer> <silent> <kMinus> <C-o>:silent! foldclose<CR>
+ inoremap <buffer> <silent> <kMultiply> <C-o>:silent! %foldopen!<CR>
+ inoremap <buffer> <silent> <Space> <C-o>:call
+ \ <SID>Tlist_Window_Show_Info()<CR>
+ inoremap <buffer> <silent> u
+ \ <C-o>:call <SID>Tlist_Window_Update_File()<CR>
+ inoremap <buffer> <silent> d <C-o>:call <SID>Tlist_Remove_File(-1, 1)<CR>
+ inoremap <buffer> <silent> x <C-o>:call <SID>Tlist_Window_Zoom()<CR>
+ inoremap <buffer> <silent> [[ <C-o>:call <SID>Tlist_Window_Move_To_File(-1)<CR>
+ inoremap <buffer> <silent> <BS> <C-o>:call <SID>Tlist_Window_Move_To_File(-1)<CR>
+ inoremap <buffer> <silent> ]] <C-o>:call <SID>Tlist_Window_Move_To_File(1)<CR>
+ inoremap <buffer> <silent> <Tab> <C-o>:call <SID>Tlist_Window_Move_To_File(1)<CR>
+ inoremap <buffer> <silent> <F1> <C-o>:call <SID>Tlist_Window_Toggle_Help_Text()<CR>
+ inoremap <buffer> <silent> q <C-o>:close<CR>
+
+ " Map single left mouse click if the user wants this functionality
+ if g:Tlist_Use_SingleClick == 1
+ " Contributed by Bindu Wavell
+ " attempt to perform single click mapping, it would be much
+ " nicer if we could nnoremap <buffer> ... however vim does
+ " not fire the <buffer> <leftmouse> when you use the mouse
+ " to enter a buffer.
+ let clickmap = ':if bufname("%") =~ "__Tag_List__" <bar> ' .
+ \ 'call <SID>Tlist_Window_Jump_To_Tag("useopen") ' .
+ \ '<bar> endif <CR>'
+ if maparg('<leftmouse>', 'n') == ''
+ " no mapping for leftmouse
+ exe ':nnoremap <silent> <leftmouse> <leftmouse>' . clickmap
+ else
+ " we have a mapping
+ let mapcmd = ':nnoremap <silent> <leftmouse> <leftmouse>'
+ let mapcmd = mapcmd . substitute(substitute(
+ \ maparg('<leftmouse>', 'n'), '|', '<bar>', 'g'),
+ \ '\c^<leftmouse>', '', '')
+ let mapcmd = mapcmd . clickmap
+ exe mapcmd
+ endif
+ endif
+
+ " Define the taglist autocommands
+ augroup TagListAutoCmds
+ autocmd!
+ " Display the tag prototype for the tag under the cursor.
+ autocmd CursorHold __Tag_List__ call s:Tlist_Window_Show_Info()
+ " Highlight the current tag periodically
+ autocmd CursorHold * silent call s:Tlist_Window_Highlight_Tag(
+ \ fnamemodify(bufname('%'), ':p'), line('.'), 1, 0)
+
+ " Adjust the Vim window width when taglist window is closed
+ autocmd BufUnload __Tag_List__ call s:Tlist_Post_Close_Cleanup()
+ " Close the fold for this buffer when leaving the buffer
+ if g:Tlist_File_Fold_Auto_Close
+ autocmd BufEnter * silent
+ \ call s:Tlist_Window_Open_File_Fold(expand('<abuf>'))
+ endif
+ " Exit Vim itself if only the taglist window is present (optional)
+ if g:Tlist_Exit_OnlyWindow
+ autocmd BufEnter __Tag_List__ nested
+ \ call s:Tlist_Window_Exit_Only_Window()
+ endif
+ if s:tlist_app_name != "winmanager" &&
+ \ !g:Tlist_Process_File_Always &&
+ \ (!has('gui_running') || !g:Tlist_Show_Menu)
+ " Auto refresh the taglist window
+ autocmd BufEnter * call s:Tlist_Refresh()
+ endif
+
+ if !g:Tlist_Use_Horiz_Window
+ if v:version < 700
+ autocmd WinEnter * call s:Tlist_Window_Check_Width()
+ endif
+ endif
+ if v:version >= 700
+ autocmd TabEnter * silent call s:Tlist_Refresh_Folds()
+ endif
+ augroup end
+
+ " Restore the previous cpoptions settings
+ let &cpoptions = old_cpoptions
+endfunction
+
+" Tlist_Window_Refresh
+" Display the tags for all the files in the taglist window
+function! s:Tlist_Window_Refresh()
+ call s:Tlist_Log_Msg('Tlist_Window_Refresh()')
+ " Set report option to a huge value to prevent informational messages
+ " while deleting the lines
+ let old_report = &report
+ set report=99999
+
+ " Mark the buffer as modifiable
+ setlocal modifiable
+
+ " Delete the contents of the buffer to the black-hole register
+ silent! %delete _
+
+ " As we have cleared the taglist window, mark all the files
+ " as not visible
+ let i = 0
+ while i < s:tlist_file_count
+ let s:tlist_{i}_visible = 0
+ let i = i + 1
+ endwhile
+
+ if g:Tlist_Compact_Format == 0
+ " Display help in non-compact mode
+ call s:Tlist_Window_Display_Help()
+ endif
+
+ " Mark the buffer as not modifiable
+ setlocal nomodifiable
+
+ " Restore the report option
+ let &report = old_report
+
+ " If the tags for only one file should be displayed in the taglist
+ " window, then no need to add the tags here. The bufenter autocommand
+ " will add the tags for that file.
+ if g:Tlist_Show_One_File
+ return
+ endif
+
+ " List all the tags for the previously processed files
+ " Do this only if taglist is configured to display tags for more than
+ " one file. Otherwise, when Tlist_Show_One_File is configured,
+ " tags for the wrong file will be displayed.
+ let i = 0
+ while i < s:tlist_file_count
+ call s:Tlist_Window_Refresh_File(s:tlist_{i}_filename,
+ \ s:tlist_{i}_filetype)
+ let i = i + 1
+ endwhile
+
+ if g:Tlist_Auto_Update
+ " Add and list the tags for all buffers in the Vim buffer list
+ let i = 1
+ let last_bufnum = bufnr('$')
+ while i <= last_bufnum
+ if buflisted(i)
+ let fname = fnamemodify(bufname(i), ':p')
+ let ftype = s:Tlist_Get_Buffer_Filetype(i)
+ " If the file doesn't support tag listing, skip it
+ if !s:Tlist_Skip_File(fname, ftype)
+ call s:Tlist_Window_Refresh_File(fname, ftype)
+ endif
+ endif
+ let i = i + 1
+ endwhile
+ endif
+
+ " If Tlist_File_Fold_Auto_Close option is set, then close all the folds
+ if g:Tlist_File_Fold_Auto_Close
+ " Close all the folds
+ silent! %foldclose
+ endif
+
+ " Move the cursor to the top of the taglist window
+ normal! gg
+endfunction
+
+" Tlist_Post_Close_Cleanup()
+" Close the taglist window and adjust the Vim window width
+function! s:Tlist_Post_Close_Cleanup()
+ call s:Tlist_Log_Msg('Tlist_Post_Close_Cleanup()')
+ " Mark all the files as not visible
+ let i = 0
+ while i < s:tlist_file_count
+ let s:tlist_{i}_visible = 0
+ let i = i + 1
+ endwhile
+
+ " Remove the taglist autocommands
+ silent! autocmd! TagListAutoCmds
+
+ " Clear all the highlights
+ match none
+
+ silent! syntax clear TagListTitle
+ silent! syntax clear TagListComment
+ silent! syntax clear TagListTagScope
+
+ " Remove the left mouse click mapping if it was setup initially
+ if g:Tlist_Use_SingleClick
+ if hasmapto('<LeftMouse>')
+ nunmap <LeftMouse>
+ endif
+ endif
+
+ if s:tlist_app_name != "winmanager"
+ if g:Tlist_Use_Horiz_Window || g:Tlist_Inc_Winwidth == 0 ||
+ \ s:tlist_winsize_chgd != 1 ||
+ \ &columns < (80 + g:Tlist_WinWidth)
+ " No need to adjust window width if using horizontally split taglist
+ " window or if columns is less than 101 or if the user chose not to
+ " adjust the window width
+ else
+ " If the user didn't manually move the window, then restore the window
+ " position to the pre-taglist position
+ if s:tlist_pre_winx != -1 && s:tlist_pre_winy != -1 &&
+ \ getwinposx() == s:tlist_winx &&
+ \ getwinposy() == s:tlist_winy
+ exe 'winpos ' . s:tlist_pre_winx . ' ' . s:tlist_pre_winy
+ endif
+
+ " Adjust the Vim window width
+ let &columns= &columns - (g:Tlist_WinWidth + 1)
+ endif
+ endif
+
+ let s:tlist_winsize_chgd = -1
+
+ " Reset taglist state variables
+ if s:tlist_app_name == "winmanager"
+ let s:tlist_app_name = "none"
+ endif
+ let s:tlist_window_initialized = 0
+endfunction
+
+" Tlist_Window_Refresh_File()
+" List the tags defined in the specified file in a Vim window
+function! s:Tlist_Window_Refresh_File(filename, ftype)
+ call s:Tlist_Log_Msg('Tlist_Window_Refresh_File (' . a:filename . ')')
+ " First check whether the file already exists
+ let fidx = s:Tlist_Get_File_Index(a:filename)
+ if fidx != -1
+ let file_listed = 1
+ else
+ let file_listed = 0
+ endif
+
+ if !file_listed
+ " Check whether this file is removed based on user request
+ " If it is, then don't display the tags for this file
+ if s:Tlist_User_Removed_File(a:filename)
+ return
+ endif
+ endif
+
+ if file_listed && s:tlist_{fidx}_visible
+ " Check whether the file tags are currently valid
+ if s:tlist_{fidx}_valid
+ " Goto the first line in the file
+ exe s:tlist_{fidx}_start
+
+ " If the line is inside a fold, open the fold
+ if foldclosed('.') != -1
+ exe "silent! " . s:tlist_{fidx}_start . "," .
+ \ s:tlist_{fidx}_end . "foldopen!"
+ endif
+ return
+ endif
+
+ " Discard and remove the tags for this file from display
+ call s:Tlist_Discard_TagInfo(fidx)
+ call s:Tlist_Window_Remove_File_From_Display(fidx)
+ endif
+
+ " Process and generate a list of tags defined in the file
+ if !file_listed || !s:tlist_{fidx}_valid
+ let ret_fidx = s:Tlist_Process_File(a:filename, a:ftype)
+ if ret_fidx == -1
+ return
+ endif
+ let fidx = ret_fidx
+ endif
+
+ " Set report option to a huge value to prevent informational messages
+ " while adding lines to the taglist window
+ let old_report = &report
+ set report=99999
+
+ if g:Tlist_Show_One_File
+ " Remove the previous file
+ if s:tlist_cur_file_idx != -1
+ call s:Tlist_Window_Remove_File_From_Display(s:tlist_cur_file_idx)
+ let s:tlist_{s:tlist_cur_file_idx}_visible = 0
+ let s:tlist_{s:tlist_cur_file_idx}_start = 0
+ let s:tlist_{s:tlist_cur_file_idx}_end = 0
+ endif
+ let s:tlist_cur_file_idx = fidx
+ endif
+
+ " Mark the buffer as modifiable
+ setlocal modifiable
+
+ " Add new files to the end of the window. For existing files, add them at
+ " the same line where they were previously present. If the file is not
+ " visible, then add it at the end
+ if s:tlist_{fidx}_start == 0 || !s:tlist_{fidx}_visible
+ if g:Tlist_Compact_Format
+ let s:tlist_{fidx}_start = line('$')
+ else
+ let s:tlist_{fidx}_start = line('$') + 1
+ endif
+ endif
+
+ let s:tlist_{fidx}_visible = 1
+
+ " Goto the line where this file should be placed
+ if g:Tlist_Compact_Format
+ exe s:tlist_{fidx}_start
+ else
+ exe s:tlist_{fidx}_start - 1
+ endif
+
+ let txt = fnamemodify(s:tlist_{fidx}_filename, ':t') . ' (' .
+ \ fnamemodify(s:tlist_{fidx}_filename, ':p:h') . ')'
+ if g:Tlist_Compact_Format == 0
+ silent! put =txt
+ else
+ silent! put! =txt
+ " Move to the next line
+ exe line('.') + 1
+ endif
+ let file_start = s:tlist_{fidx}_start
+
+ " Add the tag names grouped by tag type to the buffer with a title
+ let i = 1
+ let ttype_cnt = s:tlist_{a:ftype}_count
+ while i <= ttype_cnt
+ let ttype = s:tlist_{a:ftype}_{i}_name
+ " Add the tag type only if there are tags for that type
+ let fidx_ttype = 's:tlist_' . fidx . '_' . ttype
+ let ttype_txt = {fidx_ttype}
+ if ttype_txt != ''
+ let txt = ' ' . s:tlist_{a:ftype}_{i}_fullname
+ if g:Tlist_Compact_Format == 0
+ let ttype_start_lnum = line('.') + 1
+ silent! put =txt
+ else
+ let ttype_start_lnum = line('.')
+ silent! put! =txt
+ endif
+ silent! put =ttype_txt
+
+ let {fidx_ttype}_offset = ttype_start_lnum - file_start
+
+ " create a fold for this tag type
+ let fold_start = ttype_start_lnum
+ let fold_end = fold_start + {fidx_ttype}_count
+ exe fold_start . ',' . fold_end . 'fold'
+
+ " Adjust the cursor position
+ if g:Tlist_Compact_Format == 0
+ exe ttype_start_lnum + {fidx_ttype}_count
+ else
+ exe ttype_start_lnum + {fidx_ttype}_count + 1
+ endif
+
+ if g:Tlist_Compact_Format == 0
+ " Separate the tag types by a empty line
+ silent! put =''
+ endif
+ endif
+ let i = i + 1
+ endwhile
+
+ if s:tlist_{fidx}_tag_count == 0
+ if g:Tlist_Compact_Format == 0
+ silent! put =''
+ endif
+ endif
+
+ let s:tlist_{fidx}_end = line('.') - 1
+
+ " Create a fold for the entire file
+ exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold'
+ exe 'silent! ' . s:tlist_{fidx}_start . ',' .
+ \ s:tlist_{fidx}_end . 'foldopen!'
+
+ " Goto the starting line for this file,
+ exe s:tlist_{fidx}_start
+
+ if s:tlist_app_name == "winmanager"
+ " To handle a bug in the winmanager plugin, add a space at the
+ " last line
+ call setline('$', ' ')
+ endif
+
+ " Mark the buffer as not modifiable
+ setlocal nomodifiable
+
+ " Restore the report option
+ let &report = old_report
+
+ " Update the start and end line numbers for all the files following this
+ " file
+ let start = s:tlist_{fidx}_start
+ " include the empty line after the last line
+ if g:Tlist_Compact_Format
+ let end = s:tlist_{fidx}_end
+ else
+ let end = s:tlist_{fidx}_end + 1
+ endif
+ call s:Tlist_Window_Update_Line_Offsets(fidx + 1, 1, end - start + 1)
+
+ " Now that we have updated the taglist window, update the tags
+ " menu (if present)
+ if g:Tlist_Show_Menu
+ call s:Tlist_Menu_Update_File(1)
+ endif
+endfunction
+
+" Tlist_Init_File
+" Initialize the variables for a new file
+function! s:Tlist_Init_File(filename, ftype)
+ call s:Tlist_Log_Msg('Tlist_Init_File (' . a:filename . ')')
+ " Add new files at the end of the list
+ let fidx = s:tlist_file_count
+ let s:tlist_file_count = s:tlist_file_count + 1
+ " Add the new file name to the taglist list of file names
+ let s:tlist_file_names = s:tlist_file_names . a:filename . "\n"
+
+ " Initialize the file variables
+ let s:tlist_{fidx}_filename = a:filename
+ let s:tlist_{fidx}_sort_type = g:Tlist_Sort_Type
+ let s:tlist_{fidx}_filetype = a:ftype
+ let s:tlist_{fidx}_mtime = -1
+ let s:tlist_{fidx}_start = 0
+ let s:tlist_{fidx}_end = 0
+ let s:tlist_{fidx}_valid = 0
+ let s:tlist_{fidx}_visible = 0
+ let s:tlist_{fidx}_tag_count = 0
+ let s:tlist_{fidx}_menu_cmd = ''
+
+ " Initialize the tag type variables
+ let i = 1
+ while i <= s:tlist_{a:ftype}_count
+ let ttype = s:tlist_{a:ftype}_{i}_name
+ let s:tlist_{fidx}_{ttype} = ''
+ let s:tlist_{fidx}_{ttype}_offset = 0
+ let s:tlist_{fidx}_{ttype}_count = 0
+ let i = i + 1
+ endwhile
+
+ return fidx
+endfunction
+
+" Tlist_Get_Tag_Type_By_Tag
+" Return the tag type for the specified tag index
+function! s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx)
+ let ttype_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_type'
+
+ " Already parsed and have the tag name
+ if exists(ttype_var)
+ return {ttype_var}
+ endif
+
+ let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
+ let {ttype_var} = s:Tlist_Extract_Tagtype(tag_line)
+
+ return {ttype_var}
+endfunction
+
+" Tlist_Get_Tag_Prototype
+function! s:Tlist_Get_Tag_Prototype(fidx, tidx)
+ let tproto_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_proto'
+
+ " Already parsed and have the tag prototype
+ if exists(tproto_var)
+ return {tproto_var}
+ endif
+
+ " Parse and extract the tag prototype
+ let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
+ let start = stridx(tag_line, '/^') + 2
+ let end = stridx(tag_line, '/;"' . "\t")
+ if tag_line[end - 1] == '$'
+ let end = end -1
+ endif
+ let tag_proto = strpart(tag_line, start, end - start)
+ let {tproto_var} = substitute(tag_proto, '\s*', '', '')
+
+ return {tproto_var}
+endfunction
+
+" Tlist_Get_Tag_SearchPat
+function! s:Tlist_Get_Tag_SearchPat(fidx, tidx)
+ let tpat_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_searchpat'
+
+ " Already parsed and have the tag search pattern
+ if exists(tpat_var)
+ return {tpat_var}
+ endif
+
+ " Parse and extract the tag search pattern
+ let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
+ let start = stridx(tag_line, '/^') + 2
+ let end = stridx(tag_line, '/;"' . "\t")
+ if tag_line[end - 1] == '$'
+ let end = end -1
+ endif
+ let {tpat_var} = '\V\^' . strpart(tag_line, start, end - start) .
+ \ (tag_line[end] == '$' ? '\$' : '')
+
+ return {tpat_var}
+endfunction
+
+" Tlist_Get_Tag_Linenum
+" Return the tag line number, given the tag index
+function! s:Tlist_Get_Tag_Linenum(fidx, tidx)
+ let tline_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_linenum'
+
+ " Already parsed and have the tag line number
+ if exists(tline_var)
+ return {tline_var}
+ endif
+
+ " Parse and extract the tag line number
+ let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
+ let start = strridx(tag_line, 'line:') + 5
+ let end = strridx(tag_line, "\t")
+ if end < start
+ let {tline_var} = strpart(tag_line, start) + 0
+ else
+ let {tline_var} = strpart(tag_line, start, end - start) + 0
+ endif
+
+ return {tline_var}
+endfunction
+
+" Tlist_Parse_Tagline
+" Parse a tag line from the ctags output. Separate the tag output based on the
+" tag type and store it in the tag type variable.
+" The format of each line in the ctags output is:
+"
+" tag_name<TAB>file_name<TAB>ex_cmd;"<TAB>extension_fields
+"
+function! s:Tlist_Parse_Tagline(tag_line)
+ if a:tag_line == ''
+ " Skip empty lines
+ return
+ endif
+
+ " Extract the tag type
+ let ttype = s:Tlist_Extract_Tagtype(a:tag_line)
+
+ " Make sure the tag type is a valid and supported one
+ if ttype == '' || stridx(s:ctags_flags, ttype) == -1
+ " Line is not in proper tags format or Tag type is not supported
+ return
+ endif
+
+ " Update the total tag count
+ let s:tidx = s:tidx + 1
+
+ " The following variables are used to optimize this code. Vim is slow in
+ " using curly brace names. To reduce the amount of processing needed, the
+ " curly brace variables are pre-processed here
+ let fidx_tidx = 's:tlist_' . s:fidx . '_' . s:tidx
+ let fidx_ttype = 's:tlist_' . s:fidx . '_' . ttype
+
+ " Update the count of this tag type
+ let ttype_idx = {fidx_ttype}_count + 1
+ let {fidx_ttype}_count = ttype_idx
+
+ " Store the ctags output for this tag
+ let {fidx_tidx}_tag = a:tag_line
+
+ " Store the tag index and the tag type index (back pointers)
+ let {fidx_ttype}_{ttype_idx} = s:tidx
+ let {fidx_tidx}_ttype_idx = ttype_idx
+
+ " Extract the tag name
+ let tag_name = strpart(a:tag_line, 0, stridx(a:tag_line, "\t"))
+
+ " Extract the tag scope/prototype
+ if g:Tlist_Display_Prototype
+ let ttxt = ' ' . s:Tlist_Get_Tag_Prototype(s:fidx, s:tidx)
+ else
+ let ttxt = ' ' . tag_name
+
+ " Add the tag scope, if it is available and is configured. Tag
+ " scope is the last field after the 'line:<num>\t' field
+ if g:Tlist_Display_Tag_Scope
+ let tag_scope = s:Tlist_Extract_Tag_Scope(a:tag_line)
+ if tag_scope != ''
+ let ttxt = ttxt . ' [' . tag_scope . ']'
+ endif
+ endif
+ endif
+
+ " Add this tag to the tag type variable
+ let {fidx_ttype} = {fidx_ttype} . ttxt . "\n"
+
+ " Save the tag name
+ let {fidx_tidx}_tag_name = tag_name
+endfunction
+
+" Tlist_Process_File
+" Get the list of tags defined in the specified file and store them
+" in Vim variables. Returns the file index where the tags are stored.
+function! s:Tlist_Process_File(filename, ftype)
+ call s:Tlist_Log_Msg('Tlist_Process_File (' . a:filename . ', ' .
+ \ a:ftype . ')')
+ " Check whether this file is supported
+ if s:Tlist_Skip_File(a:filename, a:ftype)
+ return -1
+ endif
+
+ " If the tag types for this filetype are not yet created, then create
+ " them now
+ let var = 's:tlist_' . a:ftype . '_count'
+ if !exists(var)
+ if s:Tlist_FileType_Init(a:ftype) == 0
+ return -1
+ endif
+ endif
+
+ " If this file is already processed, then use the cached values
+ let fidx = s:Tlist_Get_File_Index(a:filename)
+ if fidx == -1
+ " First time, this file is loaded
+ let fidx = s:Tlist_Init_File(a:filename, a:ftype)
+ else
+ " File was previously processed. Discard the tag information
+ call s:Tlist_Discard_TagInfo(fidx)
+ endif
+
+ let s:tlist_{fidx}_valid = 1
+
+ " Exuberant ctags arguments to generate a tag list
+ let ctags_args = ' -f - --format=2 --excmd=pattern --fields=nks '
+
+ " Form the ctags argument depending on the sort type
+ if s:tlist_{fidx}_sort_type == 'name'
+ let ctags_args = ctags_args . '--sort=yes'
+ else
+ let ctags_args = ctags_args . '--sort=no'
+ endif
+
+ " Add the filetype specific arguments
+ let ctags_args = ctags_args . ' ' . s:tlist_{a:ftype}_ctags_args
+
+ " Ctags command to produce output with regexp for locating the tags
+ let ctags_cmd = g:Tlist_Ctags_Cmd . ctags_args
+ let ctags_cmd = ctags_cmd . ' "' . a:filename . '"'
+
+ if &shellxquote == '"'
+ " Double-quotes within double-quotes will not work in the
+ " command-line.If the 'shellxquote' option is set to double-quotes,
+ " then escape the double-quotes in the ctags command-line.
+ let ctags_cmd = escape(ctags_cmd, '"')
+ endif
+
+ " In Windows 95, if not using cygwin, disable the 'shellslash'
+ " option. Otherwise, this will cause problems when running the
+ " ctags command.
+ if has('win95') && !has('win32unix')
+ let old_shellslash = &shellslash
+ set noshellslash
+ endif
+
+ if has('win32') && !has('win32unix') && !has('win95')
+ \ && (&shell =~ 'cmd.exe')
+ " Windows does not correctly deal with commands that have more than 1
+ " set of double quotes. It will strip them all resulting in:
+ " 'C:\Program' is not recognized as an internal or external command
+ " operable program or batch file. To work around this, place the
+ " command inside a batch file and call the batch file.
+ " Do this only on Win2K, WinXP and above.
+ " Contributed by: David Fishburn.
+ let s:taglist_tempfile = fnamemodify(tempname(), ':h') .
+ \ '\taglist.cmd'
+ exe 'redir! > ' . s:taglist_tempfile
+ silent echo ctags_cmd
+ redir END
+
+ call s:Tlist_Log_Msg('Cmd inside batch file: ' . ctags_cmd)
+ let ctags_cmd = '"' . s:taglist_tempfile . '"'
+ endif
+
+ call s:Tlist_Log_Msg('Cmd: ' . ctags_cmd)
+
+ " Run ctags and get the tag list
+ let cmd_output = system(ctags_cmd)
+
+ " Restore the value of the 'shellslash' option.
+ if has('win95') && !has('win32unix')
+ let &shellslash = old_shellslash
+ endif
+
+ if exists('s:taglist_tempfile')
+ " Delete the temporary cmd file created on MS-Windows
+ call delete(s:taglist_tempfile)
+ endif
+
+ " Handle errors
+ if v:shell_error
+ let msg = "Taglist: Failed to generate tags for " . a:filename
+ call s:Tlist_Warning_Msg(msg)
+ if cmd_output != ''
+ call s:Tlist_Warning_Msg(cmd_output)
+ endif
+ return fidx
+ endif
+
+ " Store the modification time for the file
+ let s:tlist_{fidx}_mtime = getftime(a:filename)
+
+ " No tags for current file
+ if cmd_output == ''
+ call s:Tlist_Log_Msg('No tags defined in ' . a:filename)
+ return fidx
+ endif
+
+ call s:Tlist_Log_Msg('Generated tags information for ' . a:filename)
+
+ if v:version > 601
+ " The following script local variables are used by the
+ " Tlist_Parse_Tagline() function.
+ let s:ctags_flags = s:tlist_{a:ftype}_ctags_flags
+ let s:fidx = fidx
+ let s:tidx = 0
+
+ " Process the ctags output one line at a time. The substitute()
+ " command is used to parse the tag lines instead of using the
+ " matchstr()/stridx()/strpart() functions for performance reason
+ call substitute(cmd_output, "\\([^\n]\\+\\)\n",
+ \ '\=s:Tlist_Parse_Tagline(submatch(1))', 'g')
+
+ " Save the number of tags for this file
+ let s:tlist_{fidx}_tag_count = s:tidx
+
+ " The following script local variables are no longer needed
+ unlet! s:ctags_flags
+ unlet! s:tidx
+ unlet! s:fidx
+ else
+ " Due to a bug in Vim earlier than version 6.1,
+ " we cannot use substitute() to parse the ctags output.
+ " Instead the slow str*() functions are used
+ let ctags_flags = s:tlist_{a:ftype}_ctags_flags
+ let tidx = 0
+
+ while cmd_output != ''
+ " Extract one line at a time
+ let idx = stridx(cmd_output, "\n")
+ let one_line = strpart(cmd_output, 0, idx)
+ " Remove the line from the tags output
+ let cmd_output = strpart(cmd_output, idx + 1)
+
+ if one_line == ''
+ " Line is not in proper tags format
+ continue
+ endif
+
+ " Extract the tag type
+ let ttype = s:Tlist_Extract_Tagtype(one_line)
+
+ " Make sure the tag type is a valid and supported one
+ if ttype == '' || stridx(ctags_flags, ttype) == -1
+ " Line is not in proper tags format or Tag type is not
+ " supported
+ continue
+ endif
+
+ " Update the total tag count
+ let tidx = tidx + 1
+
+ " The following variables are used to optimize this code. Vim is
+ " slow in using curly brace names. To reduce the amount of
+ " processing needed, the curly brace variables are pre-processed
+ " here
+ let fidx_tidx = 's:tlist_' . fidx . '_' . tidx
+ let fidx_ttype = 's:tlist_' . fidx . '_' . ttype
+
+ " Update the count of this tag type
+ let ttype_idx = {fidx_ttype}_count + 1
+ let {fidx_ttype}_count = ttype_idx
+
+ " Store the ctags output for this tag
+ let {fidx_tidx}_tag = one_line
+
+ " Store the tag index and the tag type index (back pointers)
+ let {fidx_ttype}_{ttype_idx} = tidx
+ let {fidx_tidx}_ttype_idx = ttype_idx
+
+ " Extract the tag name
+ let tag_name = strpart(one_line, 0, stridx(one_line, "\t"))
+
+ " Extract the tag scope/prototype
+ if g:Tlist_Display_Prototype
+ let ttxt = ' ' . s:Tlist_Get_Tag_Prototype(fidx, tidx)
+ else
+ let ttxt = ' ' . tag_name
+
+ " Add the tag scope, if it is available and is configured. Tag
+ " scope is the last field after the 'line:<num>\t' field
+ if g:Tlist_Display_Tag_Scope
+ let tag_scope = s:Tlist_Extract_Tag_Scope(one_line)
+ if tag_scope != ''
+ let ttxt = ttxt . ' [' . tag_scope . ']'
+ endif
+ endif
+ endif
+
+ " Add this tag to the tag type variable
+ let {fidx_ttype} = {fidx_ttype} . ttxt . "\n"
+
+ " Save the tag name
+ let {fidx_tidx}_tag_name = tag_name
+ endwhile
+
+ " Save the number of tags for this file
+ let s:tlist_{fidx}_tag_count = tidx
+ endif
+
+ call s:Tlist_Log_Msg('Processed ' . s:tlist_{fidx}_tag_count .
+ \ ' tags in ' . a:filename)
+
+ return fidx
+endfunction
+
+" Tlist_Update_File
+" Update the tags for a file (if needed)
+function! Tlist_Update_File(filename, ftype)
+ call s:Tlist_Log_Msg('Tlist_Update_File (' . a:filename . ')')
+ " If the file doesn't support tag listing, skip it
+ if s:Tlist_Skip_File(a:filename, a:ftype)
+ return
+ endif
+
+ " Convert the file name to a full path
+ let fname = fnamemodify(a:filename, ':p')
+
+ " First check whether the file already exists
+ let fidx = s:Tlist_Get_File_Index(fname)
+
+ if fidx != -1 && s:tlist_{fidx}_valid
+ " File exists and the tags are valid
+ " Check whether the file was modified after the last tags update
+ " If it is modified, then update the tags
+ if s:tlist_{fidx}_mtime == getftime(fname)
+ return
+ endif
+ else
+ " If the tags were removed previously based on a user request,
+ " as we are going to update the tags (based on the user request),
+ " remove the filename from the deleted list
+ call s:Tlist_Update_Remove_List(fname, 0)
+ endif
+
+ " If the taglist window is opened, update it
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum == -1
+ " Taglist window is not present. Just update the taglist
+ " and return
+ call s:Tlist_Process_File(fname, a:ftype)
+ else
+ if g:Tlist_Show_One_File && s:tlist_cur_file_idx != -1
+ " If tags for only one file are displayed and we are not
+ " updating the tags for that file, then no need to
+ " refresh the taglist window. Otherwise, the taglist
+ " window should be updated.
+ if s:tlist_{s:tlist_cur_file_idx}_filename != fname
+ call s:Tlist_Process_File(fname, a:ftype)
+ return
+ endif
+ endif
+
+ " Save the current window number
+ let save_winnr = winnr()
+
+ " Goto the taglist window
+ call s:Tlist_Window_Goto_Window()
+
+ " Save the cursor position
+ let save_line = line('.')
+ let save_col = col('.')
+
+ " Update the taglist window
+ call s:Tlist_Window_Refresh_File(fname, a:ftype)
+
+ " Restore the cursor position
+ if v:version >= 601
+ call cursor(save_line, save_col)
+ else
+ exe save_line
+ exe 'normal! ' . save_col . '|'
+ endif
+
+ if winnr() != save_winnr
+ " Go back to the original window
+ call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w')
+ endif
+ endif
+
+ " Update the taglist menu
+ if g:Tlist_Show_Menu
+ call s:Tlist_Menu_Update_File(1)
+ endif
+endfunction
+
+" Tlist_Window_Close
+" Close the taglist window
+function! s:Tlist_Window_Close()
+ call s:Tlist_Log_Msg('Tlist_Window_Close()')
+ " Make sure the taglist window exists
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum == -1
+ call s:Tlist_Warning_Msg('Error: Taglist window is not open')
+ return
+ endif
+
+ if winnr() == winnum
+ " Already in the taglist window. Close it and return
+ if winbufnr(2) != -1
+ " If a window other than the taglist window is open,
+ " then only close the taglist window.
+ close
+ endif
+ else
+ " Goto the taglist window, close it and then come back to the
+ " original window
+ let curbufnr = bufnr('%')
+ exe winnum . 'wincmd w'
+ close
+ " Need to jump back to the original window only if we are not
+ " already in that window
+ let winnum = bufwinnr(curbufnr)
+ if winnr() != winnum
+ exe winnum . 'wincmd w'
+ endif
+ endif
+endfunction
+
+" Tlist_Window_Mark_File_Window
+" Mark the current window as the file window to use when jumping to a tag.
+" Only if the current window is a non-plugin, non-preview and non-taglist
+" window
+function! s:Tlist_Window_Mark_File_Window()
+ if getbufvar('%', '&buftype') == '' && !&previewwindow
+ let w:tlist_file_window = "yes"
+ endif
+endfunction
+
+" Tlist_Window_Open
+" Open and refresh the taglist window
+function! s:Tlist_Window_Open()
+ call s:Tlist_Log_Msg('Tlist_Window_Open()')
+ " If the window is open, jump to it
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum != -1
+ " Jump to the existing window
+ if winnr() != winnum
+ exe winnum . 'wincmd w'
+ endif
+ return
+ endif
+
+ if s:tlist_app_name == "winmanager"
+ " Taglist plugin is no longer part of the winmanager app
+ let s:tlist_app_name = "none"
+ endif
+
+ " Get the filename and filetype for the specified buffer
+ let curbuf_name = fnamemodify(bufname('%'), ':p')
+ let curbuf_ftype = s:Tlist_Get_Buffer_Filetype('%')
+ let cur_lnum = line('.')
+
+ " Mark the current window as the desired window to open a file when a tag
+ " is selected.
+ call s:Tlist_Window_Mark_File_Window()
+
+ " Open the taglist window
+ call s:Tlist_Window_Create()
+
+ call s:Tlist_Window_Refresh()
+
+ if g:Tlist_Show_One_File
+ " Add only the current buffer and file
+ "
+ " If the file doesn't support tag listing, skip it
+ if !s:Tlist_Skip_File(curbuf_name, curbuf_ftype)
+ call s:Tlist_Window_Refresh_File(curbuf_name, curbuf_ftype)
+ endif
+ endif
+
+ if g:Tlist_File_Fold_Auto_Close
+ " Open the fold for the current file, as all the folds in
+ " the taglist window are closed
+ let fidx = s:Tlist_Get_File_Index(curbuf_name)
+ if fidx != -1
+ exe "silent! " . s:tlist_{fidx}_start . "," .
+ \ s:tlist_{fidx}_end . "foldopen!"
+ endif
+ endif
+
+ " Highlight the current tag
+ call s:Tlist_Window_Highlight_Tag(curbuf_name, cur_lnum, 1, 1)
+endfunction
+
+" Tlist_Window_Toggle()
+" Open or close a taglist window
+function! s:Tlist_Window_Toggle()
+ call s:Tlist_Log_Msg('Tlist_Window_Toggle()')
+ " If taglist window is open then close it.
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum != -1
+ call s:Tlist_Window_Close()
+ return
+ endif
+
+ call s:Tlist_Window_Open()
+
+ " Go back to the original window, if Tlist_GainFocus_On_ToggleOpen is not
+ " set
+ if !g:Tlist_GainFocus_On_ToggleOpen
+ call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
+ endif
+
+ " Update the taglist menu
+ if g:Tlist_Show_Menu
+ call s:Tlist_Menu_Update_File(0)
+ endif
+endfunction
+
+" Tlist_Process_Filelist
+" Process multiple files. Each filename is separated by "\n"
+" Returns the number of processed files
+function! s:Tlist_Process_Filelist(file_names)
+ let flist = a:file_names
+
+ " Enable lazy screen updates
+ let old_lazyredraw = &lazyredraw
+ set lazyredraw
+
+ " Keep track of the number of processed files
+ let fcnt = 0
+
+ " Process one file at a time
+ while flist != ''
+ let nl_idx = stridx(flist, "\n")
+ let one_file = strpart(flist, 0, nl_idx)
+
+ " Remove the filename from the list
+ let flist = strpart(flist, nl_idx + 1)
+
+ if one_file == ''
+ continue
+ endif
+
+ " Skip directories
+ if isdirectory(one_file)
+ continue
+ endif
+
+ let ftype = s:Tlist_Detect_Filetype(one_file)
+
+ echon "\r "
+ echon "\rProcessing tags for " . fnamemodify(one_file, ':p:t')
+
+ let fcnt = fcnt + 1
+
+ call Tlist_Update_File(one_file, ftype)
+ endwhile
+
+ " Clear the displayed informational messages
+ echon "\r "
+
+ " Restore the previous state
+ let &lazyredraw = old_lazyredraw
+
+ return fcnt
+endfunction
+
+" Tlist_Process_Dir
+" Process the files in a directory matching the specified pattern
+function! s:Tlist_Process_Dir(dir_name, pat)
+ let flist = glob(a:dir_name . '/' . a:pat) . "\n"
+
+ let fcnt = s:Tlist_Process_Filelist(flist)
+
+ let len = strlen(a:dir_name)
+ if a:dir_name[len - 1] == '\' || a:dir_name[len - 1] == '/'
+ let glob_expr = a:dir_name . '*'
+ else
+ let glob_expr = a:dir_name . '/*'
+ endif
+ let all_files = glob(glob_expr) . "\n"
+
+ while all_files != ''
+ let nl_idx = stridx(all_files, "\n")
+ let one_file = strpart(all_files, 0, nl_idx)
+
+ let all_files = strpart(all_files, nl_idx + 1)
+ if one_file == ''
+ continue
+ endif
+
+ " Skip non-directory names
+ if !isdirectory(one_file)
+ continue
+ endif
+
+ echon "\r "
+ echon "\rProcessing files in directory " . fnamemodify(one_file, ':t')
+ let fcnt = fcnt + s:Tlist_Process_Dir(one_file, a:pat)
+ endwhile
+
+ return fcnt
+endfunction
+
+" Tlist_Add_Files_Recursive
+" Add files recursively from a directory
+function! s:Tlist_Add_Files_Recursive(dir, ...)
+ let dir_name = fnamemodify(a:dir, ':p')
+ if !isdirectory(dir_name)
+ call s:Tlist_Warning_Msg('Error: ' . dir_name . ' is not a directory')
+ return
+ endif
+
+ if a:0 == 1
+ " User specified file pattern
+ let pat = a:1
+ else
+ " Default file pattern
+ let pat = '*'
+ endif
+
+ echon "\r "
+ echon "\rProcessing files in directory " . fnamemodify(dir_name, ':t')
+ let fcnt = s:Tlist_Process_Dir(dir_name, pat)
+
+ echon "\rAdded " . fcnt . " files to the taglist"
+endfunction
+
+" Tlist_Add_Files
+" Add the specified list of files to the taglist
+function! s:Tlist_Add_Files(...)
+ let flist = ''
+ let i = 1
+
+ " Get all the files matching the file patterns supplied as argument
+ while i <= a:0
+ let flist = flist . glob(a:{i}) . "\n"
+ let i = i + 1
+ endwhile
+
+ if flist == ''
+ call s:Tlist_Warning_Msg('Error: No matching files are found')
+ return
+ endif
+
+ let fcnt = s:Tlist_Process_Filelist(flist)
+ echon "\rAdded " . fcnt . " files to the taglist"
+endfunction
+
+" Tlist_Extract_Tagtype
+" Extract the tag type from the tag text
+function! s:Tlist_Extract_Tagtype(tag_line)
+ " The tag type is after the tag prototype field. The prototype field
+ " ends with the /;"\t string. We add 4 at the end to skip the characters
+ " in this special string..
+ let start = strridx(a:tag_line, '/;"' . "\t") + 4
+ let end = strridx(a:tag_line, 'line:') - 1
+ let ttype = strpart(a:tag_line, start, end - start)
+
+ return ttype
+endfunction
+
+" Tlist_Extract_Tag_Scope
+" Extract the tag scope from the tag text
+function! s:Tlist_Extract_Tag_Scope(tag_line)
+ let start = strridx(a:tag_line, 'line:')
+ let end = strridx(a:tag_line, "\t")
+ if end <= start
+ return ''
+ endif
+
+ let tag_scope = strpart(a:tag_line, end + 1)
+ let tag_scope = strpart(tag_scope, stridx(tag_scope, ':') + 1)
+
+ return tag_scope
+endfunction
+
+" Tlist_Refresh()
+" Refresh the taglist
+function! s:Tlist_Refresh()
+ call s:Tlist_Log_Msg('Tlist_Refresh (Skip_Refresh = ' .
+ \ s:Tlist_Skip_Refresh . ', ' . bufname('%') . ')')
+ " If we are entering the buffer from one of the taglist functions, then
+ " no need to refresh the taglist window again.
+ if s:Tlist_Skip_Refresh
+ " We still need to update the taglist menu
+ if g:Tlist_Show_Menu
+ call s:Tlist_Menu_Update_File(0)
+ endif
+ return
+ endif
+
+ " If part of the winmanager plugin and not configured to process
+ " tags always and not configured to display the tags menu, then return
+ if (s:tlist_app_name == 'winmanager') && !g:Tlist_Process_File_Always
+ \ && !g:Tlist_Show_Menu
+ return
+ endif
+
+ " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help
+ if &buftype != ''
+ return
+ endif
+
+ let filename = fnamemodify(bufname('%'), ':p')
+ let ftype = s:Tlist_Get_Buffer_Filetype('%')
+
+ " If the file doesn't support tag listing, skip it
+ if s:Tlist_Skip_File(filename, ftype)
+ return
+ endif
+
+ let tlist_win = bufwinnr(g:TagList_title)
+
+ " If the taglist window is not opened and not configured to process
+ " tags always and not displaying the tags menu, then return
+ if tlist_win == -1 && !g:Tlist_Process_File_Always && !g:Tlist_Show_Menu
+ return
+ endif
+
+ let fidx = s:Tlist_Get_File_Index(filename)
+ if fidx == -1
+ " Check whether this file is removed based on user request
+ " If it is, then don't display the tags for this file
+ if s:Tlist_User_Removed_File(filename)
+ return
+ endif
+
+ " If the taglist should not be auto updated, then return
+ if !g:Tlist_Auto_Update
+ return
+ endif
+ endif
+
+ let cur_lnum = line('.')
+
+ if fidx == -1
+ " Update the tags for the file
+ let fidx = s:Tlist_Process_File(filename, ftype)
+ else
+ let mtime = getftime(filename)
+ if s:tlist_{fidx}_mtime != mtime
+ " Invalidate the tags listed for this file
+ let s:tlist_{fidx}_valid = 0
+
+ " Update the taglist and the window
+ call Tlist_Update_File(filename, ftype)
+
+ " Store the new file modification time
+ let s:tlist_{fidx}_mtime = mtime
+ endif
+ endif
+
+ " Update the taglist window
+ if tlist_win != -1
+ " Disable screen updates
+ let old_lazyredraw = &lazyredraw
+ set nolazyredraw
+
+ " Save the current window number
+ let save_winnr = winnr()
+
+ " Goto the taglist window
+ call s:Tlist_Window_Goto_Window()
+
+ if !g:Tlist_Auto_Highlight_Tag || !g:Tlist_Highlight_Tag_On_BufEnter
+ " Save the cursor position
+ let save_line = line('.')
+ let save_col = col('.')
+ endif
+
+ " Update the taglist window
+ call s:Tlist_Window_Refresh_File(filename, ftype)
+
+ " Open the fold for the file
+ exe "silent! " . s:tlist_{fidx}_start . "," .
+ \ s:tlist_{fidx}_end . "foldopen!"
+
+ if g:Tlist_Highlight_Tag_On_BufEnter && g:Tlist_Auto_Highlight_Tag
+ if g:Tlist_Show_One_File && s:tlist_cur_file_idx != fidx
+ " If displaying tags for only one file in the taglist
+ " window and about to display the tags for a new file,
+ " then center the current tag line for the new file
+ let center_tag_line = 1
+ else
+ let center_tag_line = 0
+ endif
+
+ " Highlight the current tag
+ call s:Tlist_Window_Highlight_Tag(filename, cur_lnum, 1, center_tag_line)
+ else
+ " Restore the cursor position
+ if v:version >= 601
+ call cursor(save_line, save_col)
+ else
+ exe save_line
+ exe 'normal! ' . save_col . '|'
+ endif
+ endif
+
+ " Jump back to the original window
+ if save_winnr != winnr()
+ call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w')
+ endif
+
+ " Restore screen updates
+ let &lazyredraw = old_lazyredraw
+ endif
+
+ " Update the taglist menu
+ if g:Tlist_Show_Menu
+ call s:Tlist_Menu_Update_File(0)
+ endif
+endfunction
+
+" Tlist_Change_Sort()
+" Change the sort order of the tag listing
+" caller == 'cmd', command used in the taglist window
+" caller == 'menu', taglist menu
+" action == 'toggle', toggle sort from name to order and vice versa
+" action == 'set', set the sort order to sort_type
+function! s:Tlist_Change_Sort(caller, action, sort_type)
+ call s:Tlist_Log_Msg('Tlist_Change_Sort (caller = ' . a:caller .
+ \ ', action = ' . a:action . ', sort_type = ' . a:sort_type . ')')
+ if a:caller == 'cmd'
+ let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
+ if fidx == -1
+ return
+ endif
+
+ " Remove the previous highlighting
+ match none
+ elseif a:caller == 'menu'
+ let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
+ if fidx == -1
+ return
+ endif
+ endif
+
+ if a:action == 'toggle'
+ let sort_type = s:tlist_{fidx}_sort_type
+
+ " Toggle the sort order from 'name' to 'order' and vice versa
+ if sort_type == 'name'
+ let s:tlist_{fidx}_sort_type = 'order'
+ else
+ let s:tlist_{fidx}_sort_type = 'name'
+ endif
+ else
+ let s:tlist_{fidx}_sort_type = a:sort_type
+ endif
+
+ " Invalidate the tags listed for this file
+ let s:tlist_{fidx}_valid = 0
+
+ if a:caller == 'cmd'
+ " Save the current line for later restoration
+ let curline = '\V\^' . getline('.') . '\$'
+
+ call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename,
+ \ s:tlist_{fidx}_filetype)
+
+ exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!'
+
+ " Go back to the cursor line before the tag list is sorted
+ call search(curline, 'w')
+
+ call s:Tlist_Menu_Update_File(1)
+ else
+ call s:Tlist_Menu_Remove_File()
+
+ call s:Tlist_Refresh()
+ endif
+endfunction
+
+" Tlist_Update_Current_File()
+" Update taglist for the current buffer by regenerating the tag list
+" Contributed by WEN Guopeng.
+function! s:Tlist_Update_Current_File()
+ call s:Tlist_Log_Msg('Tlist_Update_Current_File()')
+ if winnr() == bufwinnr(g:TagList_title)
+ " In the taglist window. Update the current file
+ call s:Tlist_Window_Update_File()
+ else
+ " Not in the taglist window. Update the current buffer
+ let filename = fnamemodify(bufname('%'), ':p')
+ let fidx = s:Tlist_Get_File_Index(filename)
+ if fidx != -1
+ let s:tlist_{fidx}_valid = 0
+ endif
+ let ft = s:Tlist_Get_Buffer_Filetype('%')
+ call Tlist_Update_File(filename, ft)
+ endif
+endfunction
+
+" Tlist_Window_Update_File()
+" Update the tags displayed in the taglist window
+function! s:Tlist_Window_Update_File()
+ call s:Tlist_Log_Msg('Tlist_Window_Update_File()')
+ let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
+ if fidx == -1
+ return
+ endif
+
+ " Remove the previous highlighting
+ match none
+
+ " Save the current line for later restoration
+ let curline = '\V\^' . getline('.') . '\$'
+
+ let s:tlist_{fidx}_valid = 0
+
+ " Update the taglist window
+ call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename,
+ \ s:tlist_{fidx}_filetype)
+
+ exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!'
+
+ " Go back to the tag line before the list is updated
+ call search(curline, 'w')
+endfunction
+
+" Tlist_Window_Get_Tag_Type_By_Linenum()
+" Return the tag type index for the specified line in the taglist window
+function! s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum)
+ let ftype = s:tlist_{a:fidx}_filetype
+
+ " Determine to which tag type the current line number belongs to using the
+ " tag type start line number and the number of tags in a tag type
+ let i = 1
+ while i <= s:tlist_{ftype}_count
+ let ttype = s:tlist_{ftype}_{i}_name
+ let start_lnum =
+ \ s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_offset
+ let end = start_lnum + s:tlist_{a:fidx}_{ttype}_count
+ if a:lnum >= start_lnum && a:lnum <= end
+ break
+ endif
+ let i = i + 1
+ endwhile
+
+ " Current line doesn't belong to any of the displayed tag types
+ if i > s:tlist_{ftype}_count
+ return ''
+ endif
+
+ return ttype
+endfunction
+
+" Tlist_Window_Get_Tag_Index()
+" Return the tag index for the specified line in the taglist window
+function! s:Tlist_Window_Get_Tag_Index(fidx, lnum)
+ let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(a:fidx, a:lnum)
+
+ " Current line doesn't belong to any of the displayed tag types
+ if ttype == ''
+ return 0
+ endif
+
+ " Compute the index into the displayed tags for the tag type
+ let ttype_lnum = s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_offset
+ let tidx = a:lnum - ttype_lnum
+ if tidx == 0
+ return 0
+ endif
+
+ " Get the corresponding tag line and return it
+ return s:tlist_{a:fidx}_{ttype}_{tidx}
+endfunction
+
+" Tlist_Window_Highlight_Line
+" Highlight the current line
+function! s:Tlist_Window_Highlight_Line()
+ " Clear previously selected name
+ match none
+
+ " Highlight the current line
+ if g:Tlist_Display_Prototype == 0
+ let pat = '/\%' . line('.') . 'l\s\+\zs.*/'
+ else
+ let pat = '/\%' . line('.') . 'l.*/'
+ endif
+
+ exe 'match TagListTagName ' . pat
+endfunction
+
+" Tlist_Window_Open_File
+" Open the specified file in either a new window or an existing window
+" and place the cursor at the specified tag pattern
+function! s:Tlist_Window_Open_File(win_ctrl, filename, tagpat)
+ call s:Tlist_Log_Msg('Tlist_Window_Open_File (' . a:filename . ',' .
+ \ a:win_ctrl . ')')
+ let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh
+ let s:Tlist_Skip_Refresh = 1
+
+ if s:tlist_app_name == "winmanager"
+ " Let the winmanager edit the file
+ call WinManagerFileEdit(a:filename, a:win_ctrl == 'newwin')
+ else
+
+ if a:win_ctrl == 'newtab'
+ " Create a new tab
+ exe 'tabnew ' . escape(a:filename, ' ')
+ " Open the taglist window in the new tab
+ call s:Tlist_Window_Open()
+ endif
+
+ if a:win_ctrl == 'checktab'
+ " Check whether the file is present in any of the tabs.
+ " If the file is present in the current tab, then use the
+ " current tab.
+ if bufwinnr(a:filename) != -1
+ let file_present_in_tab = 1
+ let i = tabpagenr()
+ else
+ let i = 1
+ let bnum = bufnr(a:filename)
+ let file_present_in_tab = 0
+ while i <= tabpagenr('$')
+ if index(tabpagebuflist(i), bnum) != -1
+ let file_present_in_tab = 1
+ break
+ endif
+ let i += 1
+ endwhile
+ endif
+
+ if file_present_in_tab
+ " Goto the tab containing the file
+ exe 'tabnext ' . i
+ else
+ " Open a new tab
+ exe 'tabnew ' . escape(a:filename, ' ')
+
+ " Open the taglist window
+ call s:Tlist_Window_Open()
+ endif
+ endif
+
+ let winnum = -1
+ if a:win_ctrl == 'prevwin'
+ " Open the file in the previous window, if it is usable
+ let cur_win = winnr()
+ wincmd p
+ if &buftype == '' && !&previewwindow
+ exe "edit " . escape(a:filename, ' ')
+ let winnum = winnr()
+ else
+ " Previous window is not usable
+ exe cur_win . 'wincmd w'
+ endif
+ endif
+
+ " Goto the window containing the file. If the window is not there, open a
+ " new window
+ if winnum == -1
+ let winnum = bufwinnr(a:filename)
+ endif
+
+ if winnum == -1
+ " Locate the previously used window for opening a file
+ let fwin_num = 0
+ let first_usable_win = 0
+
+ let i = 1
+ let bnum = winbufnr(i)
+ while bnum != -1
+ if getwinvar(i, 'tlist_file_window') == 'yes'
+ let fwin_num = i
+ break
+ endif
+ if first_usable_win == 0 &&
+ \ getbufvar(bnum, '&buftype') == '' &&
+ \ !getwinvar(i, '&previewwindow')
+ " First non-taglist, non-plugin and non-preview window
+ let first_usable_win = i
+ endif
+ let i = i + 1
+ let bnum = winbufnr(i)
+ endwhile
+
+ " If a previously used window is not found, then use the first
+ " non-taglist window
+ if fwin_num == 0
+ let fwin_num = first_usable_win
+ endif
+
+ if fwin_num != 0
+ " Jump to the file window
+ exe fwin_num . "wincmd w"
+
+ " If the user asked to jump to the tag in a new window, then split
+ " the existing window into two.
+ if a:win_ctrl == 'newwin'
+ split
+ endif
+ exe "edit " . escape(a:filename, ' ')
+ else
+ " Open a new window
+ if g:Tlist_Use_Horiz_Window
+ exe 'leftabove split ' . escape(a:filename, ' ')
+ else
+ if winbufnr(2) == -1
+ " Only the taglist window is present
+ if g:Tlist_Use_Right_Window
+ exe 'leftabove vertical split ' .
+ \ escape(a:filename, ' ')
+ else
+ exe 'rightbelow vertical split ' .
+ \ escape(a:filename, ' ')
+ endif
+
+ " Go to the taglist window to change the window size to
+ " the user configured value
+ call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
+ if g:Tlist_Use_Horiz_Window
+ exe 'resize ' . g:Tlist_WinHeight
+ else
+ exe 'vertical resize ' . g:Tlist_WinWidth
+ endif
+ " Go back to the file window
+ call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
+ else
+ " A plugin or help window is also present
+ wincmd w
+ exe 'leftabove split ' . escape(a:filename, ' ')
+ endif
+ endif
+ endif
+ " Mark the window, so that it can be reused.
+ call s:Tlist_Window_Mark_File_Window()
+ else
+ if v:version >= 700
+ " If the file is opened in more than one window, then check
+ " whether the last accessed window has the selected file.
+ " If it does, then use that window.
+ let lastwin_bufnum = winbufnr(winnr('#'))
+ if bufnr(a:filename) == lastwin_bufnum
+ let winnum = winnr('#')
+ endif
+ endif
+ exe winnum . 'wincmd w'
+
+ " If the user asked to jump to the tag in a new window, then split the
+ " existing window into two.
+ if a:win_ctrl == 'newwin'
+ split
+ endif
+ endif
+ endif
+
+ " Jump to the tag
+ if a:tagpat != ''
+ " Add the current cursor position to the jump list, so that user can
+ " jump back using the ' and ` marks.
+ mark '
+ silent call search(a:tagpat, 'w')
+
+ " Bring the line to the middle of the window
+ normal! z.
+
+ " If the line is inside a fold, open the fold
+ if foldclosed('.') != -1
+ .foldopen
+ endif
+ endif
+
+ " If the user selects to preview the tag then jump back to the
+ " taglist window
+ if a:win_ctrl == 'preview'
+ " Go back to the taglist window
+ let winnum = bufwinnr(g:TagList_title)
+ exe winnum . 'wincmd w'
+ else
+ " If the user has selected to close the taglist window, when a
+ " tag is selected, close the taglist window
+ if g:Tlist_Close_On_Select
+ call s:Tlist_Window_Goto_Window()
+ close
+
+ " Go back to the window displaying the selected file
+ let wnum = bufwinnr(a:filename)
+ if wnum != -1 && wnum != winnr()
+ call s:Tlist_Exe_Cmd_No_Acmds(wnum . 'wincmd w')
+ endif
+ endif
+ endif
+
+ let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh
+endfunction
+
+" Tlist_Window_Jump_To_Tag()
+" Jump to the location of the current tag
+" win_ctrl == useopen - Reuse the existing file window
+" win_ctrl == newwin - Open a new window
+" win_ctrl == preview - Preview the tag
+" win_ctrl == prevwin - Open in previous window
+" win_ctrl == newtab - Open in new tab
+function! s:Tlist_Window_Jump_To_Tag(win_ctrl)
+ call s:Tlist_Log_Msg('Tlist_Window_Jump_To_Tag(' . a:win_ctrl . ')')
+ " Do not process comment lines and empty lines
+ let curline = getline('.')
+ if curline =~ '^\s*$' || curline[0] == '"'
+ return
+ endif
+
+ " If inside a closed fold, then use the first line of the fold
+ " and jump to the file.
+ let lnum = foldclosed('.')
+ if lnum == -1
+ " Jump to the selected tag or file
+ let lnum = line('.')
+ else
+ " Open the closed fold
+ .foldopen!
+ endif
+
+ let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
+ if fidx == -1
+ return
+ endif
+
+ " Get the tag output for the current tag
+ let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum)
+ if tidx != 0
+ let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, tidx)
+
+ " Highlight the tagline
+ call s:Tlist_Window_Highlight_Line()
+ else
+ " Selected a line which is not a tag name. Just edit the file
+ let tagpat = ''
+ endif
+
+ call s:Tlist_Window_Open_File(a:win_ctrl, s:tlist_{fidx}_filename, tagpat)
+endfunction
+
+" Tlist_Window_Show_Info()
+" Display information about the entry under the cursor
+function! s:Tlist_Window_Show_Info()
+ call s:Tlist_Log_Msg('Tlist_Window_Show_Info()')
+
+ " Clear the previously displayed line
+ echo
+
+ " Do not process comment lines and empty lines
+ let curline = getline('.')
+ if curline =~ '^\s*$' || curline[0] == '"'
+ return
+ endif
+
+ " If inside a fold, then don't display the prototype
+ if foldclosed('.') != -1
+ return
+ endif
+
+ let lnum = line('.')
+
+ " Get the file index
+ let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
+ if fidx == -1
+ return
+ endif
+
+ if lnum == s:tlist_{fidx}_start
+ " Cursor is on a file name
+ let fname = s:tlist_{fidx}_filename
+ if strlen(fname) > 50
+ let fname = fnamemodify(fname, ':t')
+ endif
+ echo fname . ', Filetype=' . s:tlist_{fidx}_filetype .
+ \ ', Tag count=' . s:tlist_{fidx}_tag_count
+ return
+ endif
+
+ " Get the tag output line for the current tag
+ let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum)
+ if tidx == 0
+ " Cursor is on a tag type
+ let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum)
+ if ttype == ''
+ return
+ endif
+
+ let ttype_name = ''
+
+ let ftype = s:tlist_{fidx}_filetype
+ let i = 1
+ while i <= s:tlist_{ftype}_count
+ if ttype == s:tlist_{ftype}_{i}_name
+ let ttype_name = s:tlist_{ftype}_{i}_fullname
+ break
+ endif
+ let i = i + 1
+ endwhile
+
+ echo 'Tag type=' . ttype_name .
+ \ ', Tag count=' . s:tlist_{fidx}_{ttype}_count
+ return
+ endif
+
+ " Get the tag search pattern and display it
+ echo s:Tlist_Get_Tag_Prototype(fidx, tidx)
+endfunction
+
+" Tlist_Find_Nearest_Tag_Idx
+" Find the tag idx nearest to the supplied line number
+" Returns -1, if a tag couldn't be found for the specified line number
+function! s:Tlist_Find_Nearest_Tag_Idx(fidx, linenum)
+ let sort_type = s:tlist_{a:fidx}_sort_type
+
+ let left = 1
+ let right = s:tlist_{a:fidx}_tag_count
+
+ if sort_type == 'order'
+ " Tags sorted by order, use a binary search.
+ " The idea behind this function is taken from the ctags.vim script (by
+ " Alexey Marinichev) available at the Vim online website.
+
+ " If the current line is the less than the first tag, then no need to
+ " search
+ let first_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, 1)
+
+ if a:linenum < first_lnum
+ return -1
+ endif
+
+ while left < right
+ let middle = (right + left + 1) / 2
+ let middle_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, middle)
+
+ if middle_lnum == a:linenum
+ let left = middle
+ break
+ endif
+
+ if middle_lnum > a:linenum
+ let right = middle - 1
+ else
+ let left = middle
+ endif
+ endwhile
+ else
+ " Tags sorted by name, use a linear search. (contributed by Dave
+ " Eggum).
+ " Look for a tag with a line number less than or equal to the supplied
+ " line number. If multiple tags are found, then use the tag with the
+ " line number closest to the supplied line number. IOW, use the tag
+ " with the highest line number.
+ let closest_lnum = 0
+ let final_left = 0
+ while left <= right
+ let lnum = s:Tlist_Get_Tag_Linenum(a:fidx, left)
+
+ if lnum < a:linenum && lnum > closest_lnum
+ let closest_lnum = lnum
+ let final_left = left
+ elseif lnum == a:linenum
+ let closest_lnum = lnum
+ let final_left = left
+ break
+ else
+ let left = left + 1
+ endif
+ endwhile
+ if closest_lnum == 0
+ return -1
+ endif
+ if left >= right
+ let left = final_left
+ endif
+ endif
+
+ return left
+endfunction
+
+" Tlist_Window_Highlight_Tag()
+" Highlight the current tag
+" cntx == 1, Called by the taglist plugin itself
+" cntx == 2, Forced by the user through the TlistHighlightTag command
+" center = 1, move the tag line to the center of the taglist window
+function! s:Tlist_Window_Highlight_Tag(filename, cur_lnum, cntx, center)
+ " Highlight the current tag only if the user configured the
+ " taglist plugin to do so or if the user explictly invoked the
+ " command to highlight the current tag.
+ if !g:Tlist_Auto_Highlight_Tag && a:cntx == 1
+ return
+ endif
+
+ if a:filename == ''
+ return
+ endif
+
+ " Make sure the taglist window is present
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum == -1
+ call s:Tlist_Warning_Msg('Error: Taglist window is not open')
+ return
+ endif
+
+ let fidx = s:Tlist_Get_File_Index(a:filename)
+ if fidx == -1
+ return
+ endif
+
+ " If the file is currently not displayed in the taglist window, then retrn
+ if !s:tlist_{fidx}_visible
+ return
+ endif
+
+ " If there are no tags for this file, then no need to proceed further
+ if s:tlist_{fidx}_tag_count == 0
+ return
+ endif
+
+ " Ignore all autocommands
+ let old_ei = &eventignore
+ set eventignore=all
+
+ " Save the original window number
+ let org_winnr = winnr()
+
+ if org_winnr == winnum
+ let in_taglist_window = 1
+ else
+ let in_taglist_window = 0
+ endif
+
+ " Go to the taglist window
+ if !in_taglist_window
+ exe winnum . 'wincmd w'
+ endif
+
+ " Clear previously selected name
+ match none
+
+ let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, a:cur_lnum)
+ if tidx == -1
+ " Make sure the current tag line is visible in the taglist window.
+ " Calling the winline() function makes the line visible. Don't know
+ " of a better way to achieve this.
+ let lnum = line('.')
+
+ if lnum < s:tlist_{fidx}_start || lnum > s:tlist_{fidx}_end
+ " Move the cursor to the beginning of the file
+ exe s:tlist_{fidx}_start
+ endif
+
+ if foldclosed('.') != -1
+ .foldopen
+ endif
+
+ call winline()
+
+ if !in_taglist_window
+ exe org_winnr . 'wincmd w'
+ endif
+
+ " Restore the autocommands
+ let &eventignore = old_ei
+ return
+ endif
+
+ " Extract the tag type
+ let ttype = s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx)
+
+ " Compute the line number
+ " Start of file + Start of tag type + offset
+ let lnum = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_offset +
+ \ s:tlist_{fidx}_{tidx}_ttype_idx
+
+ " Goto the line containing the tag
+ exe lnum
+
+ " Open the fold
+ if foldclosed('.') != -1
+ .foldopen
+ endif
+
+ if a:center
+ " Move the tag line to the center of the taglist window
+ normal! z.
+ else
+ " Make sure the current tag line is visible in the taglist window.
+ " Calling the winline() function makes the line visible. Don't know
+ " of a better way to achieve this.
+ call winline()
+ endif
+
+ " Highlight the tag name
+ call s:Tlist_Window_Highlight_Line()
+
+ " Go back to the original window
+ if !in_taglist_window
+ exe org_winnr . 'wincmd w'
+ endif
+
+ " Restore the autocommands
+ let &eventignore = old_ei
+ return
+endfunction
+
+" Tlist_Get_Tag_Prototype_By_Line
+" Get the prototype for the tag on or before the specified line number in the
+" current buffer
+function! Tlist_Get_Tag_Prototype_By_Line(...)
+ if a:0 == 0
+ " Arguments are not supplied. Use the current buffer name
+ " and line number
+ let filename = bufname('%')
+ let linenr = line('.')
+ elseif a:0 == 2
+ " Filename and line number are specified
+ let filename = a:1
+ let linenr = a:2
+ if linenr !~ '\d\+'
+ " Invalid line number
+ return ""
+ endif
+ else
+ " Sufficient arguments are not supplied
+ let msg = 'Usage: Tlist_Get_Tag_Prototype_By_Line <filename> ' .
+ \ '<line_number>'
+ call s:Tlist_Warning_Msg(msg)
+ return ""
+ endif
+
+ " Expand the file to a fully qualified name
+ let filename = fnamemodify(filename, ':p')
+ if filename == ''
+ return ""
+ endif
+
+ let fidx = s:Tlist_Get_File_Index(filename)
+ if fidx == -1
+ return ""
+ endif
+
+ " If there are no tags for this file, then no need to proceed further
+ if s:tlist_{fidx}_tag_count == 0
+ return ""
+ endif
+
+ " Get the tag text using the line number
+ let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr)
+ if tidx == -1
+ return ""
+ endif
+
+ return s:Tlist_Get_Tag_Prototype(fidx, tidx)
+endfunction
+
+" Tlist_Get_Tagname_By_Line
+" Get the tag name on or before the specified line number in the
+" current buffer
+function! Tlist_Get_Tagname_By_Line(...)
+ if a:0 == 0
+ " Arguments are not supplied. Use the current buffer name
+ " and line number
+ let filename = bufname('%')
+ let linenr = line('.')
+ elseif a:0 == 2
+ " Filename and line number are specified
+ let filename = a:1
+ let linenr = a:2
+ if linenr !~ '\d\+'
+ " Invalid line number
+ return ""
+ endif
+ else
+ " Sufficient arguments are not supplied
+ let msg = 'Usage: Tlist_Get_Tagname_By_Line <filename> <line_number>'
+ call s:Tlist_Warning_Msg(msg)
+ return ""
+ endif
+
+ " Make sure the current file has a name
+ let filename = fnamemodify(filename, ':p')
+ if filename == ''
+ return ""
+ endif
+
+ let fidx = s:Tlist_Get_File_Index(filename)
+ if fidx == -1
+ return ""
+ endif
+
+ " If there are no tags for this file, then no need to proceed further
+ if s:tlist_{fidx}_tag_count == 0
+ return ""
+ endif
+
+ " Get the tag name using the line number
+ let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr)
+ if tidx == -1
+ return ""
+ endif
+
+ return s:tlist_{fidx}_{tidx}_tag_name
+endfunction
+
+" Tlist_Window_Move_To_File
+" Move the cursor to the beginning of the current file or the next file
+" or the previous file in the taglist window
+" dir == -1, move to start of current or previous function
+" dir == 1, move to start of next function
+function! s:Tlist_Window_Move_To_File(dir)
+ if foldlevel('.') == 0
+ " Cursor is on a non-folded line (it is not in any of the files)
+ " Move it to a folded line
+ if a:dir == -1
+ normal! zk
+ else
+ " While moving down to the start of the next fold,
+ " no need to do go to the start of the next file.
+ normal! zj
+ return
+ endif
+ endif
+
+ let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
+ if fidx == -1
+ return
+ endif
+
+ let cur_lnum = line('.')
+
+ if a:dir == -1
+ if cur_lnum > s:tlist_{fidx}_start
+ " Move to the beginning of the current file
+ exe s:tlist_{fidx}_start
+ return
+ endif
+
+ if fidx != 0
+ " Move to the beginning of the previous file
+ let fidx = fidx - 1
+ else
+ " Cursor is at the first file, wrap around to the last file
+ let fidx = s:tlist_file_count - 1
+ endif
+
+ exe s:tlist_{fidx}_start
+ return
+ else
+ " Move to the beginning of the next file
+ let fidx = fidx + 1
+
+ if fidx >= s:tlist_file_count
+ " Cursor is at the last file, wrap around to the first file
+ let fidx = 0
+ endif
+
+ if s:tlist_{fidx}_start != 0
+ exe s:tlist_{fidx}_start
+ endif
+ return
+ endif
+endfunction
+
+" Tlist_Session_Load
+" Load a taglist session (information about all the displayed files
+" and the tags) from the specified file
+function! s:Tlist_Session_Load(...)
+ if a:0 == 0 || a:1 == ''
+ call s:Tlist_Warning_Msg('Usage: TlistSessionLoad <filename>')
+ return
+ endif
+
+ let sessionfile = a:1
+
+ if !filereadable(sessionfile)
+ let msg = 'Taglist: Error - Unable to open file ' . sessionfile
+ call s:Tlist_Warning_Msg(msg)
+ return
+ endif
+
+ " Mark the current window as the file window
+ call s:Tlist_Window_Mark_File_Window()
+
+ " Source the session file
+ exe 'source ' . sessionfile
+
+ let new_file_count = g:tlist_file_count
+ unlet! g:tlist_file_count
+
+ let i = 0
+ while i < new_file_count
+ let ftype = g:tlist_{i}_filetype
+ unlet! g:tlist_{i}_filetype
+
+ if !exists('s:tlist_' . ftype . '_count')
+ if s:Tlist_FileType_Init(ftype) == 0
+ let i = i + 1
+ continue
+ endif
+ endif
+
+ let fname = g:tlist_{i}_filename
+ unlet! g:tlist_{i}_filename
+
+ let fidx = s:Tlist_Get_File_Index(fname)
+ if fidx != -1
+ let s:tlist_{fidx}_visible = 0
+ let i = i + 1
+ continue
+ else
+ " As we are loading the tags from the session file, if this
+ " file was previously deleted by the user, now we need to
+ " add it back. So remove the file from the deleted list.
+ call s:Tlist_Update_Remove_List(fname, 0)
+ endif
+
+ let fidx = s:Tlist_Init_File(fname, ftype)
+
+ let s:tlist_{fidx}_filename = fname
+
+ let s:tlist_{fidx}_sort_type = g:tlist_{i}_sort_type
+ unlet! g:tlist_{i}_sort_type
+
+ let s:tlist_{fidx}_filetype = ftype
+ let s:tlist_{fidx}_mtime = getftime(fname)
+
+ let s:tlist_{fidx}_start = 0
+ let s:tlist_{fidx}_end = 0
+
+ let s:tlist_{fidx}_valid = 1
+
+ let s:tlist_{fidx}_tag_count = g:tlist_{i}_tag_count
+ unlet! g:tlist_{i}_tag_count
+
+ let j = 1
+ while j <= s:tlist_{fidx}_tag_count
+ let s:tlist_{fidx}_{j}_tag = g:tlist_{i}_{j}_tag
+ let s:tlist_{fidx}_{j}_tag_name = g:tlist_{i}_{j}_tag_name
+ let s:tlist_{fidx}_{j}_ttype_idx = g:tlist_{i}_{j}_ttype_idx
+ unlet! g:tlist_{i}_{j}_tag
+ unlet! g:tlist_{i}_{j}_tag_name
+ unlet! g:tlist_{i}_{j}_ttype_idx
+ let j = j + 1
+ endwhile
+
+ let j = 1
+ while j <= s:tlist_{ftype}_count
+ let ttype = s:tlist_{ftype}_{j}_name
+
+ if exists('g:tlist_' . i . '_' . ttype)
+ let s:tlist_{fidx}_{ttype} = g:tlist_{i}_{ttype}
+ unlet! g:tlist_{i}_{ttype}
+ let s:tlist_{fidx}_{ttype}_offset = 0
+ let s:tlist_{fidx}_{ttype}_count = g:tlist_{i}_{ttype}_count
+ unlet! g:tlist_{i}_{ttype}_count
+
+ let k = 1
+ while k <= s:tlist_{fidx}_{ttype}_count
+ let s:tlist_{fidx}_{ttype}_{k} = g:tlist_{i}_{ttype}_{k}
+ unlet! g:tlist_{i}_{ttype}_{k}
+ let k = k + 1
+ endwhile
+ else
+ let s:tlist_{fidx}_{ttype} = ''
+ let s:tlist_{fidx}_{ttype}_offset = 0
+ let s:tlist_{fidx}_{ttype}_count = 0
+ endif
+
+ let j = j + 1
+ endwhile
+
+ let i = i + 1
+ endwhile
+
+ " If the taglist window is open, then update it
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum != -1
+ let save_winnr = winnr()
+
+ " Goto the taglist window
+ call s:Tlist_Window_Goto_Window()
+
+ " Refresh the taglist window
+ call s:Tlist_Window_Refresh()
+
+ " Go back to the original window
+ if save_winnr != winnr()
+ call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
+ endif
+ endif
+endfunction
+
+" Tlist_Session_Save
+" Save a taglist session (information about all the displayed files
+" and the tags) into the specified file
+function! s:Tlist_Session_Save(...)
+ if a:0 == 0 || a:1 == ''
+ call s:Tlist_Warning_Msg('Usage: TlistSessionSave <filename>')
+ return
+ endif
+
+ let sessionfile = a:1
+
+ if s:tlist_file_count == 0
+ " There is nothing to save
+ call s:Tlist_Warning_Msg('Warning: Taglist is empty. Nothing to save.')
+ return
+ endif
+
+ if filereadable(sessionfile)
+ let ans = input('Do you want to overwrite ' . sessionfile . ' (Y/N)?')
+ if ans !=? 'y'
+ return
+ endif
+
+ echo "\n"
+ endif
+
+ let old_verbose = &verbose
+ set verbose&vim
+
+ exe 'redir! > ' . sessionfile
+
+ silent! echo '" Taglist session file. This file is auto-generated.'
+ silent! echo '" File information'
+ silent! echo 'let tlist_file_count = ' . s:tlist_file_count
+
+ let i = 0
+
+ while i < s:tlist_file_count
+ " Store information about the file
+ silent! echo 'let tlist_' . i . "_filename = '" .
+ \ s:tlist_{i}_filename . "'"
+ silent! echo 'let tlist_' . i . '_sort_type = "' .
+ \ s:tlist_{i}_sort_type . '"'
+ silent! echo 'let tlist_' . i . '_filetype = "' .
+ \ s:tlist_{i}_filetype . '"'
+ silent! echo 'let tlist_' . i . '_tag_count = ' .
+ \ s:tlist_{i}_tag_count
+ " Store information about all the tags
+ let j = 1
+ while j <= s:tlist_{i}_tag_count
+ let txt = escape(s:tlist_{i}_{j}_tag, '"\\')
+ silent! echo 'let tlist_' . i . '_' . j . '_tag = "' . txt . '"'
+ silent! echo 'let tlist_' . i . '_' . j . '_tag_name = "' .
+ \ s:tlist_{i}_{j}_tag_name . '"'
+ silent! echo 'let tlist_' . i . '_' . j . '_ttype_idx' . ' = ' .
+ \ s:tlist_{i}_{j}_ttype_idx
+ let j = j + 1
+ endwhile
+
+ " Store information about all the tags grouped by their type
+ let ftype = s:tlist_{i}_filetype
+ let j = 1
+ while j <= s:tlist_{ftype}_count
+ let ttype = s:tlist_{ftype}_{j}_name
+ if s:tlist_{i}_{ttype}_count != 0
+ let txt = escape(s:tlist_{i}_{ttype}, '"\')
+ let txt = substitute(txt, "\n", "\\\\n", 'g')
+ silent! echo 'let tlist_' . i . '_' . ttype . ' = "' .
+ \ txt . '"'
+ silent! echo 'let tlist_' . i . '_' . ttype . '_count = ' .
+ \ s:tlist_{i}_{ttype}_count
+ let k = 1
+ while k <= s:tlist_{i}_{ttype}_count
+ silent! echo 'let tlist_' . i . '_' . ttype . '_' . k .
+ \ ' = ' . s:tlist_{i}_{ttype}_{k}
+ let k = k + 1
+ endwhile
+ endif
+ let j = j + 1
+ endwhile
+
+ silent! echo
+
+ let i = i + 1
+ endwhile
+
+ redir END
+
+ let &verbose = old_verbose
+endfunction
+
+" Tlist_Buffer_Removed
+" A buffer is removed from the Vim buffer list. Remove the tags defined
+" for that file
+function! s:Tlist_Buffer_Removed(filename)
+ call s:Tlist_Log_Msg('Tlist_Buffer_Removed (' . a:filename . ')')
+
+ " Make sure a valid filename is supplied
+ if a:filename == ''
+ return
+ endif
+
+ " Get tag list index of the specified file
+ let fidx = s:Tlist_Get_File_Index(a:filename)
+ if fidx == -1
+ " File not present in the taglist
+ return
+ endif
+
+ " Remove the file from the list
+ call s:Tlist_Remove_File(fidx, 0)
+endfunction
+
+" When a buffer is deleted, remove the file from the taglist
+autocmd BufDelete * silent call s:Tlist_Buffer_Removed(expand('<afile>:p'))
+
+" Tlist_Window_Open_File_Fold
+" Open the fold for the specified file and close the fold for all the
+" other files
+function! s:Tlist_Window_Open_File_Fold(acmd_bufnr)
+ call s:Tlist_Log_Msg('Tlist_Window_Open_File_Fold (' . a:acmd_bufnr . ')')
+
+ " Make sure the taglist window is present
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum == -1
+ call s:Tlist_Warning_Msg('Taglist: Error - Taglist window is not open')
+ return
+ endif
+
+ " Save the original window number
+ let org_winnr = winnr()
+ if org_winnr == winnum
+ let in_taglist_window = 1
+ else
+ let in_taglist_window = 0
+ endif
+
+ if in_taglist_window
+ " When entering the taglist window, no need to update the folds
+ return
+ endif
+
+ " Go to the taglist window
+ if !in_taglist_window
+ call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w')
+ endif
+
+ " Close all the folds
+ silent! %foldclose
+
+ " Get tag list index of the specified file
+ let fname = fnamemodify(bufname(a:acmd_bufnr + 0), ':p')
+ if filereadable(fname)
+ let fidx = s:Tlist_Get_File_Index(fname)
+ if fidx != -1
+ " Open the fold for the file
+ exe "silent! " . s:tlist_{fidx}_start . "," .
+ \ s:tlist_{fidx}_end . "foldopen"
+ endif
+ endif
+
+ " Go back to the original window
+ if !in_taglist_window
+ call s:Tlist_Exe_Cmd_No_Acmds(org_winnr . 'wincmd w')
+ endif
+endfunction
+
+" Tlist_Window_Check_Auto_Open
+" Open the taglist window automatically on Vim startup.
+" Open the window only when files present in any of the Vim windows support
+" tags.
+function! s:Tlist_Window_Check_Auto_Open()
+ let open_window = 0
+
+ let i = 1
+ let buf_num = winbufnr(i)
+ while buf_num != -1
+ let filename = fnamemodify(bufname(buf_num), ':p')
+ let ft = s:Tlist_Get_Buffer_Filetype(buf_num)
+ if !s:Tlist_Skip_File(filename, ft)
+ let open_window = 1
+ break
+ endif
+ let i = i + 1
+ let buf_num = winbufnr(i)
+ endwhile
+
+ if open_window
+ call s:Tlist_Window_Toggle()
+ endif
+endfunction
+
+" Tlist_Refresh_Folds
+" Remove and create the folds for all the files displayed in the taglist
+" window. Used after entering a tab. If this is not done, then the folds
+" are not properly created for taglist windows displayed in multiple tabs.
+function! s:Tlist_Refresh_Folds()
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum == -1
+ return
+ endif
+
+ let save_wnum = winnr()
+ exe winnum . 'wincmd w'
+
+ " First remove all the existing folds
+ normal! zE
+
+ " Create the folds for each in the tag list
+ let fidx = 0
+ while fidx < s:tlist_file_count
+ let ftype = s:tlist_{fidx}_filetype
+
+ " Create the folds for each tag type in a file
+ let j = 1
+ while j <= s:tlist_{ftype}_count
+ let ttype = s:tlist_{ftype}_{j}_name
+ if s:tlist_{fidx}_{ttype}_count
+ let s = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_offset
+ let e = s + s:tlist_{fidx}_{ttype}_count
+ exe s . ',' . e . 'fold'
+ endif
+ let j = j + 1
+ endwhile
+
+ exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold'
+ exe 'silent! ' . s:tlist_{fidx}_start . ',' .
+ \ s:tlist_{fidx}_end . 'foldopen!'
+ let fidx = fidx + 1
+ endwhile
+
+ exe save_wnum . 'wincmd w'
+endfunction
+
+function! s:Tlist_Menu_Add_Base_Menu()
+ call s:Tlist_Log_Msg('Adding the base menu')
+
+ " Add the menu
+ anoremenu <silent> T&ags.Refresh\ menu :call <SID>Tlist_Menu_Refresh()<CR>
+ anoremenu <silent> T&ags.Sort\ menu\ by.Name
+ \ :call <SID>Tlist_Change_Sort('menu', 'set', 'name')<CR>
+ anoremenu <silent> T&ags.Sort\ menu\ by.Order
+ \ :call <SID>Tlist_Change_Sort('menu', 'set', 'order')<CR>
+ anoremenu T&ags.-SEP1- :
+
+ if &mousemodel =~ 'popup'
+ anoremenu <silent> PopUp.T&ags.Refresh\ menu
+ \ :call <SID>Tlist_Menu_Refresh()<CR>
+ anoremenu <silent> PopUp.T&ags.Sort\ menu\ by.Name
+ \ :call <SID>Tlist_Change_Sort('menu', 'set', 'name')<CR>
+ anoremenu <silent> PopUp.T&ags.Sort\ menu\ by.Order
+ \ :call <SID>Tlist_Change_Sort('menu', 'set', 'order')<CR>
+ anoremenu PopUp.T&ags.-SEP1- :
+ endif
+endfunction
+
+let s:menu_char_prefix =
+ \ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
+
+" Tlist_Menu_Get_Tag_Type_Cmd
+" Get the menu command for the specified tag type
+" fidx - File type index
+" ftype - File Type
+" add_ttype_name - To add or not to add the tag type name to the menu entries
+" ttype_idx - Tag type index
+function! s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, ttype_idx)
+ " Curly brace variable name optimization
+ let ftype_ttype_idx = a:ftype . '_' . a:ttype_idx
+
+ let ttype = s:tlist_{ftype_ttype_idx}_name
+ if a:add_ttype_name
+ " If the tag type name contains space characters, escape it. This
+ " will be used to create the menu entries.
+ let ttype_fullname = escape(s:tlist_{ftype_ttype_idx}_fullname, ' ')
+ endif
+
+ " Curly brace variable name optimization
+ let fidx_ttype = a:fidx . '_' . ttype
+
+ " Number of tag entries for this tag type
+ let tcnt = s:tlist_{fidx_ttype}_count
+ if tcnt == 0 " No entries for this tag type
+ return ''
+ endif
+
+ let mcmd = ''
+
+ " Create the menu items for the tags.
+ " Depending on the number of tags of this type, split the menu into
+ " multiple sub-menus, if needed.
+ if tcnt > g:Tlist_Max_Submenu_Items
+ let j = 1
+ while j <= tcnt
+ let final_index = j + g:Tlist_Max_Submenu_Items - 1
+ if final_index > tcnt
+ let final_index = tcnt
+ endif
+
+ " Extract the first and last tag name and form the
+ " sub-menu name
+ let tidx = s:tlist_{fidx_ttype}_{j}
+ let first_tag = s:tlist_{a:fidx}_{tidx}_tag_name
+
+ let tidx = s:tlist_{fidx_ttype}_{final_index}
+ let last_tag = s:tlist_{a:fidx}_{tidx}_tag_name
+
+ " Truncate the names, if they are greater than the
+ " max length
+ let first_tag = strpart(first_tag, 0, g:Tlist_Max_Tag_Length)
+ let last_tag = strpart(last_tag, 0, g:Tlist_Max_Tag_Length)
+
+ " Form the menu command prefix
+ let m_prefix = 'anoremenu <silent> T\&ags.'
+ if a:add_ttype_name
+ let m_prefix = m_prefix . ttype_fullname . '.'
+ endif
+ let m_prefix = m_prefix . first_tag . '\.\.\.' . last_tag . '.'
+
+ " Character prefix used to number the menu items (hotkey)
+ let m_prefix_idx = 0
+
+ while j <= final_index
+ let tidx = s:tlist_{fidx_ttype}_{j}
+
+ let tname = s:tlist_{a:fidx}_{tidx}_tag_name
+
+ let mcmd = mcmd . m_prefix . '\&' .
+ \ s:menu_char_prefix[m_prefix_idx] . '\.' .
+ \ tname . ' :call <SID>Tlist_Menu_Jump_To_Tag(' .
+ \ tidx . ')<CR>|'
+
+ let m_prefix_idx = m_prefix_idx + 1
+ let j = j + 1
+ endwhile
+ endwhile
+ else
+ " Character prefix used to number the menu items (hotkey)
+ let m_prefix_idx = 0
+
+ let m_prefix = 'anoremenu <silent> T\&ags.'
+ if a:add_ttype_name
+ let m_prefix = m_prefix . ttype_fullname . '.'
+ endif
+ let j = 1
+ while j <= tcnt
+ let tidx = s:tlist_{fidx_ttype}_{j}
+
+ let tname = s:tlist_{a:fidx}_{tidx}_tag_name
+
+ let mcmd = mcmd . m_prefix . '\&' .
+ \ s:menu_char_prefix[m_prefix_idx] . '\.' .
+ \ tname . ' :call <SID>Tlist_Menu_Jump_To_Tag(' . tidx
+ \ . ')<CR>|'
+
+ let m_prefix_idx = m_prefix_idx + 1
+ let j = j + 1
+ endwhile
+ endif
+
+ return mcmd
+endfunction
+
+" Update the taglist menu with the tags for the specified file
+function! s:Tlist_Menu_File_Refresh(fidx)
+ call s:Tlist_Log_Msg('Refreshing the tag menu for ' . s:tlist_{a:fidx}_filename)
+ " The 'B' flag is needed in the 'cpoptions' option
+ let old_cpoptions = &cpoptions
+ set cpoptions&vim
+
+ exe s:tlist_{a:fidx}_menu_cmd
+
+ " Update the popup menu (if enabled)
+ if &mousemodel =~ 'popup'
+ let cmd = substitute(s:tlist_{a:fidx}_menu_cmd, ' T\\&ags\.',
+ \ ' PopUp.T\\\&ags.', "g")
+ exe cmd
+ endif
+
+ " The taglist menu is not empty now
+ let s:tlist_menu_empty = 0
+
+ " Restore the 'cpoptions' settings
+ let &cpoptions = old_cpoptions
+endfunction
+
+" Tlist_Menu_Update_File
+" Add the taglist menu
+function! s:Tlist_Menu_Update_File(clear_menu)
+ if !has('gui_running')
+ " Not running in GUI mode
+ return
+ endif
+
+ call s:Tlist_Log_Msg('Updating the tag menu, clear_menu = ' . a:clear_menu)
+
+ " Remove the tags menu
+ if a:clear_menu
+ call s:Tlist_Menu_Remove_File()
+
+ endif
+
+ " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help
+ if &buftype != ''
+ return
+ endif
+
+ let filename = fnamemodify(bufname('%'), ':p')
+ let ftype = s:Tlist_Get_Buffer_Filetype('%')
+
+ " If the file doesn't support tag listing, skip it
+ if s:Tlist_Skip_File(filename, ftype)
+ return
+ endif
+
+ let fidx = s:Tlist_Get_File_Index(filename)
+ if fidx == -1 || !s:tlist_{fidx}_valid
+ " Check whether this file is removed based on user request
+ " If it is, then don't display the tags for this file
+ if s:Tlist_User_Removed_File(filename)
+ return
+ endif
+
+ " Process the tags for the file
+ let fidx = s:Tlist_Process_File(filename, ftype)
+ if fidx == -1
+ return
+ endif
+ endif
+
+ let fname = escape(fnamemodify(bufname('%'), ':t'), '.')
+ if fname != ''
+ exe 'anoremenu T&ags.' . fname . ' <Nop>'
+ anoremenu T&ags.-SEP2- :
+ endif
+
+ if !s:tlist_{fidx}_tag_count
+ return
+ endif
+
+ if s:tlist_{fidx}_menu_cmd != ''
+ " Update the menu with the cached command
+ call s:Tlist_Menu_File_Refresh(fidx)
+
+ return
+ endif
+
+ " We are going to add entries to the tags menu, so the menu won't be
+ " empty
+ let s:tlist_menu_empty = 0
+
+ let cmd = ''
+
+ " Determine whether the tag type name needs to be added to the menu
+ " If more than one tag type is present in the taglisting for a file,
+ " then the tag type name needs to be present
+ let add_ttype_name = -1
+ let i = 1
+ while i <= s:tlist_{ftype}_count && add_ttype_name < 1
+ let ttype = s:tlist_{ftype}_{i}_name
+ if s:tlist_{fidx}_{ttype}_count
+ let add_ttype_name = add_ttype_name + 1
+ endif
+ let i = i + 1
+ endwhile
+
+ " Process the tags by the tag type and get the menu command
+ let i = 1
+ while i <= s:tlist_{ftype}_count
+ let mcmd = s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, i)
+ if mcmd != ''
+ let cmd = cmd . mcmd
+ endif
+
+ let i = i + 1
+ endwhile
+
+ " Cache the menu command for reuse
+ let s:tlist_{fidx}_menu_cmd = cmd
+
+ " Update the menu
+ call s:Tlist_Menu_File_Refresh(fidx)
+endfunction
+
+" Tlist_Menu_Remove_File
+" Remove the tags displayed in the tags menu
+function! s:Tlist_Menu_Remove_File()
+ if !has('gui_running') || s:tlist_menu_empty
+ return
+ endif
+
+ call s:Tlist_Log_Msg('Removing the tags menu for a file')
+
+ " Cleanup the Tags menu
+ silent! unmenu T&ags
+ if &mousemodel =~ 'popup'
+ silent! unmenu PopUp.T&ags
+ endif
+
+ " Add a dummy menu item to retain teared off menu
+ noremenu T&ags.Dummy l
+
+ silent! unmenu! T&ags
+ if &mousemodel =~ 'popup'
+ silent! unmenu! PopUp.T&ags
+ endif
+
+ call s:Tlist_Menu_Add_Base_Menu()
+
+ " Remove the dummy menu item
+ unmenu T&ags.Dummy
+
+ let s:tlist_menu_empty = 1
+endfunction
+
+" Tlist_Menu_Refresh
+" Refresh the taglist menu
+function! s:Tlist_Menu_Refresh()
+ call s:Tlist_Log_Msg('Refreshing the tags menu')
+ let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
+ if fidx != -1
+ " Invalidate the cached menu command
+ let s:tlist_{fidx}_menu_cmd = ''
+ endif
+
+ " Update the taglist, menu and window
+ call s:Tlist_Update_Current_File()
+endfunction
+
+" Tlist_Menu_Jump_To_Tag
+" Jump to the selected tag
+function! s:Tlist_Menu_Jump_To_Tag(tidx)
+ let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
+ if fidx == -1
+ return
+ endif
+
+ let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, a:tidx)
+ if tagpat == ''
+ return
+ endif
+
+ " Add the current cursor position to the jump list, so that user can
+ " jump back using the ' and ` marks.
+ mark '
+
+ silent call search(tagpat, 'w')
+
+ " Bring the line to the middle of the window
+ normal! z.
+
+ " If the line is inside a fold, open the fold
+ if foldclosed('.') != -1
+ .foldopen
+ endif
+endfunction
+
+" Tlist_Menu_Init
+" Initialize the taglist menu
+function! s:Tlist_Menu_Init()
+ call s:Tlist_Menu_Add_Base_Menu()
+
+ " Automatically add the tags defined in the current file to the menu
+ augroup TagListMenuCmds
+ autocmd!
+
+ if !g:Tlist_Process_File_Always
+ autocmd BufEnter * call s:Tlist_Refresh()
+ endif
+ autocmd BufLeave * call s:Tlist_Menu_Remove_File()
+ augroup end
+
+ call s:Tlist_Menu_Update_File(0)
+endfunction
+
+" Tlist_Vim_Session_Load
+" Initialize the taglist window/buffer, which is created when loading
+" a Vim session file.
+function! s:Tlist_Vim_Session_Load()
+ call s:Tlist_Log_Msg('Tlist_Vim_Session_Load')
+
+ " Initialize the taglist window
+ call s:Tlist_Window_Init()
+
+ " Refresh the taglist window
+ call s:Tlist_Window_Refresh()
+endfunction
+
+" Tlist_Set_App
+" Set the name of the external plugin/application to which taglist
+" belongs.
+" Taglist plugin is part of another plugin like cream or winmanager.
+function! Tlist_Set_App(name)
+ if a:name == ""
+ return
+ endif
+
+ let s:tlist_app_name = a:name
+endfunction
+
+" Winmanager integration
+
+" Initialization required for integration with winmanager
+function! TagList_Start()
+ " If current buffer is not taglist buffer, then don't proceed
+ if bufname('%') != '__Tag_List__'
+ return
+ endif
+
+ call Tlist_Set_App('winmanager')
+
+ " Get the current filename from the winmanager plugin
+ let bufnum = WinManagerGetLastEditedFile()
+ if bufnum != -1
+ let filename = fnamemodify(bufname(bufnum), ':p')
+ let ftype = s:Tlist_Get_Buffer_Filetype(bufnum)
+ endif
+
+ " Initialize the taglist window, if it is not already initialized
+ if !exists('s:tlist_window_initialized') || !s:tlist_window_initialized
+ call s:Tlist_Window_Init()
+ call s:Tlist_Window_Refresh()
+ let s:tlist_window_initialized = 1
+ endif
+
+ " Update the taglist window
+ if bufnum != -1
+ if !s:Tlist_Skip_File(filename, ftype) && g:Tlist_Auto_Update
+ call s:Tlist_Window_Refresh_File(filename, ftype)
+ endif
+ endif
+endfunction
+
+function! TagList_IsValid()
+ return 0
+endfunction
+
+function! TagList_WrapUp()
+ return 0
+endfunction
+
+" restore 'cpo'
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
diff --git a/vim/plugin/unimpaired.vim b/vim/plugin/unimpaired.vim
new file mode 100644
index 0000000..60b6c02
--- /dev/null
+++ b/vim/plugin/unimpaired.vim
@@ -0,0 +1,315 @@
+" unimpaired.vim - Pairs of handy bracket mappings
+" Maintainer: Tim Pope <http://tpo.pe/>
+" Version: 1.1
+" GetLatestVimScripts: 1590 1 :AutoInstall: unimpaired.vim
+
+if exists("g:loaded_unimpaired") || &cp || v:version < 700
+ finish
+endif
+let g:loaded_unimpaired = 1
+
+" Next and previous {{{1
+
+function! s:MapNextFamily(map,cmd)
+ let map = '<Plug>unimpaired'.toupper(a:map)
+ let end = ' ".(v:count ? v:count : "")<CR>'
+ execute 'nmap <silent> '.map.'Previous :<C-U>exe "'.a:cmd.'previous'.end
+ execute 'nmap <silent> '.map.'Next :<C-U>exe "'.a:cmd.'next'.end
+ execute 'nmap <silent> '.map.'First :<C-U>exe "'.a:cmd.'first'.end
+ execute 'nmap <silent> '.map.'Last :<C-U>exe "'.a:cmd.'last'.end
+ execute 'nmap <silent> ['. a:map .' '.map.'Previous'
+ execute 'nmap <silent> ]'. a:map .' '.map.'Next'
+ execute 'nmap <silent> ['.toupper(a:map).' '.map.'First'
+ execute 'nmap <silent> ]'.toupper(a:map).' '.map.'Last'
+endfunction
+
+call s:MapNextFamily('a','')
+call s:MapNextFamily('b','b')
+call s:MapNextFamily('l','l')
+call s:MapNextFamily('q','c')
+call s:MapNextFamily('t','t')
+
+function! s:entries(path)
+ let path = substitute(a:path,'[\\/]$','','')
+ let files = split(glob(path."/.*"),"\n")
+ let files += split(glob(path."/*"),"\n")
+ call map(files,'substitute(v:val,"[\\/]$","","")')
+ call filter(files,'v:val !~# "[\\\\/]\\.\\.\\=$"')
+ call filter(files,'v:val[-4:-1] !=# ".swp" && v:val[-1:-1] !=# "~"')
+ return files
+endfunction
+
+function! s:FileByOffset(num)
+ let file = expand('%:p')
+ let num = a:num
+ while num
+ let files = s:entries(fnamemodify(file,':h'))
+ if a:num < 0
+ call reverse(sort(filter(files,'v:val < file')))
+ else
+ call sort(filter(files,'v:val > file'))
+ endif
+ let temp = get(files,0,'')
+ if temp == ''
+ let file = fnamemodify(file,':h')
+ else
+ let file = temp
+ while isdirectory(file)
+ let files = s:entries(file)
+ if files == []
+ " TODO: walk back up the tree and continue
+ break
+ endif
+ let file = files[num > 0 ? 0 : -1]
+ endwhile
+ let num += num > 0 ? -1 : 1
+ endif
+ endwhile
+ return file
+endfunction
+
+nnoremap <silent> <Plug>unimpairedONext :<C-U>edit `=<SID>FileByOffset(v:count1)`<CR>
+nnoremap <silent> <Plug>unimpairedOPrevious :<C-U>edit `=<SID>FileByOffset(-v:count1)`<CR>
+
+nmap ]o <Plug>unimpairedONext
+nmap [o <Plug>unimpairedOPrevious
+
+nmap [, :call search('^[<=>]\{7\}','bW')<CR>
+nmap ], :call search('^[<=>]\{7\}','W')<CR>
+omap [, V:call search('^[<=>]\{7\}','bW')<CR>
+omap ], V:call search('^[<=>]\{7\}','W')<CR>
+xmap [, :<C-U>exe 'norm! gv'<Bar>call search('^[<=>]\{7\}','bW')<CR>
+xmap ], :<C-U>exe 'norm! gv'<Bar>call search('^[<=>]\{7\}','W')<CR>
+nmap [< :call search('^<<<<<<<','bW')<CR>
+nmap [= :call search('^=======','bW')<CR>
+nmap [> :call search('^>>>>>>>','bW')<CR>
+nmap ]< :call search('^<<<<<<<','W')<CR>
+nmap ]= :call search('^=======','W')<CR>
+nmap ]> :call search('^>>>>>>>','W')<CR>
+xmap [< :<C-U>exe 'norm! gv'<Bar>call search('^<<<<<<<','bW')<CR>
+xmap [= :<C-U>exe 'norm! gv'<Bar>call search('^=======','bW')<CR>
+xmap [> :<C-U>exe 'norm! gv'<Bar>call search('^>>>>>>>','bW')<CR>
+xmap ]< :<C-U>exe 'norm! gv'<Bar>call search('^<<<<<<<','W')<CR>
+xmap ]= :<C-U>exe 'norm! gv'<Bar>call search('^=======','W')<CR>
+xmap ]> :<C-U>exe 'norm! gv'<Bar>call search('^>>>>>>>','W')<CR>
+omap [< V:call search('^<<<<<<<','bW')<CR>
+omap [= V:call search('^=======','bW')<CR>
+omap [> V:call search('^>>>>>>>','bW')<CR>
+omap ]< V:call search('^<<<<<<<','W')<CR>
+omap ]= V:call search('^=======','W')<CR>
+omap ]> V:call search('^>>>>>>>','W')<CR>
+
+" }}}1
+" Line operations {{{1
+
+function! s:BlankUp(count) abort
+ put!=repeat(nr2char(10), a:count)
+ ']+1
+ silent! call repeat#set("\<Plug>unimpairedBlankUp", a:count)
+endfunction
+
+function! s:BlankDown(count) abort
+ put =repeat(nr2char(10), a:count)
+ '[-1
+ silent! call repeat#set("\<Plug>unimpairedBlankDown", a:count)
+endfunction
+
+nnoremap <silent> <Plug>unimpairedBlankUp :<C-U>call <SID>BlankUp(v:count1)<CR>
+nnoremap <silent> <Plug>unimpairedBlankDown :<C-U>call <SID>BlankDown(v:count1)<CR>
+
+nmap [<Space> <Plug>unimpairedBlankUp
+nmap ]<Space> <Plug>unimpairedBlankDown
+
+function! s:Move(cmd, count, map) abort
+ normal! m`
+ exe 'move'.a:cmd.a:count
+ norm! ``
+ call repeat#set("\<Plug>unimpairedMove".a:map, a:count)
+endfunction
+
+nnoremap <silent> <Plug>unimpairedMoveUp :<C-U>call <SID>Move('--',v:count1,'Up')<CR>
+nnoremap <silent> <Plug>unimpairedMoveDown :<C-U>call <SID>Move('+',v:count1,'Down')<CR>
+xnoremap <silent> <Plug>unimpairedMoveUp :<C-U>exe 'normal! m`'<Bar>exe '''<,''>move--'.v:count1<CR>``
+xnoremap <silent> <Plug>unimpairedMoveDown :<C-U>exe 'normal! m`'<Bar>exe '''<,''>move''>+'.v:count1<CR>``
+
+nmap [e <Plug>unimpairedMoveUp
+nmap ]e <Plug>unimpairedMoveDown
+xmap [e <Plug>unimpairedMoveUp
+xmap ]e <Plug>unimpairedMoveDown
+
+" }}}1
+" Encoding and decoding {{{1
+
+function! s:StringEncode(str)
+ let map = {"\n": 'n', "\r": 'r', "\t": 't', "\b": 'b', "\f": '\f', '"': '"', '\': '\'}
+ return substitute(a:str,"[\001-\033\\\\\"]",'\="\\".get(map,submatch(0),printf("%03o",char2nr(submatch(0))))','g')
+endfunction
+
+function! s:StringDecode(str)
+ let map = {'n': "\n", 'r': "\r", 't': "\t", 'b': "\b", 'f': "\f", 'e': "\e", 'a': "\001", 'v': "\013"}
+ let str = a:str
+ if str =~ '^\s*".\{-\}\\\@<!\%(\\\\\)*"\s*\n\=$'
+ let str = substitute(substitute(str,'^\s*\zs"','',''),'"\ze\s*\n\=$','','')
+ endif
+ let str = substitute(str,'\\n\%(\n$\)\=','\n','g')
+ return substitute(str,'\\\(\o\{1,3\}\|x\x\{1,2\}\|u\x\{1,4\}\|.\)','\=get(map,submatch(1),submatch(1) =~? "^[0-9xu]" ? nr2char("0".substitute(submatch(1),"^[Uu]","x","")) : submatch(1))','g')
+endfunction
+
+function! s:UrlEncode(str)
+ return substitute(a:str,'[^A-Za-z0-9_.~-]','\="%".printf("%02X",char2nr(submatch(0)))','g')
+endfunction
+
+function! s:UrlDecode(str)
+ let str = substitute(substitute(substitute(a:str,'%0[Aa]\n$','%0A',''),'%0[Aa]','\n','g'),'+',' ','g')
+ return substitute(str,'%\(\x\x\)','\=nr2char("0x".submatch(1))','g')
+endfunction
+
+" HTML entities {{{2
+
+let g:unimpaired_html_entities = {
+ \ 'nbsp': 160, 'iexcl': 161, 'cent': 162, 'pound': 163,
+ \ 'curren': 164, 'yen': 165, 'brvbar': 166, 'sect': 167,
+ \ 'uml': 168, 'copy': 169, 'ordf': 170, 'laquo': 171,
+ \ 'not': 172, 'shy': 173, 'reg': 174, 'macr': 175,
+ \ 'deg': 176, 'plusmn': 177, 'sup2': 178, 'sup3': 179,
+ \ 'acute': 180, 'micro': 181, 'para': 182, 'middot': 183,
+ \ 'cedil': 184, 'sup1': 185, 'ordm': 186, 'raquo': 187,
+ \ 'frac14': 188, 'frac12': 189, 'frac34': 190, 'iquest': 191,
+ \ 'Agrave': 192, 'Aacute': 193, 'Acirc': 194, 'Atilde': 195,
+ \ 'Auml': 196, 'Aring': 197, 'AElig': 198, 'Ccedil': 199,
+ \ 'Egrave': 200, 'Eacute': 201, 'Ecirc': 202, 'Euml': 203,
+ \ 'Igrave': 204, 'Iacute': 205, 'Icirc': 206, 'Iuml': 207,
+ \ 'ETH': 208, 'Ntilde': 209, 'Ograve': 210, 'Oacute': 211,
+ \ 'Ocirc': 212, 'Otilde': 213, 'Ouml': 214, 'times': 215,
+ \ 'Oslash': 216, 'Ugrave': 217, 'Uacute': 218, 'Ucirc': 219,
+ \ 'Uuml': 220, 'Yacute': 221, 'THORN': 222, 'szlig': 223,
+ \ 'agrave': 224, 'aacute': 225, 'acirc': 226, 'atilde': 227,
+ \ 'auml': 228, 'aring': 229, 'aelig': 230, 'ccedil': 231,
+ \ 'egrave': 232, 'eacute': 233, 'ecirc': 234, 'euml': 235,
+ \ 'igrave': 236, 'iacute': 237, 'icirc': 238, 'iuml': 239,
+ \ 'eth': 240, 'ntilde': 241, 'ograve': 242, 'oacute': 243,
+ \ 'ocirc': 244, 'otilde': 245, 'ouml': 246, 'divide': 247,
+ \ 'oslash': 248, 'ugrave': 249, 'uacute': 250, 'ucirc': 251,
+ \ 'uuml': 252, 'yacute': 253, 'thorn': 254, 'yuml': 255,
+ \ 'OElig': 338, 'oelig': 339, 'Scaron': 352, 'scaron': 353,
+ \ 'Yuml': 376, 'circ': 710, 'tilde': 732, 'ensp': 8194,
+ \ 'emsp': 8195, 'thinsp': 8201, 'zwnj': 8204, 'zwj': 8205,
+ \ 'lrm': 8206, 'rlm': 8207, 'ndash': 8211, 'mdash': 8212,
+ \ 'lsquo': 8216, 'rsquo': 8217, 'sbquo': 8218, 'ldquo': 8220,
+ \ 'rdquo': 8221, 'bdquo': 8222, 'dagger': 8224, 'Dagger': 8225,
+ \ 'permil': 8240, 'lsaquo': 8249, 'rsaquo': 8250, 'euro': 8364,
+ \ 'fnof': 402, 'Alpha': 913, 'Beta': 914, 'Gamma': 915,
+ \ 'Delta': 916, 'Epsilon': 917, 'Zeta': 918, 'Eta': 919,
+ \ 'Theta': 920, 'Iota': 921, 'Kappa': 922, 'Lambda': 923,
+ \ 'Mu': 924, 'Nu': 925, 'Xi': 926, 'Omicron': 927,
+ \ 'Pi': 928, 'Rho': 929, 'Sigma': 931, 'Tau': 932,
+ \ 'Upsilon': 933, 'Phi': 934, 'Chi': 935, 'Psi': 936,
+ \ 'Omega': 937, 'alpha': 945, 'beta': 946, 'gamma': 947,
+ \ 'delta': 948, 'epsilon': 949, 'zeta': 950, 'eta': 951,
+ \ 'theta': 952, 'iota': 953, 'kappa': 954, 'lambda': 955,
+ \ 'mu': 956, 'nu': 957, 'xi': 958, 'omicron': 959,
+ \ 'pi': 960, 'rho': 961, 'sigmaf': 962, 'sigma': 963,
+ \ 'tau': 964, 'upsilon': 965, 'phi': 966, 'chi': 967,
+ \ 'psi': 968, 'omega': 969, 'thetasym': 977, 'upsih': 978,
+ \ 'piv': 982, 'bull': 8226, 'hellip': 8230, 'prime': 8242,
+ \ 'Prime': 8243, 'oline': 8254, 'frasl': 8260, 'weierp': 8472,
+ \ 'image': 8465, 'real': 8476, 'trade': 8482, 'alefsym': 8501,
+ \ 'larr': 8592, 'uarr': 8593, 'rarr': 8594, 'darr': 8595,
+ \ 'harr': 8596, 'crarr': 8629, 'lArr': 8656, 'uArr': 8657,
+ \ 'rArr': 8658, 'dArr': 8659, 'hArr': 8660, 'forall': 8704,
+ \ 'part': 8706, 'exist': 8707, 'empty': 8709, 'nabla': 8711,
+ \ 'isin': 8712, 'notin': 8713, 'ni': 8715, 'prod': 8719,
+ \ 'sum': 8721, 'minus': 8722, 'lowast': 8727, 'radic': 8730,
+ \ 'prop': 8733, 'infin': 8734, 'ang': 8736, 'and': 8743,
+ \ 'or': 8744, 'cap': 8745, 'cup': 8746, 'int': 8747,
+ \ 'there4': 8756, 'sim': 8764, 'cong': 8773, 'asymp': 8776,
+ \ 'ne': 8800, 'equiv': 8801, 'le': 8804, 'ge': 8805,
+ \ 'sub': 8834, 'sup': 8835, 'nsub': 8836, 'sube': 8838,
+ \ 'supe': 8839, 'oplus': 8853, 'otimes': 8855, 'perp': 8869,
+ \ 'sdot': 8901, 'lceil': 8968, 'rceil': 8969, 'lfloor': 8970,
+ \ 'rfloor': 8971, 'lang': 9001, 'rang': 9002, 'loz': 9674,
+ \ 'spades': 9824, 'clubs': 9827, 'hearts': 9829, 'diams': 9830,
+ \ 'apos': 39}
+
+" }}}2
+
+function! s:XmlEncode(str)
+ let str = a:str
+ let str = substitute(str,'&','\&amp;','g')
+ let str = substitute(str,'<','\&lt;','g')
+ let str = substitute(str,'>','\&gt;','g')
+ let str = substitute(str,'"','\&quot;','g')
+ return str
+endfunction
+
+function! s:XmlEntityDecode(str)
+ let str = substitute(a:str,'\c&#\%(0*38\|x0*26\);','&amp;','g')
+ let str = substitute(str,'\c&#\(\d\+\);','\=nr2char(submatch(1))','g')
+ let str = substitute(str,'\c&#\(x\x\+\);','\=nr2char("0".submatch(1))','g')
+ let str = substitute(str,'\c&apos;',"'",'g')
+ let str = substitute(str,'\c&quot;','"','g')
+ let str = substitute(str,'\c&gt;','>','g')
+ let str = substitute(str,'\c&lt;','<','g')
+ let str = substitute(str,'\C&\(\%(amp;\)\@!\w*\);','\=nr2char(get(g:unimpaired_html_entities,submatch(1),63))','g')
+ return substitute(str,'\c&amp;','\&','g')
+endfunction
+
+function! s:XmlDecode(str)
+ let str = substitute(a:str,'<\%([[:alnum:]-]\+=\%("[^"]*"\|''[^'']*''\)\|.\)\{-\}>','','g')
+ return s:XmlEntityDecode(str)
+endfunction
+
+function! s:Transform(algorithm,type)
+ let sel_save = &selection
+ let cb_save = &clipboard
+ set selection=inclusive clipboard-=unnamed clipboard-=unnamedplus
+ let reg_save = @@
+ if a:type =~ '^\d\+$'
+ silent exe 'norm! ^v'.a:type.'$hy'
+ elseif a:type =~ '^.$'
+ silent exe "normal! `<" . a:type . "`>y"
+ elseif a:type == 'line'
+ silent exe "normal! '[V']y"
+ elseif a:type == 'block'
+ silent exe "normal! `[\<C-V>`]y"
+ else
+ silent exe "normal! `[v`]y"
+ endif
+ let @@ = s:{a:algorithm}(@@)
+ norm! gvp
+ let @@ = reg_save
+ let &selection = sel_save
+ let &clipboard = cb_save
+ if a:type =~ '^\d\+$'
+ silent! call repeat#set("\<Plug>unimpairedLine".a:algorithm,a:type)
+ endif
+endfunction
+
+function! s:TransformOpfunc(type)
+ return s:Transform(s:encode_algorithm, a:type)
+endfunction
+
+function! s:TransformSetup(algorithm)
+ let s:encode_algorithm = a:algorithm
+ let &opfunc = matchstr(expand('<sfile>'), '<SNR>\d\+_').'TransformOpfunc'
+endfunction
+
+function! s:MapTransform(algorithm, key)
+ exe 'nnoremap <silent> <Plug>unimpaired' .a:algorithm.' :<C-U>call <SID>TransformSetup("'.a:algorithm.'")<CR>g@'
+ exe 'xnoremap <silent> <Plug>unimpaired' .a:algorithm.' :<C-U>call <SID>Transform("'.a:algorithm.'",visualmode())<CR>'
+ exe 'nnoremap <silent> <Plug>unimpairedLine'.a:algorithm.' :<C-U>call <SID>Transform("'.a:algorithm.'",v:count1)<CR>'
+ exe 'nmap '.a:key.' <Plug>unimpaired'.a:algorithm
+ exe 'xmap '.a:key.' <Plug>unimpaired'.a:algorithm
+ exe 'nmap '.a:key.a:key[strlen(a:key)-1].' <Plug>unimpairedLine'.a:algorithm
+endfunction
+
+call s:MapTransform('StringEncode','[y')
+call s:MapTransform('StringDecode',']y')
+call s:MapTransform('UrlEncode','[u')
+call s:MapTransform('UrlDecode',']u')
+call s:MapTransform('XmlEncode','[x')
+call s:MapTransform('XmlDecode',']x')
+
+" }}}1
+
+" vim:set sw=2 sts=2:
diff --git a/vim/plugin/vim-rspec.rb b/vim/plugin/vim-rspec.rb
new file mode 100644
index 0000000..4d7f4c3
--- /dev/null
+++ b/vim/plugin/vim-rspec.rb
@@ -0,0 +1,32 @@
+require "rubygems"
+require "hpricot"
+
+doc = Hpricot(STDIN.read)
+h1 = (doc/"h1")
+classes = {"spec passed"=>"+","spec failed"=>"-","spec not_implemented"=>"#"}
+
+puts "* #{h1.inner_html}"
+
+stats = (doc/"script").select {|script| script.innerHTML =~ /duration|totals/ }.map {|script| script.inner_html.scan(/".*"/).first.gsub(/<\/?strong>/,"") }
+stats.each do |stat|
+ puts "* #{stat.gsub(/\"/,'')}"
+end
+puts "* Parsed with Hpricot (http://wiki.github.com/why/hpricot)"
+puts " "
+
+(doc/"div[@class='example_group']").each do |example|
+ puts "[#{(example/"dl/dt").inner_html}]"
+ (example/"dd").each do |dd|
+ txt = (dd/"span:first").inner_html
+ puts "#{classes[dd[:class]]} #{txt}"
+ next if dd[:class]!="spec failed"
+ failure = (dd/"div[@class='failure']")
+ msg = (failure/"div[@class='message']/pre").inner_html
+ back = (failure/"div[@class='backtrace']/pre").inner_html
+ ruby = (failure/"pre[@class='ruby']/code").inner_html.scan(/(<span class="linenum">)(\d+)(<\/span>)([^<]+)/).map {|elem| " "+elem[1]+": "+elem[3].chomp+"\n"}.join
+ puts " #{msg}"
+ puts " #{back}"
+ puts ruby
+ end
+ puts " "
+end
diff --git a/vim/plugin/vim-rspec.vim b/vim/plugin/vim-rspec.vim
new file mode 100644
index 0000000..edc7145
--- /dev/null
+++ b/vim/plugin/vim-rspec.vim
@@ -0,0 +1,174 @@
+"
+" Vim Rspec
+" Last change: March 5 2009
+" Version> 0.0.5
+" Maintainer: Eustáquio 'TaQ' Rangel
+" License: GPL
+" URL: git://github.com/taq/vim-rspec
+"
+" Script to run the spec command inside Vim
+" To install, unpack the files on your ~/.vim directory and source it
+"
+" The following options can be set/overridden in your .vimrc
+" * g:RspecXSLPath :: Path to xsl file
+" * g:RspecRBFilePath :: Path to vim-rspec.rb
+" * g:RspecBin :: Rspec binary command (in rspec 2 this is 'rspec')
+" * g:RspecOpts :: Opts to send to rspec call
+
+let s:xsltproc_cmd = ""
+let s:grep_cmd = ""
+let s:hpricot_cmd = ""
+let s:xslt = 0
+let s:hpricot = 0
+let s:helper_dir = expand("<sfile>:h")
+
+function! s:find_xslt()
+ return system("xsltproc --version | head -n1")
+endfunction
+
+function! s:find_grep()
+ return system("grep --version | head -n1")
+endfunction
+
+function! s:find_hpricot()
+ return system("gem search -i hpricot")
+endfunction
+
+function! s:error_msg(msg)
+ echohl ErrorMsg
+ echo a:msg
+ echohl None
+endfunction
+
+function! s:notice_msg(msg)
+ echohl MoreMsg
+ echo a:msg
+ echohl None
+endfunction
+
+function! s:fetch(varname, default)
+ if exists("g:".a:varname)
+ return eval("g:".a:varname)
+ else
+ return a:default
+ endif
+endfunction
+
+function! s:RunSpecMain(type)
+ if len(s:xsltproc_cmd)<1
+ let s:xsltproc_cmd = s:find_xslt()
+ let s:xslt = match(s:xsltproc_cmd,'\d')>=0
+ end
+ if len(s:hpricot_cmd)<1
+ let s:hpricot_cmd = s:find_hpricot()
+ let s:hpricot = match(s:hpricot_cmd,'true')>=0
+ end
+ if !s:hpricot && !s:xslt
+ call s:error_msg("You need the hpricot gem or xsltproc to run this script.")
+ return
+ end
+ if len(s:grep_cmd)<1
+ let s:grep_cmd = s:find_grep()
+ if match(s:grep_cmd,'\d')<0
+ call s:error_msg("You need grep to run this script.")
+ return
+ end
+ end
+ let l:bufn = bufname("%")
+
+ " find the installed rspec command
+ let l:default_cmd = ""
+ if executable("spec")==1
+ let l:default_cmd = "spec"
+ elseif executable("rspec")==1
+ let l:default_cmd = "rspec"
+ end
+
+ " filters
+ let l:xsl = s:fetch("RspecXSLPath", s:helper_dir."/vim-rspec.xsl")
+ let l:rubys = s:fetch("RspecRBPath", s:helper_dir."/vim-rspec.rb")
+
+ " hpricot gets the priority
+ let l:type = s:hpricot ? "hpricot" : "xsltproc"
+ let l:filter = s:hpricot ? "ruby ".l:rubys : "xsltproc --novalid --html ".l:xsl." - "
+
+ " run just the current file
+ if a:type=="file"
+ if match(l:bufn,'_spec.rb')>=0
+ call s:notice_msg("Running spec on the current file with ".l:type." ...")
+ let l:spec_bin = s:fetch("RspecBin",l:default_cmd)
+ let l:spec_opts = s:fetch("RspecOpts", "")
+ let l:spec = l:spec_bin . " " . l:spec_opts . " -f h " . l:bufn
+ else
+ call s:error_msg("Seems ".l:bufn." is not a *_spec.rb file")
+ return
+ end
+ else
+ let l:dir = expand("%:p:h")
+ if isdirectory(l:dir."/spec")>0
+ call s:notice_msg("Running spec on the spec directory with ".l:type." ...")
+ else
+ " try to find a spec directory on the current path
+ let l:tokens = split(l:dir,"/")
+ let l:dir = ""
+ for l:item in l:tokens
+ call remove(l:tokens,-1)
+ let l:path = "/".join(l:tokens,"/")."/spec"
+ if isdirectory(l:path)
+ let l:dir = l:path
+ break
+ end
+ endfor
+ if len(l:dir)>0
+ call s:notice_msg("Running spec with ".l:type." on the spec directory found (".l:dir.") ...")
+ else
+ call s:error_msg("No ".l:dir."/spec directory found")
+ return
+ end
+ end
+ if isdirectory(l:dir)<0
+ call s:error_msg("Could not find the ".l:dir." directory.")
+ return
+ end
+ let l:spec = s:fetch("RspecBin", "spec") . s:fetch("RspecOpts", "")
+ let l:spec = l:spec . " -f h " . l:dir . " -p **/*_spec.rb"
+ end
+
+ " run the spec command
+ let s:cmd = l:spec." | ".l:filter." 2> /dev/null | grep \"^[-\+\[\\#\\* ]\""
+ echo
+
+ " put the result on a new buffer
+ silent exec "new"
+ setl buftype=nofile
+ silent exec "r! ".s:cmd
+ setl syntax=vim-rspec
+ silent exec "nnoremap <buffer> <cr> :call <SID>TryToOpen()<cr>"
+ silent exec "nnoremap <buffer> q :q<CR>"
+ setl foldmethod=expr
+ setl foldexpr=getline(v:lnum)=~'^\+'
+ setl foldtext=\"+--\ \".string(v:foldend-v:foldstart+1).\"\ passed\ \"
+ call cursor(1,1)
+endfunction
+
+function! s:TryToOpen()
+ let l:line = getline(".")
+ if match(l:line,'^ [\/\.]')<0
+ call s:error_msg("No file found.")
+ return
+ end
+ let l:tokens = split(l:line,":")
+ silent exec "sp ".substitute(l:tokens[0],'/^\s\+',"","")
+ call cursor(l:tokens[1],1)
+endfunction
+
+function! RunSpec()
+ call s:RunSpecMain("file")
+endfunction
+
+function! RunSpecs()
+ call s:RunSpecMain("dir")
+endfunction
+
+command! RunSpec call RunSpec()
+command! RunSpecs call RunSpecs()
diff --git a/vim/plugin/vim-rspec.xsl b/vim/plugin/vim-rspec.xsl
new file mode 100644
index 0000000..432dc51
--- /dev/null
+++ b/vim/plugin/vim-rspec.xsl
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:output method="text"/>
+
+<xsl:template match="/">
+ <xsl:text>* Rspec Results&#10;</xsl:text>
+ <xsl:text>* Parsed with xsltproc (http://www.xmlsoft.org/XSLT/xsltproc2.html)&#10;</xsl:text>
+ <xsl:text> &#10;</xsl:text>
+ <xsl:apply-templates select="html/body/div[@class='rspec-report']/div[@class='results']"/>
+</xsl:template>
+
+<xsl:template match="div[@class='rspec-report']">
+ <xsl:apply-templates/>
+</xsl:template>
+
+<xsl:template match="div[@class='example_group']">
+ <xsl:text>[</xsl:text><xsl:value-of select="dl/dt"/><xsl:text>]</xsl:text>
+ <xsl:text>&#10;</xsl:text>
+ <xsl:apply-templates select="dl/dd"/>
+ <xsl:text> </xsl:text>
+</xsl:template>
+
+<xsl:template match="dd[@class='spec passed']">
+ <xsl:text>+ </xsl:text>
+ <xsl:value-of select="span"/>
+ <xsl:text>&#10;</xsl:text>
+</xsl:template>
+
+<xsl:template match="dd[@class='spec failed']">
+ <xsl:text>- </xsl:text>
+ <xsl:value-of select="span"/>
+ <xsl:text>&#10;</xsl:text>
+ <xsl:apply-templates select="div"/>
+</xsl:template>
+
+<xsl:template match="dd[@class='spec not_implemented']">
+ <xsl:text># </xsl:text>
+ <xsl:value-of select="span"/>
+ <xsl:text>&#10;</xsl:text>
+</xsl:template>
+
+<xsl:template match="dd[@class='spec failed']/div[@class='failure']">
+ <xsl:text> </xsl:text><xsl:value-of select="div[@class='message']/pre"/>
+ <xsl:text>&#10;</xsl:text>
+ <xsl:text> </xsl:text><xsl:value-of select="div[@class='backtrace']/pre"/>
+ <xsl:text>&#10;</xsl:text>
+ <xsl:apply-templates select="pre[@class='ruby']/code"/>
+</xsl:template>
+
+<xsl:template match="code">
+ <xsl:value-of select="text()"/>
+ <xsl:text>&#10;</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>