diff --git a/.vim/.netrwhist b/.vim/.netrwhist
new file mode 100644
index 0000000..9e1932d
--- /dev/null
+++ b/.vim/.netrwhist
@@ -0,0 +1,12 @@
+let g:netrw_dirhistmax =10
+let g:netrw_dirhistcnt =0
+let g:netrw_dirhist_0='/usr/local/share/doc/crispy-strife'
+let g:netrw_dirhist_9='/usr/local/share/doc/crispy-hexen'
+let g:netrw_dirhist_8='/usr/local/share/doc/crispy-heretic'
+let g:netrw_dirhist_7='/usr/local/share/doc/crispy-doom'
+let g:netrw_dirhist_6='/home/sdk'
+let g:netrw_dirhist_5='/home/sdk/.config'
+let g:netrw_dirhist_4='/home/sdk/satzung'
+let g:netrw_dirhist_3='/usr/xenocara/lib/libva'
+let g:netrw_dirhist_2='/home/dpb/usr/ports/mystuff/net/gurk-rs/files'
+let g:netrw_dirhist_1='/etc/X11/xenodm'
diff --git a/.vim/autoload/pathogen.vim b/.vim/autoload/pathogen.vim
new file mode 100644
index 0000000..3582fbf
--- /dev/null
+++ b/.vim/autoload/pathogen.vim
@@ -0,0 +1,264 @@
+" pathogen.vim - path option manipulation
+" Maintainer: Tim Pope
+" Version: 2.4
+
+" Install in ~/.vim/autoload (or ~\vimfiles\autoload).
+"
+" For management of individually installed plugins in ~/.vim/bundle (or
+" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your
+" .vimrc is the only other setup necessary.
+"
+" The API is documented inline below.
+
+if exists("g:loaded_pathogen") || &cp
+ finish
+endif
+let g:loaded_pathogen = 1
+
+" Point of entry for basic default usage. Give a relative path to invoke
+" pathogen#interpose() or an absolute path to invoke pathogen#surround().
+" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all
+" subdirectories inside "bundle" inside all directories in the runtime path.
+" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}"
+" on versions of Vim without native package support.
+function! pathogen#infect(...) abort
+ if a:0
+ let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")')
+ else
+ let paths = ['bundle/{}', 'pack/{}/start/{}']
+ endif
+ if has('packages')
+ call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"')
+ endif
+ let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$'
+ for path in filter(copy(paths), 'v:val =~# static')
+ call pathogen#surround(path)
+ endfor
+ for path in filter(copy(paths), 'v:val !~# static')
+ if path =~# '^\%([$~\\/]\|\w:[\\/]\)'
+ call pathogen#surround(path)
+ else
+ call pathogen#interpose(path)
+ endif
+ endfor
+ call pathogen#cycle_filetype()
+ if pathogen#is_disabled($MYVIMRC)
+ return 'finish'
+ endif
+ return ''
+endfunction
+
+" Split a path into a list.
+function! pathogen#split(path) abort
+ if type(a:path) == type([]) | return a:path | endif
+ if empty(a:path) | return [] | endif
+ let split = split(a:path,'\\\@]','\\&','')
+ endif
+endfunction
+
+" Like findfile(), but hardcoded to use the runtimepath.
+function! pathogen#runtime_findfile(file,count) abort
+ let rtp = pathogen#join(1,pathogen#split(&rtp))
+ let file = findfile(a:file,rtp,a:count)
+ if file ==# ''
+ return ''
+ else
+ return fnamemodify(file,':p')
+ endif
+endfunction
+
+" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=':
diff --git a/.vim/bundle/vim-easy-align/autoload/easy_align.vim b/.vim/bundle/vim-easy-align/autoload/easy_align.vim
new file mode 100644
index 0000000..795ea31
--- /dev/null
+++ b/.vim/bundle/vim-easy-align/autoload/easy_align.vim
@@ -0,0 +1,1148 @@
+" Copyright (c) 2014 Junegunn Choi
+"
+" 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.
+
+if exists("g:loaded_easy_align")
+ finish
+endif
+let g:loaded_easy_align = 1
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+let s:easy_align_delimiters_default = {
+\ ' ': { 'pattern': ' ', 'left_margin': 0, 'right_margin': 0, 'stick_to_left': 0 },
+\ '=': { 'pattern': '===\|<=>\|\(&&\|||\|<<\|>>\)=\|=\~[#?]\?\|=>\|[:+/*!%^=><&|.?-]\?=[#?]\?',
+\ 'left_margin': 1, 'right_margin': 1, 'stick_to_left': 0 },
+\ ':': { 'pattern': ':', 'left_margin': 0, 'right_margin': 1, 'stick_to_left': 1 },
+\ ',': { 'pattern': ',', 'left_margin': 0, 'right_margin': 1, 'stick_to_left': 1 },
+\ '|': { 'pattern': '|', 'left_margin': 1, 'right_margin': 1, 'stick_to_left': 0 },
+\ '.': { 'pattern': '\.', 'left_margin': 0, 'right_margin': 0, 'stick_to_left': 0 },
+\ '#': { 'pattern': '#\+', 'delimiter_align': 'l', 'ignore_groups': ['!Comment'] },
+\ '"': { 'pattern': '"\+', 'delimiter_align': 'l', 'ignore_groups': ['!Comment'] },
+\ '&': { 'pattern': '\\\@ winlen ? '..' : ''
+
+ echon "\r"
+ let yet = 0
+ for [hl, msg] in a:tokens
+ if empty(msg) | continue | endif
+ execute "echohl ". hl
+ let yet += len(msg)
+ if yet > winlen - len(ellipsis)
+ echon msg[ 0 : (winlen - len(ellipsis) - yet - 1) ] . ellipsis
+ break
+ else
+ echon msg
+ endif
+ endfor
+ finally
+ echohl None
+ let [&ruler, &showcmd] = xy
+ endtry
+endfunction
+
+function! s:echon(l, n, r, d, o, warn)
+ let tokens = [
+ \ ['Function', s:live ? ':LiveEasyAlign' : ':EasyAlign'],
+ \ ['ModeMsg', get(s:mode_labels, a:l, a:l)],
+ \ ['None', ' ']]
+
+ if a:r == -1 | call add(tokens, ['Comment', '(']) | endif
+ call add(tokens, [a:n =~ '*' ? 'Repeat' : 'Number', a:n])
+ call extend(tokens, a:r == 1 ?
+ \ [['Delimiter', '/'], ['String', a:d], ['Delimiter', '/']] :
+ \ [['Identifier', a:d == ' ' ? '\ ' : (a:d == '\' ? '\\' : a:d)]])
+ if a:r == -1 | call extend(tokens, [['Normal', '_'], ['Comment', ')']]) | endif
+ call add(tokens, ['Statement', empty(a:o) ? '' : ' '.string(a:o)])
+ if !empty(a:warn)
+ call add(tokens, ['WarningMsg', ' ('.a:warn.')'])
+ endif
+
+ call s:echon_(tokens)
+ return join(map(tokens, 'v:val[1]'), '')
+endfunction
+
+function! s:exit(msg)
+ call s:echon_([['ErrorMsg', a:msg]])
+ throw 'exit'
+endfunction
+
+function! s:ltrim(str)
+ return substitute(a:str, '^\s\+', '', '')
+endfunction
+
+function! s:rtrim(str)
+ return substitute(a:str, '\s\+$', '', '')
+endfunction
+
+function! s:trim(str)
+ return substitute(a:str, '^\s*\(.\{-}\)\s*$', '\1', '')
+endfunction
+
+function! s:fuzzy_lu(key)
+ if has_key(s:known_options, a:key)
+ return a:key
+ endif
+ let key = tolower(a:key)
+
+ " stl -> ^s.*_t.*_l.*
+ let regexp1 = '^' .key[0]. '.*' .substitute(key[1 : -1], '\(.\)', '_\1.*', 'g')
+ let matches = filter(keys(s:known_options), 'v:val =~ regexp1')
+ if len(matches) == 1
+ return matches[0]
+ endif
+
+ " stl -> ^s.*t.*l.*
+ let regexp2 = '^' . substitute(substitute(key, '-', '_', 'g'), '\(.\)', '\1.*', 'g')
+ let matches = filter(keys(s:known_options), 'v:val =~ regexp2')
+
+ if empty(matches)
+ call s:exit("Unknown option key: ". a:key)
+ elseif len(matches) == 1
+ return matches[0]
+ else
+ " Avoid ambiguity introduced by deprecated margin_left and margin_right
+ if sort(matches) == ['margin_left', 'margin_right', 'mode_sequence']
+ return 'mode_sequence'
+ endif
+ if sort(matches) == ['ignore_groups', 'ignores']
+ return 'ignore_groups'
+ endif
+ call s:exit("Ambiguous option key: ". a:key ." (" .join(matches, ', '). ")")
+ endif
+endfunction
+
+function! s:shift(modes, cycle)
+ let item = remove(a:modes, 0)
+ if a:cycle || empty(a:modes)
+ call add(a:modes, item)
+ endif
+ return item
+endfunction
+
+function! s:normalize_options(opts)
+ let ret = {}
+ for k in keys(a:opts)
+ let v = a:opts[k]
+ let k = s:fuzzy_lu(k)
+ " Backward-compatibility
+ if k == 'margin_left' | let k = 'left_margin' | endif
+ if k == 'margin_right' | let k = 'right_margin' | endif
+ if k == 'mode_sequence' | let k = 'align' | endif
+ let ret[k] = v
+ unlet v
+ endfor
+ return s:validate_options(ret)
+endfunction
+
+function! s:compact_options(opts)
+ let ret = {}
+ for k in keys(a:opts)
+ let ret[s:shorthand[k]] = a:opts[k]
+ endfor
+ return ret
+endfunction
+
+function! s:validate_options(opts)
+ for k in keys(a:opts)
+ let v = a:opts[k]
+ if index(s:known_options[k], type(v)) == -1
+ call s:exit("Invalid type for option: ". k)
+ endif
+ unlet v
+ endfor
+ return a:opts
+endfunction
+
+function! s:split_line(line, nth, modes, cycle, fc, lc, pattern, stick_to_left, ignore_unmatched, ignore_groups)
+ let mode = ''
+
+ let string = a:lc ?
+ \ strpart(getline(a:line), a:fc - 1, a:lc - a:fc + 1) :
+ \ strpart(getline(a:line), a:fc - 1)
+ let idx = 0
+ let nomagic = match(a:pattern, '\\v') > match(a:pattern, '\C\\[mMV]')
+ let pattern = '^.\{-}\s*\zs\('.a:pattern.(nomagic ? ')' : '\)')
+ let tokens = []
+ let delims = []
+
+ " Phase 1: split
+ let ignorable = 0
+ let token = ''
+ let phantom = 0
+ while 1
+ let matchidx = match(string, pattern, idx)
+ " No match
+ if matchidx < 0 | break | endif
+ let matchend = matchend(string, pattern, idx)
+ let spaces = matchstr(string, '\s'.(a:stick_to_left ? '*' : '\{-}'), matchend + (matchidx == matchend))
+
+ " Match, but empty
+ if len(spaces) + matchend - idx == 0
+ let char = strpart(string, idx, 1)
+ if empty(char) | break | endif
+ let [match, part, delim] = [char, char, '']
+ " Match
+ else
+ let match = strpart(string, idx, matchend - idx + len(spaces))
+ let part = strpart(string, idx, matchidx - idx)
+ let delim = strpart(string, matchidx, matchend - matchidx)
+ endif
+
+ let ignorable = s:highlighted_as(a:line, idx + len(part) + a:fc, a:ignore_groups)
+ if ignorable
+ let token .= match
+ else
+ let [pmode, mode] = [mode, s:shift(a:modes, a:cycle)]
+ call add(tokens, token . match)
+ call add(delims, delim)
+ let token = ''
+ endif
+
+ let idx += len(match)
+
+ " If the string is non-empty and ends with the delimiter,
+ " append an empty token to the list
+ if idx == len(string)
+ let phantom = 1
+ break
+ endif
+ endwhile
+
+ let leftover = token . strpart(string, idx)
+ if !empty(leftover)
+ let ignorable = s:highlighted_as(a:line, len(string) + a:fc - 1, a:ignore_groups)
+ call add(tokens, leftover)
+ call add(delims, '')
+ elseif phantom
+ call add(tokens, '')
+ call add(delims, '')
+ endif
+ let [pmode, mode] = [mode, s:shift(a:modes, a:cycle)]
+
+ " Preserve indentation - merge first two tokens
+ if len(tokens) > 1 && empty(s:rtrim(tokens[0]))
+ let tokens[1] = tokens[0] . tokens[1]
+ call remove(tokens, 0)
+ call remove(delims, 0)
+ let mode = pmode
+ endif
+
+ " Skip comment line
+ if ignorable && len(tokens) == 1 && a:ignore_unmatched
+ let tokens = []
+ let delims = []
+ " Append an empty item to enable right/center alignment of the last token
+ " - if the last token is not ignorable or ignorable but not the only token
+ elseif a:ignore_unmatched != 1 &&
+ \ (mode ==? 'r' || mode ==? 'c') &&
+ \ (!ignorable || len(tokens) > 1) &&
+ \ a:nth >= 0 " includes -0
+ call add(tokens, '')
+ call add(delims, '')
+ endif
+
+ return [tokens, delims]
+endfunction
+
+function! s:do_align(todo, modes, all_tokens, all_delims, fl, ll, fc, lc, nth, recur, dict)
+ let mode = a:modes[0]
+ let lines = {}
+ let min_indent = -1
+ let max = { 'pivot_len2': 0, 'token_len': 0, 'just_len': 0, 'delim_len': 0,
+ \ 'indent': 0, 'tokens': 0, 'strip_len': 0 }
+ let d = a:dict
+ let [f, fx] = s:parse_filter(d.filter)
+
+ " Phase 1
+ for line in range(a:fl, a:ll)
+ let snip = a:lc > 0 ? getline(line)[a:fc-1 : a:lc-1] : getline(line)
+ if f == 1 && snip !~ fx
+ continue
+ elseif f == -1 && snip =~ fx
+ continue
+ endif
+
+ if !has_key(a:all_tokens, line)
+ " Split line into the tokens by the delimiters
+ let [tokens, delims] = s:split_line(
+ \ line, a:nth, copy(a:modes), a:recur == 2,
+ \ a:fc, a:lc, d.pattern,
+ \ d.stick_to_left, d.ignore_unmatched, d.ignore_groups)
+
+ " Remember tokens for subsequent recursive calls
+ let a:all_tokens[line] = tokens
+ let a:all_delims[line] = delims
+ else
+ let tokens = a:all_tokens[line]
+ let delims = a:all_delims[line]
+ endif
+
+ " Skip empty lines
+ if empty(tokens)
+ continue
+ endif
+
+ " Calculate the maximum number of tokens for a line within the range
+ let max.tokens = max([max.tokens, len(tokens)])
+
+ if a:nth > 0 " Positive N-th
+ if len(tokens) < a:nth
+ continue
+ endif
+ let nth = a:nth - 1 " make it 0-based
+ else " -0 or Negative N-th
+ if a:nth == 0 && mode !=? 'l'
+ let nth = len(tokens) - 1
+ else
+ let nth = len(tokens) + a:nth
+ endif
+ if empty(delims[len(delims) - 1])
+ let nth -= 1
+ endif
+
+ if nth < 0 || nth == len(tokens)
+ continue
+ endif
+ endif
+
+ let prefix = nth > 0 ? join(tokens[0 : nth - 1], '') : ''
+ let delim = delims[nth]
+ let token = s:rtrim( tokens[nth] )
+ let token = s:rtrim( strpart(token, 0, len(token) - len(s:rtrim(delim))) )
+ if empty(delim) && !exists('tokens[nth + 1]') && d.ignore_unmatched
+ continue
+ endif
+
+ let indent = s:strwidth(matchstr(tokens[0], '^\s*'))
+ if min_indent < 0 || indent < min_indent
+ let min_indent = indent
+ endif
+ if mode ==? 'c'
+ let token .= substitute(matchstr(token, '^\s*'), '\t', repeat(' ', &tabstop), 'g')
+ endif
+ let [pw, tw] = [s:strwidth(prefix), s:strwidth(token)]
+ let max.indent = max([max.indent, indent])
+ let max.token_len = max([max.token_len, tw])
+ let max.just_len = max([max.just_len, pw + tw])
+ let max.delim_len = max([max.delim_len, s:strwidth(delim)])
+
+ if mode ==? 'c'
+ let pivot_len2 = pw * 2 + tw
+ if max.pivot_len2 < pivot_len2
+ let max.pivot_len2 = pivot_len2
+ endif
+ let max.strip_len = max([max.strip_len, s:strwidth(s:trim(token))])
+ endif
+ let lines[line] = [nth, prefix, token, delim]
+ endfor
+
+ " Phase 1-5: indentation handling (only on a:nth == 1)
+ if a:nth == 1
+ let idt = d.indentation
+ if idt ==? 'd'
+ let indent = max.indent
+ elseif idt ==? 's'
+ let indent = min_indent
+ elseif idt ==? 'n'
+ let indent = 0
+ elseif idt !=? 'k'
+ call s:exit('Invalid indentation: ' . idt)
+ end
+
+ if idt !=? 'k'
+ let max.just_len = 0
+ let max.token_len = 0
+ let max.pivot_len2 = 0
+
+ for [line, elems] in items(lines)
+ let [nth, prefix, token, delim] = elems
+
+ let tindent = matchstr(token, '^\s*')
+ while 1
+ let len = s:strwidth(tindent)
+ if len < indent
+ let tindent .= repeat(' ', indent - len)
+ break
+ elseif len > indent
+ let tindent = tindent[0 : -2]
+ else
+ break
+ endif
+ endwhile
+
+ let token = tindent . s:ltrim(token)
+ if mode ==? 'c'
+ let token = substitute(token, '\s*$', repeat(' ', indent), '')
+ endif
+ let [pw, tw] = [s:strwidth(prefix), s:strwidth(token)]
+ let max.token_len = max([max.token_len, tw])
+ let max.just_len = max([max.just_len, pw + tw])
+ if mode ==? 'c'
+ let pivot_len2 = pw * 2 + tw
+ if max.pivot_len2 < pivot_len2
+ let max.pivot_len2 = pivot_len2
+ endif
+ endif
+
+ let lines[line][2] = token
+ endfor
+ endif
+ endif
+
+ " Phase 2
+ for [line, elems] in items(lines)
+ let tokens = a:all_tokens[line]
+ let delims = a:all_delims[line]
+ let [nth, prefix, token, delim] = elems
+
+ " Remove the leading whitespaces of the next token
+ if len(tokens) > nth + 1
+ let tokens[nth + 1] = s:ltrim(tokens[nth + 1])
+ endif
+
+ " Pad the token with spaces
+ let [pw, tw] = [s:strwidth(prefix), s:strwidth(token)]
+ let rpad = ''
+ if mode ==? 'l'
+ let pad = repeat(' ', max.just_len - pw - tw)
+ if d.stick_to_left
+ let rpad = pad
+ else
+ let token = token . pad
+ endif
+ elseif mode ==? 'r'
+ let pad = repeat(' ', max.just_len - pw - tw)
+ let indent = matchstr(token, '^\s*')
+ let token = indent . pad . s:ltrim(token)
+ elseif mode ==? 'c'
+ let p1 = max.pivot_len2 - (pw * 2 + tw)
+ let p2 = max.token_len - tw
+ let pf1 = s:floor2(p1)
+ if pf1 < p1 | let p2 = s:ceil2(p2)
+ else | let p2 = s:floor2(p2)
+ endif
+ let strip = s:ceil2(max.token_len - max.strip_len) / 2
+ let indent = matchstr(token, '^\s*')
+ let token = indent. repeat(' ', pf1 / 2) .s:ltrim(token). repeat(' ', p2 / 2)
+ let token = substitute(token, repeat(' ', strip) . '$', '', '')
+
+ if d.stick_to_left
+ if empty(s:rtrim(token))
+ let center = len(token) / 2
+ let [token, rpad] = [strpart(token, 0, center), strpart(token, center)]
+ else
+ let [token, rpad] = [s:rtrim(token), matchstr(token, '\s*$')]
+ endif
+ endif
+ endif
+ let tokens[nth] = token
+
+ " Pad the delimiter
+ let dpadl = max.delim_len - s:strwidth(delim)
+ let da = d.delimiter_align
+ if da ==? 'l'
+ let [dl, dr] = ['', repeat(' ', dpadl)]
+ elseif da ==? 'c'
+ let dl = repeat(' ', dpadl / 2)
+ let dr = repeat(' ', dpadl - dpadl / 2)
+ elseif da ==? 'r'
+ let [dl, dr] = [repeat(' ', dpadl), '']
+ else
+ call s:exit('Invalid delimiter_align: ' . da)
+ endif
+
+ " Before and after the range (for blockwise visual mode)
+ let cline = getline(line)
+ let before = strpart(cline, 0, a:fc - 1)
+ let after = a:lc ? strpart(cline, a:lc) : ''
+
+ " Determine the left and right margin around the delimiter
+ let rest = join(tokens[nth + 1 : -1], '')
+ let nomore = empty(rest.after)
+ let ml = (empty(prefix . token) || empty(delim) && nomore) ? '' : d.ml
+ let mr = nomore ? '' : d.mr
+
+ " Adjust indentation of the lines starting with a delimiter
+ let lpad = ''
+ if nth == 0
+ let ipad = repeat(' ', min_indent - s:strwidth(token.ml))
+ if mode ==? 'l'
+ let token = ipad . token
+ else
+ let lpad = ipad
+ endif
+ endif
+
+ " Align the token
+ let aligned = join([lpad, token, ml, dl, delim, dr, mr, rpad], '')
+ let tokens[nth] = aligned
+
+ " Update the line
+ let a:todo[line] = before.join(tokens, '').after
+ endfor
+
+ if a:nth < max.tokens && (a:recur || len(a:modes) > 1)
+ call s:shift(a:modes, a:recur == 2)
+ return [a:todo, a:modes, a:all_tokens, a:all_delims,
+ \ a:fl, a:ll, a:fc, a:lc, a:nth + 1, a:recur, a:dict]
+ endif
+ return [a:todo]
+endfunction
+
+function! s:input(str, default, vis)
+ if a:vis
+ normal! gv
+ redraw
+ execute "normal! \"
+ else
+ " EasyAlign command can be called without visual selection
+ redraw
+ endif
+ let got = input(a:str, a:default)
+ return got
+endfunction
+
+function! s:atoi(str)
+ return (a:str =~ '^[0-9]\+$') ? str2nr(a:str) : a:str
+endfunction
+
+function! s:shift_opts(opts, key, vals)
+ let val = s:shift(a:vals, 1)
+ if type(val) == 0 && val == -1
+ call remove(a:opts, a:key)
+ else
+ let a:opts[a:key] = val
+ endif
+endfunction
+
+function! s:interactive(range, modes, n, d, opts, rules, vis, bvis)
+ let mode = s:shift(a:modes, 1)
+ let n = a:n
+ let d = a:d
+ let ch = ''
+ let opts = s:compact_options(a:opts)
+ let vals = deepcopy(s:option_values)
+ let regx = 0
+ let warn = ''
+ let undo = 0
+
+ while 1
+ " Live preview
+ let rdrw = 0
+ if undo
+ silent! undo
+ let undo = 0
+ let rdrw = 1
+ endif
+ if s:live && !empty(d)
+ let output = s:process(a:range, mode, n, d, s:normalize_options(opts), regx, a:rules, a:bvis)
+ let &undolevels = &undolevels " Break undo block
+ call s:update_lines(output.todo)
+ let undo = !empty(output.todo)
+ let rdrw = 1
+ endif
+ if rdrw
+ if a:vis
+ normal! gv
+ endif
+ redraw
+ if a:vis | execute "normal! \" | endif
+ endif
+ call s:echon(mode, n, -1, regx ? '/'.d.'/' : d, opts, warn)
+
+ let check = 0
+ let warn = ''
+
+ try
+ let c = getchar()
+ catch /^Vim:Interrupt$/
+ let c = 27
+ endtry
+ let ch = nr2char(c)
+ if c == 3 || c == 27 " CTRL-C / ESC
+ if undo
+ silent! undo
+ endif
+ throw 'exit'
+ elseif c == "\"
+ if !empty(d)
+ let d = ''
+ let regx = 0
+ elseif len(n) > 0
+ let n = strpart(n, 0, len(n) - 1)
+ endif
+ elseif c == 13 " Enter key
+ let mode = s:shift(a:modes, 1)
+ if has_key(opts, 'a')
+ let opts.a = mode . strpart(opts.a, 1)
+ endif
+ elseif ch == '-'
+ if empty(n) | let n = '-'
+ elseif n == '-' | let n = ''
+ else | let check = 1
+ endif
+ elseif ch == '*'
+ if empty(n) | let n = '*'
+ elseif n == '*' | let n = '**'
+ elseif n == '**' | let n = ''
+ else | let check = 1
+ endif
+ elseif empty(d) && ((c == 48 && len(n) > 0) || c > 48 && c <= 57) " Numbers
+ if n[0] == '*' | let check = 1
+ else | let n = n . ch
+ end
+ elseif ch == "\"
+ call s:shift_opts(opts, 'da', vals['delimiter_align'])
+ elseif ch == "\"
+ call s:shift_opts(opts, 'idt', vals['indentation'])
+ elseif ch == "\"
+ let lm = s:input("Left margin: ", get(opts, 'lm', ''), a:vis)
+ if empty(lm)
+ let warn = 'Set to default. Input 0 to remove it'
+ silent! call remove(opts, 'lm')
+ else
+ let opts['lm'] = s:atoi(lm)
+ endif
+ elseif ch == "\"
+ let rm = s:input("Right margin: ", get(opts, 'rm', ''), a:vis)
+ if empty(rm)
+ let warn = 'Set to default. Input 0 to remove it'
+ silent! call remove(opts, 'rm')
+ else
+ let opts['rm'] = s:atoi(rm)
+ endif
+ elseif ch == "\"
+ call s:shift_opts(opts, 'iu', vals['ignore_unmatched'])
+ elseif ch == "\"
+ call s:shift_opts(opts, 'ig', vals['ignore_groups'])
+ elseif ch == "\"
+ if s:live
+ if !empty(d)
+ let ch = d
+ break
+ else
+ let s:live = 0
+ endif
+ else
+ let s:live = 1
+ endif
+ elseif c == "\"
+ let opts['stl'] = 1
+ let opts['lm'] = 0
+ elseif c == "\"
+ let opts['stl'] = 0
+ let opts['lm'] = 1
+ elseif c == "\"
+ let opts['lm'] = 0
+ let opts['rm'] = 0
+ elseif c == "\"
+ silent! call remove(opts, 'stl')
+ silent! call remove(opts, 'lm')
+ silent! call remove(opts, 'rm')
+ elseif ch == "\" || ch == "\"
+ let modes = tolower(s:input("Alignment ([lrc...][[*]*]): ", get(opts, 'a', mode), a:vis))
+ if match(modes, '^[lrc]\+\*\{0,2}$') != -1
+ let opts['a'] = modes
+ let mode = modes[0]
+ while mode != s:shift(a:modes, 1)
+ endwhile
+ else
+ silent! call remove(opts, 'a')
+ endif
+ elseif ch == "\" || ch == "\"
+ if s:live && regx && !empty(d)
+ break
+ endif
+
+ let prompt = 'Regular expression: '
+ let ch = s:input(prompt, '', a:vis)
+ if !empty(ch) && s:valid_regexp(ch)
+ let regx = 1
+ let d = ch
+ if !s:live | break | endif
+ else
+ let warn = 'Invalid regular expression: '.ch
+ endif
+ elseif ch == "\"
+ let f = s:input("Filter (g/../ or v/../): ", get(opts, 'f', ''), a:vis)
+ let m = matchlist(f, '^[gv]/\(.\{-}\)/\?$')
+ if empty(f)
+ silent! call remove(opts, 'f')
+ elseif !empty(m) && s:valid_regexp(m[1])
+ let opts['f'] = f
+ else
+ let warn = 'Invalid filter expression'
+ endif
+ elseif ch =~ '[[:print:]]'
+ let check = 1
+ else
+ let warn = 'Invalid character'
+ endif
+
+ if check
+ if empty(d)
+ if has_key(a:rules, ch)
+ let d = ch
+ if !s:live
+ if a:vis
+ execute "normal! gv\"
+ endif
+ break
+ endif
+ else
+ let warn = 'Unknown delimiter key: '.ch
+ endif
+ else
+ if regx
+ let warn = 'Press to finish'
+ else
+ if d == ch
+ break
+ else
+ let warn = 'Press '''.d.''' again to finish'
+ endif
+ end
+ endif
+ endif
+ endwhile
+ if s:live
+ let copts = call('s:summarize', output.summarize)
+ let s:live = 0
+ let g:easy_align_last_command = s:echon('', n, regx, d, copts, '')
+ let s:live = 1
+ end
+ return [mode, n, ch, opts, regx]
+endfunction
+
+function! s:valid_regexp(regexp)
+ try
+ call matchlist('', a:regexp)
+ catch
+ return 0
+ endtry
+ return 1
+endfunction
+
+function! s:test_regexp(regexp)
+ let regexp = empty(a:regexp) ? @/ : a:regexp
+ if !s:valid_regexp(regexp)
+ call s:exit('Invalid regular expression: '. regexp)
+ endif
+ return regexp
+endfunction
+
+let s:shorthand_regex =
+ \ '\s*\%('
+ \ .'\(lm\?[0-9]\+\)\|\(rm\?[0-9]\+\)\|\(iu[01]\)\|\(\%(s\%(tl\)\?[01]\)\|[<>]\)\|'
+ \ .'\(da\?[clr]\)\|\(\%(ms\?\|a\)[lrc*]\+\)\|\(i\%(dt\)\?[kdsn]\)\|\([gv]/.*/\)\|\(ig\[.*\]\)'
+ \ .'\)\+\s*$'
+
+function! s:parse_shorthand_opts(expr)
+ let opts = {}
+ let expr = substitute(a:expr, '\s', '', 'g')
+ let regex = '^'. s:shorthand_regex
+
+ if empty(expr)
+ return opts
+ elseif expr !~ regex
+ call s:exit("Invalid expression: ". a:expr)
+ else
+ let match = matchlist(expr, regex)
+ for m in filter(match[ 1 : -1 ], '!empty(v:val)')
+ for key in ['lm', 'rm', 'l', 'r', 'stl', 's', '<', '>', 'iu', 'da', 'd', 'ms', 'm', 'ig', 'i', 'g', 'v', 'a']
+ if stridx(tolower(m), key) == 0
+ let rest = strpart(m, len(key))
+ if key == 'i' | let key = 'idt' | endif
+ if key == 'g' || key == 'v'
+ let rest = key.rest
+ let key = 'f'
+ endif
+
+ if key == 'idt' || index(['d', 'f', 'm', 'a'], key[0]) >= 0
+ let opts[key] = rest
+ elseif key == 'ig'
+ try
+ let arr = eval(rest)
+ if type(arr) == 3
+ let opts[key] = arr
+ else
+ throw 'Not an array'
+ endif
+ catch
+ call s:exit("Invalid ignore_groups: ". a:expr)
+ endtry
+ elseif key =~ '[<>]'
+ let opts['stl'] = key == '<'
+ else
+ let opts[key] = str2nr(rest)
+ endif
+ break
+ endif
+ endfor
+ endfor
+ endif
+ return s:normalize_options(opts)
+endfunction
+
+function! s:parse_args(args)
+ if empty(a:args)
+ return ['', '', {}, 0]
+ endif
+ let n = ''
+ let ch = ''
+ let args = a:args
+ let cand = ''
+ let opts = {}
+
+ " Poor man's option parser
+ let idx = 0
+ while 1
+ let midx = match(args, '\s*{.*}\s*$', idx)
+ if midx == -1 | break | endif
+
+ let cand = strpart(args, midx)
+ try
+ let [l, r, c, k, s, d, n] = ['l', 'r', 'c', 'k', 's', 'd', 'n']
+ let [L, R, C, K, S, D, N] = ['l', 'r', 'c', 'k', 's', 'd', 'n']
+ let o = eval(cand)
+ if type(o) == 4
+ let opts = o
+ if args[midx - 1 : midx] == '\ '
+ let midx += 1
+ endif
+ let args = strpart(args, 0, midx)
+ break
+ endif
+ catch
+ " Ignore
+ endtry
+ let idx = midx + 1
+ endwhile
+
+ " Invalid option dictionary
+ if len(substitute(cand, '\s', '', 'g')) > 2 && empty(opts)
+ call s:exit("Invalid option: ". cand)
+ else
+ let opts = s:normalize_options(opts)
+ endif
+
+ " Shorthand option notation
+ let sopts = matchstr(args, s:shorthand_regex)
+ if !empty(sopts)
+ let args = strpart(args, 0, len(args) - len(sopts))
+ let opts = extend(s:parse_shorthand_opts(sopts), opts)
+ endif
+
+ " Has /Regexp/?
+ let matches = matchlist(args, '^\(.\{-}\)\s*/\(.*\)/\s*$')
+
+ " Found regexp
+ if !empty(matches)
+ return [matches[1], s:test_regexp(matches[2]), opts, 1]
+ else
+ let tokens = matchlist(args, '^\([1-9][0-9]*\|-[0-9]*\|\*\*\?\)\?\s*\(.\{-}\)\?$')
+ " Try swapping n and ch
+ let [n, ch] = empty(tokens[2]) ? reverse(tokens[1:2]) : tokens[1:2]
+
+ " Resolving command-line ambiguity
+ " '\ ' => ' '
+ " '\' => ' '
+ if ch =~ '^\\\s*$'
+ let ch = ' '
+ " '\\' => '\'
+ elseif ch =~ '^\\\\\s*$'
+ let ch = '\'
+ endif
+
+ return [n, ch, opts, 0]
+ endif
+endfunction
+
+function! s:parse_filter(f)
+ let m = matchlist(a:f, '^\([gv]\)/\(.\{-}\)/\?$')
+ if empty(m)
+ return [0, '']
+ else
+ return [m[1] == 'g' ? 1 : -1, m[2]]
+ endif
+endfunction
+
+function! s:interactive_modes(bang)
+ return get(g:,
+ \ (a:bang ? 'easy_align_bang_interactive_modes' : 'easy_align_interactive_modes'),
+ \ (a:bang ? ['r', 'l', 'c'] : ['l', 'r', 'c']))
+endfunction
+
+function! s:alternating_modes(mode)
+ return a:mode ==? 'r' ? 'rl' : 'lr'
+endfunction
+
+function! s:update_lines(todo)
+ for [line, content] in items(a:todo)
+ call setline(line, s:rtrim(content))
+ endfor
+endfunction
+
+function! s:parse_nth(n)
+ let n = a:n
+ let recur = 0
+ if n == '*' | let [nth, recur] = [1, 1]
+ elseif n == '**' | let [nth, recur] = [1, 2]
+ elseif n == '-' | let nth = -1
+ elseif empty(n) | let nth = 1
+ elseif n == '0' || ( n != '-0' && n != string(str2nr(n)) )
+ call s:exit('Invalid N-th parameter: '. n)
+ else
+ let nth = n
+ endif
+ return [nth, recur]
+endfunction
+
+function! s:build_dict(delimiters, ch, regexp, opts)
+ if a:regexp
+ let dict = { 'pattern': a:ch }
+ else
+ if !has_key(a:delimiters, a:ch)
+ call s:exit('Unknown delimiter key: '. a:ch)
+ endif
+ let dict = copy(a:delimiters[a:ch])
+ endif
+ call extend(dict, a:opts)
+
+ let ml = get(dict, 'left_margin', ' ')
+ let mr = get(dict, 'right_margin', ' ')
+ if type(ml) == 0 | let ml = repeat(' ', ml) | endif
+ if type(mr) == 0 | let mr = repeat(' ', mr) | endif
+ call extend(dict, { 'ml': ml, 'mr': mr })
+
+ let dict.pattern = get(dict, 'pattern', a:ch)
+ let dict.delimiter_align =
+ \ get(dict, 'delimiter_align', get(g:, 'easy_align_delimiter_align', 'r'))[0]
+ let dict.indentation =
+ \ get(dict, 'indentation', get(g:, 'easy_align_indentation', 'k'))[0]
+ let dict.stick_to_left =
+ \ get(dict, 'stick_to_left', 0)
+ let dict.ignore_unmatched =
+ \ get(dict, 'ignore_unmatched', get(g:, 'easy_align_ignore_unmatched', 2))
+ let dict.ignore_groups =
+ \ get(dict, 'ignore_groups', get(dict, 'ignores', s:ignored_syntax()))
+ let dict.filter =
+ \ get(dict, 'filter', '')
+ return dict
+endfunction
+
+function! s:build_mode_sequence(expr, recur)
+ let [expr, recur] = [a:expr, a:recur]
+ let suffix = matchstr(a:expr, '\*\+$')
+ if suffix == '*'
+ let expr = expr[0 : -2]
+ let recur = 1
+ elseif suffix == '**'
+ let expr = expr[0 : -3]
+ let recur = 2
+ endif
+ return [tolower(expr), recur]
+endfunction
+
+function! s:process(range, mode, n, ch, opts, regexp, rules, bvis)
+ let [nth, recur] = s:parse_nth((empty(a:n) && exists('g:easy_align_nth')) ? g:easy_align_nth : a:n)
+ let dict = s:build_dict(a:rules, a:ch, a:regexp, a:opts)
+ let [mode_sequence, recur] = s:build_mode_sequence(
+ \ get(dict, 'align', recur == 2 ? s:alternating_modes(a:mode) : a:mode),
+ \ recur)
+
+ let ve = &virtualedit
+ set ve=all
+ let args = [
+ \ {}, split(mode_sequence, '\zs'),
+ \ {}, {}, a:range[0], a:range[1],
+ \ a:bvis ? min([virtcol("'<"), virtcol("'>")]) : 1,
+ \ (!recur && a:bvis) ? max([virtcol("'<"), virtcol("'>")]) : 0,
+ \ nth, recur, dict ]
+ let &ve = ve
+ while len(args) > 1
+ let args = call('s:do_align', args)
+ endwhile
+
+ " todo: lines to update
+ " summarize: arguments to s:summarize
+ return { 'todo': args[0], 'summarize': [ a:opts, recur, mode_sequence ] }
+endfunction
+
+function s:summarize(opts, recur, mode_sequence)
+ let copts = s:compact_options(a:opts)
+ let nbmode = s:interactive_modes(0)[0]
+ if !has_key(copts, 'a') && (
+ \ (a:recur == 2 && s:alternating_modes(nbmode) != a:mode_sequence) ||
+ \ (a:recur != 2 && (a:mode_sequence[0] != nbmode || len(a:mode_sequence) > 1))
+ \ )
+ call extend(copts, { 'a': a:mode_sequence })
+ endif
+ return copts
+endfunction
+
+function! s:align(bang, live, visualmode, first_line, last_line, expr)
+ " Heuristically determine if the user was in visual mode
+ if a:visualmode == 'command'
+ let vis = a:first_line == line("'<") && a:last_line == line("'>")
+ let bvis = vis && visualmode() == "\"
+ elseif empty(a:visualmode)
+ let vis = 0
+ let bvis = 0
+ else
+ let vis = 1
+ let bvis = a:visualmode == "\"
+ end
+ let range = [a:first_line, a:last_line]
+ let modes = s:interactive_modes(a:bang)
+ let mode = modes[0]
+ let s:live = a:live
+
+ let rules = s:easy_align_delimiters_default
+ if exists('g:easy_align_delimiters')
+ let rules = extend(copy(rules), g:easy_align_delimiters)
+ endif
+
+ let [n, ch, opts, regexp] = s:parse_args(a:expr)
+
+ let bypass_fold = get(g:, 'easy_align_bypass_fold', 0)
+ let ofm = &l:foldmethod
+ try
+ if bypass_fold | let &l:foldmethod = 'manual' | endif
+
+ if empty(n) && empty(ch) || s:live
+ let [mode, n, ch, opts, regexp] = s:interactive(range, copy(modes), n, ch, opts, rules, vis, bvis)
+ endif
+
+ if !s:live
+ let output = s:process(range, mode, n, ch, s:normalize_options(opts), regexp, rules, bvis)
+ call s:update_lines(output.todo)
+ let copts = call('s:summarize', output.summarize)
+ let g:easy_align_last_command = s:echon('', n, regexp, ch, copts, '')
+ endif
+ finally
+ if bypass_fold | let &l:foldmethod = ofm | endif
+ endtry
+endfunction
+
+function! easy_align#align(bang, live, visualmode, expr) range
+ try
+ call s:align(a:bang, a:live, a:visualmode, a:firstline, a:lastline, a:expr)
+ catch /^\%(Vim:Interrupt\|exit\)$/
+ if empty(a:visualmode)
+ echon "\r"
+ echon "\r"
+ else
+ normal! gv
+ endif
+ endtry
+endfunction
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
diff --git a/.vim/bundle/vim-easy-align/doc/easy_align.txt b/.vim/bundle/vim-easy-align/doc/easy_align.txt
new file mode 100644
index 0000000..5a82e5e
--- /dev/null
+++ b/.vim/bundle/vim-easy-align/doc/easy_align.txt
@@ -0,0 +1,891 @@
+easy-align.txt easy-align Last change: December 14 2014
+EASY-ALIGN - TABLE OF CONTENTS *easyalign* *easy-align* *easy-align-toc*
+==============================================================================
+
+ vim-easy-align
+ Demo |easy-align-1|
+ Features |easy-align-2|
+ Installation |easy-align-3|
+ TLDR - One-minute guide |easy-align-4|
+ Usage |easy-align-5|
+ Concept of alignment rule |easy-align-5-1|
+ Execution models |easy-align-5-2|
+ 1. Using mappings |easy-align-5-2-1|
+ 2. Using :EasyAlign command |easy-align-5-2-2|
+ Interactive mode |easy-align-5-3|
+ Predefined alignment rules |easy-align-5-3-1|
+ Examples |easy-align-5-3-2|
+ Using regular expressions |easy-align-5-3-3|
+ Alignment options in interactive mode |easy-align-5-3-4|
+ Live interactive mode |easy-align-5-4|
+ Non-interactive mode |easy-align-5-5|
+ Partial alignment in blockwise-visual mode |easy-align-5-6|
+ Alignment options |easy-align-6|
+ List of options |easy-align-6-1|
+ Filtering lines |easy-align-6-2|
+ Examples |easy-align-6-2-1|
+ Ignoring delimiters in comments or strings |easy-align-6-3|
+ Ignoring unmatched lines |easy-align-6-4|
+ Aligning delimiters of different lengths |easy-align-6-5|
+ Adjusting indentation |easy-align-6-6|
+ Alignments over multiple occurrences of delimiters |easy-align-6-7|
+ Extending alignment rules |easy-align-6-8|
+ Examples |easy-align-6-8-1|
+ Other options |easy-align-7|
+ Disabling &foldmethod during alignment |easy-align-7-1|
+ Left/right/center mode switch in interactive mode |easy-align-7-2|
+ Advanced examples and use cases |easy-align-8|
+ Related work |easy-align-9|
+ Author |easy-align-10|
+ License |easy-align-11|
+
+
+VIM-EASY-ALIGN *vim-easy-align*
+==============================================================================
+
+A simple, easy-to-use Vim alignment plugin.
+
+
+ *easy-align-1*
+DEMO *easy-align-demo*
+==============================================================================
+
+Screencast:
+https://raw.githubusercontent.com/junegunn/i/master/vim-easy-align.gif
+
+(Too fast? Slower GIF is {here}{1})
+
+{1} https://raw.githubusercontent.com/junegunn/i/master/vim-easy-align-slow.gif
+
+
+ *easy-align-2*
+FEATURES *easy-align-features*
+==============================================================================
+
+ - Easy to use
+ - Comes with a predefined set of alignment rules
+ - Provides a fast and intuitive interface
+ - Extensible
+ - You can define your own rules
+ - Supports arbitrary regular expressions
+ - Optimized for code editing
+ - Takes advantage of syntax highlighting feature to avoid unwanted
+ alignments
+
+
+ *easy-align-3*
+INSTALLATION *easy-align-installation*
+==============================================================================
+
+Use your favorite plugin manager.
+
+Using {vim-plug}{2}:
+>
+ Plug 'junegunn/vim-easy-align'
+<
+ {2} https://github.com/junegunn/vim-plug
+
+
+ *easy-align-4*
+TLDR - ONE-MINUTE GUIDE *easy-align-tldr-one-minute-guide*
+==============================================================================
+
+Add the following mappings to your .vimrc.
+
+ *(EasyAlign)*
+>
+ " Start interactive EasyAlign in visual mode (e.g. vip)
+ vmap (EasyAlign)
+
+ " Start interactive EasyAlign for a motion/text object (e.g. gaip)
+ nmap ga (EasyAlign)
+<
+And with the following lines of text,
+>
+ apple =red
+ grass+=green
+ sky-= blue
+<
+try these commands:
+
+ - vip=
+ - `v`isual-select `i`nner `p`aragraph
+ - Start EasyAlign command ()
+ - Align around `=`
+ - `gaip=`
+ - Start EasyAlign command (`ga`) for `i`nner `p`aragraph
+ - Align around `=`
+
+Notice that the commands are repeatable with `.` key if you have installed
+{repeat.vim}{3}. Install {visualrepeat}{4} as well if you want to repeat in
+visual mode.
+
+ {3} https://github.com/tpope/vim-repeat
+ {4} https://github.com/vim-scripts/visualrepeat
+
+
+ *easy-align-5*
+USAGE *easy-align-usage*
+==============================================================================
+
+
+< Concept of alignment rule >_________________________________________________~
+ *easy-align-concept-of-alignment-rule*
+ *easy-align-5-1*
+
+Though easy-align can align lines of text around any delimiter, it provides
+shortcuts for the most common use cases with the concept of "alignment rule".
+
+An alignment rule is a predefined set of options for common alignment tasks,
+which is identified by a single character, DELIMITER KEY, such as ,
+`=`, `:`, `.`, `|`, `&`, `#`, and `,`.
+
+Think of it as a shortcut. Instead of writing regular expression and setting
+several options, you can just type in a single character.
+
+
+< Execution models >__________________________________________________________~
+ *easy-align-execution-models*
+ *easy-align-5-2*
+
+There are two ways to use easy-align.
+
+
+1. Using mappings~
+ *easy-align-1-using-plug-mappings*
+ *easy-align-5-2-1*
+
+The recommended method is to use mappings as described earlier.
+
+ *(LiveEasyAlign)*
+
+ ----------------------+--------+-----------------------------------------------------
+ Mapping | Mode | Description ~
+ ----------------------+--------+-----------------------------------------------------
+ (EasyAlign) | normal | Start interactive mode for a motion/text object
+ (EasyAlign) | visual | Start interactive mode for the selection
+ (LiveEasyAlign) | normal | Start live-interactive mode for a motion/text object
+ (LiveEasyAlign) | visual | Start live-interactive mode for the selection
+ ----------------------+--------+-----------------------------------------------------
+
+
+2. Using :EasyAlign command~
+ *easy-align-2-using-easyalign-command*
+ *easy-align-5-2-2*
+
+ *:EasyAlign*
+
+If you prefer command-line or do not want to start interactive mode, you can
+use `:EasyAlign` command instead.
+
+ *:LiveEasyAlign*
+
+ -------------------------------------------+-----------------------------------------------
+ Mode | Command ~
+ -------------------------------------------+-----------------------------------------------
+ Interactive mode | `:EasyAlign[!] [OPTIONS]`
+ Live interactive mode | `:LiveEasyAlign[!] [...]`
+ Non-interactive mode (predefined rules) | `:EasyAlign[!] [N-th] DELIMITER_KEY [OPTIONS]`
+ Non-interactive mode (regular expressions) | `:EasyAlign[!] [N-th] /REGEXP/ [OPTIONS]`
+ -------------------------------------------+-----------------------------------------------
+
+
+< Interactive mode >__________________________________________________________~
+ *easy-align-interactive-mode*
+ *easy-align-5-3*
+
+The following sections will assume that you have (EasyAlign) mappings in
+your .vimrc as below:
+>
+ " Start interactive EasyAlign in visual mode (e.g. vip)
+ vmap (EasyAlign)
+
+ " Start interactive EasyAlign for a motion/text object (e.g. gaip)
+ nmap ga (EasyAlign)
+<
+With these mappings, you can align text with only a few keystrokes.
+
+ 1. key in visual mode, or `ga` followed by a motion or a text object to
+ start interactive mode
+ 2. Optional: Enter keys to select alignment mode (left, right, or center)
+ 3. Optional: N-th delimiter (default: 1)
+ - `1` Around the 1st occurrences of delimiters
+ - `2` Around the 2nd occurrences of delimiters
+ - ...
+ - `*` Around all occurrences of delimiters
+ - `**` Left-right alternating alignment around all delimiters
+ - `-` Around the last occurrences of delimiters (`-1`)
+ - `-2` Around the second to last occurrences of delimiters
+ - ...
+ 4. Delimiter key (a single keystroke; , `=`, `:`, `.`, `|`, `&`, `#`, `,`)
+
+
+Predefined alignment rules~
+ *easy-align-predefined-alignment-rules*
+ *easy-align-5-3-1*
+
+ --------------+--------------------------------------------------------------------
+ Delimiter key | Description/Use cases ~
+ --------------+--------------------------------------------------------------------
+ | General alignment around whitespaces
+ `=` | Operators containing equals sign ( `=` , `==,` `!=` , `+=` , `&&=` , ...)
+ `:` | Suitable for formatting JSON or YAML
+ `.` | Multi-line method chaining
+ `,` | Multi-line method arguments
+ `&` | LaTeX tables (matches `&` and `\\` )
+ `#` | Ruby/Python comments
+ `"` | Vim comments
+ | Table markdown
+ --------------+--------------------------------------------------------------------
+
+ *g:easy_align_delimiters*
+
+You can override these default rules or define your own rules with
+`g:easy_align_delimiters`, which will be described in {the later section}{5}.
+
+ {5} https://github.com/junegunn/vim-easy-align#extending-alignment-rules
+
+
+Examples~
+ *easy-align-examples*
+ *easy-align-5-3-2*
+
+ ------------------+------------------------------------+--------------------
+ With visual map | Description | Equivalent command ~
+ ------------------+------------------------------------+--------------------
+ | Around 1st whitespaces | :'<,'>EasyAlign\
+ 2 | Around 2nd whitespaces | :'<,'>EasyAlign2\
+ - | Around the last whitespaces | :'<,'>EasyAlign-\
+ -2 | Around the 2nd to last whitespaces | :'<,'>EasyAlign-2\
+ : | Around 1st colon ( `key: value` ) | :'<,'>EasyAlign:
+ : | Around 1st colon ( `key : value` ) | :'<,'>EasyAlign:= | Around 1st operators with = | :'<,'>EasyAlign=
+ 3= | Around 3rd operators with = | :'<,'>EasyAlign3=
+ *= | Around all operators with = | :'<,'>EasyAlign*=
+ **= | Left-right alternating around = | :'<,'>EasyAlign**=
+ = | Right alignment around 1st = | :'<,'>EasyAlign!=
+ **= | Right-left alternating around = | :'<,'>EasyAlign!**=
+ ------------------+------------------------------------+--------------------
+
+
+Using regular expressions~
+ *easy-align-using-regular-expressions*
+ *easy-align-5-3-3*
+
+Instead of finishing the command with a predefined delimiter key, you can type
+in a regular expression after CTRL-/ or CTRL-X key. For example, if you want
+to align text around all occurrences of numbers:
+
+ -
+ - `*`
+ - CTRL-X
+ - `[0-9]\+`
+
+
+Alignment options in interactive mode~
+ *easy-align-alignment-options-in-interactive-mode*
+ *easy-align-5-3-4*
+
+While in interactive mode, you can set alignment options using special
+shortcut keys listed below. The meaning of each option will be described in
+{the following sections}{6}.
+
+ --------+--------------------+---------------------------------------------------
+ Key | Option | Values ~
+ --------+--------------------+---------------------------------------------------
+ CTRL-F | `filter` | Input string ( `[gv]/.*/?` )
+ CTRL-I | `indentation` | shallow, deep, none, keep
+ CTRL-L | `left_margin` | Input number or string
+ CTRL-R | `right_margin` | Input number or string
+ CTRL-D | `delimiter_align` | left, center, right
+ CTRL-U | `ignore_unmatched` | 0, 1
+ CTRL-G | `ignore_groups` | [], ["String'], ["Comment'], ["String', "Comment']
+ CTRL-A | `align` | Input string ( `/[lrc]+\*{0,2}/` )
+ | `stick_to_left` | `{ 'stick_to_left': 1, 'left_margin': 0 }`
+ | `stick_to_left` | `{ 'stick_to_left': 0, 'left_margin': 1 }`
+ | `*_margin` | `{ 'left_margin': 0, 'right_margin': 0 }`
+ --------+--------------------+---------------------------------------------------
+
+ {6} https://github.com/junegunn/vim-easy-align#alignment-options
+
+
+< Live interactive mode >_____________________________________________________~
+ *easy-align-live-interactive-mode*
+ *easy-align-5-4*
+
+If you're performing a complex alignment where multiple options should be
+carefully adjusted, try "live interactive mode" where you can preview the
+result of the alignment on-the-fly as you type in.
+
+Live interactive mode can be started with either (LiveEasyAlign) map or
+`:LiveEasyAlign` command. Or you can switch to live interactive mode while in
+ordinary interactive mode by pressing CTRL-P. (P for Preview)
+
+In live interactive mode, you have to type in the same delimiter (or CTRL-X on
+regular expression) again to finalize the alignment. This allows you to
+preview the result of the alignment and freely change the delimiter using
+backspace key without leaving the interactive mode.
+
+
+< Non-interactive mode >______________________________________________________~
+ *easy-align-non-interactive-mode*
+ *easy-align-5-5*
+
+Instead of starting interactive mode, you can use declarative, non-interactive
+`:EasyAlign` command.
+>
+ " Using predefined alignment rules
+ " :EasyAlign[!] [N-th] DELIMITER_KEY [OPTIONS]
+ :EasyAlign :
+ :EasyAlign =
+ :EasyAlign *=
+ :EasyAlign 3\
+
+ " Using arbitrary regular expressions
+ " :EasyAlign[!] [N-th] /REGEXP/ [OPTIONS]
+ :EasyAlign /[:;]\+/
+ :EasyAlign 2/[:;]\+/
+ :EasyAlign */[:;]\+/
+ :EasyAlign **/[:;]\+/
+<
+A command can end with alignment options, {each of which will be discussed in
+detail later}{6}, in Vim dictionary format.
+
+ - `:EasyAlign * /[:;]\+/ { 'stick_to_left': 1, 'left_margin': 0 }`
+
+`stick_to_left` of 1 means that the matched delimiter should be positioned
+right next to the preceding token, and `left_margin` of 0 removes the margin
+on the left. So we get:
+>
+ apple;: banana:: cake
+ data;; exchange:; format
+<
+Option names are fuzzy-matched, so you can write as follows:
+
+ - `:EasyAlign * /[:;]\+/ { 'stl': 1, 'l': 0 }`
+
+You can even omit spaces between the arguments, so concisely (or cryptically):
+
+ - `:EasyAlign*/[:;]\+/{'s':1,'l':0}`
+
+Nice. But let's make it even shorter. Option values can be written in
+shorthand notation.
+
+ - `:EasyAlign*/[:;]\+/`
+ `ignore_unmatched` | `iu[01]`
+ `ignore_groups` | `ig\[.*\]`
+ `align` | `a[lrc*]*`
+ `delimiter_align` | `d[lrc]`
+ `indentation` | `i[ksdn]`
+ -------------------+-----------
+
+For your information, the same operation can be done in interactive mode as
+follows:
+
+ -
+ - `*`
+ -
+ - CTRL-X
+ - `[:;]\+`
+
+ {6} https://github.com/junegunn/vim-easy-align#alignment-options
+
+
+< Partial alignment in blockwise-visual mode >________________________________~
+ *easy-align-partial-alignment-in-blockwise-visual-mode*
+ *easy-align-5-6*
+
+In blockwise-visual mode (CTRL-V), EasyAlign command aligns only the selected
+text in the block, instead of the whole lines in the range.
+
+Consider the following case where you want to align text around `=>`
+operators.
+>
+ my_hash = { :a => 1,
+ :aa => 2,
+ :aaa => 3 }
+<
+In non-blockwise visual mode (`v` / `V`), = won't work since the
+assignment operator in the first line gets in the way. So we instead enter
+blockwise-visual mode (CTRL-V), and select the text around`=>` operators, then
+press =.
+>
+ my_hash = { :a => 1,
+ :aa => 2,
+ :aaa => 3 }
+<
+However, in this case, we don't really need blockwise visual mode since the
+same can be easily done using the negative N-th parameter: -=
+
+
+ *easy-align-6*
+ALIGNMENT OPTIONS *easy-align-alignment-options*
+==============================================================================
+
+
+< List of options >___________________________________________________________~
+ *easy-align-list-of-options*
+ *easy-align-6-1*
+
+ -------------------+---------+-----------------------+--------------------------------------------------------
+ Option | Type | Default | Description ~
+ -------------------+---------+-----------------------+--------------------------------------------------------
+ `filter` | string | | Line filtering expression: `g/../` or `v/../`
+ `left_margin` | number | 1 | Number of spaces to attach before delimiter
+ `left_margin` | string | `' '` | String to attach before delimiter
+ `right_margin` | number | 1 | Number of spaces to attach after delimiter
+ `right_margin` | string | `' '` | String to attach after delimiter
+ `stick_to_left` | boolean | 0 | Whether to position delimiter on the left-side
+ `ignore_groups` | list | ["String', "Comment'] | Delimiters in these syntax highlight groups are ignored
+ `ignore_unmatched` | boolean | 1 | Whether to ignore lines without matching delimiter
+ `indentation` | string | `k` | Indentation method (keep, deep, shallow, none)
+ `delimiter_align` | string | `r` | Determines how to align delimiters of different lengths
+ `align` | string | `l` | Alignment modes for multiple occurrences of delimiters
+ -------------------+---------+-----------------------+--------------------------------------------------------
+
+There are 4 ways to set alignment options (from lowest precedence to highest):
+
+ 1. Some option values can be set with corresponding global variables
+ 2. Option values can be specified in the definition of each alignment rule
+ 3. Option values can be given as arguments to `:EasyAlign` command
+ 4. Option values can be set in interactive mode using special shortcut keys
+
+ *g:easy_align_ignore_groups* *g:easy_align_ignore_unmatched*
+ *g:easy_align_indentation* *g:easy_align_delimiter_align*
+
+ -------------------+-----------------+-------------+--------------------------------
+ Option name | Shortcut key | Abbreviated | Global variable ~
+ -------------------+-----------------+-------------+--------------------------------
+ `filter` | CTRL-F | `[gv]/.*/` |
+ `left_margin` | CTRL-L | `l[0-9]+` |
+ `right_margin` | CTRL-R | `r[0-9]+` |
+ `stick_to_left` | , | `<` or `>` |
+ `ignore_groups` | CTRL-G | `ig\[.*\]` | `g:easy_align_ignore_groups`
+ `ignore_unmatched` | CTRL-U | `iu[01]` | `g:easy_align_ignore_unmatched`
+ `indentation` | CTRL-I | `i[ksdn]` | `g:easy_align_indentation`
+ `delimiter_align` | CTRL-D | `d[lrc]` | `g:easy_align_delimiter_align`
+ `align` | CTRL-A | `a[lrc*]*` |
+ -------------------+-----------------+-------------+--------------------------------
+
+
+< Filtering lines >___________________________________________________________~
+ *easy-align-filtering-lines*
+ *easy-align-6-2*
+
+With `filter` option, you can align lines that only match or do not match a
+given pattern. There are several ways to set the pattern.
+
+ 1. Press CTRL-F in interactive mode and type in `g/pat/` or `v/pat/`
+ 2. In command-line, it can be written in dictionary format: `{'filter':
+ 'g/pat/'}`
+ 3. Or in shorthand notation: `g/pat/` or `v/pat/`
+
+(You don't need to escape "/'s in the regular expression)
+
+
+Examples~
+
+ *easy-align-6-2-1*
+>
+ " Start interactive mode with filter option set to g/hello/
+ EasyAlign g/hello/
+
+ " Start live interactive mode with filter option set to v/goodbye/
+ LiveEasyAlign v/goodbye/
+
+ " Align the lines with 'hi' around the first colons
+ EasyAlign:g/hi/
+<
+
+< Ignoring delimiters in comments or strings >________________________________~
+ *easy-align-ignoring-delimiters-in-comments-or-strings*
+ *easy-align-6-3*
+
+EasyAlign can be configured to ignore delimiters in certain syntax highlight
+groups, such as code comments or strings. By default, delimiters that are
+highlighted as code comments or strings are ignored.
+>
+ " Default:
+ " If a delimiter is in a highlight group whose name matches
+ " any of the followings, it will be ignored.
+ let g:easy_align_ignore_groups = ['Comment', 'String']
+<
+For example, the following paragraph
+>
+ {
+ # Quantity of apples: 1
+ apple: 1,
+ # Quantity of bananas: 2
+ bananas: 2,
+ # Quantity of grape:fruits: 3
+ 'grape:fruits': 3
+ }
+<
+becomes as follows on : (or `:EasyAlign:`)
+>
+ {
+ # Quantity of apples: 1
+ apple: 1,
+ # Quantity of bananas: 2
+ bananas: 2,
+ # Quantity of grape:fruits: 3
+ 'grape:fruits': 3
+ }
+<
+Naturally, this feature only works when syntax highlighting is enabled.
+
+You can change the default rule by using one of these 4 methods.
+
+ 1. Press CTRL-G in interactive mode to switch groups
+ 2. Define global `g:easy_align_ignore_groups` list
+ 3. Define a custom rule in `g:easy_align_delimiters` with `ignore_groups` option
+ 4. Provide `ignore_groups` option to `:EasyAlign` command. e.g. `:EasyAlign:ig[]`
+
+For example if you set `ignore_groups` option to be an empty list, you get
+>
+ {
+ # Quantity of apples: 1
+ apple: 1,
+ # Quantity of bananas: 2
+ bananas: 2,
+ # Quantity of grape: fruits: 3
+ 'grape: fruits': 3
+ }
+<
+If a pattern in `ignore_groups` is prepended by a `!`, it will have the
+opposite meaning. For instance, if `ignore_groups` is given as `['!Comment']`,
+delimiters that are not highlighted as Comment will be ignored during the
+alignment.
+
+
+< Ignoring unmatched lines >__________________________________________________~
+ *easy-align-ignoring-unmatched-lines*
+ *easy-align-6-4*
+
+`ignore_unmatched` option determines how EasyAlign command processes lines
+that do not have N-th delimiter.
+
+ 1. In left-alignment mode, they are ignored
+ 2. In right or center-alignment mode, they are not ignored, and the last tokens
+ from those lines are aligned as well as if there is an invisible trailing
+ delimiter at the end of each line
+ 3. If `ignore_unmatched` is 1, they are ignored regardless of the alignment mode
+ 4. If `ignore_unmatched` is 0, they are not ignored regardless of the mode
+
+Let's take an example. When we align the following code block around the (1st)
+colons,
+>
+ {
+ apple: proc {
+ this_line_does_not_have_a_colon
+ },
+ bananas: 2,
+ grapefruits: 3
+ }
+<
+this is usually what we want.
+>
+ {
+ apple: proc {
+ this_line_does_not_have_a_colon
+ },
+ bananas: 2,
+ grapefruits: 3
+ }
+<
+However, we can override this default behavior by setting `ignore_unmatched`
+option to zero using one of the following methods.
+
+ 1. Press CTRL-U in interactive mode to toggle `ignore_unmatched` option
+ 2. Set the global `g:easy_align_ignore_unmatched` variable to 0
+ 3. Define a custom alignment rule with `ignore_unmatched` option set to 0
+ 4. Provide `ignore_unmatched` option to `:EasyAlign` command. e.g.
+ `:EasyAlign:iu0`
+
+Then we get,
+>
+ {
+ apple: proc {
+ this_line_does_not_have_a_colon
+ },
+ bananas: 2,
+ grapefruits: 3
+ }
+<
+
+< Aligning delimiters of different lengths >__________________________________~
+ *easy-align-aligning-delimiters-of-different-lengths*
+ *easy-align-6-5*
+
+Global `g:easy_align_delimiter_align` option and rule-wise/command-wise
+`delimiter_align` option determines how matched delimiters of different
+lengths are aligned.
+>
+ apple = 1
+ banana += apple
+ cake ||= banana
+<
+By default, delimiters are right-aligned as follows.
+>
+ apple = 1
+ banana += apple
+ cake ||= banana
+<
+However, with `:EasyAlign=dl`, delimiters are left-aligned.
+>
+ apple = 1
+ banana += apple
+ cake ||= banana
+<
+And on `:EasyAlign=dc`, center-aligned.
+>
+ apple = 1
+ banana += apple
+ cake ||= banana
+<
+In interactive mode, you can change the option value with CTRL-D key.
+
+
+< Adjusting indentation >_____________________________________________________~
+ *easy-align-adjusting-indentation*
+ *easy-align-6-6*
+
+By default :EasyAlign command keeps the original indentation of the lines. But
+then again we have `indentation` option. See the following example.
+>
+ # Lines with different indentation
+ apple = 1
+ banana = 2
+ cake = 3
+ daisy = 4
+ eggplant = 5
+
+ # Default: _k_eep the original indentation
+ # :EasyAlign=
+ apple = 1
+ banana = 2
+ cake = 3
+ daisy = 4
+ eggplant = 5
+
+ # Use the _s_hallowest indentation among the lines
+ # :EasyAlign=is
+ apple = 1
+ banana = 2
+ cake = 3
+ daisy = 4
+ eggplant = 5
+
+ # Use the _d_eepest indentation among the lines
+ # :EasyAlign=id
+ apple = 1
+ banana = 2
+ cake = 3
+ daisy = 4
+ eggplant = 5
+
+ # Indentation: _n_one
+ # :EasyAlign=in
+ apple = 1
+ banana = 2
+ cake = 3
+ daisy = 4
+ eggplant = 5
+<
+In interactive mode, you can change the option value with CTRL-I key.
+
+
+< Alignments over multiple occurrences of delimiters >________________________~
+ *easy-align-alignments-over-multiple-occurrences-of-delimiters*
+ *easy-align-6-7*
+
+As stated above, "N-th" parameter is used to target specific occurrences of
+the delimiter when it appears multiple times in each line.
+
+To recap:
+>
+ " Left-alignment around the FIRST occurrences of delimiters
+ :EasyAlign =
+
+ " Left-alignment around the SECOND occurrences of delimiters
+ :EasyAlign 2=
+
+ " Left-alignment around the LAST occurrences of delimiters
+ :EasyAlign -=
+
+ " Left-alignment around ALL occurrences of delimiters
+ :EasyAlign *=
+
+ " Left-right ALTERNATING alignment around all occurrences of delimiters
+ :EasyAlign **=
+
+ " Right-left ALTERNATING alignment around all occurrences of delimiters
+ :EasyAlign! **=
+<
+In addition to these, you can fine-tune alignments over multiple occurrences
+of the delimiters with "align' option. (The option can also be set in
+interactive mode with the special key CTRL-A)
+>
+ " Left alignment over the first two occurrences of delimiters
+ :EasyAlign = { 'align': 'll' }
+
+ " Right, left, center alignment over the 1st to 3rd occurrences of delimiters
+ :EasyAlign = { 'a': 'rlc' }
+
+ " Using shorthand notation
+ :EasyAlign = arlc
+
+ " Right, left, center alignment over the 2nd to 4th occurrences of delimiters
+ :EasyAlign 2=arlc
+
+ " (*) Repeating alignments (default: l, r, or c)
+ " Right, left, center, center, center, center, ...
+ :EasyAlign *=arlc
+
+ " (**) Alternating alignments (default: lr or rl)
+ " Right, left, center, right, left, center, ...
+ :EasyAlign **=arlc
+
+ " Right, left, center, center, center, ... repeating alignment
+ " over the 3rd to the last occurrences of delimiters
+ :EasyAlign 3=arlc*
+
+ " Right, left, center, right, left, center, ... alternating alignment
+ " over the 3rd to the last occurrences of delimiters
+ :EasyAlign 3=arlc**
+<
+
+< Extending alignment rules >_________________________________________________~
+ *easy-align-extending-alignment-rules*
+ *easy-align-6-8*
+
+Although the default rules should cover the most of the use cases, you can
+extend the rules by setting a dictionary named `g:easy_align_delimiters`.
+
+You may refer to the definitions of the default alignment rules {here}{7}.
+
+{7} https://github.com/junegunn/vim-easy-align/blob/2.9.6/autoload/easy_align.vim#L32-L46
+
+
+Examples~
+
+ *easy-align-6-8-1*
+>
+ let g:easy_align_delimiters = {
+ \ '>': { 'pattern': '>>\|=>\|>' },
+ \ '/': {
+ \ 'pattern': '//\+\|/\*\|\*/',
+ \ 'delimiter_align': 'l',
+ \ 'ignore_groups': ['!Comment'] },
+ \ ']': {
+ \ 'pattern': '[[\]]',
+ \ 'left_margin': 0,
+ \ 'right_margin': 0,
+ \ 'stick_to_left': 0
+ \ },
+ \ ')': {
+ \ 'pattern': '[()]',
+ \ 'left_margin': 0,
+ \ 'right_margin': 0,
+ \ 'stick_to_left': 0
+ \ },
+ \ 'd': {
+ \ 'pattern': ' \(\S\+\s*[;=]\)\@=',
+ \ 'left_margin': 0,
+ \ 'right_margin': 0
+ \ }
+ \ }
+<
+
+ *easy-align-7*
+OTHER OPTIONS *easy-align-other-options*
+==============================================================================
+
+
+< Disabling &foldmethod during alignment >____________________________________~
+ *easy-align-disabling-foldmethod-during-alignment*
+ *easy-align-7-1*
+
+ *g:easy_align_bypass_fold*
+
+{It is reported}{8} that 'foldmethod' value of `expr` or `syntax` can
+significantly slow down the alignment when editing a large, complex file with
+many folds. To alleviate this issue, EasyAlign provides an option to
+temporarily set 'foldmethod' to `manual` during the alignment task. In order
+to enable this feature, set `g:easy_align_bypass_fold` switch to 1.
+>
+ let g:easy_align_bypass_fold = 1
+<
+ {8} https://github.com/junegunn/vim-easy-align/issues/14
+
+
+< Left/right/center mode switch in interactive mode >_________________________~
+ *easy-align-left-right-center-mode-switch-in-interactive-mode*
+ *easy-align-7-2*
+
+In interactive mode, you can choose the alignment mode you want by pressing
+enter keys. The non-bang command, `:EasyAlign` starts in left-alignment mode
+and changes to right and center mode as you press enter keys, while the bang
+version first starts in right-alignment mode.
+
+ - `:EasyAlign`
+ - Left, Right, Center
+ - `:EasyAlign!`
+ - Right, Left, Center
+
+If you do not prefer this default mode transition, you can define your own
+settings as follows.
+
+ *g:easy_align_interactive_modes* *g:easy_align_bang_interactive_modes*
+>
+ let g:easy_align_interactive_modes = ['l', 'r']
+ let g:easy_align_bang_interactive_modes = ['c', 'r']
+<
+
+ *easy-align-8*
+ADVANCED EXAMPLES AND USE CASES *easy-align-advanced-examples-and-use-cases*
+==============================================================================
+
+See {EXAMPLES.md}{9} for more examples.
+
+ {9} https://github.com/junegunn/vim-easy-align/blob/master/EXAMPLES.md
+
+
+ *easy-align-9*
+RELATED WORK *easy-align-related-work*
+==============================================================================
+
+ - {DrChip's Alignment Tool for Vim}{10}
+ - {Tabular}{11}
+
+ {10} http://www.drchip.org/astronaut/vim/align.html
+ {11} https://github.com/godlygeek/tabular
+
+
+ *easy-align-10*
+AUTHOR *easy-align-author*
+==============================================================================
+
+{Junegunn Choi}{12}
+
+ {12} https://github.com/junegunn
+
+
+ *easy-align-11*
+LICENSE *easy-align-license*
+==============================================================================
+
+MIT
+
+==============================================================================
+vim:tw=78:sw=2:ts=2:ft=help:norl:nowrap:
diff --git a/.vim/bundle/vim-easy-align/doc/tags b/.vim/bundle/vim-easy-align/doc/tags
new file mode 100644
index 0000000..0411c5f
--- /dev/null
+++ b/.vim/bundle/vim-easy-align/doc/tags
@@ -0,0 +1,84 @@
+:EasyAlign easy_align.txt /*:EasyAlign*
+:LiveEasyAlign easy_align.txt /*:LiveEasyAlign*
+(EasyAlign) easy_align.txt /*(EasyAlign)*
+(LiveEasyAlign) easy_align.txt /*(LiveEasyAlign)*
+easy-align easy_align.txt /*easy-align*
+easy-align-1 easy_align.txt /*easy-align-1*
+easy-align-1-using-plug-mappings easy_align.txt /*easy-align-1-using-plug-mappings*
+easy-align-10 easy_align.txt /*easy-align-10*
+easy-align-11 easy_align.txt /*easy-align-11*
+easy-align-2 easy_align.txt /*easy-align-2*
+easy-align-2-using-easyalign-command easy_align.txt /*easy-align-2-using-easyalign-command*
+easy-align-3 easy_align.txt /*easy-align-3*
+easy-align-4 easy_align.txt /*easy-align-4*
+easy-align-5 easy_align.txt /*easy-align-5*
+easy-align-5-1 easy_align.txt /*easy-align-5-1*
+easy-align-5-2 easy_align.txt /*easy-align-5-2*
+easy-align-5-2-1 easy_align.txt /*easy-align-5-2-1*
+easy-align-5-2-2 easy_align.txt /*easy-align-5-2-2*
+easy-align-5-3 easy_align.txt /*easy-align-5-3*
+easy-align-5-3-1 easy_align.txt /*easy-align-5-3-1*
+easy-align-5-3-2 easy_align.txt /*easy-align-5-3-2*
+easy-align-5-3-3 easy_align.txt /*easy-align-5-3-3*
+easy-align-5-3-4 easy_align.txt /*easy-align-5-3-4*
+easy-align-5-4 easy_align.txt /*easy-align-5-4*
+easy-align-5-5 easy_align.txt /*easy-align-5-5*
+easy-align-5-6 easy_align.txt /*easy-align-5-6*
+easy-align-6 easy_align.txt /*easy-align-6*
+easy-align-6-1 easy_align.txt /*easy-align-6-1*
+easy-align-6-2 easy_align.txt /*easy-align-6-2*
+easy-align-6-2-1 easy_align.txt /*easy-align-6-2-1*
+easy-align-6-3 easy_align.txt /*easy-align-6-3*
+easy-align-6-4 easy_align.txt /*easy-align-6-4*
+easy-align-6-5 easy_align.txt /*easy-align-6-5*
+easy-align-6-6 easy_align.txt /*easy-align-6-6*
+easy-align-6-7 easy_align.txt /*easy-align-6-7*
+easy-align-6-8 easy_align.txt /*easy-align-6-8*
+easy-align-6-8-1 easy_align.txt /*easy-align-6-8-1*
+easy-align-7 easy_align.txt /*easy-align-7*
+easy-align-7-1 easy_align.txt /*easy-align-7-1*
+easy-align-7-2 easy_align.txt /*easy-align-7-2*
+easy-align-8 easy_align.txt /*easy-align-8*
+easy-align-9 easy_align.txt /*easy-align-9*
+easy-align-adjusting-indentation easy_align.txt /*easy-align-adjusting-indentation*
+easy-align-advanced-examples-and-use-cases easy_align.txt /*easy-align-advanced-examples-and-use-cases*
+easy-align-aligning-delimiters-of-different-lengths easy_align.txt /*easy-align-aligning-delimiters-of-different-lengths*
+easy-align-alignment-options easy_align.txt /*easy-align-alignment-options*
+easy-align-alignment-options-in-interactive-mode easy_align.txt /*easy-align-alignment-options-in-interactive-mode*
+easy-align-alignments-over-multiple-occurrences-of-delimiters easy_align.txt /*easy-align-alignments-over-multiple-occurrences-of-delimiters*
+easy-align-author easy_align.txt /*easy-align-author*
+easy-align-concept-of-alignment-rule easy_align.txt /*easy-align-concept-of-alignment-rule*
+easy-align-demo easy_align.txt /*easy-align-demo*
+easy-align-disabling-foldmethod-during-alignment easy_align.txt /*easy-align-disabling-foldmethod-during-alignment*
+easy-align-examples easy_align.txt /*easy-align-examples*
+easy-align-execution-models easy_align.txt /*easy-align-execution-models*
+easy-align-extending-alignment-rules easy_align.txt /*easy-align-extending-alignment-rules*
+easy-align-features easy_align.txt /*easy-align-features*
+easy-align-filtering-lines easy_align.txt /*easy-align-filtering-lines*
+easy-align-ignoring-delimiters-in-comments-or-strings easy_align.txt /*easy-align-ignoring-delimiters-in-comments-or-strings*
+easy-align-ignoring-unmatched-lines easy_align.txt /*easy-align-ignoring-unmatched-lines*
+easy-align-installation easy_align.txt /*easy-align-installation*
+easy-align-interactive-mode easy_align.txt /*easy-align-interactive-mode*
+easy-align-left-right-center-mode-switch-in-interactive-mode easy_align.txt /*easy-align-left-right-center-mode-switch-in-interactive-mode*
+easy-align-license easy_align.txt /*easy-align-license*
+easy-align-list-of-options easy_align.txt /*easy-align-list-of-options*
+easy-align-live-interactive-mode easy_align.txt /*easy-align-live-interactive-mode*
+easy-align-non-interactive-mode easy_align.txt /*easy-align-non-interactive-mode*
+easy-align-other-options easy_align.txt /*easy-align-other-options*
+easy-align-partial-alignment-in-blockwise-visual-mode easy_align.txt /*easy-align-partial-alignment-in-blockwise-visual-mode*
+easy-align-predefined-alignment-rules easy_align.txt /*easy-align-predefined-alignment-rules*
+easy-align-related-work easy_align.txt /*easy-align-related-work*
+easy-align-tldr-one-minute-guide easy_align.txt /*easy-align-tldr-one-minute-guide*
+easy-align-toc easy_align.txt /*easy-align-toc*
+easy-align-usage easy_align.txt /*easy-align-usage*
+easy-align-using-regular-expressions easy_align.txt /*easy-align-using-regular-expressions*
+easyalign easy_align.txt /*easyalign*
+g:easy_align_bang_interactive_modes easy_align.txt /*g:easy_align_bang_interactive_modes*
+g:easy_align_bypass_fold easy_align.txt /*g:easy_align_bypass_fold*
+g:easy_align_delimiter_align easy_align.txt /*g:easy_align_delimiter_align*
+g:easy_align_delimiters easy_align.txt /*g:easy_align_delimiters*
+g:easy_align_ignore_groups easy_align.txt /*g:easy_align_ignore_groups*
+g:easy_align_ignore_unmatched easy_align.txt /*g:easy_align_ignore_unmatched*
+g:easy_align_indentation easy_align.txt /*g:easy_align_indentation*
+g:easy_align_interactive_modes easy_align.txt /*g:easy_align_interactive_modes*
+vim-easy-align easy_align.txt /*vim-easy-align*
diff --git a/.vim/bundle/vim-easy-align/plugin/easy_align.vim b/.vim/bundle/vim-easy-align/plugin/easy_align.vim
new file mode 100644
index 0000000..c71af4e
--- /dev/null
+++ b/.vim/bundle/vim-easy-align/plugin/easy_align.vim
@@ -0,0 +1,142 @@
+" Copyright (c) 2014 Junegunn Choi
+"
+" 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.
+
+if exists("g:loaded_easy_align_plugin")
+ finish
+endif
+let g:loaded_easy_align_plugin = 1
+
+command! -nargs=* -range -bang EasyAlign ,call easy_align#align(0, 0, 'command', )
+command! -nargs=* -range -bang LiveEasyAlign ,call easy_align#align(0, 1, 'command', )
+
+let s:last_command = 'EasyAlign'
+
+function! s:abs(v)
+ return a:v >= 0 ? a:v : - a:v
+endfunction
+
+function! s:remember_visual(mode)
+ let s:last_visual = [a:mode, s:abs(line("'>") - line("'<")), s:abs(col("'>") - col("'<"))]
+endfunction
+
+function! s:repeat_visual()
+ let [mode, ldiff, cdiff] = s:last_visual
+ let cmd = 'normal! '.mode
+ if ldiff > 0
+ let cmd .= ldiff . 'j'
+ endif
+
+ let ve_save = &virtualedit
+ try
+ if mode == "\"
+ if cdiff > 0
+ let cmd .= cdiff . 'l'
+ endif
+ set virtualedit+=block
+ endif
+ execute cmd.":\=g:easy_align_last_command\\"
+ call s:set_repeat()
+ finally
+ if ve_save != &virtualedit
+ let &virtualedit = ve_save
+ endif
+ endtry
+endfunction
+
+function! s:repeat_in_visual()
+ if exists('g:easy_align_last_command')
+ call s:remember_visual(visualmode())
+ call s:repeat_visual()
+ endif
+endfunction
+
+function! s:set_repeat()
+ silent! call repeat#set("\(EasyAlignRepeat)")
+endfunction
+
+function! s:generic_easy_align_op(type, vmode, live)
+ if !&modifiable
+ if a:vmode
+ normal! gv
+ endif
+ return
+ endif
+ let sel_save = &selection
+ let &selection = "inclusive"
+
+ if a:vmode
+ let vmode = a:type
+ let [l1, l2] = ["'<", "'>"]
+ call s:remember_visual(vmode)
+ else
+ let vmode = ''
+ let [l1, l2] = [line("'["), line("']")]
+ unlet! s:last_visual
+ endif
+
+ try
+ let range = l1.','.l2
+ if get(g:, 'easy_align_need_repeat', 0)
+ execute range . g:easy_align_last_command
+ else
+ execute range . "call easy_align#align(0, a:live, vmode, '')"
+ end
+ call s:set_repeat()
+ finally
+ let &selection = sel_save
+ endtry
+endfunction
+
+function! s:easy_align_op(type, ...)
+ call s:generic_easy_align_op(a:type, a:0, 0)
+endfunction
+
+function! s:live_easy_align_op(type, ...)
+ call s:generic_easy_align_op(a:type, a:0, 1)
+endfunction
+
+function! s:easy_align_repeat()
+ if exists('s:last_visual')
+ call s:repeat_visual()
+ else
+ try
+ let g:easy_align_need_repeat = 1
+ normal! .
+ finally
+ unlet! g:easy_align_need_repeat
+ endtry
+ endif
+endfunction
+
+nnoremap (EasyAlign) :set opfunc=easy_align_opg@
+vnoremap (EasyAlign) :call easy_align_op(visualmode(), 1)
+nnoremap (LiveEasyAlign) :set opfunc=live_easy_align_opg@
+vnoremap (LiveEasyAlign) :call live_easy_align_op(visualmode(), 1)
+
+" vim-repeat support
+nnoremap (EasyAlignRepeat) :call easy_align_repeat()
+vnoremap (EasyAlignRepeat) :call repeat_in_visual()
+
+" Backward-compatibility (deprecated)
+nnoremap (EasyAlignOperator) :set opfunc=easy_align_opg@
+
diff --git a/.vim/bundle/vim-gnupg/plugin/gnupg.vim b/.vim/bundle/vim-gnupg/plugin/gnupg.vim
new file mode 100644
index 0000000..da5768e
--- /dev/null
+++ b/.vim/bundle/vim-gnupg/plugin/gnupg.vim
@@ -0,0 +1,1459 @@
+" Name: gnupg.vim
+" Last Change: 2018 Jun 22
+" Maintainer: James McCoy
+" Original Author: Markus Braun
+" Summary: Vim plugin for transparent editing of gpg encrypted files.
+" License: This program is free software; you can redistribute it and/or
+" modify it under the terms of the GNU General Public License
+" as published by the Free Software Foundation; either version
+" 2 of the License, or (at your option) any later version.
+" See http://www.gnu.org/copyleft/gpl-2.0.txt
+"
+" Section: Documentation {{{1
+"
+" Description: {{{2
+"
+" This script implements transparent editing of gpg encrypted files. The
+" filename must have a ".gpg", ".pgp" or ".asc" suffix. When opening such
+" a file the content is decrypted, when opening a new file the script will
+" ask for the recipients of the encrypted file. The file content will be
+" encrypted to all recipients before it is written. The script turns off
+" viminfo, swapfile, and undofile to increase security.
+"
+" Installation: {{{2
+"
+" Copy the gnupg.vim file to the $HOME/.vim/plugin directory.
+" Refer to ':help add-plugin', ':help add-global-plugin' and ':help
+" runtimepath' for more details about Vim plugins.
+"
+" From "man 1 gpg-agent":
+"
+" ...
+" You should always add the following lines to your .bashrc or whatever
+" initialization file is used for all shell invocations:
+"
+" GPG_TTY=`tty`
+" export GPG_TTY
+"
+" It is important that this environment variable always reflects the out‐
+" put of the tty command. For W32 systems this option is not required.
+" ...
+"
+" Most distributions provide software to ease handling of gpg and gpg-agent.
+" Examples are keychain or seahorse.
+"
+" If there are specific actions that should take place when editing a
+" GnuPG-managed buffer, an autocmd for the User event and GnuPG pattern can
+" be defined. For example, the following will set 'textwidth' to 72 for all
+" GnuPG-encrypted buffers:
+"
+" autocmd User GnuPG setl textwidth=72
+"
+" This will be triggered before any BufRead or BufNewFile autocmds, and
+" therefore will not take precedence over settings specific to any filetype
+" that may get set.
+"
+" Commands: {{{2
+"
+" :GPGEditRecipients
+" Opens a scratch buffer to change the list of recipients. Recipients that
+" are unknown (not in your public key) are highlighted and have
+" a prepended "!". Closing the buffer makes the changes permanent.
+"
+" :GPGViewRecipients
+" Prints the list of recipients.
+"
+" :GPGEditOptions
+" Opens a scratch buffer to change the options for encryption (symmetric,
+" asymmetric, signing). Closing the buffer makes the changes permanent.
+" WARNING: There is no check of the entered options, so you need to know
+" what you are doing.
+"
+" :GPGViewOptions
+" Prints the list of options.
+"
+" Variables: {{{2
+"
+" g:GPGExecutable
+" If set used as gpg executable. If unset, defaults to
+" "gpg --trust-model always" if "gpg" is available, falling back to
+" "gpg2 --trust-model always" if not.
+"
+" g:GPGUseAgent
+" If set to 0 a possible available gpg-agent won't be used. Defaults to 1.
+"
+" g:GPGPreferSymmetric
+" If set to 1 symmetric encryption is preferred for new files. Defaults to 0.
+"
+" g:GPGPreferArmor
+" If set to 1 armored data is preferred for new files. Defaults to 0
+" unless a "*.asc" file is being edited.
+"
+" g:GPGPreferSign
+" If set to 1 signed data is preferred for new files. Defaults to 0.
+"
+" g:GPGDefaultRecipients
+" If set, these recipients are used as defaults when no other recipient is
+" defined. This variable is a Vim list. Default is unset.
+"
+" g:GPGPossibleRecipients
+" If set, these contents are loaded into the recipients dialog. This
+" allows to add commented lines with possible recipients to the list,
+" which can be uncommented to select the actual recipients. Default is
+" unset. Example:
+"
+" let g:GPGPossibleRecipients=[
+" \"Example User ",
+" \"Other User "
+" \]
+"
+"
+" g:GPGUsePipes
+" If set to 1, use pipes instead of temporary files when interacting with
+" gnupg. When set to 1, this can cause terminal-based gpg agents to not
+" display correctly when prompting for passwords. Defaults to 0.
+"
+" g:GPGHomedir
+" If set, specifies the directory that will be used for GPG's homedir.
+" This corresponds to gpg's --homedir option. This variable is a Vim
+" string. Default is unset.
+"
+" g:GPGFilePattern
+" If set, overrides the default set of file patterns that determine
+" whether this plugin will be activated. Defaults to
+" '*.\(gpg\|asc\|pgp\)'.
+"
+" Known Issues: {{{2
+"
+" In some cases gvim can't decrypt files
+
+" This is caused by the fact that a running gvim has no TTY and thus gpg is
+" not able to ask for the passphrase by itself. This is a problem for Windows
+" and Linux versions of gvim and could not be solved unless a "terminal
+" emulation" is implemented for gvim. To circumvent this you have to use any
+" combination of gpg-agent and a graphical pinentry program:
+"
+" - gpg-agent only:
+" you need to provide the passphrase for the needed key to gpg-agent
+" in a terminal before you open files with gvim which require this key.
+"
+" - pinentry only:
+" you will get a popup window every time you open a file that needs to
+" be decrypted.
+"
+" - gpgagent and pinentry:
+" you will get a popup window the first time you open a file that
+" needs to be decrypted.
+"
+" If you're using Vim <7.4.959, after the plugin runs any external command,
+" Vim will no longer be able to yank to/paste from the X clipboard or
+" primary selections. This is caused by a workaround for a different bug
+" where Vim no longer recognizes the key codes for keys such as the arrow
+" keys after running GnuPG. See the discussion at
+" https://github.com/jamessan/vim-gnupg/issues/36 for more details.
+"
+" Credits: {{{2
+"
+" - Mathieu Clabaut for inspirations through his vimspell.vim script.
+" - Richard Bronosky for patch to enable ".pgp" suffix.
+" - Erik Remmelzwaal for patch to enable windows support and patient beta
+" testing.
+" - Lars Becker for patch to make gpg2 working.
+" - Thomas Arendsen Hein for patch to convert encoding of gpg output.
+" - Karl-Heinz Ruskowski for patch to fix unknown recipients and trust model
+" and patient beta testing.
+" - Giel van Schijndel for patch to get GPG_TTY dynamically.
+" - Sebastian Luettich for patch to fix issue with symmetric encryption an set
+" recipients.
+" - Tim Swast for patch to generate signed files.
+" - James Vega for patches for better '*.asc' handling, better filename
+" escaping and better handling of multiple keyrings.
+"
+" Section: Plugin header {{{1
+
+" guard against multiple loads {{{2
+if (exists("g:loaded_gnupg") || &cp || exists("#GnuPG"))
+ finish
+endif
+let g:loaded_gnupg = '2.6.1-dev'
+let s:GPGInitRun = 0
+
+" check for correct vim version {{{2
+if (v:version < 702)
+ echohl ErrorMsg | echo 'plugin gnupg.vim requires Vim version >= 7.2' | echohl None
+ finish
+endif
+
+" Section: Autocmd setup {{{1
+
+if (!exists("g:GPGFilePattern"))
+ let g:GPGFilePattern = '*.\(gpg\|asc\|pgp\)'
+endif
+
+augroup GnuPG
+ autocmd!
+
+ " do the decryption
+ exe "autocmd BufReadCmd " . g:GPGFilePattern . " call s:GPGInit(1) |" .
+ \ " call s:GPGDecrypt(1)"
+ exe "autocmd FileReadCmd " . g:GPGFilePattern . " call s:GPGInit(0) |" .
+ \ " call s:GPGDecrypt(0)"
+
+ " convert all text to encrypted text before writing
+ " We check for GPGCorrespondingTo to avoid triggering on writes in GPG Options/Recipient windows
+ exe "autocmd BufWriteCmd,FileWriteCmd " . g:GPGFilePattern . " if !exists('b:GPGCorrespondingTo') |" .
+ \ " call s:GPGInit(0) |" .
+ \ " call s:GPGEncrypt() |" .
+ \ " endif"
+augroup END
+
+" Section: Constants {{{1
+
+let s:GPGMagicString = "\t \t"
+let s:keyPattern = '\%(0x\)\=[[:xdigit:]]\{8,16}'
+
+" Section: Highlight setup {{{1
+
+highlight default link GPGWarning WarningMsg
+highlight default link GPGError ErrorMsg
+highlight default link GPGHighlightUnknownRecipient ErrorMsg
+
+" Section: Functions {{{1
+
+" Function: s:shellescape(s[, dict]) {{{2
+"
+" Calls shellescape(), also taking into account 'shellslash'
+" when on Windows and using $COMSPEC as the shell.
+"
+" Recognized keys are:
+" special - Passed through as special argument for Vim's shellescape()
+" cygpath - When true and s:useCygpath is true, adjust the path to work with
+" Gpg4win from cygwin
+"
+" Returns: shellescaped string
+"
+function s:shellescape(s, ...)
+ let opts = a:0 ? a:1 : {}
+ let special = get(opts, 'special', 0)
+ let cygpath = get(opts, 'cygpath', 0)
+ let s = a:s
+ if cygpath && s:useCygpath
+ let s = matchstr(system('cygpath -am '.shellescape(s)), '[^\x0a\x0d]*')
+ endif
+ if exists('+shellslash') && &shell == $COMSPEC
+ let ssl = &shellslash
+ set noshellslash
+
+ let escaped = shellescape(s, special)
+
+ let &shellslash = ssl
+ else
+ let escaped = shellescape(s, special)
+ endif
+
+ return escaped
+endfunction
+
+" Function: s:unencrypted() {{{2
+"
+" Determines if the buffer corresponds to an existing, unencrypted file and,
+" if so, warns the user that GPG functionality has been disabled.
+"
+" Returns: true if current buffer corresponds to an existing, unencrypted file
+function! s:unencrypted()
+ if (exists("b:GPGEncrypted") && b:GPGEncrypted == 0)
+ echohl GPGWarning
+ echom "File is not encrypted, all GPG functions disabled!"
+ echohl None
+ return 1
+ endif
+
+ return 0
+endfunction
+
+" Function: s:GPGInit(bufread) {{{2
+"
+" initialize the plugin
+" The bufread argument specifies whether this was called due to BufReadCmd
+"
+function s:GPGInit(bufread)
+ call s:GPGDebug(3, printf(">>>>>>>> Entering s:GPGInit(%d)", a:bufread))
+
+ " For FileReadCmd, we're reading the contents into another buffer. If that
+ " buffer is also destined to be encrypted, then these settings will have
+ " already been set, otherwise don't set them since it limits the
+ " functionality of the cleartext buffer.
+ if a:bufread
+ " we don't want a swap file, as it writes unencrypted data to disk
+ setl noswapfile
+
+ " if persistent undo is present, disable it for this buffer
+ if exists('+undofile')
+ setl noundofile
+ endif
+
+ " first make sure nothing is written to ~/.viminfo while editing
+ " an encrypted file.
+ set viminfo=
+ endif
+
+ " the rest only has to be run once
+ if s:GPGInitRun
+ return
+ endif
+
+ " check what gpg command to use
+ if (!exists("g:GPGExecutable"))
+ if executable("gpg")
+ let g:GPGExecutable = "gpg --trust-model always"
+ else
+ let g:GPGExecutable = "gpg2 --trust-model always"
+ endif
+ endif
+
+ " check if gpg-agent is allowed
+ if (!exists("g:GPGUseAgent"))
+ let g:GPGUseAgent = 1
+ endif
+
+ " check if symmetric encryption is preferred
+ if (!exists("g:GPGPreferSymmetric"))
+ let g:GPGPreferSymmetric = 0
+ endif
+
+ " check if signed files are preferred
+ if (!exists("g:GPGPreferSign"))
+ let g:GPGPreferSign = 0
+ endif
+
+ " start with empty default recipients if none is defined so far
+ if (!exists("g:GPGDefaultRecipients"))
+ let g:GPGDefaultRecipients = []
+ endif
+
+ if (!exists("g:GPGPossibleRecipients"))
+ let g:GPGPossibleRecipients = []
+ endif
+
+
+ " prefer not to use pipes since it can garble gpg agent display
+ if (!exists("g:GPGUsePipes"))
+ let g:GPGUsePipes = 0
+ endif
+
+ " allow alternate gnupg homedir
+ if (!exists('g:GPGHomedir'))
+ let g:GPGHomedir = ''
+ endif
+
+ " print version
+ call s:GPGDebug(1, "gnupg.vim ". g:loaded_gnupg)
+
+ let s:GPGCommand = g:GPGExecutable
+
+ " don't use tty in gvim except for windows: we get their a tty for free.
+ " FIXME find a better way to avoid an error.
+ " with this solution only --use-agent will work
+ if (has("gui_running") && !has("gui_win32"))
+ let s:GPGCommand .= " --no-tty"
+ endif
+
+ " setup shell environment for unix and windows
+ let s:shellredirsave = &shellredir
+ let s:shellsave = &shell
+ let s:shelltempsave = &shelltemp
+ " noshelltemp isn't currently supported on Windows, but it doesn't cause any
+ " errors and this future proofs us against requiring changes if Windows
+ " gains noshelltemp functionality
+ let s:shelltemp = !g:GPGUsePipes
+ if (has("unix"))
+ " unix specific settings
+ let s:shellredir = ">%s 2>&1"
+ let s:shell = '/bin/sh'
+ let s:stderrredirnull = '2>/dev/null'
+ else
+ " windows specific settings
+ let s:shellredir = '>%s'
+ let s:shell = &shell
+ let s:stderrredirnull = '2>nul'
+ endif
+
+ call s:GPGDebug(3, "shellredirsave: " . s:shellredirsave)
+ call s:GPGDebug(3, "shellsave: " . s:shellsave)
+ call s:GPGDebug(3, "shelltempsave: " . s:shelltempsave)
+
+ call s:GPGDebug(3, "shell: " . s:shell)
+ call s:GPGDebug(3, "shellcmdflag: " . &shellcmdflag)
+ call s:GPGDebug(3, "shellxquote: " . &shellxquote)
+ call s:GPGDebug(3, "shellredir: " . s:shellredir)
+ call s:GPGDebug(3, "stderrredirnull: " . s:stderrredirnull)
+
+ call s:GPGDebug(3, "shell implementation: " . resolve(s:shell))
+
+ " find the supported algorithms
+ let output = s:GPGSystem({ 'level': 2, 'args': '--version' })
+
+ let gpgversion = substitute(output, '^gpg (GnuPG) \([0-9]\+\.\d\+\).*', '\1', '')
+ let s:GPGPubkey = substitute(output, ".*Pubkey: \\(.\\{-}\\)\n.*", "\\1", "")
+ let s:GPGCipher = substitute(output, ".*Cipher: \\(.\\{-}\\)\n.*", "\\1", "")
+ let s:GPGHash = substitute(output, ".*Hash: \\(.\\{-}\\)\n.*", "\\1", "")
+ let s:GPGCompress = substitute(output, ".*Compress.\\{-}: \\(.\\{-}\\)\n.*", "\\1", "")
+ let s:GPGHome = matchstr(output, '.*Home: \zs.\{-}\ze\r\=\n')
+
+ let s:useCygpath = 0
+ if has('win32unix') && s:GPGHome =~ '\a:[/\\]'
+ call s:GPGDebug(1, 'Enabling use of cygpath')
+ let s:useCygpath = 1
+ endif
+
+ " determine if gnupg can use the gpg-agent
+ if (str2float(gpgversion) >= 2.1 || (exists("$GPG_AGENT_INFO") && g:GPGUseAgent == 1))
+ if (!exists("$GPG_TTY") && !has("gui_running"))
+ " Need to determine the associated tty by running a command in the
+ " shell. We can't use system() here because that doesn't run in a shell
+ " connected to a tty, so it's rather useless.
+ "
+ " Save/restore &modified so the buffer isn't incorrectly marked as
+ " modified just by detecting the correct tty value.
+ " Do the &undolevels dance so the :read and :delete don't get added into
+ " the undo tree, as the user needn't be aware of these.
+ let [mod, levels] = [&l:modified, &undolevels]
+ set undolevels=-1
+ silent read !tty
+ let $GPG_TTY = getline('.')
+ silent delete
+ let [&l:modified, &undolevels] = [mod, levels]
+ " redraw is needed since we're using silent to run !tty, c.f. :help :!
+ redraw!
+ if (v:shell_error)
+ let $GPG_TTY = ""
+ echohl GPGWarning
+ echom "$GPG_TTY is not set and the `tty` command failed! gpg-agent might not work."
+ echohl None
+ endif
+ endif
+ let s:GPGCommand .= " --use-agent"
+ else
+ let s:GPGCommand .= " --no-use-agent"
+ endif
+
+ call s:GPGDebug(2, "public key algorithms: " . s:GPGPubkey)
+ call s:GPGDebug(2, "cipher algorithms: " . s:GPGCipher)
+ call s:GPGDebug(2, "hashing algorithms: " . s:GPGHash)
+ call s:GPGDebug(2, "compression algorithms: " . s:GPGCompress)
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGInit()")
+ let s:GPGInitRun = 1
+endfunction
+
+
+" Function: s:GPGDecrypt(bufread) {{{2
+"
+" decrypt the buffer and find all recipients of the encrypted file
+" The bufread argument specifies whether this was called due to BufReadCmd
+"
+function s:GPGDecrypt(bufread)
+ call s:GPGDebug(3, printf(">>>>>>>> Entering s:GPGDecrypt(%d)", a:bufread))
+
+ " get the filename of the current buffer
+ let filename = resolve(expand(":p"))
+
+ " clear GPGRecipients and GPGOptions
+ if type(g:GPGDefaultRecipients) == type([])
+ let b:GPGRecipients = copy(g:GPGDefaultRecipients)
+ else
+ let b:GPGRecipients = []
+ echohl GPGWarning
+ echom "g:GPGDefaultRecipients is not a Vim list, please correct this in your vimrc!"
+ echohl None
+ endif
+ let b:GPGOptions = []
+
+ " file name minus extension
+ let autocmd_filename = fnamemodify(filename, ':r')
+
+ " File doesn't exist yet, so nothing to decrypt
+ if !filereadable(filename)
+ if !a:bufread
+ redraw!
+ echohl GPGError
+ echom "E484: Can't open file" filename
+ echohl None
+ return
+ endif
+
+ " Allow the user to define actions for GnuPG buffers
+ silent doautocmd User GnuPG
+ silent execute ':doautocmd BufNewFile ' . fnameescape(autocmd_filename)
+ call s:GPGDebug(2, 'called BufNewFile autocommand for ' . autocmd_filename)
+
+ set buftype=acwrite
+ " Remove the buffer name ...
+ silent 0file
+ " ... so we can force it to be absolute
+ exe 'silent file' fnameescape(filename)
+
+ " This is a new file, so force the user to edit the recipient list if
+ " they open a new file and public keys are preferred
+ if (g:GPGPreferSymmetric == 0)
+ call s:GPGEditRecipients()
+ endif
+
+ return
+ endif
+
+ " Only let this if the file actually exists, otherwise GPG functionality
+ " will be disabled when editing a buffer that doesn't yet have a backing
+ " file
+ let b:GPGEncrypted = 0
+
+ " find the recipients of the file
+ let cmd = { 'level': 3 }
+ let cmd.args = '--verbose --decrypt --list-only --dry-run --no-use-agent --logger-fd 1 ' . s:shellescape(filename, { 'cygpath': 1 })
+ let output = s:GPGSystem(cmd)
+
+ " Suppress the "N more lines" message when editing a file, not when reading
+ " the contents of a file into a buffer
+ let silent = a:bufread ? 'silent ' : ''
+
+ let asymmPattern = 'gpg: public key is ' . s:keyPattern
+ " check if the file is symmetric/asymmetric encrypted
+ if (match(output, "gpg: encrypted with [[:digit:]]\\+ passphrase") >= 0)
+ " file is symmetric encrypted
+ let b:GPGEncrypted = 1
+ call s:GPGDebug(1, "this file is symmetric encrypted")
+
+ let b:GPGOptions += ["symmetric"]
+
+ " find the used cipher algorithm
+ let cipher = substitute(output, ".*gpg: \\([^ ]\\+\\) encrypted data.*", "\\1", "")
+ if (match(s:GPGCipher, "\\<" . cipher . "\\>") >= 0)
+ let b:GPGOptions += ["cipher-algo " . cipher]
+ call s:GPGDebug(1, "cipher-algo is " . cipher)
+ else
+ echohl GPGWarning
+ echom "The cipher " . cipher . " is not known by the local gpg command. Using default!"
+ echo
+ echohl None
+ endif
+ elseif (match(output, asymmPattern) >= 0)
+ " file is asymmetric encrypted
+ let b:GPGEncrypted = 1
+ call s:GPGDebug(1, "this file is asymmetric encrypted")
+
+ let b:GPGOptions += ["encrypt"]
+
+ " find the used public keys
+ let start = match(output, asymmPattern)
+ while (start >= 0)
+ let start = start + strlen("gpg: public key is ")
+ let recipient = matchstr(output, s:keyPattern, start)
+ call s:GPGDebug(1, "recipient is " . recipient)
+ " In order to support anonymous communication, GnuPG allows eliding
+ " information in the encryption metadata specifying what keys the file
+ " was encrypted to (c.f., --throw-keyids and --hidden-recipient). In
+ " that case, the recipient(s) will be listed as having used a key of all
+ " zeroes.
+ " Since this will obviously never actually be in a keyring, only try to
+ " convert to an ID or add to the recipients list if it's not a hidden
+ " recipient.
+ if recipient !~? '^0x0\+$'
+ let name = s:GPGNameToID(recipient)
+ if !empty(name)
+ let b:GPGRecipients += [name]
+ call s:GPGDebug(1, "name of recipient is " . name)
+ else
+ let b:GPGRecipients += [recipient]
+ echohl GPGWarning
+ echom "The recipient \"" . recipient . "\" is not in your public keyring!"
+ echohl None
+ end
+ end
+ let start = match(output, asymmPattern, start)
+ endwhile
+ else
+ " file is not encrypted
+ let b:GPGEncrypted = 0
+ call s:GPGDebug(1, "this file is not encrypted")
+ echohl GPGWarning
+ echom "File is not encrypted, all GPG functions disabled!"
+ echohl None
+ endif
+
+ let bufname = b:GPGEncrypted ? autocmd_filename : filename
+ if a:bufread
+ silent execute ':doautocmd BufReadPre ' . fnameescape(bufname)
+ call s:GPGDebug(2, 'called BufReadPre autocommand for ' . bufname)
+ else
+ silent execute ':doautocmd FileReadPre ' . fnameescape(bufname)
+ call s:GPGDebug(2, 'called FileReadPre autocommand for ' . bufname)
+ endif
+
+ if b:GPGEncrypted
+ " check if the message is armored
+ if (match(output, "gpg: armor header") >= 0)
+ call s:GPGDebug(1, "this file is armored")
+ let b:GPGOptions += ["armor"]
+ endif
+
+ " finally decrypt the buffer content
+ " since even with the --quiet option passphrase typos will be reported,
+ " we must redirect stderr (using shell temporarily)
+ call s:GPGDebug(1, "decrypting file")
+ let cmd = { 'level': 1, 'ex': silent . 'read ++edit !' }
+ let cmd.args = '--quiet --decrypt ' . s:shellescape(filename, { 'special': 1, 'cygpath': 1 })
+ call s:GPGExecute(cmd)
+
+ if (v:shell_error) " message could not be decrypted
+ echohl GPGError
+ let blackhole = input("Message could not be decrypted! (Press ENTER)")
+ echohl None
+ " Only wipeout the buffer if we were creating one to start with.
+ " FileReadCmd just reads the content into the existing buffer
+ if a:bufread
+ silent bwipeout!
+ endif
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()")
+ return
+ endif
+ if a:bufread
+ " Ensure the buffer is only saved by using our BufWriteCmd
+ set buftype=acwrite
+ " Always set the buffer name to the absolute path, otherwise Vim won't
+ " track the correct buffer name when changing directories (due to
+ " buftype=acwrite).
+ exe 'file' fnameescape(filename)
+ endif
+ else
+ execute silent 'read' fnameescape(filename)
+ endif
+
+ if a:bufread
+ " In order to make :undo a no-op immediately after the buffer is read,
+ " we need to do this dance with 'undolevels'. Actually discarding the undo
+ " history requires performing a change after setting 'undolevels' to -1 and,
+ " luckily, we have one we need to do (delete the extra line from the :r
+ " command)
+ let levels = &undolevels
+ set undolevels=-1
+ " :lockmarks doesn't actually prevent '[,'] from being overwritten, so we
+ " need to manually set them ourselves instead
+ silent 1delete
+ 1mark [
+ $mark ]
+ let &undolevels = levels
+ " The buffer should be readonly if
+ " - 'readonly' is already set (e.g., when using view/vim -R)
+ " - permissions don't allow writing
+ let &readonly = &readonly || (filereadable(filename) && filewritable(filename) == 0)
+ silent execute ':doautocmd BufReadPost ' . fnameescape(bufname)
+ call s:GPGDebug(2, 'called BufReadPost autocommand for ' . bufname)
+ else
+ silent execute ':doautocmd FileReadPost ' . fnameescape(bufname)
+ call s:GPGDebug(2, 'called FileReadPost autocommand for ' . bufname)
+ endif
+
+ if b:GPGEncrypted
+ " Allow the user to define actions for GnuPG buffers
+ silent doautocmd User GnuPG
+
+ " refresh screen
+ redraw!
+ endif
+
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGDecrypt()")
+endfunction
+
+" Function: s:GPGEncrypt() {{{2
+"
+" encrypts the buffer to all previous recipients
+"
+function s:GPGEncrypt()
+ call s:GPGDebug(3, ">>>>>>>> Entering s:GPGEncrypt()")
+
+ " FileWriteCmd is only called when a portion of a buffer is being written to
+ " disk. Since Vim always sets the '[,'] marks to the part of a buffer that
+ " is being written, that can be used to determine whether BufWriteCmd or
+ " FileWriteCmd triggered us.
+ if [line("'["), line("']")] == [1, line('$')]
+ let auType = 'BufWrite'
+ else
+ let auType = 'FileWrite'
+ endif
+
+ " file name minus extension
+ let autocmd_filename = expand(':p:r')
+
+ silent exe ':doautocmd '. auType .'Pre '. fnameescape(autocmd_filename)
+ call s:GPGDebug(2, 'called '. auType .'Pre autocommand for ' . autocmd_filename)
+
+ " guard for unencrypted files
+ if (exists("b:GPGEncrypted") && b:GPGEncrypted == 0)
+ echohl GPGError
+ let blackhole = input("Message could not be encrypted! (Press ENTER)")
+ echohl None
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()")
+ return
+ endif
+
+ let filename = resolve(expand(':p'))
+ " initialize GPGOptions if not happened before
+ if (!exists("b:GPGOptions") || empty(b:GPGOptions))
+ let b:GPGOptions = []
+ if (exists("g:GPGPreferSymmetric") && g:GPGPreferSymmetric == 1)
+ let b:GPGOptions += ["symmetric"]
+ let b:GPGRecipients = []
+ else
+ let b:GPGOptions += ["encrypt"]
+ endif
+ " Fallback to preference by filename if the user didn't indicate
+ " their preference.
+ let preferArmor = get(g:, 'GPGPreferArmor', -1)
+ if (preferArmor >= 0 && preferArmor) || filename =~ '\.asc$'
+ let b:GPGOptions += ["armor"]
+ endif
+ if (exists("g:GPGPreferSign") && g:GPGPreferSign == 1)
+ let b:GPGOptions += ["sign"]
+ endif
+ call s:GPGDebug(1, "no options set, so using default options: " . string(b:GPGOptions))
+ endif
+
+ " built list of options
+ let options = ""
+ for option in b:GPGOptions
+ let options = options . " --" . option . " "
+ endfor
+
+ if (!exists('b:GPGRecipients'))
+ let b:GPGRecipients = []
+ endif
+
+ " check here again if all recipients are available in the keyring
+ let recipients = s:GPGCheckRecipients(b:GPGRecipients)
+
+ " check if there are unknown recipients and warn
+ if !empty(recipients.unknown)
+ echohl GPGWarning
+ echom "Please use GPGEditRecipients to correct!!"
+ echo
+ echohl None
+
+ " Let user know whats happend and copy known_recipients back to buffer
+ let dummy = input("Press ENTER to quit")
+ endif
+
+ " built list of recipients
+ let options .= ' ' . join(map(recipients.valid, '"-r ".v:val'), ' ')
+
+ " encrypt the buffer
+ let destfile = tempname()
+ let cmd = { 'level': 1, 'ex': "'[,']write !" }
+ let cmd.args = '--quiet --no-encrypt-to ' . options
+ let cmd.redirect = '>' . s:shellescape(destfile, { 'special': 1, 'cygpath': 1 })
+ silent call s:GPGExecute(cmd)
+
+ if (v:shell_error) " message could not be encrypted
+ " Command failed, so clean up the tempfile
+ call delete(destfile)
+ echohl GPGError
+ let blackhole = input("Message could not be encrypted! (Press ENTER)")
+ echohl None
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()")
+ return
+ endif
+
+ if rename(destfile, filename)
+ " Rename failed, so clean up the tempfile
+ call delete(destfile)
+ echohl GPGError
+ echom printf("\"%s\" E212: Can't open file for writing", filename)
+ echohl None
+ return
+ endif
+
+ if auType == 'BufWrite'
+ if expand('%:p') == filename
+ setl nomodified
+ endif
+ setl buftype=acwrite
+ let &readonly = filereadable(filename) && filewritable(filename) == 0
+ endif
+
+ silent exe ':doautocmd '. auType .'Post '. fnameescape(autocmd_filename)
+ call s:GPGDebug(2, 'called '. auType .'Post autocommand for ' . autocmd_filename)
+
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEncrypt()")
+endfunction
+
+" Function: s:GPGViewRecipients() {{{2
+"
+" echo the recipients
+"
+function s:GPGViewRecipients()
+ call s:GPGDebug(3, ">>>>>>>> Entering s:GPGViewRecipients()")
+
+ " guard for unencrypted files
+ if (exists("b:GPGEncrypted") && b:GPGEncrypted == 0)
+ echohl GPGWarning
+ echom "File is not encrypted, all GPG functions disabled!"
+ echohl None
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGViewRecipients()")
+ return
+ endif
+
+ let recipients = s:GPGCheckRecipients(b:GPGRecipients)
+
+ echo 'This file has following recipients (Unknown recipients have a prepended "!"):'
+ if empty(recipients.valid)
+ echohl GPGError
+ echo 'There are no known recipients!'
+ echohl None
+ else
+ echo join(map(recipients.valid, 's:GPGIDToName(v:val)'), "\n")
+ endif
+
+ if !empty(recipients.unknown)
+ echohl GPGWarning
+ echo join(map(recipients.unknown, '"!".v:val'), "\n")
+ echohl None
+ endif
+
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGViewRecipients()")
+endfunction
+
+" Function: s:GPGEditRecipients() {{{2
+"
+" create a scratch buffer with all recipients to add/remove recipients
+"
+function s:GPGEditRecipients()
+ call s:GPGDebug(3, ">>>>>>>> Entering s:GPGEditRecipients()")
+
+ if s:unencrypted()
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEditRecipients()")
+ return
+ endif
+
+ " only do this if it isn't already a GPGRecipients_* buffer
+ if (!exists('b:GPGCorrespondingTo'))
+
+ " save buffer name
+ let buffername = bufnr("%")
+ let editbuffername = "GPGRecipients_" . buffername
+
+ " check if this buffer exists
+ if (!bufexists(editbuffername))
+ " create scratch buffer
+ execute 'silent! split ' . fnameescape(editbuffername)
+
+ " add a autocommand to regenerate the recipients after a write
+ autocmd BufHidden,BufUnload,BufWriteCmd call s:GPGFinishRecipientsBuffer()
+ else
+ if (bufwinnr(editbuffername) >= 0)
+ " switch to scratch buffer window
+ execute 'silent! ' . bufwinnr(editbuffername) . "wincmd w"
+ else
+ " split scratch buffer window
+ execute 'silent! sbuffer ' . fnameescape(editbuffername)
+
+ " add a autocommand to regenerate the recipients after a write
+ autocmd BufHidden,BufUnload,BufWriteCmd call s:GPGFinishRecipientsBuffer()
+ endif
+
+ " empty the buffer
+ silent %delete
+ endif
+
+ " Mark the buffer as a scratch buffer
+ setlocal buftype=acwrite
+ setlocal bufhidden=hide
+ setlocal noswapfile
+ setlocal nowrap
+ setlocal nobuflisted
+ setlocal nonumber
+
+ " so we know for which other buffer this edit buffer is
+ let b:GPGCorrespondingTo = buffername
+
+ " put some comments to the scratch buffer
+ silent put ='GPG: ----------------------------------------------------------------------'
+ silent put ='GPG: Please edit the list of recipients, one recipient per line.'
+ silent put ='GPG: Unknown recipients have a prepended \"!\".'
+ silent put ='GPG: Lines beginning with \"GPG:\" are removed automatically.'
+ silent put ='GPG: Data after recipients between and including \"(\" and \")\" is ignored.'
+ silent put ='GPG: Closing this buffer commits changes.'
+ silent put ='GPG: ----------------------------------------------------------------------'
+
+ " get the recipients
+ let recipients = s:GPGCheckRecipients(getbufvar(b:GPGCorrespondingTo, "GPGRecipients"))
+
+ " if there are no known or unknown recipients, use the default ones
+ if (empty(recipients.valid) && empty(recipients.unknown))
+ if (type(g:GPGDefaultRecipients) == type([]))
+ let recipients = s:GPGCheckRecipients(g:GPGDefaultRecipients)
+ else
+ echohl GPGWarning
+ echom "g:GPGDefaultRecipients is not a Vim list, please correct this in your vimrc!"
+ echohl None
+ endif
+ endif
+
+ " put the recipients in the scratch buffer
+ for name in recipients.valid
+ let name = s:GPGIDToName(name)
+ silent put =name
+ endfor
+
+ " put the unknown recipients in the scratch buffer
+ let syntaxPattern = ''
+ if !empty(recipients.unknown)
+ let flaggedNames = map(recipients.unknown, '"!".v:val')
+ call append('$', flaggedNames)
+ let syntaxPattern = '\(' . join(flaggedNames, '\|') . '\)'
+ endif
+
+ for line in g:GPGPossibleRecipients
+ silent put ='GPG: '.line
+ endfor
+
+ " define highlight
+ if (has("syntax") && exists("g:syntax_on"))
+ highlight clear GPGUnknownRecipient
+ if !empty(syntaxPattern)
+ execute 'syntax match GPGUnknownRecipient "' . syntaxPattern . '"'
+ highlight link GPGUnknownRecipient GPGHighlightUnknownRecipient
+ endif
+
+ syntax match GPGComment "^GPG:.*$"
+ execute 'syntax match GPGComment "' . s:GPGMagicString . '.*$"'
+ highlight clear GPGComment
+ highlight link GPGComment Comment
+ endif
+
+ " delete the empty first line
+ silent 1delete
+
+ " jump to the first recipient
+ silent $
+
+ endif
+
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEditRecipients()")
+endfunction
+
+" Function: s:GPGFinishRecipientsBuffer() {{{2
+"
+" create a new recipient list from RecipientsBuffer
+"
+function s:GPGFinishRecipientsBuffer()
+ call s:GPGDebug(3, ">>>>>>>> Entering s:GPGFinishRecipientsBuffer()")
+
+ if s:unencrypted()
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGFinishRecipientsBuffer()")
+ return
+ endif
+
+ " go to buffer before doing work
+ if (bufnr("%") != expand(""))
+ " switch to scratch buffer window
+ execute 'silent! ' . bufwinnr(expand(":p")) . "wincmd w"
+ endif
+
+ " delete the autocommand
+ autocmd! *
+
+ " get the recipients from the scratch buffer
+ let recipients = []
+ let lines = getline(1,"$")
+ for recipient in lines
+ let matches = matchlist(recipient, '^\(.\{-}\)\%(' . s:GPGMagicString . '(ID:\s\+\(' . s:keyPattern . '\)\s\+.*\)\=$')
+
+ let recipient = matches[2] ? matches[2] : matches[1]
+
+ " delete all spaces at beginning and end of the recipient
+ " also delete a '!' at the beginning of the recipient
+ let recipient = substitute(recipient, "^[[:space:]!]*\\(.\\{-}\\)[[:space:]]*$", "\\1", "")
+
+ " delete comment lines
+ let recipient = substitute(recipient, "^GPG:.*$", "", "")
+
+ " only do this if the line is not empty
+ if !empty(recipient)
+ let gpgid = s:GPGNameToID(recipient)
+ if !empty(gpgid)
+ if (match(recipients, gpgid) < 0)
+ let recipients += [gpgid]
+ endif
+ else
+ if (match(recipients, recipient) < 0)
+ let recipients += [recipient]
+ echohl GPGWarning
+ echom "The recipient \"" . recipient . "\" is not in your public keyring!"
+ echohl None
+ endif
+ endif
+ endif
+ endfor
+
+ " write back the new recipient list to the corresponding buffer and mark it
+ " as modified. Buffer is now for sure an encrypted buffer.
+ call setbufvar(b:GPGCorrespondingTo, "GPGRecipients", recipients)
+ call setbufvar(b:GPGCorrespondingTo, "&mod", 1)
+ call setbufvar(b:GPGCorrespondingTo, "GPGEncrypted", 1)
+
+ " check if there is any known recipient
+ if empty(recipients)
+ echohl GPGError
+ echom 'There are no known recipients!'
+ echohl None
+ endif
+
+ " reset modified flag
+ setl nomodified
+
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGFinishRecipientsBuffer()")
+endfunction
+
+" Function: s:GPGViewOptions() {{{2
+"
+" echo the recipients
+"
+function s:GPGViewOptions()
+ call s:GPGDebug(3, ">>>>>>>> Entering s:GPGViewOptions()")
+
+ if s:unencrypted()
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGViewOptions()")
+ return
+ endif
+
+ if (exists("b:GPGOptions"))
+ echo 'This file has following options:'
+ echo join(b:GPGOptions, "\n")
+ endif
+
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGViewOptions()")
+endfunction
+
+" Function: s:GPGEditOptions() {{{2
+"
+" create a scratch buffer with all recipients to add/remove recipients
+"
+function s:GPGEditOptions()
+ call s:GPGDebug(3, ">>>>>>>> Entering s:GPGEditOptions()")
+
+ if s:unencrypted()
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEditOptions()")
+ return
+ endif
+
+ " only do this if it isn't already a GPGOptions_* buffer
+ if (!exists('b:GPGCorrespondingTo'))
+
+ " save buffer name
+ let buffername = bufnr("%")
+ let editbuffername = "GPGOptions_" . buffername
+
+ " check if this buffer exists
+ if (!bufexists(editbuffername))
+ " create scratch buffer
+ execute 'silent! split ' . fnameescape(editbuffername)
+
+ " add a autocommand to regenerate the options after a write
+ autocmd BufHidden,BufUnload,BufWriteCmd call s:GPGFinishOptionsBuffer()
+ else
+ if (bufwinnr(editbuffername) >= 0)
+ " switch to scratch buffer window
+ execute 'silent! ' . bufwinnr(editbuffername) . "wincmd w"
+ else
+ " split scratch buffer window
+ execute 'silent! sbuffer ' . fnameescape(editbuffername)
+
+ " add a autocommand to regenerate the options after a write
+ autocmd BufHidden,BufUnload,BufWriteCmd call s:GPGFinishOptionsBuffer()
+ endif
+
+ " empty the buffer
+ silent %delete
+ endif
+
+ " Mark the buffer as a scratch buffer
+ setlocal buftype=nofile
+ setlocal noswapfile
+ setlocal nowrap
+ setlocal nobuflisted
+ setlocal nonumber
+
+ " so we know for which other buffer this edit buffer is
+ let b:GPGCorrespondingTo = buffername
+
+ " put some comments to the scratch buffer
+ silent put ='GPG: ----------------------------------------------------------------------'
+ silent put ='GPG: THERE IS NO CHECK OF THE ENTERED OPTIONS!'
+ silent put ='GPG: YOU NEED TO KNOW WHAT YOU ARE DOING!'
+ silent put ='GPG: IF IN DOUBT, QUICKLY EXIT USING :x OR :bd.'
+ silent put ='GPG: Please edit the list of options, one option per line.'
+ silent put ='GPG: Please refer to the gpg documentation for valid options.'
+ silent put ='GPG: Lines beginning with \"GPG:\" are removed automatically.'
+ silent put ='GPG: Closing this buffer commits changes.'
+ silent put ='GPG: ----------------------------------------------------------------------'
+
+ " put the options in the scratch buffer
+ let options = getbufvar(b:GPGCorrespondingTo, "GPGOptions")
+
+ for option in options
+ silent put =option
+ endfor
+
+ " delete the empty first line
+ silent 1delete
+
+ " jump to the first option
+ silent $
+
+ " define highlight
+ if (has("syntax") && exists("g:syntax_on"))
+ syntax match GPGComment "^GPG:.*$"
+ highlight clear GPGComment
+ highlight link GPGComment Comment
+ endif
+ endif
+
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGEditOptions()")
+endfunction
+
+" Function: s:GPGFinishOptionsBuffer() {{{2
+"
+" create a new option list from OptionsBuffer
+"
+function s:GPGFinishOptionsBuffer()
+ call s:GPGDebug(3, ">>>>>>>> Entering s:GPGFinishOptionsBuffer()")
+
+ if s:unencrypted()
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGFinishOptionsBuffer()")
+ return
+ endif
+
+ " go to buffer before doing work
+ if (bufnr("%") != expand(""))
+ " switch to scratch buffer window
+ execute 'silent! ' . bufwinnr(expand(":p")) . "wincmd w"
+ endif
+
+ " clear options and unknownOptions
+ let options = []
+ let unknownOptions = []
+
+ " delete the autocommand
+ autocmd! *
+
+ " get the options from the scratch buffer
+ let lines = getline(1, "$")
+ for option in lines
+ " delete all spaces at beginning and end of the option
+ " also delete a '!' at the beginning of the option
+ let option = substitute(option, "^[[:space:]!]*\\(.\\{-}\\)[[:space:]]*$", "\\1", "")
+ " delete comment lines
+ let option = substitute(option, "^GPG:.*$", "", "")
+
+ " only do this if the line is not empty
+ if (!empty(option) && match(options, option) < 0)
+ let options += [option]
+ endif
+ endfor
+
+ " write back the new option list to the corresponding buffer and mark it
+ " as modified
+ call setbufvar(b:GPGCorrespondingTo, "GPGOptions", options)
+ call setbufvar(b:GPGCorrespondingTo, "&mod", 1)
+
+ " reset modified flag
+ setl nomodified
+
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGFinishOptionsBuffer()")
+endfunction
+
+" Function: s:GPGCheckRecipients(tocheck) {{{2
+"
+" check if recipients are known
+" Returns: dictionary of recipients, {'valid': [], 'unknown': []}
+"
+function s:GPGCheckRecipients(tocheck)
+ call s:GPGDebug(3, ">>>>>>>> Entering s:GPGCheckRecipients()")
+
+ let recipients = {'valid': [], 'unknown': []}
+
+ if (type(a:tocheck) == type([]))
+ for recipient in a:tocheck
+ let gpgid = s:GPGNameToID(recipient)
+ if !empty(gpgid)
+ if (match(recipients.valid, gpgid) < 0)
+ call add(recipients.valid, gpgid)
+ endif
+ else
+ if (match(recipients.unknown, recipient) < 0)
+ call add(recipients.unknown, recipient)
+ echohl GPGWarning
+ echom "The recipient \"" . recipient . "\" is not in your public keyring!"
+ echohl None
+ endif
+ end
+ endfor
+ endif
+
+ call s:GPGDebug(2, "recipients are: " . string(recipients.valid))
+ call s:GPGDebug(2, "unknown recipients are: " . string(recipients.unknown))
+
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGCheckRecipients()")
+ return recipients
+endfunction
+
+" Function: s:GPGNameToID(name) {{{2
+"
+" find GPG key ID corresponding to a name
+" Returns: ID for the given name
+"
+function s:GPGNameToID(name)
+ call s:GPGDebug(3, ">>>>>>>> Entering s:GPGNameToID()")
+
+ " ask gpg for the id for a name
+ let cmd = { 'level': 2 }
+ let cmd.args = '--quiet --with-colons --fixed-list-mode --list-keys ' . s:shellescape(a:name)
+ let output = s:GPGSystem(cmd)
+
+ " when called with "--with-colons" gpg encodes its output _ALWAYS_ as UTF-8,
+ " so convert it, if necessary
+ if (&encoding != "utf-8")
+ let output = iconv(output, "utf-8", &encoding)
+ endif
+ let lines = split(output, "\n")
+
+ " parse the output of gpg
+ let pubseen = 0
+ let counter = 0
+ let gpgids = []
+ let seen_keys = {}
+ let skip_key = 0
+ let has_strftime = exists('*strftime')
+ let choices = "The name \"" . a:name . "\" is ambiguous. Please select the correct key:\n"
+ for line in lines
+
+ let fields = split(line, ":")
+
+ " search for the next pub
+ if (fields[0] == "pub")
+ " check if this key has already been processed
+ if has_key(seen_keys, fields[4])
+ let skip_key = 1
+ continue
+ endif
+ let skip_key = 0
+ let seen_keys[fields[4]] = 1
+
+ " Ignore keys which are not usable for encryption
+ if fields[11] !~? 'e'
+ continue
+ endif
+
+ let identity = fields[4]
+ let gpgids += [identity]
+ if has_strftime
+ let choices = choices . counter . ": ID: 0x" . identity . " created at " . strftime("%c", fields[5]) . "\n"
+ else
+ let choices = choices . counter . ": ID: 0x" . identity . "\n"
+ endif
+ let counter = counter+1
+ let pubseen = 1
+ " search for the next uid
+ elseif (!skip_key && fields[0] == "uid")
+ let choices = choices . " " . fields[9] . "\n"
+ endif
+
+ endfor
+
+ " counter > 1 means we have more than one results
+ let answer = 0
+ if (counter > 1)
+ let choices = choices . "Enter number: "
+ let answer = input(choices, "0")
+ while (answer == "")
+ let answer = input("Enter number: ", "0")
+ endwhile
+ endif
+
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGNameToID()")
+ return get(gpgids, answer, "")
+endfunction
+
+" Function: s:GPGIDToName(identity) {{{2
+"
+" find name corresponding to a GPG key ID
+" Returns: Name for the given ID
+"
+function s:GPGIDToName(identity)
+ call s:GPGDebug(3, ">>>>>>>> Entering s:GPGIDToName()")
+
+ " TODO is the encryption subkey really unique?
+
+ " ask gpg for the id for a name
+ let cmd = { 'level': 2 }
+ let cmd.args = '--quiet --with-colons --fixed-list-mode --list-keys ' . a:identity
+ let output = s:GPGSystem(cmd)
+
+ " when called with "--with-colons" gpg encodes its output _ALWAYS_ as UTF-8,
+ " so convert it, if necessary
+ if (&encoding != "utf-8")
+ let output = iconv(output, "utf-8", &encoding)
+ endif
+ let lines = split(output, "\n")
+
+ " parse the output of gpg
+ let pubseen = 0
+ let uid = ""
+ for line in lines
+ let fields = split(line, ":")
+
+ if !pubseen " search for the next pub
+ if (fields[0] == "pub")
+ " Ignore keys which are not usable for encryption
+ if fields[11] !~? 'e'
+ continue
+ endif
+
+ let pubseen = 1
+ endif
+ else " search for the next uid
+ if (fields[0] == "uid")
+ let pubseen = 0
+ if exists("*strftime")
+ let uid = fields[9] . s:GPGMagicString . "(ID: 0x" . a:identity . " created at " . strftime("%c", fields[5]) . ")"
+ else
+ let uid = fields[9] . s:GPGMagicString . "(ID: 0x" . a:identity . ")"
+ endif
+ break
+ endif
+ endif
+ endfor
+
+ call s:GPGDebug(3, "<<<<<<<< Leaving s:GPGIDToName()")
+ return uid
+endfunction
+
+" Function: s:GPGPreCmd() {{{2
+"
+" Setup the environment for running the gpg command
+"
+function s:GPGPreCmd()
+ let &shellredir = s:shellredir
+ let &shell = s:shell
+ let &shelltemp = s:shelltemp
+ " Force C locale so GPG output is consistent
+ let s:messages = v:lang
+ language messages C
+endfunction
+
+
+" Function: s:GPGPostCmd() {{{2
+"
+" Restore the user's environment after running the gpg command
+"
+function s:GPGPostCmd()
+ let &shellredir = s:shellredirsave
+ let &shell = s:shellsave
+ let &shelltemp = s:shelltempsave
+ execute 'language messages' s:messages
+ " Workaround a bug in the interaction between console vim and
+ " pinentry-curses by forcing Vim to re-detect and setup its terminal
+ " settings
+ let &term = &term
+ silent doautocmd TermChanged
+endfunction
+
+" Function: s:GPGSystem(dict) {{{2
+"
+" run g:GPGCommand using system(), logging the commandline and output. This
+" uses temp files (regardless of how 'shelltemp' is set) to hold the output of
+" the command, so it must not be used for sensitive commands.
+" Recognized keys are:
+" level - Debug level at which the commandline and output will be logged
+" args - Arguments to be given to g:GPGCommand
+"
+" Returns: command output
+"
+function s:GPGSystem(dict)
+ let commandline = s:GPGCommand
+ if (!empty(g:GPGHomedir))
+ let commandline .= ' --homedir ' . s:shellescape(g:GPGHomedir, { 'cygpath': 1 })
+ endif
+ let commandline .= ' ' . a:dict.args
+ let commandline .= ' ' . s:stderrredirnull
+ call s:GPGDebug(a:dict.level, "command: ". commandline)
+
+ call s:GPGPreCmd()
+ let output = system(commandline)
+ call s:GPGPostCmd()
+
+ call s:GPGDebug(a:dict.level, "rc: ". v:shell_error)
+ call s:GPGDebug(a:dict.level, "output: ". output)
+ return output
+endfunction
+
+" Function: s:GPGExecute(dict) {{{2
+"
+" run g:GPGCommand using :execute, logging the commandline
+" Recognized keys are:
+" level - Debug level at which the commandline will be logged
+" args - Arguments to be given to g:GPGCommand
+" ex - Ex command which will be :executed
+" redirect - Shell redirect to use, if needed
+"
+function s:GPGExecute(dict)
+ let commandline = printf('%s%s', a:dict.ex, s:GPGCommand)
+ if (!empty(g:GPGHomedir))
+ let commandline .= ' --homedir ' . s:shellescape(g:GPGHomedir, { 'special': 1, 'cygpath': 1 })
+ endif
+ let commandline .= ' ' . a:dict.args
+ if (has_key(a:dict, 'redirect'))
+ let commandline .= ' ' . a:dict.redirect
+ endif
+ let commandline .= ' ' . s:stderrredirnull
+ call s:GPGDebug(a:dict.level, "command: " . commandline)
+
+ call s:GPGPreCmd()
+ execute commandline
+ call s:GPGPostCmd()
+
+ call s:GPGDebug(a:dict.level, "rc: ". v:shell_error)
+endfunction
+
+" Function: s:GPGDebug(level, text) {{{2
+"
+" output debug message, if this message has high enough importance
+" only define function if GPGDebugLevel set at all
+"
+function s:GPGDebug(level, text)
+ if exists("g:GPGDebugLevel") && g:GPGDebugLevel >= a:level
+ if exists("g:GPGDebugLog")
+ execute "redir >> " . g:GPGDebugLog
+ silent echom "GnuPG: " . a:text
+ redir END
+ else
+ echom "GnuPG: " . a:text
+ endif
+ endif
+endfunction
+
+" Section: Commands {{{1
+
+command! GPGViewRecipients call s:GPGViewRecipients()
+command! GPGEditRecipients call s:GPGEditRecipients()
+command! GPGViewOptions call s:GPGViewOptions()
+command! GPGEditOptions call s:GPGEditOptions()
+
+" Section: Menu {{{1
+
+if (has("menu"))
+ amenu Plugin.GnuPG.View\ Recipients :GPGViewRecipients
+ amenu Plugin.GnuPG.Edit\ Recipients :GPGEditRecipients
+ amenu Plugin.GnuPG.View\ Options :GPGViewOptions
+ amenu Plugin.GnuPG.Edit\ Options :GPGEditOptions
+endif
+
+" vim600: set foldmethod=marker foldlevel=0 :
diff --git a/.vim/bundle/vim-mail/ftplugin/mail.vim b/.vim/bundle/vim-mail/ftplugin/mail.vim
new file mode 100644
index 0000000..0f92422
--- /dev/null
+++ b/.vim/bundle/vim-mail/ftplugin/mail.vim
@@ -0,0 +1,38 @@
+setl wrap " softwrap the text
+setl linebreak " don't break in the middle of the word
+setl nolist " list disables linebreak
+setl textwidth=72
+setl formatprg=par\ -B+.,\\-\\!\\?\\\"\\\'\\*\\<\ -w72qie
+setl enc=utf-8
+setl nojs
+setl nosmartindent
+setl spell
+
+setl comments=n:>
+setl formatoptions=
+setl fo+=r " Insert the current comment leader after hitting in Insert mode.
+setl fo+=o " Insert the current comment leader after hitting 'o' or 'O' in Normal mode.
+setl fo+=q " Allow formatting of comments with "gq".
+setl fo+=w " Trailing white space indicates a paragraph continues in the next line.
+setl fo+=b " Like 'v', but only auto-wrap if you enter a blank at or before the wrap margin.
+setl fo+=j " Where it makes sense, remove a comment leader when joining lines.
+
+match ErrorMsg '\s\s\+$'
+
+syn match quote0 "^>"
+syn match quote1 "^> *>"
+syn match quote2 "^> *> *>"
+syn match quote3 "^> *> *> *>"
+syn match quote4 "^> *> *> *> *>"
+syn match quote5 "^> *> *> *> *> *>"
+syn match quote6 "^> *> *> *> *> *> *>"
+syn match quote7 "^> *> *> *> *> *> *> *>"
+
+hi quote0 ctermfg=magenta
+hi quote1 ctermfg=cyan
+hi quote2 ctermfg=blue
+hi quote3 ctermfg=yellow
+hi quote4 ctermfg=magenta
+hi quote5 ctermfg=cyan
+hi quote6 ctermfg=blue
+hi quote7 ctermfg=yellow
diff --git a/.vim/bundle/vim-snipmate/after/plugin/snipMate.vim b/.vim/bundle/vim-snipmate/after/plugin/snipMate.vim
new file mode 100644
index 0000000..03e79ae
--- /dev/null
+++ b/.vim/bundle/vim-snipmate/after/plugin/snipMate.vim
@@ -0,0 +1,35 @@
+" These are the mappings for snipMate.vim. Putting it here ensures that it
+" will be mapped after other plugins such as supertab.vim.
+if !exists('loaded_snips') || exists('s:did_snips_mappings')
+ finish
+endif
+let s:did_snips_mappings = 1
+
+ino =TriggerSnippet()
+snor i=TriggerSnippet()
+ino =BackwardsSnippet()
+snor i=BackwardsSnippet()
+ino =ShowAvailableSnips()
+
+" The default mappings for these are annoying & sometimes break snipMate.
+" You can change them back if you want, I've put them here for convenience.
+snor b
+snor a
+snor bi
+snor ' b'
+snor ` b`
+snor % b%
+snor U bU
+snor ^ b^
+snor \ b\
+snor b
+
+" By default load snippets in snippets_dir
+if empty(snippets_dir)
+ finish
+endif
+
+call GetSnippets(snippets_dir, '_') " Get global snippets
+
+au FileType * if &ft != 'help' | call GetSnippets(snippets_dir, &ft) | endif
+" vim:noet:sw=4:ts=4:ft=vim
diff --git a/.vim/bundle/vim-snipmate/autoload/snipMate.vim b/.vim/bundle/vim-snipmate/autoload/snipMate.vim
new file mode 100644
index 0000000..dcd28f6
--- /dev/null
+++ b/.vim/bundle/vim-snipmate/autoload/snipMate.vim
@@ -0,0 +1,433 @@
+fun! Filename(...)
+ let filename = expand('%:t:r')
+ if filename == '' | return a:0 == 2 ? a:2 : '' | endif
+ return !a:0 || a:1 == '' ? filename : substitute(a:1, '$1', filename, 'g')
+endf
+
+fun s:RemoveSnippet()
+ unl! g:snipPos s:curPos s:snipLen s:endCol s:endLine s:prevLen
+ \ s:lastBuf s:oldWord
+ if exists('s:update')
+ unl s:startCol s:origWordLen s:update
+ if exists('s:oldVars') | unl s:oldVars s:oldEndCol | endif
+ endif
+ aug! snipMateAutocmds
+endf
+
+fun snipMate#expandSnip(snip, col)
+ let lnum = line('.') | let col = a:col
+
+ let snippet = s:ProcessSnippet(a:snip)
+ " Avoid error if eval evaluates to nothing
+ if snippet == '' | return '' | endif
+
+ " Expand snippet onto current position with the tab stops removed
+ let snipLines = split(substitute(snippet, '$\d\+\|${\d\+.\{-}}', '', 'g'), "\n", 1)
+
+ let line = getline(lnum)
+ let afterCursor = strpart(line, col - 1)
+ " Keep text after the cursor
+ if afterCursor != "\t" && afterCursor != ' '
+ let line = strpart(line, 0, col - 1)
+ let snipLines[-1] .= afterCursor
+ else
+ let afterCursor = ''
+ " For some reason the cursor needs to move one right after this
+ if line != '' && col == 1 && &ve != 'all' && &ve != 'onemore'
+ let col += 1
+ endif
+ endif
+
+ call setline(lnum, line.snipLines[0])
+
+ " Autoindent snippet according to previous indentation
+ let indent = matchend(line, '^.\{-}\ze\(\S\|$\)') + 1
+ call append(lnum, map(snipLines[1:], "'".strpart(line, 0, indent - 1)."'.v:val"))
+
+ " Open any folds snippet expands into
+ if &fen | sil! exe lnum.','.(lnum + len(snipLines) - 1).'foldopen' | endif
+
+ let [g:snipPos, s:snipLen] = s:BuildTabStops(snippet, lnum, col - indent, indent)
+
+ if s:snipLen
+ aug snipMateAutocmds
+ au CursorMovedI * call s:UpdateChangedSnip(0)
+ au InsertEnter * call s:UpdateChangedSnip(1)
+ aug END
+ let s:lastBuf = bufnr(0) " Only expand snippet while in current buffer
+ let s:curPos = 0
+ let s:endCol = g:snipPos[s:curPos][1]
+ let s:endLine = g:snipPos[s:curPos][0]
+
+ call cursor(g:snipPos[s:curPos][0], g:snipPos[s:curPos][1])
+ let s:prevLen = [line('$'), col('$')]
+ if g:snipPos[s:curPos][2] != -1 | return s:SelectWord() | endif
+ else
+ unl g:snipPos s:snipLen
+ " Place cursor at end of snippet if no tab stop is given
+ let newlines = len(snipLines) - 1
+ call cursor(lnum + newlines, indent + len(snipLines[-1]) - len(afterCursor)
+ \ + (newlines ? 0: col - 1))
+ endif
+ return ''
+endf
+
+" Prepare snippet to be processed by s:BuildTabStops
+fun s:ProcessSnippet(snip)
+ let snippet = a:snip
+ " Evaluate eval (`...`) expressions.
+ " Using a loop here instead of a regex fixes a bug with nested "\=".
+ if stridx(snippet, '`') != -1
+ while match(snippet, '`.\{-}`') != -1
+ let snippet = substitute(snippet, '`.\{-}`',
+ \ substitute(eval(matchstr(snippet, '`\zs.\{-}\ze`')),
+ \ "\n\\%$", '', ''), '')
+ endw
+ let snippet = substitute(snippet, "\r", "\n", 'g')
+ endif
+
+ " Place all text after a colon in a tab stop after the tab stop
+ " (e.g. "${#:foo}" becomes "${:foo}foo").
+ " This helps tell the position of the tab stops later.
+ let snippet = substitute(snippet, '${\d\+:\(.\{-}\)}', '&\1', 'g')
+
+ " Update the a:snip so that all the $# become the text after
+ " the colon in their associated ${#}.
+ " (e.g. "${1:foo}" turns all "$1"'s into "foo")
+ let i = 1
+ while stridx(snippet, '${'.i) != -1
+ let s = matchstr(snippet, '${'.i.':\zs.\{-}\ze}')
+ if s != ''
+ let snippet = substitute(snippet, '$'.i, s.'&', 'g')
+ endif
+ let i += 1
+ endw
+
+ if &et " Expand tabs to spaces if 'expandtab' is set.
+ return substitute(snippet, '\t', repeat(' ', &sts ? &sts : &sw), 'g')
+ endif
+ return snippet
+endf
+
+" Counts occurences of haystack in needle
+fun s:Count(haystack, needle)
+ let counter = 0
+ let index = stridx(a:haystack, a:needle)
+ while index != -1
+ let index = stridx(a:haystack, a:needle, index+1)
+ let counter += 1
+ endw
+ return counter
+endf
+
+" Builds a list of a list of each tab stop in the snippet containing:
+" 1.) The tab stop's line number.
+" 2.) The tab stop's column number
+" (by getting the length of the string between the last "\n" and the
+" tab stop).
+" 3.) The length of the text after the colon for the current tab stop
+" (e.g. "${1:foo}" would return 3). If there is no text, -1 is returned.
+" 4.) If the "${#:}" construct is given, another list containing all
+" the matches of "$#", to be replaced with the placeholder. This list is
+" composed the same way as the parent; the first item is the line number,
+" and the second is the column.
+fun s:BuildTabStops(snip, lnum, col, indent)
+ let snipPos = []
+ let i = 1
+ let withoutVars = substitute(a:snip, '$\d\+', '', 'g')
+ while stridx(a:snip, '${'.i) != -1
+ let beforeTabStop = matchstr(withoutVars, '^.*\ze${'.i.'\D')
+ let withoutOthers = substitute(withoutVars, '${\('.i.'\D\)\@!\d\+.\{-}}', '', 'g')
+
+ let j = i - 1
+ call add(snipPos, [0, 0, -1])
+ let snipPos[j][0] = a:lnum + s:Count(beforeTabStop, "\n")
+ let snipPos[j][1] = a:indent + len(matchstr(withoutOthers, '.*\(\n\|^\)\zs.*\ze${'.i.'\D'))
+ if snipPos[j][0] == a:lnum | let snipPos[j][1] += a:col | endif
+
+ " Get all $# matches in another list, if ${#:name} is given
+ if stridx(withoutVars, '${'.i.':') != -1
+ let snipPos[j][2] = len(matchstr(withoutVars, '${'.i.':\zs.\{-}\ze}'))
+ let dots = repeat('.', snipPos[j][2])
+ call add(snipPos[j], [])
+ let withoutOthers = substitute(a:snip, '${\d\+.\{-}}\|$'.i.'\@!\d\+', '', 'g')
+ while match(withoutOthers, '$'.i.'\(\D\|$\)') != -1
+ let beforeMark = matchstr(withoutOthers, '^.\{-}\ze'.dots.'$'.i.'\(\D\|$\)')
+ call add(snipPos[j][3], [0, 0])
+ let snipPos[j][3][-1][0] = a:lnum + s:Count(beforeMark, "\n")
+ let snipPos[j][3][-1][1] = a:indent + (snipPos[j][3][-1][0] > a:lnum
+ \ ? len(matchstr(beforeMark, '.*\n\zs.*'))
+ \ : a:col + len(beforeMark))
+ let withoutOthers = substitute(withoutOthers, '$'.i.'\ze\(\D\|$\)', '', '')
+ endw
+ endif
+ let i += 1
+ endw
+ return [snipPos, i - 1]
+endf
+
+fun snipMate#jumpTabStop(backwards)
+ let leftPlaceholder = exists('s:origWordLen')
+ \ && s:origWordLen != g:snipPos[s:curPos][2]
+ if leftPlaceholder && exists('s:oldEndCol')
+ let startPlaceholder = s:oldEndCol + 1
+ endif
+
+ if exists('s:update')
+ call s:UpdatePlaceholderTabStops()
+ else
+ call s:UpdateTabStops()
+ endif
+
+ " Don't reselect placeholder if it has been modified
+ if leftPlaceholder && g:snipPos[s:curPos][2] != -1
+ if exists('startPlaceholder')
+ let g:snipPos[s:curPos][1] = startPlaceholder
+ else
+ let g:snipPos[s:curPos][1] = col('.')
+ let g:snipPos[s:curPos][2] = 0
+ endif
+ endif
+
+ let s:curPos += a:backwards ? -1 : 1
+ " Loop over the snippet when going backwards from the beginning
+ if s:curPos < 0 | let s:curPos = s:snipLen - 1 | endif
+
+ if s:curPos == s:snipLen
+ let sMode = s:endCol == g:snipPos[s:curPos-1][1]+g:snipPos[s:curPos-1][2]
+ call s:RemoveSnippet()
+ return sMode ? "\" : TriggerSnippet()
+ endif
+
+ call cursor(g:snipPos[s:curPos][0], g:snipPos[s:curPos][1])
+
+ let s:endLine = g:snipPos[s:curPos][0]
+ let s:endCol = g:snipPos[s:curPos][1]
+ let s:prevLen = [line('$'), col('$')]
+
+ return g:snipPos[s:curPos][2] == -1 ? '' : s:SelectWord()
+endf
+
+fun s:UpdatePlaceholderTabStops()
+ let changeLen = s:origWordLen - g:snipPos[s:curPos][2]
+ unl s:startCol s:origWordLen s:update
+ if !exists('s:oldVars') | return | endif
+ " Update tab stops in snippet if text has been added via "$#"
+ " (e.g., in "${1:foo}bar$1${2}").
+ if changeLen != 0
+ let curLine = line('.')
+
+ for pos in g:snipPos
+ if pos == g:snipPos[s:curPos] | continue | endif
+ let changed = pos[0] == curLine && pos[1] > s:oldEndCol
+ let changedVars = 0
+ let endPlaceholder = pos[2] - 1 + pos[1]
+ " Subtract changeLen from each tab stop that was after any of
+ " the current tab stop's placeholders.
+ for [lnum, col] in s:oldVars
+ if lnum > pos[0] | break | endif
+ if pos[0] == lnum
+ if pos[1] > col || (pos[2] == -1 && pos[1] == col)
+ let changed += 1
+ elseif col < endPlaceholder
+ let changedVars += 1
+ endif
+ endif
+ endfor
+ let pos[1] -= changeLen * changed
+ let pos[2] -= changeLen * changedVars " Parse variables within placeholders
+ " e.g., "${1:foo} ${2:$1bar}"
+
+ if pos[2] == -1 | continue | endif
+ " Do the same to any placeholders in the other tab stops.
+ for nPos in pos[3]
+ let changed = nPos[0] == curLine && nPos[1] > s:oldEndCol
+ for [lnum, col] in s:oldVars
+ if lnum > nPos[0] | break | endif
+ if nPos[0] == lnum && nPos[1] > col
+ let changed += 1
+ endif
+ endfor
+ let nPos[1] -= changeLen * changed
+ endfor
+ endfor
+ endif
+ unl s:endCol s:oldVars s:oldEndCol
+endf
+
+fun s:UpdateTabStops()
+ let changeLine = s:endLine - g:snipPos[s:curPos][0]
+ let changeCol = s:endCol - g:snipPos[s:curPos][1]
+ if exists('s:origWordLen')
+ let changeCol -= s:origWordLen
+ unl s:origWordLen
+ endif
+ let lnum = g:snipPos[s:curPos][0]
+ let col = g:snipPos[s:curPos][1]
+ " Update the line number of all proceeding tab stops if has
+ " been inserted.
+ if changeLine != 0
+ let changeLine -= 1
+ for pos in g:snipPos
+ if pos[0] >= lnum
+ if pos[0] == lnum | let pos[1] += changeCol | endif
+ let pos[0] += changeLine
+ endif
+ if pos[2] == -1 | continue | endif
+ for nPos in pos[3]
+ if nPos[0] >= lnum
+ if nPos[0] == lnum | let nPos[1] += changeCol | endif
+ let nPos[0] += changeLine
+ endif
+ endfor
+ endfor
+ elseif changeCol != 0
+ " Update the column of all proceeding tab stops if text has
+ " been inserted/deleted in the current line.
+ for pos in g:snipPos
+ if pos[1] >= col && pos[0] == lnum
+ let pos[1] += changeCol
+ endif
+ if pos[2] == -1 | continue | endif
+ for nPos in pos[3]
+ if nPos[0] > lnum | break | endif
+ if nPos[0] == lnum && nPos[1] >= col
+ let nPos[1] += changeCol
+ endif
+ endfor
+ endfor
+ endif
+endf
+
+fun s:SelectWord()
+ let s:origWordLen = g:snipPos[s:curPos][2]
+ let s:oldWord = strpart(getline('.'), g:snipPos[s:curPos][1] - 1,
+ \ s:origWordLen)
+ let s:prevLen[1] -= s:origWordLen
+ if !empty(g:snipPos[s:curPos][3])
+ let s:update = 1
+ let s:endCol = -1
+ let s:startCol = g:snipPos[s:curPos][1] - 1
+ endif
+ if !s:origWordLen | return '' | endif
+ let l = col('.') != 1 ? 'l' : ''
+ if &sel == 'exclusive'
+ return "\".l.'v'.s:origWordLen."l\"
+ endif
+ return s:origWordLen == 1 ? "\".l.'gh'
+ \ : "\".l.'v'.(s:origWordLen - 1)."l\"
+endf
+
+" This updates the snippet as you type when text needs to be inserted
+" into multiple places (e.g. in "${1:default text}foo$1bar$1",
+" "default text" would be highlighted, and if the user types something,
+" UpdateChangedSnip() would be called so that the text after "foo" & "bar"
+" are updated accordingly)
+"
+" It also automatically quits the snippet if the cursor is moved out of it
+" while in insert mode.
+fun s:UpdateChangedSnip(entering)
+ if exists('g:snipPos') && bufnr(0) != s:lastBuf
+ call s:RemoveSnippet()
+ elseif exists('s:update') " If modifying a placeholder
+ if !exists('s:oldVars') && s:curPos + 1 < s:snipLen
+ " Save the old snippet & word length before it's updated
+ " s:startCol must be saved too, in case text is added
+ " before the snippet (e.g. in "foo$1${2}bar${1:foo}").
+ let s:oldEndCol = s:startCol
+ let s:oldVars = deepcopy(g:snipPos[s:curPos][3])
+ endif
+ let col = col('.') - 1
+
+ if s:endCol != -1
+ let changeLen = col('$') - s:prevLen[1]
+ let s:endCol += changeLen
+ else " When being updated the first time, after leaving select mode
+ if a:entering | return | endif
+ let s:endCol = col - 1
+ endif
+
+ " If the cursor moves outside the snippet, quit it
+ if line('.') != g:snipPos[s:curPos][0] || col < s:startCol ||
+ \ col - 1 > s:endCol
+ unl! s:startCol s:origWordLen s:oldVars s:update
+ return s:RemoveSnippet()
+ endif
+
+ call s:UpdateVars()
+ let s:prevLen[1] = col('$')
+ elseif exists('g:snipPos')
+ if !a:entering && g:snipPos[s:curPos][2] != -1
+ let g:snipPos[s:curPos][2] = -2
+ endif
+
+ let col = col('.')
+ let lnum = line('.')
+ let changeLine = line('$') - s:prevLen[0]
+
+ if lnum == s:endLine
+ let s:endCol += col('$') - s:prevLen[1]
+ let s:prevLen = [line('$'), col('$')]
+ endif
+ if changeLine != 0
+ let s:endLine += changeLine
+ let s:endCol = col
+ endif
+
+ " Delete snippet if cursor moves out of it in insert mode
+ if (lnum == s:endLine && (col > s:endCol || col < g:snipPos[s:curPos][1]))
+ \ || lnum > s:endLine || lnum < g:snipPos[s:curPos][0]
+ call s:RemoveSnippet()
+ endif
+ endif
+endf
+
+" This updates the variables in a snippet when a placeholder has been edited.
+" (e.g., each "$1" in "${1:foo} $1bar $1bar")
+fun s:UpdateVars()
+ let newWordLen = s:endCol - s:startCol + 1
+ let newWord = strpart(getline('.'), s:startCol, newWordLen)
+ if newWord == s:oldWord || empty(g:snipPos[s:curPos][3])
+ return
+ endif
+
+ let changeLen = g:snipPos[s:curPos][2] - newWordLen
+ let curLine = line('.')
+ let startCol = col('.')
+ let oldStartSnip = s:startCol
+ let updateTabStops = changeLen != 0
+ let i = 0
+
+ for [lnum, col] in g:snipPos[s:curPos][3]
+ if updateTabStops
+ let start = s:startCol
+ if lnum == curLine && col <= start
+ let s:startCol -= changeLen
+ let s:endCol -= changeLen
+ endif
+ for nPos in g:snipPos[s:curPos][3][(i):]
+ " This list is in ascending order, so quit if we've gone too far.
+ if nPos[0] > lnum | break | endif
+ if nPos[0] == lnum && nPos[1] > col
+ let nPos[1] -= changeLen
+ endif
+ endfor
+ if lnum == curLine && col > start
+ let col -= changeLen
+ let g:snipPos[s:curPos][3][i][1] = col
+ endif
+ let i += 1
+ endif
+
+ " "Very nomagic" is used here to allow special characters.
+ call setline(lnum, substitute(getline(lnum), '\%'.col.'c\V'.
+ \ escape(s:oldWord, '\'), escape(newWord, '\&'), ''))
+ endfor
+ if oldStartSnip != s:startCol
+ call cursor(0, startCol + s:startCol - oldStartSnip)
+ endif
+
+ let s:oldWord = newWord
+ let g:snipPos[s:curPos][2] = newWordLen
+endf
+" vim:noet:sw=4:ts=4:ft=vim
diff --git a/.vim/bundle/vim-snipmate/doc/snipMate.txt b/.vim/bundle/vim-snipmate/doc/snipMate.txt
new file mode 100644
index 0000000..704d44a
--- /dev/null
+++ b/.vim/bundle/vim-snipmate/doc/snipMate.txt
@@ -0,0 +1,286 @@
+*snipMate.txt* Plugin for using TextMate-style snippets in Vim.
+
+snipMate *snippet* *snippets* *snipMate*
+Last Change: July 13, 2009
+
+|snipMate-description| Description
+|snipMate-syntax| Snippet syntax
+|snipMate-usage| Usage
+|snipMate-settings| Settings
+|snipMate-features| Features
+|snipMate-disadvantages| Disadvantages to TextMate
+|snipMate-contact| Contact
+
+For Vim version 7.0 or later.
+This plugin only works if 'compatible' is not set.
+{Vi does not have any of these features.}
+
+==============================================================================
+DESCRIPTION *snipMate-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 .
+
+For instance, in a C file using the default installation of snipMate.vim, if
+you type "for" in insert mode, it will expand a typical for loop in C: >
+
+ for (i = 0; i < count; i++) {
+
+ }
+
+
+To go to the next item in the loop, simply over to it; if there is
+repeated code, such as the "i" variable in this example, you can simply
+start typing once it's highlighted and all the matches specified in the
+snippet will be updated. To go in reverse, use .
+
+==============================================================================
+SYNTAX *snippet-syntax*
+
+Snippets can be defined in two ways. They can be in their own file, named
+after their trigger in 'snippets//.snippet', or they can be
+defined together in a 'snippets/.snippets' file. Note that dotted
+'filetype' syntax is supported -- e.g., you can use >
+
+ :set ft=html.eruby
+
+to activate snippets for both HTML and eRuby for the current file.
+
+The syntax for snippets in *.snippets files is the following: >
+
+ snippet trigger
+ expanded text
+ more expanded text
+
+Note that the first hard tab after the snippet trigger is required, and not
+expanded in the actual snippet. The syntax for *.snippet files is the same,
+only without the trigger declaration and starting indentation.
+
+Also note that snippets must be defined using hard tabs. They can be expanded
+to spaces later if desired (see |snipMate-indenting|).
+
+"#" is used as a line-comment character in *.snippets files; however, they can
+only be used outside of a snippet declaration. E.g.: >
+
+ # this is a correct comment
+ snippet trigger
+ expanded text
+ snippet another_trigger
+ # this isn't a comment!
+ expanded text
+<
+This should hopefully be obvious with the included syntax highlighting.
+
+ *snipMate-${#}*
+Tab stops ~
+
+By default, the cursor is placed at the end of a snippet. To specify where the
+cursor is to be placed next, use "${#}", where the # is the number of the tab
+stop. E.g., to place the cursor first on the id of a
tag, and then allow
+the user to press to go to the middle of it:
+ >
+ snippet div
+
+ ${2}
+
+<
+ *snipMate-placeholders* *snipMate-${#:}* *snipMate-$#*
+Placeholders ~
+
+Placeholder text can be supplied using "${#:text}", where # is the number of
+the tab stop. This text then can be copied throughout the snippet using "$#",
+given # is the same number as used before. So, to make a C for loop: >
+
+ snippet for
+ for (${2:i}; $2 < ${1:count}; $1++) {
+ ${4}
+ }
+
+This will cause "count" to first be selected and change if the user starts
+typing. When is pressed, the "i" in ${2}'s position will be selected;
+all $2 variables will default to "i" and automatically be updated if the user
+starts typing.
+NOTE: "$#" syntax is used only for variables, not for tab stops as in TextMate.
+
+Variables within variables are also possible. For instance: >
+
+ snippet opt
+
+
+Will, as usual, cause "option" to first be selected and update all the $1
+variables if the user starts typing. Since one of these variables is inside of
+${2}, this text will then be used as a placeholder for the next tab stop,
+allowing the user to change it if he wishes.
+
+To copy a value throughout a snippet without supplying default text, simply
+use the "${#:}" construct without the text; e.g.: >
+
+ snippet foo
+ ${1:}bar$1
+< *snipMate-commands*
+Interpolated Vim Script ~
+
+Snippets can also contain Vim script commands that are executed (via |eval()|)
+when the snippet is inserted. Commands are given inside backticks (`...`); for
+TextMates's functionality, use the |system()| function. E.g.: >
+
+ snippet date
+ `system("date +%Y-%m-%d")`
+
+will insert the current date, assuming you are on a Unix system. Note that you
+can also (and should) use |strftime()| for this example.
+
+Filename([{expr}] [, {defaultText}]) *snipMate-filename* *Filename()*
+
+Since the current filename is used often in snippets, a default function
+has been defined for it in snipMate.vim, appropriately called Filename().
+
+With no arguments, the default filename without an extension is returned;
+the first argument specifies what to place before or after the filename,
+and the second argument supplies the default text to be used if the file
+has not been named. "$1" in the first argument is replaced with the filename;
+if you only want the filename to be returned, the first argument can be left
+blank. Examples: >
+
+ snippet filename
+ `Filename()`
+ snippet filename_with_default
+ `Filename('', 'name')`
+ snippet filename_foo
+ `filename('$1_foo')`
+
+The first example returns the filename if it the file has been named, and an
+empty string if it hasn't. The second returns the filename if it's been named,
+and "name" if it hasn't. The third returns the filename followed by "_foo" if
+it has been named, and an empty string if it hasn't.
+
+ *multi_snip*
+To specify that a snippet can have multiple matches in a *.snippets file, use
+this syntax: >
+
+ snippet trigger A description of snippet #1
+ expand this text
+ snippet trigger A description of snippet #2
+ expand THIS text!
+
+In this example, when "trigger" is typed, a numbered menu containing all
+of the descriptions of the "trigger" will be shown; when the user presses the
+corresponding number, that snippet will then be expanded.
+
+To create a snippet with multiple matches using *.snippet files,
+simply place all the snippets in a subdirectory with the trigger name:
+'snippets///.snippet'.
+
+==============================================================================
+USAGE *snipMate-usage*
+
+ *'snippets'* *g:snippets_dir*
+Snippets are by default looked for any 'snippets' directory in your
+'runtimepath'. Typically, it is located at '~/.vim/snippets/' on *nix or
+'$HOME\vimfiles\snippets\' on Windows. To change that location or add another
+one, change the g:snippets_dir variable in your |.vimrc| to your preferred
+directory, or use the |ExtractSnips()|function. This will be used by the
+|globpath()| function, and so accepts the same syntax as it (e.g.,
+comma-separated paths).
+
+ExtractSnipsFile({directory}, {filetype}) *ExtractSnipsFile()* *.snippets*
+
+ExtractSnipsFile() extracts the specified *.snippets file for the given
+filetype. A .snippets file contains multiple snippet declarations for the
+filetype. It is further explained above, in |snippet-syntax|.
+
+ExtractSnips({directory}, {filetype}) *ExtractSnips()* *.snippet*
+
+ExtractSnips() extracts *.snippet files from the specified directory and
+defines them as snippets for the given filetype. The directory tree should
+look like this: 'snippets//.snippet'. If the snippet has
+multiple matches, it should look like this:
+'snippets///.snippet' (see |multi_snip|).
+
+ *ResetSnippets()*
+The ResetSnippets() function removes all snippets from memory. This is useful
+to put at the top of a snippet setup file for if you would like to |:source|
+it multiple times.
+
+ *list-snippets* *i_CTRL-R_*
+If you would like to see what snippets are available, simply type
+in the current buffer to show a list via |popupmenu-completion|.
+
+==============================================================================
+SETTINGS *snipMate-settings* *g:snips_author*
+
+The g:snips_author string (similar to $TM_FULLNAME in TextMate) should be set
+to your name; it can then be used in snippets to automatically add it. E.g.: >
+
+ let g:snips_author = 'Hubert Farnsworth'
+ snippet name
+ `g:snips_author`
+<
+ *snipMate-expandtab* *snipMate-indenting*
+If you would like your snippets to be expanded using spaces instead of tabs,
+just enable 'expandtab' and set 'softtabstop' to your preferred amount of
+spaces. If 'softtabstop' is not set, 'shiftwidth' is used instead.
+
+ *snipMate-remap*
+snipMate does not come with a setting to customize the trigger key, but you
+can remap it easily in the two lines it's defined in the 'after' directory
+under 'plugin/snipMate.vim'. For instance, to change the trigger key
+to CTRL-J, just change this: >
+
+ ino =TriggerSnippet()
+ snor i=TriggerSnippet()
+
+to this: >
+ ino =TriggerSnippet()
+ snor i=TriggerSnippet()
+
+==============================================================================
+FEATURES *snipMate-features*
+
+snipMate.vim has the following features among others:
+ - The syntax of snippets is very similar to TextMate's, allowing
+ easy conversion.
+ - The position of the snippet is kept transparently (i.e. it does not use
+ markers/placeholders written to the buffer), which allows you to escape
+ out of an incomplete snippet, something particularly useful in Vim.
+ - Variables in snippets are updated as-you-type.
+ - Snippets can have multiple matches.
+ - Snippets can be out of order. For instance, in a do...while loop, the
+ condition can be added before the code.
+ - [New] File-based snippets are supported.
+ - [New] Triggers after non-word delimiters are expanded, e.g. "foo"
+ in "bar.foo".
+ - [New] can now be used to jump tab stops in reverse order.
+
+==============================================================================
+DISADVANTAGES *snipMate-disadvantages*
+
+snipMate.vim currently has the following disadvantages to TextMate's snippets:
+ - There is no $0; the order of tab stops must be explicitly stated.
+ - Placeholders within placeholders are not possible. E.g.: >
+
+ '
${3}
'
+<
+ In TextMate this would first highlight ' id="some_id"', and if
+ you hit delete it would automatically skip ${2} and go to ${3}
+ on the next , but if you didn't delete it it would highlight
+ "some_id" first. You cannot do this in snipMate.vim.
+ - Regex cannot be performed on variables, such as "${1/.*/\U&}"
+ - Placeholders cannot span multiple lines.
+ - Activating snippets in different scopes of the same file is
+ not possible.
+
+Perhaps some of these features will be added in a later release.
+
+==============================================================================
+CONTACT *snipMate-contact* *snipMate-author*
+
+To contact the author (Michael Sanders), please email:
+ msanders42+snipmate gmail com
+
+I greatly appreciate any suggestions or improvements offered for the script.
+
+==============================================================================
+
+vim:tw=78:ts=8:ft=help:norl:
diff --git a/.vim/bundle/vim-snipmate/doc/tags b/.vim/bundle/vim-snipmate/doc/tags
new file mode 100644
index 0000000..b21f751
--- /dev/null
+++ b/.vim/bundle/vim-snipmate/doc/tags
@@ -0,0 +1,33 @@
+'snippets' snipMate.txt /*'snippets'*
+.snippet snipMate.txt /*.snippet*
+.snippets snipMate.txt /*.snippets*
+ExtractSnips() snipMate.txt /*ExtractSnips()*
+ExtractSnipsFile() snipMate.txt /*ExtractSnipsFile()*
+Filename() snipMate.txt /*Filename()*
+ResetSnippets() snipMate.txt /*ResetSnippets()*
+g:snippets_dir snipMate.txt /*g:snippets_dir*
+g:snips_author snipMate.txt /*g:snips_author*
+i_CTRL-R_ snipMate.txt /*i_CTRL-R_*
+list-snippets snipMate.txt /*list-snippets*
+multi_snip snipMate.txt /*multi_snip*
+snipMate snipMate.txt /*snipMate*
+snipMate-$# snipMate.txt /*snipMate-$#*
+snipMate-${#:} snipMate.txt /*snipMate-${#:}*
+snipMate-${#} snipMate.txt /*snipMate-${#}*
+snipMate-author snipMate.txt /*snipMate-author*
+snipMate-commands snipMate.txt /*snipMate-commands*
+snipMate-contact snipMate.txt /*snipMate-contact*
+snipMate-description snipMate.txt /*snipMate-description*
+snipMate-disadvantages snipMate.txt /*snipMate-disadvantages*
+snipMate-expandtab snipMate.txt /*snipMate-expandtab*
+snipMate-features snipMate.txt /*snipMate-features*
+snipMate-filename snipMate.txt /*snipMate-filename*
+snipMate-indenting snipMate.txt /*snipMate-indenting*
+snipMate-placeholders snipMate.txt /*snipMate-placeholders*
+snipMate-remap snipMate.txt /*snipMate-remap*
+snipMate-settings snipMate.txt /*snipMate-settings*
+snipMate-usage snipMate.txt /*snipMate-usage*
+snipMate.txt snipMate.txt /*snipMate.txt*
+snippet snipMate.txt /*snippet*
+snippet-syntax snipMate.txt /*snippet-syntax*
+snippets snipMate.txt /*snippets*
diff --git a/.vim/bundle/vim-snipmate/ftplugin/html_snip_helper.vim b/.vim/bundle/vim-snipmate/ftplugin/html_snip_helper.vim
new file mode 100644
index 0000000..2e54570
--- /dev/null
+++ b/.vim/bundle/vim-snipmate/ftplugin/html_snip_helper.vim
@@ -0,0 +1,10 @@
+" Helper function for (x)html snippets
+if exists('s:did_snip_helper') || &cp || !exists('loaded_snips')
+ finish
+endif
+let s:did_snip_helper = 1
+
+" Automatically closes tag if in xhtml
+fun! Close()
+ return stridx(&ft, 'xhtml') == -1 ? '' : ' /'
+endf
diff --git a/.vim/bundle/vim-snipmate/plugin/snipMate.vim b/.vim/bundle/vim-snipmate/plugin/snipMate.vim
new file mode 100644
index 0000000..3efee2a
--- /dev/null
+++ b/.vim/bundle/vim-snipmate/plugin/snipMate.vim
@@ -0,0 +1,247 @@
+" File: snipMate.vim
+" Author: Michael Sanders
+" Last Updated: July 13, 2009
+" Version: 0.83
+" 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 "".
+"
+" 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
+
+fun! ResetSnippets()
+ let s:snippets = {} | let s:multi_snips = {} | let g:did_ft = {}
+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 == ""
+ let SuperTabKey = "\"
+ elseif g:SuperTabMappingBackward == ""
+ let SuperTabKey = "\"
+ endif
+ endif
+
+ if pumvisible() " Update snippet if completion is used, or deal with supertab
+ if exists('SuperTabKey')
+ call feedkeys(SuperTabKey) | return ''
+ endif
+ call feedkeys("\a", 'n') " Close completion menu
+ call feedkeys("\") | 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 "\"
+endf
+
+fun! BackwardsSnippet()
+ if exists('g:snipPos') | return snipMate#jumpTabStop(1) | endif
+
+ if exists('g:SuperTabMappingForward')
+ if g:SuperTabMappingBackward == "