--- /dev/null
+" genutils.vim: Please see plugin/genutils.vim
+"
+" TODO:
+" - Vim7: redir can be used with a variable.
+" - fnamemodify() on Unix doesn't expand to full name if the filename doesn't
+" really exist on the filesystem.
+" - Is setting 'scrolloff' and 'sidescrolloff' to 0 required while moving the
+" cursor?
+" - http://www.vim.org/tips/tip.php?tip_id=1379
+"
+" - EscapeCommand() didn't work for David Fishburn.
+" - Save/RestoreWindowSettings doesn't work well.
+"
+" Vim7:
+" - Save/RestoreWindowSettings can use winsave/restview() functions.
+"
+
+" Make sure line-continuations won't cause any problem. This will be restored
+" at the end
+let s:save_cpo = &cpo
+set cpo&vim
+
+
+let g:makeArgumentString = 'exec genutils#MakeArgumentString()'
+let g:makeArgumentList = 'exec genutils#MakeArgumentList()'
+
+let s:makeArgumentString = ''
+function! genutils#MakeArgumentString(...)
+ if s:makeArgumentString == ''
+ let s:makeArgumentString = genutils#ExtractFuncListing(s:SNR().
+ \ '_makeArgumentString', 0, 0)
+ endif
+ if a:0 > 0 && a:1 != ''
+ return substitute(s:makeArgumentString, '\<argumentString\>', a:1, 'g')
+ else
+ return s:makeArgumentString
+ endif
+endfunction
+
+
+let s:makeArgumentList = ''
+function! genutils#MakeArgumentList(...)
+ if s:makeArgumentList == ''
+ let s:makeArgumentList = genutils#ExtractFuncListing(s:SNR().
+ \ '_makeArgumentList', 0, 0)
+ endif
+ if a:0 > 0 && a:1 != ''
+ let mkArgLst = substitute(s:makeArgumentList, '\<argumentList\>', a:1, 'g')
+ if a:0 > 1 && a:2 != ''
+ let mkArgLst = substitute(s:makeArgumentList,
+ \ '\(\s\+let __argSeparator = \)[^'."\n".']*', "\\1'".a:2."'", '')
+ endif
+ return mkArgLst
+ else
+ return s:makeArgumentList
+ endif
+endfunction
+
+function! genutils#ExtractFuncListing(funcName, hLines, tLines)
+ let listing = genutils#GetVimCmdOutput('func '.a:funcName)
+ let listing = substitute(listing,
+ \ '^\%(\s\|'."\n".'\)*function '.a:funcName.'([^)]*)'."\n", '', '')
+ "let listing = substitute(listing, '\%(\s\|'."\n".'\)*endfunction\%(\s\|'."\n".'\)*$', '', '')
+ " Leave the last newline character.
+ let listing = substitute(listing, '\%('."\n".'\)\@<=\s*endfunction\s*$', '', '')
+ let listing = substitute(listing, '\(\%(^\|'."\n".'\)\s*\)\@<=\d\+',
+ \ '', 'g')
+ if a:hLines > 0
+ let listing = substitute(listing, '^\%([^'."\n".']*'."\n".'\)\{'.
+ \ a:hLines.'}', '', '')
+ endif
+ if a:tLines > 0
+ let listing = substitute(listing, '\%([^'."\n".']*'."\n".'\)\{'.
+ \ a:tLines.'}$', '', '')
+ endif
+ return listing
+endfunction
+
+function! genutils#CreateArgString(argList, sep, ...)
+ let sep = (a:0 == 0) ? a:sep : a:1 " This is no longer used.
+ " Matching multvals functionality means, we need to ignore the trailing
+ " separator.
+ let argList = split(substitute(a:argList, a:sep.'$', '', ''), a:sep, 1)
+ let argString = "'"
+ for nextArg in argList
+ " FIXME: I think this check is not required. If "'" is the separator, we
+ " don't expect to see them in the elements.
+ if a:sep != "'"
+ let nextArg = substitute(nextArg, "'", "' . \"'\" . '", 'g')
+ endif
+ let argString = argString . nextArg . "', '"
+ endfor
+ let argString = strpart(argString, 0, strlen(argString) - 3)
+ return argString
+endfunction
+
+" {{{
+function! s:_makeArgumentString()
+ let __argCounter = 1
+ let argumentString = ''
+ while __argCounter <= a:0
+ if type(a:{__argCounter})
+ let __nextArg = "'" .
+ \ substitute(a:{__argCounter}, "'", "' . \"'\" . '", "g") . "'"
+ else
+ let __nextArg = a:{__argCounter}
+ endif
+ let argumentString = argumentString. __nextArg .
+ \ ((__argCounter == a:0) ? '' : ', ')
+ let __argCounter = __argCounter + 1
+ endwhile
+ unlet __argCounter
+ if exists('__nextArg')
+ unlet __nextArg
+ endif
+endfunction
+
+function! s:_makeArgumentList()
+ let __argCounter = 1
+ let __argSeparator = ','
+ let argumentList = ''
+ while __argCounter <= a:0
+ let argumentList = argumentList . a:{__argCounter}
+ if __argCounter != a:0
+ let argumentList = argumentList . __argSeparator
+ endif
+ let __argCounter = __argCounter + 1
+ endwhile
+ unlet __argCounter
+ unlet __argSeparator
+endfunction
+" }}}
+
+
+function! genutils#DebugShowArgs(...)
+ let i = 0
+ let argString = ''
+ while i < a:0
+ let argString = argString . a:{i + 1} . ', '
+ let i = i + 1
+ endwhile
+ let argString = strpart(argString, 0, strlen(argString) - 2)
+ call input("Args: " . argString)
+endfunction
+
+" Window related functions {{{
+
+function! genutils#NumberOfWindows()
+ let i = 1
+ while winbufnr(i) != -1
+ let i = i+1
+ endwhile
+ return i - 1
+endfunction
+
+" Find the window number for the buffer passed.
+" The fileName argument is treated literally, unlike the bufnr() which treats
+" the argument as a regex pattern.
+function! genutils#FindWindowForBuffer(bufferName, checkUnlisted)
+ return bufwinnr(genutils#FindBufferForName(a:bufferName))
+endfunction
+
+function! genutils#FindBufferForName(fileName)
+ " The name could be having extra backslashes to protect certain chars (such
+ " as '#' and '%'), so first expand them.
+ return s:FindBufferForName(genutils#UnEscape(a:fileName, '#%'))
+endfunction
+
+function! s:FindBufferForName(fileName)
+ let fileName = genutils#Escape(a:fileName, '[?,{')
+ let _isf = &isfname
+ try
+ set isfname-=\
+ set isfname-=[
+ let i = bufnr('^' . fileName . '$')
+ finally
+ let &isfname = _isf
+ endtry
+ return i
+endfunction
+
+function! genutils#GetBufNameForAu(bufName)
+ let bufName = a:bufName
+ " Autocommands always require forward-slashes.
+ let bufName = substitute(bufName, "\\\\", '/', 'g')
+ let bufName = escape(bufName, '*?,{}[ ')
+ return bufName
+endfunction
+
+function! genutils#MoveCursorToWindow(winno)
+ if genutils#NumberOfWindows() != 1
+ execute a:winno . " wincmd w"
+ endif
+endfunction
+
+function! genutils#MoveCurLineToWinLine(n)
+ normal! zt
+ if a:n == 1
+ return
+ endif
+ let _wrap = &l:wrap
+ setl nowrap
+ let n = a:n
+ if n >= winheight(0)
+ let n = winheight(0)
+ endif
+ let n = n - 1
+ execute "normal! " . n . "\<C-Y>"
+ let &l:wrap = _wrap
+endfunction
+
+function! genutils#CloseWindow(win, force)
+ let _eventignore = &eventignore
+ try
+ set eventignore=all
+ call genutils#MarkActiveWindow()
+
+ let &eventignore = _eventignore
+ exec a:win 'wincmd w'
+ exec 'close'.(a:force ? '!' : '')
+ set eventignore=all
+
+ if a:win < t:curWinnr
+ let t:curWinnr = t:curWinnr - 1
+ endif
+ if a:win < t:prevWinnr
+ let t:prevWinnr = t:prevWinnr - 1
+ endif
+ finally
+ call genutils#RestoreActiveWindow()
+ let &eventignore = _eventignore
+ endtry
+endfunction
+
+function! genutils#MarkActiveWindow()
+ let t:curWinnr = winnr()
+ " We need to restore the previous-window also at the end.
+ silent! wincmd p
+ let t:prevWinnr = winnr()
+ silent! wincmd p
+endfunction
+
+function! genutils#RestoreActiveWindow()
+ if !exists('t:curWinnr')
+ return
+ endif
+
+ " Restore the original window.
+ if winnr() != t:curWinnr
+ exec t:curWinnr'wincmd w'
+ endif
+ if t:curWinnr != t:prevWinnr
+ exec t:prevWinnr'wincmd w'
+ wincmd p
+ endif
+endfunction
+
+function! genutils#IsOnlyVerticalWindow()
+ let onlyVertWin = 1
+ let _eventignore = &eventignore
+
+ try
+ "set eventignore+=WinEnter,WinLeave
+ set eventignore=all
+ call genutils#MarkActiveWindow()
+
+ wincmd j
+ if winnr() != t:curWinnr
+ let onlyVertWin = 0
+ else
+ wincmd k
+ if winnr() != t:curWinnr
+ let onlyVertWin = 0
+ endif
+ endif
+ finally
+ call genutils#RestoreActiveWindow()
+ let &eventignore = _eventignore
+ endtry
+ return onlyVertWin
+endfunction
+
+function! genutils#IsOnlyHorizontalWindow()
+ let onlyHorizWin = 1
+ let _eventignore = &eventignore
+ try
+ set eventignore=all
+ call genutils#MarkActiveWindow()
+ wincmd l
+ if winnr() != t:curWinnr
+ let onlyHorizWin = 0
+ else
+ wincmd h
+ if winnr() != t:curWinnr
+ let onlyHorizWin = 0
+ endif
+ endif
+ finally
+ call genutils#RestoreActiveWindow()
+ let &eventignore = _eventignore
+ endtry
+ return onlyHorizWin
+endfunction
+
+function! genutils#MoveCursorToNextInWinStack(dir)
+ let newwin = genutils#GetNextWinnrInStack(a:dir)
+ if newwin != 0
+ exec newwin 'wincmd w'
+ endif
+endfunction
+
+function! genutils#GetNextWinnrInStack(dir)
+ let newwin = winnr()
+ let _eventignore = &eventignore
+ try
+ set eventignore=all
+ call genutils#MarkActiveWindow()
+ let newwin = s:GetNextWinnrInStack(a:dir)
+ finally
+ call genutils#RestoreActiveWindow()
+ let &eventignore = _eventignore
+ endtry
+ return newwin
+endfunction
+
+function! genutils#MoveCursorToLastInWinStack(dir)
+ let newwin = genutils#GetLastWinnrInStack(a:dir)
+ if newwin != 0
+ exec newwin 'wincmd w'
+ endif
+endfunction
+
+function! genutils#GetLastWinnrInStack(dir)
+ let newwin = winnr()
+ let _eventignore = &eventignore
+ try
+ set eventignore=all
+ call genutils#MarkActiveWindow()
+ while 1
+ let wn = s:GetNextWinnrInStack(a:dir)
+ if wn != 0
+ let newwin = wn
+ exec newwin 'wincmd w'
+ else
+ break
+ endif
+ endwhile
+ finally
+ call genutils#RestoreActiveWindow()
+ let &eventignore = _eventignore
+ endtry
+ return newwin
+endfunction
+
+" Based on the WinStackMv() function posted by Charles E. Campbell, Jr. on vim
+" mailing list on Jul 14, 2004.
+function! s:GetNextWinnrInStack(dir)
+ "call Decho("genutils#MoveCursorToNextInWinStack(dir<".a:dir.">)")
+
+ let isHorizontalMov = (a:dir ==# 'h' || a:dir ==# 'l') ? 1 : 0
+
+ let orgwin = winnr()
+ let orgdim = s:GetWinDim(a:dir, orgwin)
+
+ let _winwidth = &winwidth
+ let _winheight = &winheight
+ try
+ set winwidth=1
+ set winheight=1
+ exec 'wincmd' a:dir
+ let newwin = winnr()
+ if orgwin == newwin
+ " No more windows in this direction.
+ "call Decho("newwin=".newwin." stopped".winheight(newwin)."x".winwidth(newwin))
+ return 0
+ endif
+ if s:GetWinDim(a:dir, newwin) != orgdim
+ " Window dimension has changed, indicates a move across window stacks.
+ "call Decho("newwin=".newwin." height changed".winheight(newwin)."x".winwidth(newwin))
+ return 0
+ endif
+ " Determine if changing original window height affects current window
+ " height.
+ exec orgwin 'wincmd w'
+ try
+ if orgdim == 1
+ exec 'wincmd' (isHorizontalMov ? '_' : '|')
+ else
+ exec 'wincmd' (isHorizontalMov ? '-' : '<')
+ endif
+ if s:GetWinDim(a:dir, newwin) != s:GetWinDim(a:dir, orgwin)
+ "call Decho("newwin=".newwin." different row".winheight(newwin)."x".winwidth(newwin))
+ return 0
+ endif
+ "call Decho("newwin=".newwin." same row".winheight(newwin)."x".winwidth(newwin))
+ finally
+ exec (isHorizontalMov ? '' : 'vert') 'resize' orgdim
+ endtry
+
+ "call Decho("genutils#MoveCursorToNextInWinStack")
+
+ return newwin
+ finally
+ let &winwidth = _winwidth
+ let &winheight = _winheight
+ endtry
+endfunction
+
+function! s:GetWinDim(dir, win)
+ return (a:dir ==# 'h' || a:dir ==# 'l') ? winheight(a:win) : winwidth(a:win)
+endfunction
+
+function! genutils#OpenWinNoEa(winOpenCmd)
+ call s:ExecWinCmdNoEa(a:winOpenCmd)
+endfunction
+
+function! genutils#CloseWinNoEa(winnr, force)
+ call s:ExecWinCmdNoEa(a:winnr.'wincmd w | close'.(a:force?'!':''))
+endfunction
+
+function! s:ExecWinCmdNoEa(winCmd)
+ let _eventignore = &eventignore
+ try
+ set eventignore=all
+ call genutils#MarkActiveWindow()
+ windo let w:_winfixheight = &winfixheight
+ windo set winfixheight
+ call genutils#RestoreActiveWindow()
+
+ let &eventignore = _eventignore
+ exec a:winCmd
+ set eventignore=all
+
+ call genutils#MarkActiveWindow()
+ silent! windo let &winfixheight = w:_winfixheight
+ silent! windo unlet w:_winfixheight
+ call genutils#RestoreActiveWindow()
+ finally
+ let &eventignore = _eventignore
+ endtry
+endfunction
+
+" Window related functions }}}
+
+function! genutils#SetupScratchBuffer()
+ setlocal nobuflisted
+ setlocal noswapfile
+ setlocal buftype=nofile
+ " Just in case, this will make sure we are always hidden.
+ setlocal bufhidden=delete
+ setlocal nolist
+ setlocal nonumber
+ setlocal foldcolumn=0 nofoldenable
+ setlocal noreadonly
+endfunction
+
+function! genutils#CleanDiffOptions()
+ setlocal nodiff
+ setlocal noscrollbind
+ setlocal scrollopt-=hor
+ setlocal wrap
+ setlocal foldmethod=manual
+ setlocal foldcolumn=0
+ normal zE
+endfunction
+
+function! genutils#ArrayVarExists(varName, index)
+ try
+ exec "let test = " . a:varName . "{a:index}"
+ catch /^Vim\%((\a\+)\)\=:E121/
+ return 0
+ endtry
+ return 1
+endfunction
+
+function! genutils#Escape(str, chars)
+ return substitute(a:str, '\\\@<!\(\%(\\\\\)*\)\([' . a:chars .']\)', '\1\\\2',
+ \ 'g')
+endfunction
+
+function! genutils#UnEscape(str, chars)
+ return substitute(a:str, '\\\@<!\(\\\\\)*\\\([' . a:chars . ']\)',
+ \ '\1\2', 'g')
+endfunction
+
+function! genutils#DeEscape(str)
+ let str = a:str
+ let str = substitute(str, '\\\(\\\|[^\\]\)', '\1', 'g')
+ return str
+endfunction
+
+" - For windoze+native, use double-quotes to sorround the arguments and for
+" embedded double-quotes, just double them.
+" - For windoze+sh, use single-quotes to sorround the aruments and for embedded
+" single-quotes, just replace them with '""'""' (if 'shq' or 'sxq' is a
+" double-quote) and just '"'"' otherwise. Embedded double-quotes also need
+" to be doubled.
+" - For Unix+sh, use single-quotes to sorround the arguments and for embedded
+" single-quotes, just replace them with '"'"'.
+function! genutils#EscapeCommand(cmd, args, pipe)
+ if type(a:args) == 3
+ let args = copy(a:args)
+ else
+ let args = split(a:args, genutils#CrUnProtectedCharsPattern(' '))
+ endif
+ " I am only worried about passing arguments with spaces as they are to the
+ " external commands, I currently don't care about back-slashes
+ " (backslashes are normally expected only on windows when 'shellslash'
+ " option is set, but even then the 'shell' is expected to take care of
+ " them.). However, for cygwin bash, there is a loss of one level
+ " of the back-slashes somewhere in the chain of execution (most probably
+ " between CreateProcess() and cygwin?), so we need to double them.
+ let shellEnvType = genutils#GetShellEnvType()
+ if shellEnvType ==# g:ST_WIN_CMD
+ let quoteChar = '"'
+ " genutils#Escape the existing double-quotes (by doubling them).
+ call map(args, "substitute(v:val, '\"', '\"\"', 'g')")
+ else
+ let quoteChar = "'"
+ if shellEnvType ==# g:ST_WIN_SH
+ " genutils#Escape the existing double-quotes (by doubling them).
+ call map(args, "substitute(v:val, '\"', '\"\"', 'g')")
+ endif
+ " Take care of existing single-quotes (by exposing them, as you can't have
+ " single-quotes inside a single-quoted string).
+ if &shellquote == '"' || &shellxquote == '"'
+ let squoteRepl = "'\"\"'\"\"'"
+ else
+ let squoteRepl = "'\"'\"'"
+ endif
+ call map(args, "substitute(v:val, \"'\", squoteRepl, 'g')")
+ endif
+
+ " Now sorround the arguments with quotes, considering the protected
+ " spaces. Skip the && or || construct from doing this.
+ call map(args, 'v:val=~"^[&|]\\{2}$"?(v:val):(quoteChar.v:val.quoteChar)')
+ let fullCmd = join(args, ' ')
+ " We delay adding pipe part so that we can avoid the above processing.
+ let pipe = ''
+ if type(a:pipe) == 3 && len(a:pipe) > 0
+ let pipe = join(a:pipe, ' ')
+ elseif type(a:pipe) == 1 && a:pipe !~# '^\s*$'
+ let pipe = a:pipe
+ endif
+ if pipe != ''
+ let fullCmd = fullCmd . ' ' . a:pipe
+ endif
+ if a:cmd !~# '^\s*$'
+ let fullCmd = a:cmd . ' ' . fullCmd
+ endif
+ if shellEnvType ==# g:ST_WIN_SH && &shell =~# '\<bash\>'
+ let fullCmd = substitute(fullCmd, '\\', '\\\\', 'g')
+ endif
+ return fullCmd
+endfunction
+
+let g:ST_WIN_CMD = 0 | let g:ST_WIN_SH = 1 | let g:ST_UNIX = 2
+function! genutils#GetShellEnvType()
+ " When 'shellslash' option is available, then the platform must be one of
+ " those that support '\' as a pathsep.
+ if exists('+shellslash')
+ if stridx(&shell, 'cmd.exe') != -1 ||
+ \ stridx(&shell, 'command.com') != -1
+ return g:ST_WIN_CMD
+ else
+ return g:ST_WIN_SH
+ endif
+ else
+ return g:ST_UNIX
+ endif
+endfunction
+
+function! genutils#ExpandStr(str)
+ let str = substitute(a:str, '"', '\\"', 'g')
+ exec "let str = \"" . str . "\""
+ return str
+endfunction
+
+function! genutils#QuoteStr(str)
+ return "'".substitute(a:str, "'", "'.\"'\".'", 'g')."'"
+endfunction
+
+function! genutils#GetPreviewWinnr()
+ let _eventignore = &eventignore
+ let curWinNr = winnr()
+ let winnr = -1
+ try
+ set eventignore=all
+ exec "wincmd P"
+ let winnr = winnr()
+ catch /^Vim\%((\a\+)\)\=:E441/
+ " Ignore, winnr is already set to -1.
+ finally
+ if winnr() != curWinNr
+ exec curWinNr.'wincmd w'
+ endif
+ let &eventignore = _eventignore
+ endtry
+ return winnr
+endfunction
+
+" Save/Restore window settings {{{
+function! genutils#SaveWindowSettings()
+ call genutils#SaveWindowSettings2('SaveWindowSettings', 1)
+endfunction
+
+function! genutils#RestoreWindowSettings()
+ call genutils#RestoreWindowSettings2('SaveWindowSettings')
+endfunction
+
+
+function! genutils#ResetWindowSettings()
+ call genutils#ResetWindowSettings2('SaveWindowSettings')
+endfunction
+
+function! genutils#SaveWindowSettings2(id, overwrite)
+ if genutils#ArrayVarExists("t:winSettings", a:id) && ! a:overwrite
+ return
+ endif
+
+ let t:winSettings{a:id} = []
+ call add(t:winSettings{a:id}, genutils#NumberOfWindows())
+ call add(t:winSettings{a:id}, &lines)
+ call add(t:winSettings{a:id}, &columns)
+ call add(t:winSettings{a:id}, winnr())
+ let i = 1
+ while winbufnr(i) != -1
+ call add(t:winSettings{a:id}, winheight(i))
+ call add(t:winSettings{a:id}, winwidth(i))
+ let i = i + 1
+ endwhile
+ "let g:savedWindowSettings = t:winSettings{a:id} " Debug.
+endfunction
+
+function! genutils#RestoreWindowSettings2(id)
+ " Calling twice fixes most of the resizing issues. This seems to be how the
+ " :mksession with "winsize" in 'sesionoptions' seems to work.
+ call s:RestoreWindowSettings2(a:id)
+ call s:RestoreWindowSettings2(a:id)
+endfunction
+
+function! s:RestoreWindowSettings2(id)
+ "if ! exists("t:winSettings" . a:id)
+ if ! genutils#ArrayVarExists("t:winSettings", a:id)
+ return
+ endif
+
+ let nWindows = t:winSettings{a:id}[0]
+ if nWindows != genutils#NumberOfWindows()
+ unlet t:winSettings{a:id}
+ return
+ endif
+ let orgLines = t:winSettings{a:id}[1]
+ let orgCols = t:winSettings{a:id}[2]
+ let activeWindow = t:winSettings{a:id}[3]
+ let mainWinSizeSame = (orgLines == &lines && orgCols == &columns)
+
+ let winNo = 1
+ let i = 4
+ while i < len(t:winSettings{a:id})
+ let height = t:winSettings{a:id}[i]
+ let width = t:winSettings{a:id}[i+1]
+ let height = (mainWinSizeSame ? height :
+ \ ((&lines * height + (orgLines / 2)) / orgLines))
+ let width = (mainWinSizeSame ? width :
+ \ ((&columns * width + (orgCols / 2)) / orgCols))
+ if winheight(winnr()) != height
+ exec winNo'resize' height
+ endif
+ if winwidth(winnr()) != width
+ exec 'vert' winNo 'resize' width
+ endif
+ let winNo = winNo + 1
+ let i = i + 2
+ endwhile
+
+ " Restore the current window.
+ call genutils#MoveCursorToWindow(activeWindow)
+ "unlet g:savedWindowSettings
+endfunction
+
+
+function! genutils#ResetWindowSettings2(id)
+ if genutils#ArrayVarExists("t:winSettings", a:id)
+ unlet t:winSettings{a:id}
+ endif
+endfunction
+
+" Save/Restore window settings }}}
+
+" Save/Restore selection {{{
+
+function! genutils#SaveVisualSelection(id)
+ let curmode = mode()
+ if curmode == 'n'
+ normal! gv
+ endif
+ let s:vismode{a:id} = mode()
+ let s:firstline{a:id} = line("'<")
+ let s:lastline{a:id} = line("'>")
+ let s:firstcol{a:id} = col("'<")
+ let s:lastcol{a:id} = col("'>")
+ if curmode !=# s:vismode{a:id}
+ exec "normal \<Esc>"
+ endif
+endfunction
+
+function! genutils#RestoreVisualSelection(id)
+ if mode() !=# 'n'
+ exec "normal \<Esc>"
+ endif
+ if exists('s:vismode{id}')
+ exec 'normal' s:firstline{a:id}.'gg'.s:firstcol{a:id}.'|'.
+ \ s:vismode{a:id}.(s:lastline{a:id}-s:firstline{a:id}).'j'.
+ \ (s:lastcol{a:id}-s:firstcol{a:id}).'l'
+ endif
+endfunction
+" Save/Restore selection }}}
+
+function! genutils#CleanupFileName(fileName)
+ return genutils#CleanupFileName2(a:fileName, '')
+endfunction
+
+function! genutils#CleanupFileName2(fileName, win32ProtectedChars)
+ let fileName = substitute(a:fileName, '^\s\+\|\s\+$', '', 'g')
+
+ " Expand relative paths and paths containing relative components (takes care
+ " of ~ also).
+ if ! genutils#PathIsAbsolute(fileName)
+ let fileName = fnamemodify(fileName, ':p')
+ endif
+
+ " I think we can have UNC paths on UNIX, if samba is installed.
+ if genutils#OnMS() && (match(fileName, '^//') == 0 ||
+ \ match(fileName, '^\\\\') == 0)
+ let uncPath = 1
+ else
+ let uncPath = 0
+ endif
+
+ " Remove multiple path separators.
+ if has('win32')
+ if a:win32ProtectedChars != ''
+ let fileName=substitute(fileName, '\\['.a:win32ProtectedChars.']\@!', '/',
+ \ 'g')
+ else
+ let fileName=substitute(fileName, '\\', '/', 'g')
+ endif
+ elseif genutils#OnMS()
+ " On non-win32 systems, the forward-slash is not supported, so leave
+ " back-slash.
+ let fileName=substitute(fileName, '\\\{2,}', '\', 'g')
+ endif
+ let fileName=substitute(fileName, '/\{2,}', '/', 'g')
+
+ " Remove ending extra path separators.
+ let fileName=substitute(fileName, '/$', '', '')
+ let fileName=substitute(fileName, '\\$', '', '')
+
+ " If it was an UNC path, add back an extra slash.
+ if uncPath
+ let fileName = '/'.fileName
+ endif
+
+ if genutils#OnMS()
+ let fileName=substitute(fileName, '^[A-Z]:', '\L&', '')
+
+ " Add drive letter if missing (just in case).
+ if !uncPath && match(fileName, '^/') == 0
+ let curDrive = substitute(getcwd(), '^\([a-zA-Z]:\).*$', '\L\1', '')
+ let fileName = curDrive . fileName
+ endif
+ endif
+ return fileName
+endfunction
+"echo genutils#CleanupFileName('\\a///b/c\')
+"echo genutils#CleanupFileName('C:\a/b/c\d')
+"echo genutils#CleanupFileName('a/b/c\d')
+"echo genutils#CleanupFileName('~/a/b/c\d')
+"echo genutils#CleanupFileName('~/a/b/../c\d')
+
+function! genutils#OnMS()
+ return has('win32') || has('dos32') || has('win16') || has('dos16') ||
+ \ has('win95')
+endfunction
+
+function! genutils#PathIsAbsolute(path)
+ let absolute=0
+ if has('unix') || genutils#OnMS()
+ if match(a:path, '^/') == 0
+ let absolute=1
+ endif
+ endif
+ if (! absolute) && genutils#OnMS()
+ if match(a:path, "^\\") == 0
+ let absolute=1
+ endif
+ endif
+ if (! absolute) && genutils#OnMS()
+ if match(a:path, "^[A-Za-z]:") == 0
+ let absolute=1
+ endif
+ endif
+ return absolute
+endfunction
+
+function! genutils#PathIsFileNameOnly(path)
+ return (match(a:path, "\\") < 0) && (match(a:path, "/") < 0)
+endfunction
+
+let s:mySNR = ''
+function! s:SNR()
+ if s:mySNR == ''
+ let s:mySNR = matchstr(expand('<sfile>'), '<SNR>\d\+_\zeSNR$')
+ endif
+ return s:mySNR
+endfun
+
+
+"" --- START save/restore position. {{{
+
+function! genutils#SaveSoftPosition(id)
+ let b:sp_startline_{a:id} = getline(".")
+ call genutils#SaveHardPosition(a:id)
+endfunction
+
+function! genutils#RestoreSoftPosition(id)
+ 0
+ call genutils#RestoreHardPosition(a:id)
+ let stLine = b:sp_startline_{a:id}
+ if getline('.') !=# stLine
+ if ! search('\V\^'.escape(stLine, "\\").'\$', 'W')
+ call search('\V\^'.escape(stLine, "\\").'\$', 'bW')
+ endif
+ endif
+ call genutils#MoveCurLineToWinLine(b:sp_winline_{a:id})
+endfunction
+
+function! genutils#ResetSoftPosition(id)
+ unlet b:sp_startline_{a:id}
+endfunction
+
+" A synonym for genutils#SaveSoftPosition.
+function! genutils#SaveHardPositionWithContext(id)
+ call genutils#SaveSoftPosition(a:id)
+endfunction
+
+" A synonym for genutils#RestoreSoftPosition.
+function! genutils#RestoreHardPositionWithContext(id)
+ call genutils#RestoreSoftPosition(a:id)
+endfunction
+
+" A synonym for genutils#ResetSoftPosition.
+function! genutils#ResetHardPositionWithContext(id)
+ call genutils#ResetSoftPosition(a:id)
+endfunction
+
+function! genutils#SaveHardPosition(id)
+ let b:sp_col_{a:id} = virtcol(".")
+ let b:sp_lin_{a:id} = line(".")
+ " Avoid accounting for wrapped lines.
+ let _wrap = &l:wrap
+ try
+ setl nowrap
+ let b:sp_winline_{a:id} = winline()
+ finally
+ let &l:wrap = _wrap
+ endtry
+endfunction
+
+function! genutils#RestoreHardPosition(id)
+ " This doesn't take virtual column.
+ "call cursor(b:sp_lin_{a:id}, b:sp_col_{a:id})
+ " Vim7 generates E16 if line number is invalid.
+ " TODO: Why is this leaving cursor on the last-but-one line when the
+ " condition meets?
+ execute ((line('$') < b:sp_lin_{a:id}) ? line('$') :
+ \ b:sp_lin_{a:id})
+ "execute b:sp_lin_{a:id}
+ execute ((line('$') < b:sp_lin_{a:id}) ? line('$') :
+ \ b:sp_lin_{a:id})
+ "execute b:sp_lin_{a:id}
+ execute "normal!" b:sp_col_{a:id} . "|"
+ call genutils#MoveCurLineToWinLine(b:sp_winline_{a:id})
+endfunction
+
+function! genutils#ResetHardPosition(id)
+ unlet b:sp_col_{a:id}
+ unlet b:sp_lin_{a:id}
+ unlet b:sp_winline_{a:id}
+endfunction
+
+function! genutils#GetLinePosition(id)
+ return b:sp_lin_{a:id}
+endfunction
+
+function! genutils#GetColPosition(id)
+ return b:sp_col_{a:id}
+endfunction
+
+function! genutils#IsPositionSet(id)
+ return exists('b:sp_col_' . a:id)
+endfunction
+
+"" --- END save/restore position. }}}
+
+
+
+""
+"" --- START: Notify window close -- {{{
+""
+
+let s:notifyWindow = {}
+function! genutils#AddNotifyWindowClose(windowTitle, functionName)
+ let bufName = a:windowTitle
+
+ let s:notifyWindow[bufName] = a:functionName
+
+ "let g:notifyWindow = s:notifyWindow " Debug.
+
+ " Start listening to events.
+ aug NotifyWindowClose
+ au!
+ au WinEnter * :call genutils#CheckWindowClose()
+ au BufEnter * :call genutils#CheckWindowClose()
+ aug END
+endfunction
+
+function! genutils#RemoveNotifyWindowClose(windowTitle)
+ let bufName = a:windowTitle
+
+ if has_key(s:notifyWindow, bufName)
+ call remove(s:notifyWindow, bufName)
+ if len(s:notifyWindow) == 0
+ "unlet g:notifyWindow " Debug.
+
+ aug NotifyWindowClose
+ au!
+ aug END
+ endif
+ endif
+endfunction
+
+function! genutils#CheckWindowClose()
+ if !exists('s:notifyWindow')
+ return
+ endif
+
+ " Now iterate over all the registered window titles and see which one's are
+ " closed.
+ for nextWin in keys(s:notifyWindow)
+ if bufwinnr(s:FindBufferForName(nextWin)) == -1
+ let funcName = s:notifyWindow[nextWin]
+ " Remove this entry as these are going to be processed. The caller can add
+ " them back if needed.
+ unlet s:notifyWindow[nextWin]
+ "call input("cmd: " . cmd)
+ call call(funcName, [nextWin])
+ endif
+ endfor
+endfunction
+
+"function! NotifyWindowCloseF(title)
+" call input(a:title . " closed")
+"endfunction
+"
+"function! RunNotifyWindowCloseTest()
+" call input("Creating three windows, 'ABC', 'XYZ' and 'b':")
+" split ABC
+" split X Y Z
+" split b
+" redraw
+" call genutils#AddNotifyWindowClose("ABC", "NotifyWindowCloseF")
+" call genutils#AddNotifyWindowClose("X Y Z", "NotifyWindowCloseF")
+" call input("notifyWindow: " . string(s:notifyWindow))
+" au NotifyWindowClose WinEnter
+" call input("Added notifications for 'ABC' and 'XYZ'\n".
+" \ "Now closing the windows, you should see ONLY two notifications:")
+" quit
+" quit
+" quit
+"endfunction
+
+""
+"" --- END: Notify window close -- }}}
+""
+
+" TODO: For large ranges, the cmd can become too big, so make it one cmd per
+" line.
+function! genutils#ShowLinesWithSyntax() range
+ " This makes sure we start (subsequent) echo's on the first line in the
+ " command-line area.
+ "
+ echo ''
+
+ let cmd = ''
+ let prev_group = ' x ' " Something that won't match any syntax group.
+
+ let show_line = a:firstline
+ let isMultiLine = ((a:lastline - a:firstline) > 1)
+ while show_line <= a:lastline
+ let cmd = ''
+ let length = strlen(getline(show_line))
+ let column = 1
+
+ while column <= length
+ let group = synIDattr(synID(show_line, column, 1), 'name')
+ if group != prev_group
+ if cmd != ''
+ let cmd = cmd . "'|"
+ endif
+ let cmd = cmd . 'echohl ' . (group == '' ? 'NONE' : group) . "|echon '"
+ let prev_group = group
+ endif
+ let char = strpart(getline(show_line), column - 1, 1)
+ if char == "'"
+ let char = "'."'".'"
+ endif
+ let cmd = cmd . char
+ let column = column + 1
+ endwhile
+
+ try
+ exec cmd."\n'"
+ catch
+ echo ''
+ endtry
+ let show_line = show_line + 1
+ endwhile
+ echohl NONE
+endfunction
+
+
+function! genutils#AlignWordWithWordInPreviousLine()
+ "First go to the first col in the word.
+ if getline('.')[col('.') - 1] =~ '\s'
+ normal! w
+ else
+ normal! "_yiw
+ endif
+ let orgVcol = virtcol('.')
+ let prevLnum = prevnonblank(line('.') - 1)
+ if prevLnum == -1
+ return
+ endif
+ let prevLine = getline(prevLnum)
+
+ " First get the column to align with.
+ if prevLine[orgVcol - 1] =~ '\s'
+ " column starts from 1 where as index starts from 0.
+ let nonSpaceStrInd = orgVcol " column starts from 1 where as index starts from 0.
+ while prevLine[nonSpaceStrInd] =~ '\s'
+ let nonSpaceStrInd = nonSpaceStrInd + 1
+ endwhile
+ else
+ if strlen(prevLine) < orgVcol
+ let nonSpaceStrInd = strlen(prevLine) - 1
+ else
+ let nonSpaceStrInd = orgVcol - 1
+ endif
+
+ while prevLine[nonSpaceStrInd - 1] !~ '\s' && nonSpaceStrInd > 0
+ let nonSpaceStrInd = nonSpaceStrInd - 1
+ endwhile
+ endif
+ let newVcol = nonSpaceStrInd + 1 " Convert to column number.
+
+ if orgVcol > newVcol " We need to reduce the spacing.
+ let sub = strpart(getline('.'), newVcol - 1, (orgVcol - newVcol))
+ if sub =~ '^\s\+$'
+ " Remove the excess space.
+ exec 'normal! ' . newVcol . '|'
+ exec 'normal! ' . (orgVcol - newVcol) . 'x'
+ endif
+ elseif orgVcol < newVcol " We need to insert spacing.
+ exec 'normal! ' . orgVcol . '|'
+ exec 'normal! ' . (newVcol - orgVcol) . 'i '
+ endif
+endfunction
+
+function! genutils#ShiftWordInSpace(dir)
+ if a:dir == 1 " forward.
+ " If currently on <Space>...
+ if getline(".")[col(".") - 1] == " "
+ let move1 = 'wf '
+ else
+ " If next col is a
+ "if getline(".")[col(".") + 1]
+ let move1 = 'f '
+ endif
+ let removeCommand = "x"
+ let pasteCommand = "bi "
+ let move2 = 'w'
+ let offset = 0
+ else " backward.
+ " If currently on <Space>...
+ if getline(".")[col(".") - 1] == " "
+ let move1 = 'w'
+ else
+ let move1 = '"_yiW'
+ endif
+ let removeCommand = "hx"
+ let pasteCommand = 'h"_yiwEa '
+ let move2 = 'b'
+ let offset = -3
+ endif
+
+ let savedCol = col(".")
+ exec "normal!" move1
+ let curCol = col(".")
+ let possible = 0
+ " Check if there is a space at the end.
+ if col("$") == (curCol + 1) " Works only for forward case, as expected.
+ let possible = 1
+ elseif getline(".")[curCol + offset] == " "
+ " Remove the space from here.
+ exec "normal!" removeCommand
+ let possible = 1
+ endif
+
+ " Move back into the word.
+ "exec "normal!" savedCol . "|"
+ if possible == 1
+ exec "normal!" pasteCommand
+ exec "normal!" move2
+ else
+ " Move to the original location.
+ exec "normal!" savedCol . "|"
+ endif
+endfunction
+
+
+function! genutils#CenterWordInSpace()
+ let line = getline('.')
+ let orgCol = col('.')
+ " If currently on <Space>...
+ if line[orgCol - 1] == " "
+ let matchExpr = ' *\%'. orgCol . 'c *\w\+ \+'
+ else
+ let matchExpr = ' \+\(\w*\%' . orgCol . 'c\w*\) \+'
+ endif
+ let matchInd = match(line, matchExpr)
+ if matchInd == -1
+ return
+ endif
+ let matchStr = matchstr(line, matchExpr)
+ let nSpaces = strlen(substitute(matchStr, '[^ ]', '', 'g'))
+ let word = substitute(matchStr, ' ', '', 'g')
+ let middle = nSpaces / 2
+ let left = nSpaces - middle
+ let newStr = ''
+ while middle > 0
+ let newStr = newStr . ' '
+ let middle = middle - 1
+ endwhile
+ let newStr = newStr . word
+ while left > 0
+ let newStr = newStr . ' '
+ let left = left - 1
+ endwhile
+
+ let newLine = strpart(line, 0, matchInd)
+ let newLine = newLine . newStr
+ let newLine = newLine . strpart (line, matchInd + strlen(matchStr))
+ silent! keepjumps call setline(line('.'), newLine)
+endfunction
+
+function! genutils#MapAppendCascaded(lhs, rhs, mapMode)
+
+ " Determine the map mode from the map command.
+ let mapChar = strpart(a:mapMode, 0, 1)
+
+ " Check if this is already mapped.
+ let oldrhs = maparg(a:lhs, mapChar)
+ if oldrhs != ""
+ let self = oldrhs
+ else
+ let self = a:lhs
+ endif
+ "echomsg a:mapMode . "oremap" . " " . a:lhs . " " . self . a:rhs
+ exec a:mapMode . "oremap" a:lhs self . a:rhs
+endfunction
+
+" smartSlash simply says whether to depend on shellslash and ArgLead for
+" determining path separator. If it shouldn't depend, it will always assume
+" that the required pathsep is forward-slash.
+function! genutils#UserFileComplete(ArgLead, CmdLine, CursorPos, smartSlash,
+ \ searchPath)
+ let glob = ''
+ let opathsep = "\\"
+ let npathsep = '/'
+ if exists('+shellslash') && ! &shellslash && a:smartSlash &&
+ \ stridx(a:ArgLead, "\\") != -1
+ let opathsep = '/'
+ let npathsep = "\\"
+ endif
+ if a:searchPath !=# ''
+ for nextPath in split(a:searchPath, genutils#CrUnProtectedCharsPattern(','))
+ let nextPath = genutils#CleanupFileName(nextPath)
+ let matches = glob(nextPath.'/'.a:ArgLead.'*')
+ if matches !~# '^\_s*$'
+ let matches = s:FixPathSep(matches, opathsep, npathsep)
+ let nextPath = substitute(nextPath, opathsep, npathsep, 'g')
+ let matches = substitute(matches, '\V'.escape(nextPath.npathsep, "\\"),
+ \ '', 'g')
+ let glob = glob . matches . "\n"
+ endif
+ endfor
+ else
+ let glob = s:FixPathSep(glob(a:ArgLead.'*'), opathsep, npathsep)
+ endif
+ " FIXME: Need an option to control if ArgLead should also be returned or
+ " not.
+ return glob."\n".a:ArgLead
+endfunction
+
+command! -complete=file -nargs=* GUDebugEcho :echo <q-args>
+function! genutils#UserFileExpand(fileArgs)
+ return substitute(genutils#GetVimCmdOutput(
+ \ 'GUDebugEcho ' . a:fileArgs), '^\_s\+\|\_s\+$', '', 'g')
+endfunction
+
+function! s:FixPathSep(matches, opathsep, npathsep)
+ let matches = a:matches
+ let matches = substitute(matches, a:opathsep, a:npathsep, 'g')
+ let matches = substitute(matches, "\\([^\n]\\+\\)", '\=submatch(1).'.
+ \ '(isdirectory(submatch(1)) ? a:npathsep : "")', 'g')
+ return matches
+endfunction
+
+function! genutils#GetVimCmdOutput(cmd)
+ let v:errmsg = ''
+ let output = ''
+ let _z = @z
+ let _shortmess = &shortmess
+ try
+ set shortmess=
+ redir @z
+ silent exec a:cmd
+ catch /.*/
+ let v:errmsg = substitute(v:exception, '^[^:]\+:', '', '')
+ finally
+ redir END
+ let &shortmess = _shortmess
+ if v:errmsg == ''
+ let output = @z
+ endif
+ let @z = _z
+ endtry
+ return output
+endfunction
+
+function! genutils#OptClearBuffer()
+ " Go as far as possible in the undo history to conserve Vim resources.
+ let _modifiable = &l:modifiable
+ let _undolevels = &undolevels
+ try
+ setl modifiable
+ set undolevels=-1
+ silent! keepjumps 0,$delete _
+ finally
+ let &undolevels = _undolevels
+ let &l:modifiable = _modifiable
+ endtry
+endfunction
+
+
+"" START: Sorting support. {{{
+""
+
+"
+" Comapare functions.
+"
+
+function! genutils#CmpByLineLengthNname(line1, line2, ...)
+ let direction = (a:0?a:1:1)
+ let cmp = genutils#CmpByLength(a:line1, a:line2, direction)
+ if cmp == 0
+ let cmp = genutils#CmpByString(a:line1, a:line2, direction)
+ endif
+ return cmp
+endfunction
+
+function! genutils#CmpByLength(line1, line2, ...)
+ let direction = (a:0?a:1:1)
+ let len1 = strlen(a:line1)
+ let len2 = strlen(a:line2)
+ return direction * (len1 - len2)
+endfunction
+
+" Compare first by name and then by length.
+" Useful for sorting Java imports.
+function! genutils#CmpJavaImports(line1, line2, ...)
+ let direction = (a:0?a:1:1)
+ " FIXME: Simplify this.
+ if stridx(a:line1, '.') == -1
+ let pkg1 = ''
+ let cls1 = substitute(a:line1, '.* \(^[ ]\+\)', '\1', '')
+ else
+ let pkg1 = substitute(a:line1, '.*import\s\+\(.*\)\.[^. ;]\+.*$', '\1', '')
+ let cls1 = substitute(a:line1, '^.*\.\([^. ;]\+\).*$', '\1', '')
+ endif
+ if stridx(a:line2, '.') == -1
+ let pkg2 = ''
+ let cls2 = substitute(a:line2, '.* \(^[ ]\+\)', '\1', '')
+ else
+ let pkg2 = substitute(a:line2, '.*import\s\+\(.*\)\.[^. ;]\+.*$', '\1', '')
+ let cls2 = substitute(a:line2, '^.*\.\([^. ;]\+\).*$', '\1', '')
+ endif
+
+ let cmp = genutils#CmpByString(pkg1, pkg2, direction)
+ if cmp == 0
+ let cmp = genutils#CmpByLength(cls1, cls2, direction)
+ endif
+ return cmp
+endfunction
+
+function! genutils#CmpByString(line1, line2, ...)
+ let direction = (a:0?a:1:1)
+ if a:line1 < a:line2
+ return -direction
+ elseif a:line1 > a:line2
+ return direction
+ else
+ return 0
+ endif
+endfunction
+
+function! genutils#CmpByStringIgnoreCase(line1, line2, ...)
+ let direction = (a:0?a:1:1)
+ if a:line1 <? a:line2
+ return -direction
+ elseif a:line1 >? a:line2
+ return direction
+ else
+ return 0
+ endif
+endfunction
+
+function! genutils#CmpByNumber(line1, line2, ...)
+ let direction = (a:0 ? a:1 :1)
+ let num1 = a:line1 + 0
+ let num2 = a:line2 + 0
+
+ if num1 < num2
+ return -direction
+ elseif num1 > num2
+ return direction
+ else
+ return 0
+ endif
+endfunction
+
+function! genutils#QSort(cmp, direction) range
+ call s:QSortR(a:firstline, a:lastline, a:cmp, a:direction,
+ \ 's:BufLineAccessor', 's:BufLineSwapper', '')
+endfunction
+
+function! genutils#QSort2(start, end, cmp, direction, accessor, swapper, context)
+ call s:QSortR(a:start, a:end, a:cmp, a:direction, a:accessor, a:swapper,
+ \ a:context)
+endfunction
+
+" The default swapper that swaps lines in the current buffer.
+function! s:BufLineSwapper(line1, line2, context)
+ let str2 = getline(a:line1)
+ silent! keepjumps call setline(a:line1, getline(a:line2))
+ silent! keepjumps call setline(a:line2, str2)
+endfunction
+
+" The default accessor that returns lines from the current buffer.
+function! s:BufLineAccessor(line, context)
+ return getline(a:line)
+endfunction
+
+" The default mover that moves lines from one place to another in the current
+" buffer.
+function! s:BufLineMover(from, to, context)
+ let line = getline(a:from)
+ exec a:from.'d_'
+ call append(a:to, line)
+endfunction
+
+"
+" Sort lines. QSortR() is called recursively.
+"
+function! s:QSortR(start, end, cmp, direction, accessor, swapper, context)
+ if a:end > a:start
+ let low = a:start
+ let high = a:end
+
+ " Arbitrarily establish partition element at the midpoint of the data.
+ let midStr = {a:accessor}(((a:start + a:end) / 2), a:context)
+
+ " Loop through the data until indices cross.
+ while low <= high
+
+ " Find the first element that is greater than or equal to the partition
+ " element starting from the left Index.
+ while low < a:end
+ let result = {a:cmp}({a:accessor}(low, a:context), midStr, a:direction)
+ if result < 0
+ let low = low + 1
+ else
+ break
+ endif
+ endwhile
+
+ " Find an element that is smaller than or equal to the partition element
+ " starting from the right Index.
+ while high > a:start
+ let result = {a:cmp}({a:accessor}(high, a:context), midStr, a:direction)
+ if result > 0
+ let high = high - 1
+ else
+ break
+ endif
+ endwhile
+
+ " If the indexes have not crossed, swap.
+ if low <= high
+ " Swap lines low and high.
+ call {a:swapper}(high, low, a:context)
+ let low = low + 1
+ let high = high - 1
+ endif
+ endwhile
+
+ " If the right index has not reached the left side of data must now sort
+ " the left partition.
+ if a:start < high
+ call s:QSortR(a:start, high, a:cmp, a:direction, a:accessor, a:swapper,
+ \ a:context)
+ endif
+
+ " If the left index has not reached the right side of data must now sort
+ " the right partition.
+ if low < a:end
+ call s:QSortR(low, a:end, a:cmp, a:direction, a:accessor, a:swapper,
+ \ a:context)
+ endif
+ endif
+endfunction
+
+function! genutils#BinSearchForInsert(start, end, line, cmp, direction)
+ return genutils#BinSearchForInsert2(a:start, a:end, a:line, a:cmp,
+ \ a:direction, 's:BufLineAccessor', '')
+endfunction
+
+function! genutils#BinSearchForInsert2(start, end, line, cmp, direction,
+ \ accessor, context)
+ let start = a:start - 1
+ let end = a:end
+ while start < end
+ let middle = (start + end + 1) / 2
+ " Support passing both Funcref's as well as names.
+ if type(a:cmp) == 2
+ if type(a:accessor) == 2
+ let result = a:cmp(a:accessor(middle, a:context), a:line, a:direction)
+ else
+ let result = a:cmp({a:accessor}(middle, a:context), a:line, a:direction)
+ endif
+ else
+ if type(a:accessor) == 2
+ let result = {a:cmp}(a:accessor(middle, a:context), a:line, a:direction)
+ else
+ let result = {a:cmp}({a:accessor}(middle, a:context), a:line, a:direction)
+ endif
+ endif
+ if result < 0
+ let start = middle
+ else
+ let end = middle - 1
+ endif
+ endwhile
+ return start
+endfunction
+
+function! genutils#BinSearchList(list, start, end, item, cmp)
+ let start = a:start - 1
+ let end = a:end
+ while start < end
+ let middle = (start + end + 1) / 2
+ let result = call(a:cmp, [get(a:list, middle), a:item])
+ if result < 0
+ let start = middle
+ else
+ let end = middle - 1
+ endif
+ endwhile
+ return start
+endfunction
+
+function! genutils#BinInsertSort(cmp, direction) range
+ call genutils#BinInsertSort2(a:firstline, a:lastline, a:cmp, a:direction,
+ \ 's:BufLineAccessor', 's:BufLineMover', '')
+endfunction
+
+function! genutils#BinInsertSort2(start, end, cmp, direction, accessor, mover, context)
+ let i = a:start + 1
+ while i <= a:end
+ let low = s:BinSearchToAppend2(a:start, i, {a:accessor}(i, a:context),
+ \ a:cmp, a:direction, a:accessor, a:context)
+ " Move the object.
+ if low < i
+ call {a:mover}(i, low - 1, a:context)
+ endif
+ let i = i + 1
+ endwhile
+endfunction
+
+function! s:BinSearchToAppend(start, end, line, cmp, direction)
+ return s:BinSearchToAppend2(a:start, a:end, a:line, a:cmp, a:direction,
+ \ 's:BufLineAccessor', '')
+endfunction
+
+function! s:BinSearchToAppend2(start, end, line, cmp, direction, accessor,
+ \ context)
+ let low = a:start
+ let high = a:end
+ while low < high
+ let mid = (low + high) / 2
+ let diff = {a:cmp}({a:accessor}(mid, a:context), a:line, a:direction)
+ if diff > 0
+ let high = mid
+ else
+ let low = mid + 1
+ if diff == 0
+ break
+ endif
+ endif
+ endwhile
+ return low
+endfunction
+
+""" END: Sorting support. }}}
+
+
+" Eats character if it matches the given pattern.
+"
+" Originally,
+" From: Benji Fisher <
[email protected]>
+" Date: Mon, 25 Mar 2002 15:05:14 -0500
+"
+" Based on Bram's idea of eating a character while type <Space> to expand an
+" abbreviation. This solves the problem with abbreviations, where we are
+" left with an extra space after the expansion.
+" Ex:
+" inoreabbr \stdout\ System.out.println("");<Left><Left><Left><C-R>=genutils#EatChar('\s')<CR>
+function! genutils#EatChar(pat)
+ let c = nr2char(getchar())
+ "call input('Pattern: '.a:pat.' '.
+ " \ ((c =~ a:pat) ? 'Returning empty' : 'Returning: '.char2nr(c)))
+ return (c =~ a:pat) ? '' : c
+endfun
+
+
+" Can return a spacer from 0 to 80 characters width.
+let s:spacer= " ".
+ \ " "
+function! genutils#GetSpacer(width)
+ return strpart(s:spacer, 0, a:width)
+endfunction
+
+function! genutils#SilentSubstitute(pat, cmd)
+ call genutils#SaveHardPosition('SilentSubstitute')
+ let _search = @/
+ try
+ let @/ = a:pat
+ keepjumps silent! exec a:cmd
+ finally
+ let @/ = _search
+ call genutils#RestoreHardPosition('SilentSubstitute')
+ call genutils#ResetHardPosition('SilentSubstitute')
+ endtry
+endfunction
+
+function! genutils#SilentDelete(arg1, ...)
+ " For backwards compatibility.
+ if a:0
+ let range = a:arg1
+ let pat = a:1
+ else
+ let range = ''
+ let pat = a:arg1
+ endif
+ let _search = @/
+ call genutils#SaveHardPosition('SilentDelete')
+ try
+ let @/ = pat
+ keepjumps silent! exec range'g//d _'
+ finally
+ let @/ = _search
+ call genutils#RestoreHardPosition('SilentDelete')
+ call genutils#ResetHardPosition('SilentDelete')
+ endtry
+endfunction
+
+" START: genutils#Roman2Decimal {{{
+let s:I = 1
+let s:V = 5
+let s:X = 10
+let s:L = 50
+let s:C = 100
+let s:D = 500
+let s:M = 1000
+
+function! s:Char2Num(c)
+ " A bit of magic on empty strings
+ if a:c == ""
+ return 0
+ endif
+ exec 'let n = s:' . toupper(a:c)
+ return n
+endfun
+
+function! genutils#Roman2Decimal(str)
+ if a:str !~? '^[IVXLCDM]\+$'
+ return a:str
+ endif
+ let sum = 0
+ let i = 0
+ let n0 = s:Char2Num(a:str[i])
+ let len = strlen(a:str)
+ while i < len
+ let i = i + 1
+ let n1 = s:Char2Num(a:str[i])
+ " Magic: n1=0 when i exceeds len
+ if n1 > n0
+ let sum = sum - n0
+ else
+ let sum = sum + n0
+ endif
+ let n0 = n1
+ endwhile
+ return sum
+endfun
+" END: genutils#Roman2Decimal }}}
+
+
+" BEGIN: Relative path {{{
+function! genutils#CommonPath(path1, path2, ...)
+ let path1 = genutils#CleanupFileName(a:path1) . ((a:0 > 0 ? a:1 : 0) ? '/' : '')
+ let path2 = genutils#CleanupFileName(a:path2) . ((a:0 > 1 ? a:2 : 0) ? '/' : '')
+ return genutils#CommonString(path1, path2)
+endfunction
+
+function! genutils#CommonString(str1, str2)
+ let str1 = a:str1
+ let str2 = a:str2
+ if str1 == str2
+ return str1
+ endif
+ let n = 0
+ while str1[n] == str2[n]
+ let n = n+1
+ endwhile
+ return strpart(str1, 0, n)
+endfunction
+
+function! genutils#RelPathFromFile(srcFile, tgtFile)
+ return genutils#RelPathFromDir(fnamemodify(a:srcFile, ':h'), a:tgtFile)
+endfunction
+
+function! genutils#RelPathFromDir(srcDir, tgtFile)
+ let cleanDir = genutils#CleanupFileName(a:srcDir).'/'
+ let cleanFile = genutils#CleanupFileName(a:tgtFile)
+ let cmnPath = genutils#CommonPath(cleanDir, cleanFile, 1)
+ let relDirFromCmnPath = strpart(cleanDir, strlen(cmnPath))
+ if relDirFromCmnPath == '/' " This means the file is under the srcDir.
+ let relDirFromCmnPath = ''
+ endif
+ let relFileFromCmnPath = strpart(cleanFile, strlen(cmnPath))
+ return substitute(relDirFromCmnPath, '[^/]\+', '..', 'g') .
+ \ relFileFromCmnPath
+endfunction
+
+" END: Relative path }}}
+
+
+" BEGIN: Persistent settings {{{
+if ! exists("g:genutilsNoPersist") || ! g:genutilsNoPersist
+ " Make sure the '!' option to store global variables that are upper cased are
+ " stored in viminfo file.
+ " Make sure it is the first option, so that it will not interfere with the
+ " 'n' option ("Todd J. Cosgrove" (todd dot cosgrove at softechnics dot
+ " com)).
+ " Also take care of empty value, when 'compatible' mode is on (Bram
+ " Moolenar)
+ if &viminfo == ''
+ set viminfo=!,'20,"50,h
+ else
+ set viminfo^=!
+ endif
+endif
+
+function! genutils#PutPersistentVar(pluginName, persistentVar, value)
+ if ! exists("g:genutilsNoPersist") || ! g:genutilsNoPersist
+ let globalVarName = s:PersistentVarName(a:pluginName, a:persistentVar)
+ exec 'let ' . globalVarName . " = '" . a:value . "'"
+ endif
+endfunction
+
+function! genutils#GetPersistentVar(pluginName, persistentVar, default)
+ if ! exists("g:genutilsNoPersist") || ! g:genutilsNoPersist
+ let globalVarName = s:PersistentVarName(a:pluginName, a:persistentVar)
+ if (exists(globalVarName))
+ exec 'let value = ' . globalVarName
+ exec 'unlet ' . globalVarName
+ else
+ let value = a:default
+ endif
+ return value
+ else
+ return default
+ endif
+endfunction
+
+function! s:PersistentVarName(pluginName, persistentVar)
+ return 'g:GU_' . toupper(a:pluginName) . '_' . toupper(a:persistentVar)
+endfunction
+" END: Persistent settings }}}
+
+
+" FileChangedShell handling {{{
+if !exists('s:fcShellPreFuncs')
+ let s:fcShellPreFuncs = {}
+endif
+
+function! genutils#AddToFCShellPre(funcName)
+ let s:fcShellPreFuncs[a:funcName] = a:funcName
+endfunction
+
+function! genutils#RemoveFromFCShellPre(funcName)
+ if has_key(s:fcShellPreFuncs, a:funcName)
+ unlet s:fcShellPreFuncs[a:funcName]
+ endif
+endfunction
+
+let s:defFCShellInstalled = 0
+function! genutils#DefFCShellInstall()
+ if ! s:defFCShellInstalled
+ aug DefFCShell
+ au!
+ au FileChangedShell * nested call genutils#DefFileChangedShell()
+ aug END
+ endif
+ let s:defFCShellInstalled = s:defFCShellInstalled + 1
+endfunction
+
+function! genutils#DefFCShellUninstall()
+ if s:defFCShellInstalled <= 0
+ return
+ endif
+ let s:defFCShellInstalled = s:defFCShellInstalled - 1
+ if ! s:defFCShellInstalled
+ aug DefFCShell
+ au!
+ aug END
+ endif
+endfunction
+
+function! genutils#DefFileChangedShell()
+ let autoread = s:InvokeFuncs(s:fcShellPreFuncs)
+ let bufNo = expand('<abuf>') + 0
+ let fName = expand('<afile>')
+ let msg = ''
+ let v:fcs_choice = ''
+ if getbufvar(bufNo, '&modified')
+ let v:fcs_choice = 'ask'
+ elseif ! autoread
+ let v:fcs_choice = 'ask'
+ else
+ let v:fcs_choice = 'reload'
+ endif
+ return
+endfunction
+
+function! s:InvokeFuncs(funcList)
+ let autoread = &autoread
+ if len(a:funcList) != 0
+ for nextFunc in keys(a:funcList)
+ let result = call(nextFunc, [])
+ if result != -1
+ let autoread = autoread || result
+ endif
+ endfor
+ endif
+ return autoread
+endfunction
+" FileChangedShell handling }}}
+
+
+" Sign related utilities {{{
+function! genutils#CurLineHasSign()
+ let signs = genutils#GetVimCmdOutput('sign place buffer=' . bufnr('%'), 1)
+ return (match(signs,
+ \ 'line=' . line('.') . '\s\+id=\d\+\s\+name=VimBreakPt') != -1)
+endfunction
+
+function! genutils#ClearAllSigns()
+ let signs = genutils#GetVimCmdOutput('sign place buffer=' . bufnr('%'), 1)
+ let curIdx = 0
+ let pat = 'line=\d\+\s\+id=\zs\d\+\ze\s\+name=VimBreakPt'
+ let id = 0
+ while curIdx != -1 && curIdx < strlen(signs)
+ let id = matchstr(signs, pat, curIdx)
+ if id != ''
+ exec 'sign unplace ' . id . ' buffer=' . bufnr('%')
+ endif
+ let curIdx = matchend(signs, pat, curIdx)
+ endwhile
+endfunction
+" }}}
+
+let s:UNPROTECTED_CHAR_PRFX = '\%(\%([^\\]\|^\)\\\%(\\\\\)*\)\@<!' " Doesn't eat slashes.
+"let s:UNPROTECTED_CHAR_PRFX = '\\\@<!\%(\\\\\)*' " Eats slashes.
+function! genutils#CrUnProtectedCharsPattern(chars, ...)
+ let capture = (a:0 > 0?1:0)
+ let regex = s:UNPROTECTED_CHAR_PRFX
+ let chars = a:chars
+ if strlen(chars) > 1
+ let chars = '['.chars.']'
+ endif
+ if capture
+ let chars = '\('.chars.'\)'
+ endif
+ return regex.chars
+endfunction
+
+function! genutils#PromptForElement(array, default, msg, skip, useDialog,
+ \ nCols)
+ let nCols = a:nCols
+ let index = 0
+ let line = ""
+ let element = ""
+ let optionsMsg = ""
+ let colWidth = &columns / nCols - 1 " Leave a margin of one column as a gap.
+ let curCol = 1
+ let nElements = len(a:array)
+ let newArray = [] " Without the skip element.
+ if index(a:array, a:skip) != -1
+ let nElements = nElements - 1
+ endif
+ for element in a:array
+ if element ==# a:skip
+ continue
+ endif
+ call add(newArray, element)
+ let element = strpart(index." ", 0, 4) . element
+ let eleColWidth = (strlen(element) - 1) / colWidth + 1
+ " Fill up the spacer for the rest of the partial column.
+ let element = element . genutils#GetSpacer(
+ \ eleColWidth * (colWidth + 1) - strlen(element) - 1)
+ let wouldBeLength = strlen(line) + strlen(element) + 1
+ if wouldBeLength > (curCol * (colWidth + eleColWidth)) &&
+ \ wouldBeLength > &columns
+ let splitLine = 2 " Split before adding the new element.
+ elseif curCol == nCols
+ let splitLine = 1 " Split after adding the new element.
+ else
+ let splitLine = 0
+ endif
+ if splitLine == 2
+ if strlen(line) == &columns
+ " Remove the last space as it otherwise results in an extra empty line
+ " on the screen.
+ let line = strpart(line, 0, strlen(line) - 1)
+ endif
+ let optionsMsg = optionsMsg . line . "\n"
+ let line = element . ' '
+ let curCol = strlen(element) / (colWidth + 1)
+ else
+ let line = line . element . ' '
+ if splitLine == 1
+ if strlen(line) == &columns
+ " Remove the last space as it otherwise results in an extra empty line
+ " on the screen.
+ let line = strpart(line, 0, strlen(line) - 1)
+ endif
+ let curCol = 0 " Reset col count.
+ let optionsMsg = optionsMsg . line . "\n"
+ let line = ""
+ endif
+ endif
+ let curCol = curCol + 1
+ let index = index + 1
+ endfor
+ " Finally if there is anything left in line, then append that too.
+ if line.'' != ''
+ let optionsMsg = optionsMsg . line . "\n"
+ let line = ""
+ endif
+
+ " Default index or empty string.
+ let default = ''
+ if type(a:default) == 0
+ let default = a:default
+ elseif a:default.'' != ''
+ let default = index(a:array, a:default)
+ endif
+ if a:default == -1
+ let default = ''
+ endif
+
+ while !exists("selectedElement")
+ if a:useDialog
+ let s:selection = inputdialog(optionsMsg . a:msg, default)
+ else
+ let s:selection = input(optionsMsg . a:msg, default)
+ endif
+ if s:selection.'' == ''
+ let selectedElement = ''
+ let s:selection = -1
+ else
+ let s:selection = (s:selection !~# '^\d\+$') ? -1 : (s:selection + 0)
+ if s:selection >= 0 && s:selection < nElements
+ let selectedElement = newArray[s:selection]
+ else
+ echohl ERROR | echo "\nInvalid selection, please try again" |
+ \ echohl NONE
+ endif
+ endif
+ echo "\n"
+ endwhile
+ return selectedElement
+endfunction
+
+let s:selection = -1
+function! genutils#GetSelectedIndex()
+ return s:selection
+endfunction
+
+" Always match() with 'ignorecase' and 'smartcase' off.
+function! s:Match(expr, pat, start)
+ let _ic = &ignorecase
+ let _scs = &smartcase
+ let result = -1
+ try
+ set noignorecase
+ set nosmartcase
+ let result = match(a:expr, a:pat, a:start)
+ finally
+ let &ignorecase = _ic
+ let &smartcase = _scs
+ endtry
+ return result
+endfunction
+
+" Restore cpo.
+let &cpo = s:save_cpo
+unlet s:save_cpo
+
+" vim6:fdm=marker et
--- /dev/null
+" lookupfile.vim: See plugin/lookupfile.vim
+
+" Make sure line-continuations won't cause any problem. This will be restored
+" at the end
+let s:save_cpo = &cpo
+set cpo&vim
+
+" Some onetime initialization of variables
+if !exists('s:myBufNum')
+ let s:windowName = '[Lookup File]'
+ let s:myBufNum = -1
+ let s:popupIsHidden = 0
+endif
+let g:lookupfile#lastPattern = ""
+let g:lookupfile#lastResults = []
+let g:lookupfile#lastStatsMsg = []
+let g:lookupfile#recentFiles = []
+
+function! lookupfile#OpenWindow(bang, initPat)
+ let origWinnr = winnr()
+ let _isf = &isfname
+ let _splitbelow = &splitbelow
+ set nosplitbelow
+ try
+ if s:myBufNum == -1
+ " Temporarily modify isfname to avoid treating the name as a pattern.
+ set isfname-=\
+ set isfname-=[
+ if exists('+shellslash')
+ call genutils#OpenWinNoEa("1sp \\\\". escape(s:windowName, ' '))
+ else
+ call genutils#OpenWinNoEa("1sp \\". escape(s:windowName, ' '))
+ endif
+ let s:myBufNum = bufnr('%')
+ else
+ let winnr = bufwinnr(s:myBufNum)
+ if winnr == -1
+ call genutils#OpenWinNoEa('1sb '. s:myBufNum)
+ else
+ let wasVisible = 1
+ exec winnr 'wincmd w'
+ endif
+ endif
+ finally
+ let &isfname = _isf
+ let &splitbelow = _splitbelow
+ endtry
+
+ call s:SetupBuf()
+ let initPat = ''
+ if a:bang != ''
+ let initPat = ''
+ elseif a:initPat != ''
+ let initPat = a:initPat
+ elseif g:lookupfile#lastPattern != '' && g:LookupFile_PreserveLastPattern
+ let initPat = g:lookupfile#lastPattern
+ endif
+ $
+ if getline('.') !=# initPat
+ silent! put=''
+ call setline('.', initPat)
+ endif
+ startinsert!
+ if !g:LookupFile_OnCursorMovedI
+ " This is a hack to bring up the popup immediately, while reopening the
+ " window, just for a better response.
+ aug LookupFileCursorHoldImm
+ au!
+ au CursorMovedI <buffer> nested exec 'doautocmd LookupFile CursorHoldI' |
+ \ au! LookupFileCursorHoldImm
+ aug END
+ endif
+ call s:LookupFileSet()
+ aug LookupFileReset
+ au!
+ au CursorMovedI <buffer> call <SID>LookupFileSet()
+ au CursorMoved <buffer> call <SID>LookupFileSet()
+ au WinEnter <buffer> call <SID>LookupFileSet()
+ au TabEnter <buffer> call <SID>LookupFileSet()
+ au WinEnter * call <SID>LookupFileReset(0)
+ au TabEnter * call <SID>LookupFileReset(0)
+ au CursorMoved * call <SID>LookupFileReset(0)
+ " Better be safe than sorry.
+ au BufHidden <buffer> call <SID>LookupFileReset(1)
+ aug END
+endfunction
+
+function! lookupfile#CloseWindow()
+ if bufnr('%') != s:myBufNum
+ return
+ endif
+
+ call s:LookupFileReset(1)
+ close
+endfunction
+
+function! lookupfile#ClearCache()
+ let g:lookupfile#lastPattern = ""
+ let g:lookupfile#lastResults = []
+endfunction
+
+function! s:LookupFileSet()
+ if bufnr('%') != s:myBufNum || exists('s:_backspace')
+ return
+ endif
+ let s:_backspace = &backspace
+ set backspace=start
+ let s:_completeopt = &completeopt
+ set completeopt+=menuone
+ let s:_updatetime = &updatetime
+ let &updatetime = g:LookupFile_UpdateTime
+endfunction
+
+function! s:LookupFileReset(force)
+ if a:force
+ aug LookupFileReset
+ au!
+ aug END
+ endif
+ " Ignore the event while in the same buffer.
+ if exists('s:_backspace') && (a:force || (bufnr('%') != s:myBufNum))
+ let &backspace = s:_backspace
+ let &completeopt = s:_completeopt
+ let &updatetime = s:_updatetime
+ unlet s:_backspace s:_completeopt s:_updatetime
+ endif
+endfunction
+
+function! s:HidePopup()
+ let s:popupIsHidden = 1
+ return "\<C-E>"
+endfunction
+
+function! lookupfile#IsPopupHidden()
+ return s:popupIsHidden
+endfunction
+
+function! s:SetupBuf()
+ call genutils#SetupScratchBuffer()
+ resize 1
+ setlocal wrap
+ setlocal bufhidden=hide
+ setlocal winfixheight
+ setlocal wrapmargin=0
+ setlocal textwidth=0
+ setlocal completefunc=lookupfile#Complete
+ syn clear
+ set ft=lookupfile
+ " Setup maps to open the file.
+ inoremap <silent> <buffer> <expr> <C-E> <SID>HidePopup()
+ inoremap <silent> <buffer> <expr> <CR> <SID>AcceptFile(0, "\<CR>")
+ inoremap <silent> <buffer> <expr> <C-O> <SID>AcceptFile(1, "\<C-O>")
+ " This prevents the "Whole line completion" from getting triggered with <BS>,
+ " however this might make the dropdown kind of flash.
+ inoremap <buffer> <expr> <BS> pumvisible()?"\<C-E>\<BS>":"\<BS>"
+ inoremap <buffer> <expr> <S-BS> pumvisible()?"\<C-E>\<BS>":"\<BS>"
+ " Make <C-Y> behave just like <CR>
+ imap <buffer> <C-Y> <CR>
+ if g:LookupFile_EscCancelsPopup
+ inoremap <buffer> <expr> <Esc> pumvisible()?"\<C-E>\<C-C>":"\<Esc>"
+ endif
+ inoremap <buffer> <expr> <silent> <Down> <SID>GetCommand(1, 1, "\<C-N>",
+ \ "\"\\<Lt>C-N>\"")
+ inoremap <buffer> <expr> <silent> <Up> <SID>GetCommand(1, 1, "\<C-P>",
+ \ "\"\\<Lt>C-P>\"")
+ inoremap <buffer> <expr> <silent> <PageDown> <SID>GetCommand(1, 0,
+ \ "\<PageDown>", '')
+ inoremap <buffer> <expr> <silent> <PageUp> <SID>GetCommand(1, 0,
+ \ "\<PageUp>", '')
+ nnoremap <silent> <buffer> o :OpenFile<CR>
+ nnoremap <silent> <buffer> O :OpenFile!<CR>
+ command! -buffer -nargs=0 -bang OpenFile
+ \ :call <SID>OpenCurFile('<bang>' != '')
+ command! -buffer -nargs=0 -bang AddPattern :call <SID>AddPattern()
+ nnoremap <buffer> <silent> <Plug>LookupFile :call lookupfile#CloseWindow()<CR>
+ inoremap <buffer> <silent> <Plug>LookupFile <C-E><C-C>:call lookupfile#CloseWindow()<CR>
+
+ aug LookupFile
+ au!
+ if g:LookupFile_ShowFiller
+ exec 'au' (g:LookupFile_OnCursorMovedI ? 'CursorMovedI' : 'CursorHoldI')
+ \ '<buffer> call <SID>ShowFiller()'
+ endif
+ exec 'au' (g:LookupFile_OnCursorMovedI ? 'CursorMovedI' : 'CursorHoldI')
+ \ '<buffer> call lookupfile#LookupFile(0)'
+ aug END
+endfunction
+
+function! s:GetCommand(withPopupTrigger, withSkipPat, actCmd, innerCmd)
+ let cmd = ''
+ if a:withPopupTrigger && !pumvisible()
+ let cmd .= "\<C-X>\<C-U>"
+ endif
+ let cmd .= a:actCmd. "\<C-R>=(getline('.') == lookupfile#lastPattern) ? ".
+ \ a:innerCmd." : ''\<CR>"
+ return cmd
+endfunction
+
+function! s:AddPattern()
+ if g:LookupFile_PreservePatternHistory
+ silent! put! =g:lookupfile#lastPattern
+ $
+ endif
+endfunction
+
+function! s:AcceptFile(splitWin, key)
+ if s:popupIsHidden
+ return a:key
+ endif
+ if !pumvisible()
+ call lookupfile#LookupFile(0, 1)
+ endif
+ let acceptCmd = ''
+ if type(g:LookupFile_LookupAcceptFunc) == 2 ||
+ \ (type(g:LookupFile_LookupAcceptFunc) == 1 &&
+ \ substitute(g:LookupFile_LookupAcceptFunc, '\s', '', 'g') != '')
+ let acceptCmd = call(g:LookupFile_LookupAcceptFunc, [a:splitWin, a:key])
+ else
+ let acceptCmd = lookupfile#AcceptFile(a:splitWin, a:key)
+ endif
+
+ return (!pumvisible() ? "\<C-X>\<C-U>" : '').acceptCmd
+endfunction
+
+function! s:IsValid(fileName)
+ if bufnr('%') != s:myBufNum || a:fileName == ''
+ return 0
+ endif
+ if !filereadable(a:fileName) && !isdirectory(a:fileName)
+ if g:LookupFile_AllowNewFiles
+ " Check if the parent directory exists, then we can create a new buffer
+ " (Ido feature)
+ let parent = fnamemodify(a:fileName, ':h')
+ if parent == '' || (parent != '' && !isdirectory(parent))
+ return 1
+ endif
+ endif
+ return 0
+ endif
+ return 1
+endfunction
+
+function! lookupfile#AcceptFile(splitWin, key)
+ if len(g:lookupfile#lastResults) == 0 && !s:IsValid(getline('.'))
+ return "\<C-O>:echohl ErrorMsg | echo 'No such file or directory' | echohl NONE\<CR>"
+ endif
+
+ " Skip the first match, which is essentially the same as pattern.
+ let nextCmd = "\<C-N>\<C-R>=(getline('.') == lookupfile#lastPattern)?\"\\<C-N>\":''\<CR>"
+ let acceptCmd = "\<C-Y>\<Esc>:AddPattern\<CR>:OpenFile".(a:splitWin?'!':'').
+ \ "\<CR>"
+ if getline('.') ==# g:lookupfile#lastPattern
+ if len(g:lookupfile#lastResults) == 0
+ " FIXME: shouldn't this be an error?
+ let acceptCmd = acceptCmd
+ elseif len(g:lookupfile#lastResults) == 1 || g:LookupFile_AlwaysAcceptFirst
+ " If there is only one file, we will also select it (if not already
+ " selected)
+ let acceptCmd = nextCmd.acceptCmd
+ else
+ let acceptCmd = nextCmd
+ endif
+ endif
+
+ return acceptCmd
+endfunction
+
+function! s:OpenCurFile(splitWin)
+ let fileName = getline('.')
+ if fileName =~ '^\s*$'
+ return
+ endif
+ if !s:IsValid(fileName)
+ echohl ErrorMsg | echo 'No such file or directory' | echohl NONE
+ endif
+
+ if type(g:LookupFile_LookupNotifyFunc) == 2 ||
+ \ (type(g:LookupFile_LookupNotifyFunc) == 1 &&
+ \ substitute(g:LookupFile_LookupNotifyFunc, '\s', '', 'g') != '')
+ call call(g:LookupFile_LookupNotifyFunc, [])
+ endif
+ call lookupfile#CloseWindow()
+
+ " Update the recent files list.
+ if g:LookupFile_RecentFileListSize > 0
+ let curPos = index(g:lookupfile#recentFiles, fileName)
+ call add(g:lookupfile#recentFiles, fileName)
+ if curPos != -1
+ call remove(g:lookupfile#recentFiles, curPos)
+ elseif len(g:lookupfile#recentFiles) > g:LookupFile_RecentFileListSize
+ let g:lookupfile#recentFiles = g:lookupfile#recentFiles[
+ \ -g:LookupFile_RecentFileListSize :]
+ endif
+ endif
+
+ let bufnr = genutils#FindBufferForName(fileName)
+ let winnr = bufwinnr(bufnr)
+ if winnr == -1 && g:LookupFile_SearchForBufsInTabs
+ for i in range(tabpagenr('$'))
+ if index(tabpagebuflist(i+1), bufnr) != -1
+ " Switch to the tab and set winnr.
+ exec 'tabnext' (i+1)
+ let winnr = bufwinnr(bufnr)
+ endif
+ endfor
+ endif
+ if winnr != -1
+ exec winnr.'wincmd w'
+ else
+ let splitOpen = 0
+ if &switchbuf ==# 'split' || a:splitWin
+ let splitOpen = 1
+ endif
+ " First try opening as a buffer, if it fails, we will open as a file.
+ try
+ if bufnr == -1
+ throw ''
+ endif
+ exec (splitOpen?'s':'').'buffer' bufnr
+ catch /^Vim\%((\a\+)\)\=:E325/
+ " Ignore, this anyway means the file was found.
+ catch
+ try
+ exec (splitOpen?'split':'edit') fileName
+ catch /^Vim\%((\a\+)\)\=:E325/
+ " Ignore, this anyway means the file was found.
+ endtry
+ endtry
+ endif
+endfunction
+
+function! s:ShowFiller()
+ return lookupfile#LookupFile(1)
+endfunction
+
+function! lookupfile#Complete(findstart, base)
+ if a:findstart
+ return 0
+ else
+ call lookupfile#LookupFile(0, 1, a:base)
+ return g:lookupfile#lastStatsMsg+g:lookupfile#lastResults
+ endif
+endfunction
+
+function! lookupfile#LookupFile(showingFiller, ...)
+ let generateMode = (a:0 == 0 ? 0 : a:1)
+ if generateMode
+ let pattern = (a:0 > 1) ? a:2 : getline('.')
+ else
+ let pattern = getline('.')
+ " The normal completion behavior is to stop completion when cursor is moved.
+ if col('.') == 1 || (col('.') != col('$'))
+ return ''
+ endif
+ endif
+ if pattern == '' || (pattern ==# g:lookupfile#lastPattern && pumvisible())
+ return ''
+ endif
+
+ if s:popupIsHidden && g:lookupfile#lastPattern ==# pattern
+ return ''
+ endif
+ let s:popupIsHidden = 0
+
+ let statusMsg = ''
+ if pattern == ' '
+ if len(g:lookupfile#recentFiles) == 0
+ let statusMsg = '<<< No recent files >>>'
+ let files = []
+ else
+ let statusMsg = '<<< Showing '.len(g:lookupfile#recentFiles).' recent files >>>'
+ let files = reverse(copy(g:lookupfile#recentFiles))
+ endif
+ elseif strlen(pattern) < g:LookupFile_MinPatLength
+ let statusMsg = '<<< Type at least '.g:LookupFile_MinPatLength.
+ \ ' characters >>>'
+ let files = []
+ " We ignore filler when we have the result in hand.
+ elseif g:lookupfile#lastPattern ==# pattern
+ " This helps at every startup as we start with the previous pattern.
+ let files = g:lookupfile#lastResults
+ elseif a:showingFiller
+ " Just show a filler and return. We could return this as the only match, but
+ " unless 'completeopt' has "menuone", menu doesn't get shown.
+ let statusMsg = '<<< Looking up files... hit ^C to break >>>'
+ let files = []
+ else
+ if type(g:LookupFile_LookupFunc) == 2 ||
+ \ (type(g:LookupFile_LookupFunc) == 1 &&
+ \ substitute(g:LookupFile_LookupFunc, '\s', '', 'g') != '')
+ let files = call(g:LookupFile_LookupFunc, [pattern])
+ else
+ let _tags = &tags
+ try
+ let &tags = eval(g:LookupFile_TagExpr)
+ let taglist = taglist(g:LookupFile_TagsExpandCamelCase ?
+ \ lookupfile#ExpandCamelCase(pattern) : pattern)
+ catch
+ echohl ErrorMsg | echo "Exception: " . v:exception | echohl NONE
+ return ''
+ finally
+ let &tags = _tags
+ endtry
+
+ " Show the matches for what is typed so far.
+ if g:LookupFile_UsingSpecializedTags
+ let files = map(taglist, '{'.
+ \ '"word": fnamemodify(v:val["filename"], ":p"), '.
+ \ '"abbr": v:val["name"], '.
+ \ '"menu": fnamemodify(v:val["filename"], ":h"), '.
+ \ '"dup": 1, '.
+ \ '}')
+ else
+ let files = map(taglist, 'fnamemodify(v:val["filename"], ":p")')
+ endif
+ endif
+
+ let pat = g:LookupFile_FileFilter
+ if pat != ''
+ call filter(files, '(type(v:val) == 4) ? v:val["word"] !~ pat : v:val !~ pat')
+ endif
+
+ if g:LookupFile_SortMethod ==# 'alpha'
+ " When UsingSpecializedTags, sort by the actual name (Timothy, Guo
+ " (firemeteor dot guo at gmail dot com)).
+ if type(get(files, 0)) == 4
+ call sort(files, "s:CmpByName")
+ else
+ call sort(files)
+ endif
+ endif
+ let g:lookupfile#lastPattern = pattern
+ let g:lookupfile#lastResults = files
+ endif
+ if statusMsg == ''
+ if len(files) > 0
+ let statusMsg = '<<< '.len(files).' Matching >>>'
+ else
+ let statusMsg = '<<< None Matching >>>'
+ endif
+ endif
+ let msgLine = [{'word': pattern, 'abbr': statusMsg, 'menu': pattern}]
+ let g:lookupfile#lastStatsMsg = msgLine
+ if !generateMode
+ call complete(1, msgLine+files)
+ endif
+ return ''
+endfunction
+
+function! lookupfile#ExpandCamelCase(str)
+ let pat = a:str
+ " Check if there are at least two consecutive uppercase letters to turn on
+ " the CamelCase expansion.
+ if match(a:str, '\u\u') != -1
+ let pat = '\C'.substitute(a:str, '\u\+',
+ \ '\=substitute(submatch(0), ".", '."'".'&\\U*'."'".', "g")', 'g')
+ let @*=pat
+ endif
+ return pat
+endfunction
+
+function! s:CmpByName(i1, i2)
+ let ileft = a:i1["abbr"]
+ let iright = a:i2["abbr"]
+ return ileft == iright ? 0 : ileft > iright ? 1 : -1
+endfunc
+
+" Restore cpo.
+let &cpo = s:save_cpo
+unlet s:save_cpo
+
+" vim6:fdm=marker et sw=2
--- /dev/null
+*lookupfile.txt* Lookup files using Vim7 ins-completion
+ Requires Vim 7.0
+ Last Change: 24-Aug-2007 @ 18:25
+ Author: Hari Krishna Dara (hari.vim at gmail dot com)
+
+ *lookupfile-introduction*
+ *lookupfile-plugin*
+Lookupfile is a very simple approach to opening files by typing a pattern to
+represent the file you are looking for, and selecting a file from the completion
+dropdown to open in the current Vim session. It provides a consistent interface
+to lookup files by various means (tags, path, buffers, external tools etc.). It
+uses the new Vim7 insert-mode completion mechanism to show matching files. It
+is a new tool
+
+
+The default functionality of the plugin is to lookup filenames from the tag
+files, by matching the pattern against tag names. However, using the standard
+tags (generated by ctags) can be very slow at best, so it is recommended to use
+specially generated tagfiles, that are meant only for finding the filenames. You
+don't however need to generate tag files at all to use the plugin, as there are
+ways to lookup files from sources other than tag files.
+
+==============================================================================
+OVERVIEW *lookupfile-overview*
+
+|lookupfile-installation| Installing the plugin.
+
+|lookupfile-usage| A brief usage to get you quickly started.
+
+|lookupfile-maps| Mappings defined in the lookup window.
+
+|lookupfile-tags| Creating index of files for a fast lookup.
+
+|lookupfile-settings| An explanation of various configure options.
+
+|lookupfile-extend| Features that make the plugin extensible.
+
+|lookupfile-known-issues| A list of known issues.
+
+|lookupfile-wishlist| Wishlist items that may be worth doing for a future
+ version.
+
+|lookupfile-changes| A change list for current version from the previous
+ versions.
+
+|lookupfile-acknowledgements| Acknowledgements.
+==============================================================================
+
+ *lookupfile-installation*
+The distribution comes as a zipfile that can be extracted straight into your
+runtime directory (vimfiles/.vim). Please note that it depends on genutils
+plugin that needs to be downloaded separately and installed. Also note that
+the version of genutils that this plugin depends on is a newer autoload
+version that is not backwards compatible with the older versions of genutils.
+This means, if you have other plugins that depend on the non-autoload version
+of genutils, you need to follow special instructions given in genutils such
+that you can have both installed at the same time.
+
+To install the help file, you need to run :helptags command on your runtime
+doc directory.
+
+ *lookupfile-map*
+ *lookupfile-default-cmd*
+ *LookupFile-command*
+ *:LookupFile*
+Once installed, you can optionally choose a key to be used to open the
+lookupfile window. The default is <F5>. To change this value, choose a key of
+your liking, say <A-S-L>, and add the below line to your vimrc: >
+
+ nmap <unique> <silent> <A-S-L> <Plug>LookupFile
+<
+Note that the plugin creates a mapping for the insert-mode as well, so unless
+you also explicitly specify a mapping for insert mode, the default <F5> will get
+mapped to invoke lookupfile in the insert-mode. >
+
+ imap <unique> <silent> <A-S-L> <C-O><Plug>LookupFile
+<
+The <Plug>LookupFile mapping is mapped to the :LookupFile command, which always
+assumes the last :LU command you use. This means, after using |:LUWalk|,
+pressing <F5> would result in executing the :LUWalk command until you type
+another command. Take a look at the |LookupFile_DefaultCmd| to specify the
+initial command that this map should get assigned to and
+|LookupFile_EnableRemapCmd| to disable this behavior. If you want a map to
+always execute a specific command, you can also create additional maps. E.g.,
+if you want <F7> to always execute :LUTags, irrespective of what command you
+last used, then you can define something like:
+>
+ nnoremap <silent> <F7> :LUTags<CR>
+<
+You can also disable the default map completely, see
+|LookupFile_DisableDefaultMap| for details.
+==============================================================================
+
+ *lookupfile-usage*
+To lookup a file, press the assigned key (default: F5) or use the :LookupFile
+command. This will open a small window above the current window, where you can
+type in a regex, and the matching filenames will be shown in the Vim7 completion
+style. Selecting a matching file and pressing Enter (<CR>) will open it in the
+previous window (or ^O (C-O) will open it in a split window). You can also
+press <Esc> and scroll back to previous filenames to press o or O (or use
+:OpenFile[!]) to open the file in the previous window or a new window,
+respectively.
+
+If you want to quickly close the [Lookup File] window without making a file
+selection, you can press the same key that you assigned to open the plugin, to
+also cancel the completion menu and close the window.
+
+Note that this works only when you use the <Plug> mapping to create a mapping
+(see |lookupfile-map|), not when you assign a mapping directly while disablign
+the default <Plug> mapping (see |LookupFile_DisableDefaultMap|).
+
+Note that the completion menu will be shown only when you are in the insert
+mode and the cursor is at the end of the line (this is the normal Vim behavior).
+
+Here is a summary of all the commands that the plugin defines. All commands
+accept the initial pattern as an argument, and support appropriate
+|command-completion| mode.
+
+ Command Lookup source ~
+ LUTags Lookup files from tag files. This is a like a fast GNU
+ find on name. It can lookup files from any Vim
+ compatible tag file (which includes those from ctags),
+ but at the moment it is advisable to generate
+ specialized tag files using :find command (see
+ |lookupfile-tags|).
+ LUPath Lookup files from 'path' using |globpath()|. The :find
+ command while being able to lookup files from 'path', it
+ doesn't provide any completion mechanism, and it is
+ clumsy when there are multiple files with the same name.
+ The :find command doesn't even accept a pattern.
+ LUBufs Lookup loaded files (buffers) using |bufname()|. This is
+ a great addition to whatever buffer-explorer you are
+ using. When there are too many buffers open, this
+ sometimes makes it easy to find the right buffer, by
+ typing part of its name.
+ LUWalk Lookup files using |glob()|. This works like the Emacs
+ ido.el, allowing you to walk up and down a path looking
+ for files. If you use the filename completion with :edit
+ command, then you will find this a lot more convenient
+ and faster to use.
+ LUArgs Lookup files from |:args| list.
+ LookupFile A shortcut to the last command used from above set.
+
+It is also very easy to add new commands to or customize the plugin at various
+levels. At the simplest, you can create custom command on top of the above that
+either pass dynamic arguments or tmporarily change the settings (e.g., you could
+have a command that will start LUPath with the 'path' temporarily changed to
+find only the include header files). You can also take advantage of the the
+|lookupfile-extend| features to add new commands that lookup files from a
+completely new source. You can even add commands that lookup something
+completely different than a file (like e.g., a spelling using spellsuggest()).
+
+The :LookupFile and all the above commands accept an argument which is treated
+as the initial pattern. Specify a bang(!) after the command to always start with
+an empty line.
+
+ *:LUTags*
+ *lookupfile-from-tags-files*
+The LUTags command provides a fast lookup of files from tags files. This works
+similar to the "Open Resource" command in eclipse where you can type part of the
+name and all the resources whose name has matching part are shown for selection.
+
+To use the :LUTags command, it is recommended to generate and maintain
+separate tags files containing only filenames, for this plugin to work
+efficiently (see |lookupfile-tags|). Though it will work with the regular tags
+files, it could be very slow (due to the current performance of |taglist()| and
+might not return the right set of filenames. Configure the tag expression such
+that the plugin will use the right tag files. It is any valid Vim {rhs}, the
+evaluated value should be a valid 'tags' value. For a static string, use extra
+quotes. Ex:
+>
+ let g:LookupFile_TagExpr = string('./filenametags')
+
+< or >
+ let g:myLookupFileTagExpr = './filenanmetags'
+ let g:LookupFile_TagExpr = 'g:myLookupFileTagExpr'
+<
+Also see |LookupFile_UsingSpecializedTags| to enable better formatting of
+results once these specialized tags are generated and lookupfile is configured
+to take advantage of them.
+ *:LUPath*
+ *lookupfile-find-cmd-alternative*
+The LUPath command is a complete replacement for the built-in |:find| command.
+The completion popup alone is a good enough reason to use this command instead
+of the :find, but since it also recognizes the 'ignorecase' and 'smartcase'
+settings it makes it easier to type and still be able to do exact match when
+required.
+
+ *lookupfile-ido*
+The LUWalk and LUBufs commands are special in that they provide features that
+will be very fimilar to those who used Emacs ido lisp package.
+
+Similar to the ido, you can quickly switch from file lookup to buffer lookup
+using <C-B> and from buffer lookup to file lookup using <C-F> while in insert
+mode.
+
+ *:LUBufs*
+ *lookupfile-buffer-cmd-alternative*
+LUBufs command allows you to quickly search the already loaded buffers for a
+match and open it, so it can be used in the place of the built-in |:buffer|
+command and provides the same matching semantics by default. Take a look at the
+settings that start with "LookupFile_Bufs_" in their name to configure the
+behavior of this command. The :LUBufs command also supports an initial pattern
+as an arguments and supports filename completion.
+
+A good use case for :LUBufs command is when you have several files named
+similarly (e.g., having several buffers named Makefile or build.xml is very
+common). Using a traditional buffer explorer plugin, finding the right file can
+become cumbersome when you have a large set of buffers opened. In this case, the
+:LUBufs command can help you locate the buffer much faster, as only the buffers
+that match what you specify will be shown with their path clearly visible.
+
+ *:LUWalk*
+ *lookupfile-walk-path*
+The LUWalk command is very useful to quickly navigate or "walk" filesystem
+paths. The plugin provides a popup with matches for each path component as you
+type in a partial string. The matches are based on the Vim |glob()| expression
+rules. The :LUWalk command also accepts the initial directory name with or
+without a pattern as an argument, and supports directory name completion.
+
+When no root is specified, the match starts from the current directory.
+Pressing <Tab> before typing in any pattern will result in inserting the
+directory of the last file automatically. Type an extra "/" after a directory
+name to have only the directories shown in the results.
+
+To accept the first entry in the matches, you can simply press <CR> or <C-O>,
+and if the entry happens to be a directory, new matches will be shown for that
+directory.
+
+ *lookupfile-recent-files*
+The plugin saves a list of most recently opened files using any of the above
+commands. To trigger showing this list, simply use a space by itself. For more
+details, see |LookupFile_RecentFileListSize|.
+==============================================================================
+
+ *lookupfile-maps*
+The maps that are available in the [Lookup File] window are listed below. Some
+of them are the same from |popupmenu-keys|, but have been modified to behave
+slightly differently. All the below maps are applicable only when the popup menu
+is visible, otherwise, they should have their default behavior.
+ Key mode Action ~
+ <CR> i Opens the selected file in the previous window/
+ Select the first file.
+ <C-Y> i Same as <CR>
+ <C-O> i Same as <CR>, except that the file opens in a split
+ window.
+ <Down> i Selects next file. Same as |i_CTRL-N|.
+ <Up> i Selects previous file. Same as |i_CTRL-P|.
+ <PageDown> i Selects a file several entries down.
+ <PageUp> i Selects a file several entries up.
+ <Esc> i Stops completion and insert mode, and restores
+ pattern.
+ <BS> i Stops completion, restores pattern and executes
+ o n Opens the current file in the previous window.
+ O n Same as o, except the file opens in a split window.
+==============================================================================
+
+ *lookupfile-tags*
+Unless you want to lookup files from alternate sources such as 'path', you
+should generate special tags files for the lookup from filesystem to work well.
+
+It is very easy to generate a tag file for an efficient lookup of filenames.
+If you have Unixy tools installed, you can run the below shell command to
+generate a tags file (you can put it in a shell-script and schedule it to be run
+every now and then to keep this file up to date) >
+
+ (echo "!_TAG_FILE_SORTED 2 /2=foldcase/";
+ (find . -type f -printf "%f\t%p\t1\n" | \
+ sort -f)) > ./filenametags
+
+Typically you would want to exclude generated files such as .class and
+.o. You can do this easily by specifying additional expressions to
+the find command (see manpage for find command). E.g., replace the find
+command above with: >
+
+ find . -not -iname "*.class" -type f -printf "%f\t%p\t1\n" \
+
+< or, with something more useful: >
+
+ find . \( -name .svn -o -wholename ./classes \) -prune -o -not -iregex '.*\.\(jar\|gif\|jpg\|class\|exe\|dll\|pdd\|sw[op]\|xls\|doc\|pdf\|zip\|tar\|ico\|ear\|war\|dat\).*' -type f -printf "%f\t%p\t1\n" \
+<
+==============================================================================
+
+ *lookupfile-settings*
+The settings are global variables that you can set in your vimrc. All settings
+are optional, as they all have default values, but it is highly recommended that
+you fine tune the g:LookupFile_TagExpr setting, as per |lookupfile-tags|.
+ *LookupFile_DefaultCmd*
+- This specifies the |lookupfile-command| that should be invoked when the
+ |LookupFile-command| or |lookupfile-map| is used. This defaults to ":LUTags",
+ but you can change it to say, ":LUWalk". The :LookupFile command always
+ assumes the last command that you used, so this setting only specifies the
+ command to be invoked for the first time.
+ Ex: >
+ let g:LookupFile_DefaultCmd = ':LUWalk'
+<
+ *LookupFile_EnableRemapCmd*
+- When this is set (the default), the :LookupFile command takes the form of
+ the last command that is used. Disabling this while setting
+ |LookupFile_DefaultCmd| allows you to configure a custom command as the
+ command to run when you press the <Plug>LookupFile mapping. See
+ |LookupFile-command| for more details.
+
+ *LookupFile_DisableDefaultMap*
+- Setting this flag turns off the default maps created by the plugin such that
+ the user has full control on what maps to what command. >
+ let g:LookupFile_DisableDefaultMap = 1
+<
+NOTE: setting this doesn't prevent the <Plug> mapping from created, try
+setting no_lookupfile_maps or no_plugin_maps for this (see |usr_41.txt|).
+
+ *LookupFile_TagExpr*
+- Use g:LookupFile_TagExpr to use custom tagfiles. A valid Vim expression
+ resulting in a String should be used, which means "eval(g:LookupFile_TagExpr)"
+ should return a valid value for 'tags' setting. Once you set a value for this
+ setting and startup Vim, try >
+ echo eval(g:LookupFile_TagExpr)
+< to make sure it is valid. Ex: >
+ let g:LookupFile_TagExpr = string('./filenametags')
+<
+ *LookupFile_MinPatLength*
+- By default g:LookupFile_MinPatLength is set to 4, which means you have to type
+ at least 4 characters before the lookup is triggered. This is because the
+ current taglist() function is too slow if the tag file is large. Depending on
+ the number of files you have, you may be able to set a lower value (or may
+ even have to increase the value) for this setting.
+ *LookupFile_ShowFiller*
+- If you don't want the filler to be shown while the tags are being
+ looked up, you can disable it by setting g:LookupFile_ShowFiller to 0. If you
+ know for sure that the lookup never takes too long, then disabling the filler
+ could make the completion menu less flashy.
+ *LookupFile_UsingSpecializedTags*
+- When you generate specialized tags as described in the |lookupfile-tags|
+ section, you can set g:LookupFile_UsingSpecializedTags to enabled better
+ formatting for showing the results.
+ *LookupFile_PreservePatternHistory*
+- By default, the plugin leaves a copy of the pattern that you used to
+ lookup the file, so that you can scroll-back and find them (this is like a
+ history), but you can disable this behavior by setting
+ g:LookupFile_PreservePatternHistory to 0.
+ *LookupFile_PreserveLastPattern*
+- By default, the lookup window is started with the last pattern, which you can
+ remove by quick pressing <Ctrl-U>, but if you always want to start blank, set
+ g:LookupFile_PreserveLastPattern to 0.
+ *LookupFile_LookupFunc*
+ *LookupFile_LookupNotifyFunc*
+ *LookupFile_LookupAcceptFunc*
+- If you want to lookup matches yourself using an alternative procedure, you
+ can specify a user function that should be called by the plugin, and
+ by-pass the default tag based lookup. Use g:LookupFile_LookupFunc
+ setting to specify the name or Funcref for such a function. The function
+ will be called with one argument, which is the pattern typed so far. The
+ results will be sorted by the plugin anyway, so your function need not.
+ You can also set g:LookupFile_LookupNotifyFunc to be notified when a
+ file is selected from the matches (not called with o or O commands), and
+ g:LookupFile_LookupAcceptFunc to override the default handling of selection.
+ *LookupFile_switchbuf*
+- If you have 'switchbuf' set to "split" for your quickfix commands to
+ always split open windows, the plugin recognizes this setting and split-opens
+ all files.
+ *LookupFile_AlwaysAcceptFirst*
+- Normally when <CR> or <C-O> is pressed while the popup is visible, the first
+ item in the list is selected, unless there is exactly only one item matching.
+ This means, if you want to select the first item, you have to press it
+ twice. You can change this behavior to always accept the first item by
+ setting g:LookupFile_AlwaysAcceptFirst (like ido.el).
+ *LookupFile_FileFilter*
+- Use the g:LookupFile_FileFilter to specify a Vim regular expression pattern
+ that, when matched against the filename (or path, depending on the mode)
+ results in filtered out. E.x: >
+
+ " Don't display binary files
+ let g:LookupFile_FileFilter = '\.class$\|\.o$\|\.obj$\|\.exe$\|\.jar$\|\.zip$\|\.war$\|\.ear$'
+<
+ NOTE that the |:LUPath| and |:LUWalk| commands use the Vim functions |globpath()|
+ and |glob()| that recognize the Vim setting 'wildignore', so setting this in
+ addition to 'wildignore' will have the matches filtered by both rules.
+ *LookupFile_AllowNewFiles*
+- Use the g:LookupFile_AllowNewFiles to specify whether entering non-existent
+ files should generate an error or result in getting a new buffer created.
+ *LookupFile_ignorecase*
+ *LookupFile_smartcase*
+- The plugin now recognizes 'ignorecase' and 'smartcase' settings to match files
+ even on systems that are case-sensitive. On unix like platforms, glob()
+ matches patterns in a case-sensitive manner, so setting 'ignorecase' will
+ enable special translation of patterns so that you get case-insensitive
+ results. On Windows, since glob() is already case-insensitive no special
+ handling is required for 'ignorecase', however, when 'smartcase' is set, there
+ is no way to force glob() to return case-sensitive results, so a
+ post-processing of the results is done to drop files that would not otherwise
+ have matched.
+ *LookupFile_SortMethod*
+- Use this setting to specify the sort method to use for sorting results. The
+ default value is "alpha", which means that they will be sorted alphabatically.
+ You can also set an empty value to disable sorting. See also
+ |LookupFile_Bufs_BufListExpr| to enable MRU sorting for |:LUBufs| command.
+ *LookupFile_Bufs_BufListExpr*
+- Use g:LookupFile_Bufs_BufListExpr to specify an expression that returns a
+ |List| of buffers to display. By default this is set to an empty string, but
+ you can set any valid Vim expression that results in a List. If you also have
+ the latest version of SelectBuf (http://www.vim.org/script.php?script_id=107)
+ installed, a useful value that you can set here is "g:SB_MRUlist", which will
+ then display buffers in the MRU order. >
+
+ let g:LookupFile_Bufs_BufListExpr = 'g:SB_MRUlist'
+<
+ You can use this setting to even specify your own global function.
+ *LookupFile_Bufs_SkipUnlisted*
+- By default, the |:LUBufs| commands skips all unlisted buffers from results,
+ but if you want them to be included, reset LookupFile_Bufs_SkipUnlisted
+ setting.
+ *LookupFile_Bufs_LikeBufCmd*
+- This setting impacts the behavior of |:LUBufs| command on how the pattern is
+ matched. By default, it matches just like the |:buffer| command, so the
+ pattern is treated as per the rules of |wildcard| matching against the current
+ |bufname()| of each buffer. Clearing this setting will cause the command to
+ match the pattern as a Vim regex against only the filename portion of each
+ buffer.
+ *LookupFile_UpdateTime*
+- LookupFile uses |CursorHoldI| autocommand to trigger the completion and this
+ event doesn't get triggered unless nothing is typed for 'updatetime'
+ milliseconds. Since the default value for 'updatetime' is rather large, the
+ plugin changes this value to g:LookupFile_UpdateTime (which defaults to 300
+ milliseconds or 3/10th of a second) while the [Lookup File] window is active.
+ *LookupFile_EscCancelsPopup*
+- On some systems, the mapping for <Esc> to cancel the popup could interfere
+ with the arrow keys, so if you want the plugin to not map <Esc> key, then
+ reset |LookupFile_EscCancelsPopup| setting. >
+
+ let g:LookupFile_EscCancelsPopup = 0
+<
+ *LookupFile_SearchForBufsInTabs*
+- Normally, when you seleclt a file that is already visible in a window,
+ LookupFile simply makes that window the current window instead of opening
+ the file again. Setting this flag will make LookupFile also search in other
+ tabs for a window that already has this file visible, and switch to that tab
+ to set the focus. This setting is most useful with the |LUBufs| command. >
+
+ let g:LookupFile_SearchForBufsInTabs = 1
+<
+ *LookupFile_TagsExpandCamelCase*
+- When this setting is enabled (the default), typing consecutive upper case
+ letters are treated as abbreviations for type names that follow the
+ CamelCase naming pattern (like all the java class names are) and the pattern
+ is translated automatically. This is modelled after the "Open Type" dialog
+ in eclipse and works only for the tag lookup (|LUTags| command). To disable
+ this feature, set it to 0 >
+
+ let g:LookupFile_TagsExpandCamelCase = 0
+<
+ Ex:
+ - To match the filename VimTheSupremeEditor.txt, you could enter the pattern
+ in several variations such as: >
+ VTSE
+ VTSEditor
+ VTSEdi.*
+ VTS.*
+ VTheSE
+<
+NOTE: While using the CamelCase expansion, 'ignorecase' is disabled so
+something like "VTSEDi.*" will not match "VimTheSupremeEditor", but will match
+"VimTheSupremeEditorDictator", if it exists.
+ *LookupFile_RecentFileListSize*
+This setting allows you to control the number of most recently used filenames
+that should be rememberd by the plugin. The default size is 20, but it can be
+set to 0 to not remember any and any -ve value to remember all. The list is
+not persisted across Vim sessions. >
+
+ let g:LookupFile_RecentFileListSize = 30
+<
+See also, |lookupfile-recent-files|.
+==============================================================================
+
+ *lookupfile-extend*
+If you want to extend the functionality of the plugin, by creating new commands
+to lookup files in different ways, you can take advantage of the
+g:LookupFile_LookupFunc and lookupfile_LookupNotifyFunc settings as below:
+
+ - Create a function that can take a pattern and return file matches for it:
+ function! FileMatches(pattern)
+ let matches = []
+ " Find and fill up matches.
+ return matches
+ endfunction
+ - Create an entry function and a command:
+ function! MyLookup()
+ unlet! s:savedLookupFunc s:savedLookupNotifyFunc
+ let g:savedLookupFunc = g:LookupFile_LookupFunc
+ let g:savedLookupNotifyFunc = g:LookupFile_LookupNotifyFunc
+ unlet g:LookupFile_LookupFunc g:LookupFile_LookupNotifyFunc
+ let g:LookupFile_LookupFunc = 'FileMatches'
+ let g:LookupFile_LookupNotifyFunc = 'MyNotify'
+ LookupFile
+ endfunction
+ command! MyLookup call MyLookup()
+ - Define the MyNotify() function to clear the settings.
+ function! MyNotify()
+ unlet g:LookupFile_LookupFunc g:LookupFile_LookupNotifyFunc
+ let g:LookupFile_LookupFunc = g:savedLookupFunc
+ let g:LookupFile_LookupNotifyFunc = g:savedLookupNotifyFunc
+ endfunction
+
+Once you follow the above steps, you can use both the default LookupFile command
+as well as the new MyLookup command. The completion will behave differently
+based on how you opened the lookup window.
+
+You can also override the default action when the user presses <CR> or <C-O> to
+get your function invoked, by setting the g:LookupFile_LookupAcceptFunc. The
+function should have the below signature: >
+
+ " splitWin is 1 if a new window should be split.
+ " key is the exact key that user pressed ("\<CR>"/"\<C-O>").
+ function accept(splitWin, key)
+<
+The last pattern and the matching results for it are accessible in the global
+variables g:lookupfile#lastPattern and g:lookupfile#lastResults.
+
+You can also create ftplugin/lookupfile.vim in your vim runtime and put commands
+to further customize or override the behavior of the plugin. E.g., you could put
+a map such that pressing <Esc> twice in succession will close the window: >
+
+ nnoremap <buffer> <Esc><Esc> <C-W>q
+ inoremap <buffer> <Esc><Esc> <Esc><C-W>q
+<
+ *lookupfile-tips*
+- A pattern is a Vim regex, so you can e.g., start with an "^" to anchor the
+ pattern match to the start of the filename. This will also speed up the
+ lookup. You can also enter the extension (such as \.prop) to narrow down the
+ results further.
+- If the filename has special characters, don't forget to protect them while
+ entering the pattern, or you may not find what you are looking for (or
+ might find too much). E.g., to find a file named "abc*xyz" (not possible
+ on windows), you need to enter "abc\*" as pattern. Since the pattern is
+ used as if 'magic' is set, unless you have the "\" itself in the
+ filenames, you only have to worry about those characters that are special
+ without needing to prefix with a "\", and these are ".", "^", "[", "*" and
+ "$".
+- If the lookup is taking too long, you can stop it by pressing ^C. You may
+ still be able to see partial set of matches.
+- You can use <Ctrl-J> instead of <CR> to deliberately insert a newline into
+ the lookup buffer.
+- Pressing <Esc> after selecting a file, results in restoring the pattern. If
+ you actually want to cancel the completion menu, without restoring the
+ pattern, you can press <C-C>.
+- When you want to start entering a new pattern, press <Ctrl-U> to quickly
+ kill the previous pattern.
+- Use g:LookupFile_LookupFunc setting to modify the functionality of the
+ plugin. The plugin/lookupfile.vim comes with a few of alternative ways to
+ lookup files, such as looking up files from 'path' (see |lookupfile-usage|).
+ Other ideas for alternative lookup for files are:
+ - Use id-utils' lid to lookup files from ID database. You can e.g., use the
+ command "lid -R filenames -S newline -k token" to lookup for the typed
+ pattern as a token (there are other options for lid to treat token as regex)
+ - Use GNU find to find files matching the pattern, something like:
+ "find . -name '*pattern*'". There are a number of options for find, so this
+ could be made very flexible, but running find for every character typed
+ could be very slow.
+ - You can create an alternate tags file to store only directory names such
+ that you can lookup directory names instead of filenames. The following
+ command can create such a tags file: >
+
+ (echo "!_TAG_FILE_SORTED 2 /2=foldcase/";
+ find . -type d -printf "%f\t%p\t1\n") | \
+ sort -f > ./dirnametags
+<
+ Note that this generates tag file with relative paths, which is known to
+ cause problem with |taglist()| function when the tag file is not in the same
+ directory as Vim's current directory (see |lookupfile-known-issues|. To
+ workaround, you can generate absolute paths, you can use "`pwd`" instead of "."
+ as the root.
+- You can create custom commands/mappings that always start with a fixed or
+ computed pattern. E.g., to always start LUWalk in the root of c: drive, create
+ a command as: >
+
+ command! WalkRoot LUWalk c:/
+<
+ Another useful variation of the above is to start with the directory of the
+ current file: >
+
+ command! WalkCur :exec "LUWalk" expand('%:p:h').'/'
+<
+ Another example that works well with :LookupFile is to start with the current
+ word as pattern: >
+
+ command! CurWord :LookupFile <cword>
+<
+- The :LUWalk command maps your <BS> key such that it will remove a complete
+ directory component at a time (like ido.el). To remove only a part of the
+ directory name, first press <C-W> to remove the "/" and use <BS> to remove the
+ required number characters. You can also press <Esc> and use normal commands
+ to edit.
+- While using :LUWalk, when no pattern is entered yet, you can press <Tab> to
+ show the files in the directory of the current buffer.
+- While using :LUWalk, you can enter "**" after any directory in the path to
+ match keyword recursively under that path.
+- If you want to extend the funcationality of the plugin, take a look at the
+ plugin/lookupfile.vim for various examples.
+- Here is a sample function that you can use to lookup spellings as you type,
+ using spellsuggest() function. You need to first turn on 'spell' inside
+ lookup window for this to work. >
+ function! s:LookupSpell(pattern)
+ return spellsuggest(a:pattern)
+ endfunction
+<
+ This is a dummy accept function that prevents the word from being treated as a
+ file and open it: >
+ function! s:SpellAccept(splitWin, key)
+ call input('SpellAccept')
+ endfunction
+<
+==============================================================================
+
+ *lookupfile-known-issues*
+- Vim sometimes automatically replaces the pattern with the first filename
+ from the completion menu. You have to select back the original pattern using
+ ^P.
+- The taglist() function's performance (on which this plugin depends on)
+ seems to be bad. A newer version of Vim might accept additional arguments
+ for taglist() to limit the number of matches, which can speed up some of
+ the cases.
+- If you press the <Plug>LookupFile key while making a file selection, the
+ completion doesn't get aborted, but instead it gets selected and the
+ [Lookup File] window still remains open.
+- There is a bug in taglist() that returns incorrect relative paths if the
+ current directory of Vim is not the same as the directory in which tags file
+ resides. This impacts the :LookupFile command. If this is an issue for you,
+ you should generate the tag files with absolute paths instead of relative
+ paths, by giving absolute directory names.
+==============================================================================
+
+ *lookupfile-wishlist*
+- Allow on the fly filtering of the filenames by prompting the user for a
+ pattern to match (or not match) against the whole filename.
+- Option to sort filenames by their extension, or by MRU.
+- Save and restore matching results, for patterns that take a long time to build
+ (especially those that involve "**").
+- Option to have separate window/buffers for each type of command (Timothy,
+ Guo)
+==============================================================================
+
+ *lookupfile-changes*
+
+ *lookupfile-changes-1.8*
+- New settings |LookupFile_EnableRemapCmd|, |LookupFile_SearchForBufsInTabs|,
+ |LookupFile_TagsExpandCamelCase|, |Lookupfile_RecentFileListSize|.
+- Even more control on the mappings with the new setting
+ |LookupFile_EnableRemapCmd|.
+- New feature to specify names that follow CamelCasing pattern by abbreviating
+ them. This works more or less like for the "Open Type" dialog in Eclipse.
+ For more information see, |LookupFile_TagsExpandCamelCase|.
+- New feature to remember the recent files, see
+ |Lookupfile_RecentFileListSize|.
+- Changed the message line such that the message is shown on the left side and
+ the pattern is shown on the right side. This prevents the more important
+ message from getting lost when the filenames are too long.
+
+ *lookupfile-changes-1.7*
+- Bug fix: LUPath and LUArgs were broken (stoning at gmail dot com).
+- Removed debugging code.
+
+ *lookupfile-changes-1.6*
+ *lookupfile-changes-1.5*
+- LookupFile now uses CursorHoldI instead of CursorMovedI to show matches. This
+ means, the matches are not computed until you stop typing, which should give a
+ better experience. See |LookupFile_UpdateTime| for more information.
+- The plugin now sets 'completefunc' such that you can now hit <C-X><C-U> to
+ trigger completions explicitly (instead of waiting for
+ g:LookupFile_UpdateTime). This is useful if you are a slow typer and so prefer
+ a large value for g:LookupFile_UpdateTime.
+- The plugin now recognizes 'ignorecase' and 'smartcase' settings to match files
+ even on systems that are case-sensitive. This is mainly significant for the
+ commands that use |globpath()| or |glob()| which are, |:LUPath| and |:LUWalk|,
+ as the others already respect these settings.
+- There is now a separate command called :LUTags that always does what
+ :LookupFile used to do, while the :LookupFile command itself now gets
+ dynamically assigned to the last command used. This also means, the map that
+ is choosen in |lookupfile-map| now invokes the last command that is used, use
+ |LookupFile_DefaultCmd| and |LookupFile_DisableDefaultMap| settings to control
+ this behavior.
+- LUWalk now supports showing only directory names in the results. Just type
+ an extra / to filter those that are not directories (the suffix will then be
+ two slashes).
+- The default behavior of |:LUBufs| is now to match the entire |bufname()|,
+ just like the |:buffer| command would do. To see the old behavior, reset
+ |LookupFile_Bufs_LikeBufCmd| setting.
+- If you have the new version of SelectBuf also installed, you can have
+ |:LUBufs| sort buffers in MRU order. See, |LookupFile_Bufs_BufListExpr|.
+- When tags file is not generated as per the requirements of |lookupfile-tags|,
+ the format of the matches doesn't look good, so by default the matches just
+ show full filenames. See |LookupFile_UsingSpecializedTags| to get better
+ formatted results.
+- New settings |LookupFile_UsingSpecializedTags|, |LookupFile_SortMethod|,
+ |LookupFile_DefaultCmd|, |LookupFile_DisableDefaultMap|,
+ |LookupFile_Bufs_LikeBufCmd|, |LookupFile_Bufs_BufListExpr|,
+ |LookupFile_EscCancelsPopup|.
+- Bug fix: exact matches were getting dropped from results (Max Dyckhoff).
+- Bug fix: <BS> in |:LUWalk| right after selecting a directory match caused it
+ to misbehave.
+- Bug fix: if tags file is not in the current directory, the opening fails. Now
+ :LookupFile expands the filenames explicitly so that the paths are always
+ valid.
+- Bug fix: Unsetting |LookupFile_AllowNewFiles| didn't disable the feature.
+- Bug fix: <C-E> was not hiding the popup.
+- Bug fix: <S-BS> triggers the default insert-mode completion (Max Dyckhoff).
+- Fixed misc. bugs in opening files.
+- Workaround for <Esc> not working on some systems, allow disabling the
+ mapping.
+- Bug fix: When there is an exising swapfile, opening the files result in an
+ error message (David Fishburn).
+- When LookupFile_UsingSpecializedTags is set, sorting should be done on the
+ filename (patch by Timothy, Guo).
+
+ *lookupfile-changes-1.4*
+- Fixed a bug in the initial pattern getting ignored.
+- LUBufs now completes the full pathname of the buffers, so that it is less
+ dependent on the current directory of Vim.
+- LUBufs and LUPath commands now present the matches in a better format.
+- Pressing <F5> while popup is visible didn't close the lookupfile window.
+
+ *lookupfile-changes-1.3*
+- New feature to create a file, if the file doesn't already exist (Ido). Can be
+ disabled using g:LookupFile_AllowNewFiles setting.
+- Bug fix: while using LUWalk, if the first match is a directory, then selecting
+ files was offset by one.
+
+ *lookupfile-changes-1.2*
+- g:LookupFile_AlwaysAcceptFirst setting to always accept the first
+ entry (the default is 0).
+- g:LookupFile_FileFilter to specify a filter.
+- New LUWalk command that works very similar to Emacs ido.el to quickly navigate
+ paths.
+- All commands now accepts the initial pattern as argument. This provides
+ unlimited number of possibilities to create your own custom commands (see
+ |lookupfile-tips| for some examples).
+- The g:LookupFile_MinPatLength is automatically set to 0 except for tag and
+ 'path' lookup.
+- When Lookup window is opened, the filetype is set to "lookupfile". This allows
+ you to create ftplugins to fine tune the behavior.
+- Renamed :LUBuf command to :LUBufs.
+
+ *lookupfile-changes-1.1*
+- Added LUBuf and LUPath commands.
+- Renamed the prefix for all the settings from g:lookupfile_ to g:LookupFile_.
+ This is required to support Funcref settings.
+- Now the cursor position is preserved, while opening a file that is already
+ loaded.
+- Using genutils 2.1.
+==============================================================================
+
+ *lookupfile-acknowledgements*
+- Max Dyckhoff (maxd at microsoft dot com) for beta testing and reporting
+ numerous issues and suggesting improvements etc. The plugin is a lot
+ more stable, thanks to him.
+ I would also like to specially thank him for proof reading the first version
+ of this documentation.
+- Eddy Zhao (eddy dot y dot zhao at gmail dot com> for suggesting several
+ improvements on the lines of emacs ido.el and rigorously testing them. The
+ LUWalk command is the result of this.
+- Eddy Zhao (eddy dot y dot zhao at gmail dot com> for suggesting several
+- Dane Summers (dsummersl at yahoo dot com) for feedback and doc updates.
+- Timothy, Guo (firemeteor dot guo at gmail dot com) for improving the sorting
+ and other feedback.
+
+
+ vim6:tw=80:ts=8:ft=help:ai:sw=4:et
--- /dev/null
+*surround.txt* Plugin for deleting, changing, and adding "surroundings"
+
+Author: Tim Pope <
[email protected]> *surround-author*
+License: Same terms as Vim itself (see |license|)
+
+This plugin is only available if 'compatible' is not set.
+
+INTRODUCTION *surround*
+
+This plugin is a tool for dealing with pairs of "surroundings." Examples
+of surroundings include parentheses, quotes, and HTML tags. They are
+closely related to what Vim refers to as |text-objects|. Provided
+are mappings to allow for removing, changing, and adding surroundings.
+
+Details follow on the exact semantics, but first, consider the following
+examples. An asterisk (*) is used to denote the cursor position.
+
+ Old text Command New text ~
+ "Hello *world!" ds" Hello world!
+ [123+4*56]/2 cs]) (123+456)/2
+ "Look ma, I'm *HTML!" cs"<q> <q>Look ma, I'm HTML!</q>
+ if *x>3 { ysW( if ( x>3 ) {
+ my $str = *whee!; vlllls' my $str = 'whee!';
+
+While a few features of this plugin will work in older versions of Vim,
+Vim 7 is recommended for full functionality.
+
+MAPPINGS *surround-mappings*
+
+Delete surroundings is *ds* . The next character given determines the target
+to delete. The exact nature of the target are explained in |surround-targets|
+but essentially it is the last character of a |text-object|. This mapping
+deletes the difference between the "inner" object and "an" object. This is
+easiest to understand with some examples:
+
+ Old text Command New text ~
+ "Hello *world!" ds" Hello world!
+ (123+4*56)/2 ds) 123+456/2
+ <div>Yo!*</div> dst Yo!
+
+Change surroundings is *cs* . It takes two arguments, a target like with
+|ds|, and a replacement. Details about the second argument can be found
+below in |surround-replacements|. Once again, examples are in order.
+
+ Old text Command New text ~
+ "Hello *world!" cs"' 'Hello world!'
+ "Hello *world!" cs"<q> <q>Hello world!</q>
+ (123+4*56)/2 cs)] [123+456]/2
+ (123+4*56)/2 cs)[ [ 123+456 ]/2
+ <div>Yo!*</div> cst<p> <p>Yo!</p>
+
+*ys* takes an valid Vim motion or text object as the first object, and wraps
+it using the second argument as with |cs|. (Unfortunately there's no good
+mnemonic for "ys".)
+
+ Old text Command New text ~
+ Hello w*orld! ysiw) Hello (world)!
+
+As a special case, *yss* operates on the current line, ignoring leading
+whitespace.
+
+ Old text Command New text ~
+ Hello w*orld! yssB {Hello world!}
+
+There is also *yS* and *ySS* which indent the surrounded text and place it
+on a line of its own.
+
+In visual mode, a simple "s" with an argument wraps the selection. This is
+referred to as the *vs* mapping, although ordinarily there will be
+additional keystrokes between the v and s. In linewise visual mode, the
+surroundings are placed on separate lines. In blockwise visual mode, each
+line is surrounded.
+
+An "S" in visual mode (*vS*) behaves similarly but always places the
+surroundings on separate lines. Additionally, the surrounded text is
+indented. In blockwise visual mode, using "S" instead of "s" instead skips
+trailing whitespace.
+
+Note that "s" and "S" already have valid meaning in visual mode, but it is
+identical to "c". If you have muscle memory for "s" and would like to use a
+different key, add your own mapping and the existing one will be disabled.
+>
+ vmap <Leader>s <Plug>Vsurround
+ vmap <Leader>S <Plug>VSurround
+<
+ *i_CTRL-G_s* *i_CTRL-G_S*
+Finally, there is an experimental insert mode mapping on <C-G>s and <C-S>.
+Beware that the latter won't work on terminals with flow control (if you
+accidentally freeze your terminal, use <C-Q> to unfreeze it). The mapping
+inserts the specified surroundings and puts the cursor between them. If,
+immediately after the mapping and before the replacement, a second <C-S> or
+carriage return is pressed, the prefix, cursor, and suffix will be placed on
+three separate lines. <C-G>S (not <C-G>s) also exhibits this behavior.
+
+TARGETS *surround-targets*
+
+The |ds| and |cs| commands both take a target as their first argument. The
+possible targets are based closely on the |text-objects| provided by Vim.
+In order for a target to work, the corresponding text object must be
+supported in the version of Vim used (Vim 7 adds several text objects, and
+thus is highly recommended). All targets are currently just one character.
+
+Eight punctuation marks, (, ), {, }, [, ], <, and >, represent themselves
+and their counterpart. If the opening mark is used, contained whitespace is
+also trimmed. The targets b, B, r, and a are aliases for ), }, ], and >
+(the first two mirror Vim; the second two are completely arbitrary and
+subject to change).
+
+Three quote marks, ', ", `, represent themselves, in pairs. They are only
+searched for on the current line.
+
+A t is a pair of HTML or XML tags. See |tag-blocks| for details. Remember
+that you can specify a numerical argument if you want to get to a tag other
+than the innermost one.
+
+The letters w, W, and s correspond to a |word|, a |WORD|, and a |sentence|,
+respectively. These are special in that they have nothing to delete, and
+used with |ds| they are a no-op. With |cs|, one could consider them a
+slight shortcut for ysi (cswb == ysiwb, more or less).
+
+A p represents a |paragraph|. This behaves similarly to w, W, and s above;
+however, newlines are sometimes added and/or removed.
+
+REPLACEMENTS *surround-replacements*
+
+A replacement argument is a single character, and is required by |cs|, |ys|,
+and |vs|. Undefined replacement characters (with the exception of alphabetic
+characters) default to placing themselves at the beginning and end of the
+destination, which can be useful for characters like / and |.
+
+If either ), }, ], or > is used, the text is wrapped in the appropriate pair
+of characters. Similar behavior can be found with (, {, and [ (but not <),
+which append an additional space to the inside. Like with the targets above,
+b, B, r, and a are aliases for ), }, ], and >. To fulfill the common need for
+code blocks in C-style languages, <C-}> (which is really <C-]>) adds braces on
+lines separate from the content.
+
+If t or < is used, Vim prompts for an HTML/XML tag to insert. You may specify
+attributes here and they will be stripped from the closing tag. End your
+input by pressing <CR> or >. If <C-T> is used, the tags will appear on lines
+by themselves.
+
+A deprecated replacement of a LaTeX environment is provided on \ and l. The
+name of the environment and any arguments will be input from a prompt. This
+will be removed once a more fully functional customization system is
+implemented. The following shows the resulting environment from
+csp\tabular}{lc<CR>
+>
+ \begin{tabular}{lc}
+ \end{tabular}
+<
+CUSTOMIZING *surround-customizing*
+
+The following adds a potential replacement on "-" (ASCII 45) in PHP files.
+(To determine the ASCII code to use, :echo char2nr("-")). The carriage
+return will be replaced by the original text.
+>
+ autocmd FileType php let b:surround_45 = "<?php \r ?>"
+<
+This can be used in a PHP file as in the following example.
+
+ Old text Command New text ~
+ print "Hello *world!" yss- <?php print "Hello world!" ?>
+
+Additionally, one can use a global variable for globally available
+replacements.
+>
+ let g:surround_45 = "<% \r %>"
+ let g:surround_61 = "<%= \r %>"
+<
+Advanced, experimental, and subject to change: One can also prompt for
+replacement text. The syntax for this is to surround the replacement in pairs
+of low numbered control characters. If this sounds confusing, that's because
+it is (but it makes the parsing easy). Consider the following example for a
+LaTeX environment on the "l" replacement.
+>
+ let g:surround_108 = "\\begin{\1environment: \1}\r\\end{\1\1}"
+<
+When this replacement is used, the user is prompted with an "environment: "
+prompt for input. This input is inserted between each set of \1's.
+Additional inputs up to \7 can be used.
+
+Furthermore, one can specify a regular expression substitution to apply.
+>
+ let g:surround_108 = "\\begin{\1environment: \1}\r\\end{\1\r}.*\r\1}"
+<
+This will remove anything after the first } in the input when the text is
+placed within the \end{} slot. The first \r marks where the pattern begins,
+and the second where the replacement text begins.
+
+Here's a second example for creating an HTML <div>. The substitution cleverly
+prompts for an id, but only adds id="" if it is non-blank. You may have to
+read this one a few times slowly before you understand it.
+>
+ let g:surround_{char2nr("d")} = "<div\1id: \r..*\r id=\"&\"\1>\r</div>"
+<
+Inputting text replacements is a proof of concept at this point. The ugly,
+unintuitive interface and the brevity of the documentation reflect this.
+
+Finally, It is possible to always append a string to surroundings in insert
+mode (and only insert mode). This is useful with certain plugins and mappings
+that allow you to jump to such markings.
+>
+ let g:surround_insert_tail = "<++>"
+<
+ISSUES *surround-issues*
+
+Vim could potentially get confused when deleting/changing occurs at the very
+end of the line. Please report any repeatable instances of this.
+
+Do we need to use |inputsave()|/|inputrestore()| with the tag replacement?
+
+Indenting is handled haphazardly. Need to decide the most appropriate
+behavior and implement it. Right now one can do :let b:surround_indent = 1
+(or the global equivalent) to enable automatic re-indenting by Vim via |=|;
+should this be the default?
+
+ vim:tw=78:ts=8:ft=help:norl:
--- /dev/null
+:CVSEdit vcscommand.txt /*:CVSEdit*
+:CVSEditors vcscommand.txt /*:CVSEditors*
+:CVSUnedit vcscommand.txt /*:CVSUnedit*
+:CVSWatch vcscommand.txt /*:CVSWatch*
+:CVSWatchAdd vcscommand.txt /*:CVSWatchAdd*
+:CVSWatchOff vcscommand.txt /*:CVSWatchOff*
+:CVSWatchOn vcscommand.txt /*:CVSWatchOn*
+:CVSWatchRemove vcscommand.txt /*:CVSWatchRemove*
+:CVSWatchers vcscommand.txt /*:CVSWatchers*
+:LUBufs lookupfile.txt /*:LUBufs*
+:LUPath lookupfile.txt /*:LUPath*
+:LUTags lookupfile.txt /*:LUTags*
+:LUWalk lookupfile.txt /*:LUWalk*
+:LookupFile lookupfile.txt /*:LookupFile*
+:VCSAdd vcscommand.txt /*:VCSAdd*
+:VCSAnnotate vcscommand.txt /*:VCSAnnotate*
+:VCSBlame vcscommand.txt /*:VCSBlame*
+:VCSCommit vcscommand.txt /*:VCSCommit*
+:VCSDelete vcscommand.txt /*:VCSDelete*
+:VCSDiff vcscommand.txt /*:VCSDiff*
+:VCSGotoOriginal vcscommand.txt /*:VCSGotoOriginal*
+:VCSInfo vcscommand.txt /*:VCSInfo*
+:VCSLock vcscommand.txt /*:VCSLock*
+:VCSLog vcscommand.txt /*:VCSLog*
+:VCSRemove vcscommand.txt /*:VCSRemove*
+:VCSRevert vcscommand.txt /*:VCSRevert*
+:VCSReview vcscommand.txt /*:VCSReview*
+:VCSStatus vcscommand.txt /*:VCSStatus*
+:VCSUnlock vcscommand.txt /*:VCSUnlock*
+:VCSUpdate vcscommand.txt /*:VCSUpdate*
+:VCSVimDiff vcscommand.txt /*:VCSVimDiff*
+LookupFile-command lookupfile.txt /*LookupFile-command*
+LookupFile_AllowNewFiles lookupfile.txt /*LookupFile_AllowNewFiles*
+LookupFile_AlwaysAcceptFirst lookupfile.txt /*LookupFile_AlwaysAcceptFirst*
+LookupFile_Bufs_BufListExpr lookupfile.txt /*LookupFile_Bufs_BufListExpr*
+LookupFile_Bufs_LikeBufCmd lookupfile.txt /*LookupFile_Bufs_LikeBufCmd*
+LookupFile_Bufs_SkipUnlisted lookupfile.txt /*LookupFile_Bufs_SkipUnlisted*
+LookupFile_DefaultCmd lookupfile.txt /*LookupFile_DefaultCmd*
+LookupFile_DisableDefaultMap lookupfile.txt /*LookupFile_DisableDefaultMap*
+LookupFile_EnableRemapCmd lookupfile.txt /*LookupFile_EnableRemapCmd*
+LookupFile_EscCancelsPopup lookupfile.txt /*LookupFile_EscCancelsPopup*
+LookupFile_FileFilter lookupfile.txt /*LookupFile_FileFilter*
+LookupFile_LookupAcceptFunc lookupfile.txt /*LookupFile_LookupAcceptFunc*
+LookupFile_LookupFunc lookupfile.txt /*LookupFile_LookupFunc*
+LookupFile_LookupNotifyFunc lookupfile.txt /*LookupFile_LookupNotifyFunc*
+LookupFile_MinPatLength lookupfile.txt /*LookupFile_MinPatLength*
+LookupFile_PreserveLastPattern lookupfile.txt /*LookupFile_PreserveLastPattern*
+LookupFile_PreservePatternHistory lookupfile.txt /*LookupFile_PreservePatternHistory*
+LookupFile_RecentFileListSize lookupfile.txt /*LookupFile_RecentFileListSize*
+LookupFile_SearchForBufsInTabs lookupfile.txt /*LookupFile_SearchForBufsInTabs*
+LookupFile_ShowFiller lookupfile.txt /*LookupFile_ShowFiller*
+LookupFile_SortMethod lookupfile.txt /*LookupFile_SortMethod*
+LookupFile_TagExpr lookupfile.txt /*LookupFile_TagExpr*
+LookupFile_TagsExpandCamelCase lookupfile.txt /*LookupFile_TagsExpandCamelCase*
+LookupFile_UpdateTime lookupfile.txt /*LookupFile_UpdateTime*
+LookupFile_UsingSpecializedTags lookupfile.txt /*LookupFile_UsingSpecializedTags*
+LookupFile_ignorecase lookupfile.txt /*LookupFile_ignorecase*
+LookupFile_smartcase lookupfile.txt /*LookupFile_smartcase*
+LookupFile_switchbuf lookupfile.txt /*LookupFile_switchbuf*
+VCSCommandCVSDiffOpt vcscommand.txt /*VCSCommandCVSDiffOpt*
+VCSCommandCVSExec vcscommand.txt /*VCSCommandCVSExec*
+VCSCommandCommitOnWrite vcscommand.txt /*VCSCommandCommitOnWrite*
+VCSCommandDeleteOnHide vcscommand.txt /*VCSCommandDeleteOnHide*
+VCSCommandDiffSplit vcscommand.txt /*VCSCommandDiffSplit*
+VCSCommandDisableExtensionMappings vcscommand.txt /*VCSCommandDisableExtensionMappings*
+VCSCommandDisableMappings vcscommand.txt /*VCSCommandDisableMappings*
+VCSCommandEdit vcscommand.txt /*VCSCommandEdit*
+VCSCommandEnableBufferSetup vcscommand.txt /*VCSCommandEnableBufferSetup*
+VCSCommandResultBufferNameExtension vcscommand.txt /*VCSCommandResultBufferNameExtension*
+VCSCommandResultBufferNameFunction vcscommand.txt /*VCSCommandResultBufferNameFunction*
+VCSCommandSVKExec vcscommand.txt /*VCSCommandSVKExec*
+VCSCommandSVNDiffExt vcscommand.txt /*VCSCommandSVNDiffExt*
+VCSCommandSVNDiffOpt vcscommand.txt /*VCSCommandSVNDiffOpt*
+VCSCommandSVNExec vcscommand.txt /*VCSCommandSVNExec*
+VCSCommandSplit vcscommand.txt /*VCSCommandSplit*
+b:VCSCommandCommand vcscommand.txt /*b:VCSCommandCommand*
+b:VCSCommandOriginalBuffer vcscommand.txt /*b:VCSCommandOriginalBuffer*
+b:VCSCommandSourceFile vcscommand.txt /*b:VCSCommandSourceFile*
+b:VCSCommandVCSType vcscommand.txt /*b:VCSCommandVCSType*
+cs surround.txt /*cs*
+cvscommand-changes vcscommand.txt /*cvscommand-changes*
+ds surround.txt /*ds*
+i_CTRL-G_S surround.txt /*i_CTRL-G_S*
+i_CTRL-G_s surround.txt /*i_CTRL-G_s*
+lookupfile-acknowledgements lookupfile.txt /*lookupfile-acknowledgements*
+lookupfile-buffer-cmd-alternative lookupfile.txt /*lookupfile-buffer-cmd-alternative*
+lookupfile-changes lookupfile.txt /*lookupfile-changes*
+lookupfile-changes-1.1 lookupfile.txt /*lookupfile-changes-1.1*
+lookupfile-changes-1.2 lookupfile.txt /*lookupfile-changes-1.2*
+lookupfile-changes-1.3 lookupfile.txt /*lookupfile-changes-1.3*
+lookupfile-changes-1.4 lookupfile.txt /*lookupfile-changes-1.4*
+lookupfile-changes-1.5 lookupfile.txt /*lookupfile-changes-1.5*
+lookupfile-changes-1.6 lookupfile.txt /*lookupfile-changes-1.6*
+lookupfile-changes-1.7 lookupfile.txt /*lookupfile-changes-1.7*
+lookupfile-changes-1.8 lookupfile.txt /*lookupfile-changes-1.8*
+lookupfile-default-cmd lookupfile.txt /*lookupfile-default-cmd*
+lookupfile-extend lookupfile.txt /*lookupfile-extend*
+lookupfile-find-cmd-alternative lookupfile.txt /*lookupfile-find-cmd-alternative*
+lookupfile-from-tags-files lookupfile.txt /*lookupfile-from-tags-files*
+lookupfile-ido lookupfile.txt /*lookupfile-ido*
+lookupfile-installation lookupfile.txt /*lookupfile-installation*
+lookupfile-introduction lookupfile.txt /*lookupfile-introduction*
+lookupfile-known-issues lookupfile.txt /*lookupfile-known-issues*
+lookupfile-map lookupfile.txt /*lookupfile-map*
+lookupfile-maps lookupfile.txt /*lookupfile-maps*
+lookupfile-overview lookupfile.txt /*lookupfile-overview*
+lookupfile-plugin lookupfile.txt /*lookupfile-plugin*
+lookupfile-recent-files lookupfile.txt /*lookupfile-recent-files*
+lookupfile-settings lookupfile.txt /*lookupfile-settings*
+lookupfile-tags lookupfile.txt /*lookupfile-tags*
+lookupfile-tips lookupfile.txt /*lookupfile-tips*
+lookupfile-usage lookupfile.txt /*lookupfile-usage*
+lookupfile-walk-path lookupfile.txt /*lookupfile-walk-path*
+lookupfile-wishlist lookupfile.txt /*lookupfile-wishlist*
+lookupfile.txt lookupfile.txt /*lookupfile.txt*
+surround surround.txt /*surround*
+surround-author surround.txt /*surround-author*
+surround-customizing surround.txt /*surround-customizing*
+surround-issues surround.txt /*surround-issues*
+surround-mappings surround.txt /*surround-mappings*
+surround-replacements surround.txt /*surround-replacements*
+surround-targets surround.txt /*surround-targets*
+surround.txt surround.txt /*surround.txt*
+vcscommand vcscommand.txt /*vcscommand*
+vcscommand-buffer-management vcscommand.txt /*vcscommand-buffer-management*
+vcscommand-buffer-variables vcscommand.txt /*vcscommand-buffer-variables*
+vcscommand-bugs vcscommand.txt /*vcscommand-bugs*
+vcscommand-commands vcscommand.txt /*vcscommand-commands*
+vcscommand-config vcscommand.txt /*vcscommand-config*
+vcscommand-contents vcscommand.txt /*vcscommand-contents*
+vcscommand-customize vcscommand.txt /*vcscommand-customize*
+vcscommand-events vcscommand.txt /*vcscommand-events*
+vcscommand-install vcscommand.txt /*vcscommand-install*
+vcscommand-intro vcscommand.txt /*vcscommand-intro*
+vcscommand-manual vcscommand.txt /*vcscommand-manual*
+vcscommand-mappings vcscommand.txt /*vcscommand-mappings*
+vcscommand-mappings-override vcscommand.txt /*vcscommand-mappings-override*
+vcscommand-naming vcscommand.txt /*vcscommand-naming*
+vcscommand-options vcscommand.txt /*vcscommand-options*
+vcscommand-ssh vcscommand.txt /*vcscommand-ssh*
+vcscommand-ssh-config vcscommand.txt /*vcscommand-ssh-config*
+vcscommand-ssh-env vcscommand.txt /*vcscommand-ssh-env*
+vcscommand-ssh-other vcscommand.txt /*vcscommand-ssh-other*
+vcscommand-ssh-wrapper vcscommand.txt /*vcscommand-ssh-wrapper*
+vcscommand-statusline vcscommand.txt /*vcscommand-statusline*
+vcscommand.txt vcscommand.txt /*vcscommand.txt*
+vs surround.txt /*vs*
+yS surround.txt /*yS*
+ySS surround.txt /*ySS*
+ys surround.txt /*ys*
+yss surround.txt /*yss*
--- /dev/null
+*vcscommand.txt* vcscommand
+Copyright (c) 2007 Bob Hiestand
+
+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.
+
+For instructions on installing this file, type
+ :help add-local-help
+inside Vim.
+
+Author: Bob Hiestand <
[email protected]>
+Credits: Benji Fisher's excellent MatchIt documentation
+
+==============================================================================
+1. Contents *vcscommand-contents*
+
+ Installation : |vcscommand-install|
+ vcscommand Intro : |vcscommand|
+ vcscommand Manual : |vcscommand-manual|
+ Customization : |vcscommand-customize|
+ SSH "integration" : |vcscommand-ssh|
+ Changes from cvscommand : |cvscommand-changes|
+ Bugs : |vcscommand-bugs|
+
+==============================================================================
+
+2. vcscommand Installation *vcscommand-install*
+
+The vcscommand plugin comprises five files: vcscommand.vim, vcssvn.vim,
+vcscvs.vim, vcssvk.vim and vcscommand.txt (this file). In order to install
+the plugin, place the vcscommand.vim, vcssvn.vim, vcssvk.vim, and vcscvs.vim
+files into a plugin directory in your runtime path (please see
+|add-global-plugin| and |'runtimepath'|.
+
+This help file can be included in the VIM help system by copying it into a
+'doc' directory in your runtime path and then executing the |:helptags|
+command, specifying the full path of the 'doc' directory. Please see
+|add-local-help| for more details.
+
+vcscommand may be customized by setting variables, creating maps, and
+specifying event handlers. Please see |vcscommand-customize| for more
+details.
+
+==============================================================================
+
+3. vcscommand Intro *vcscommand*
+ *vcscommand-intro*
+
+The vcscommand plugin provides global ex commands for manipulating
+version-controlled source files, currently those controlled either by CVS or
+Subversion. In general, each command operates on the current buffer and
+accomplishes a separate source control function, such as update, commit, log,
+and others (please see |vcscommand-commands| for a list of all available
+commands). The results of each operation are displayed in a scratch buffer.
+Several buffer variables are defined for those scratch buffers (please see
+|vcscommand-buffer-variables|).
+
+The notion of "current file" means either the current buffer, or, in the case
+of a directory buffer (such as Explorer or netrw buffers), the directory (and
+all subdirectories) represented by the the buffer.
+
+For convenience, any vcscommand invoked on a vcscommand scratch buffer acts as
+though it was invoked on the original file and splits the screen so that the
+output appears in a new window.
+
+Many of the commands accept revisions as arguments. By default, most operate
+on the most recent revision on the current branch if no revision is specified.
+
+Each vcscommand is mapped to a key sequence starting with the <Leader>
+keystroke. The default mappings may be overridden by supplying different
+mappings before the plugin is loaded, such as in the vimrc, in the standard
+fashion for plugin mappings. For examples, please see
+|vcscommand-mappings-override|.
+
+The vcscommand plugin may be configured in several ways. For more details,
+please see |vcscommand-customize|.
+
+==============================================================================
+
+4. vcscommand Manual *vcscommand-manual*
+
+4.1 vcscommand commands *vcscommand-commands*
+
+vcscommand defines the following commands:
+
+|:VCSAdd|
+|:VCSAnnotate|
+|:VCSBlame|
+|:VCSCommit|
+|:VCSDelete|
+|:VCSDiff|
+|:VCSGotoOriginal|
+|:VCSLog|
+|:VCSRemove|
+|:VCSRevert|
+|:VCSReview|
+|:VCSStatus|
+|:VCSUpdate|
+|:VCSVimDiff|
+
+The following commands are specific to CVS files:
+
+|:CVSEdit|
+|:CVSEditors|
+|:CVSUnedit|
+|:CVSWatch|
+|:CVSWatchAdd|
+|:CVSWatchOn|
+|:CVSWatchOff|
+|:CVSWatchRemove|
+|:CVSWatchers|
+
+:VCSAdd *:VCSAdd*
+
+This command adds the current file to source control. Please note, this does
+not commit the newly-added file. All parameters to the command are passed to
+the underlying VCS.
+
+:VCSAnnotate *:VCSAnnotate*
+
+This command displays the current file with each line annotated with the
+version in which it was most recently changed. If an argument is given, the
+argument is used as a revision number to display. If not given an argument,
+it uses the most recent version of the file (on the current branch, if under
+CVS control). Additionally, if the current buffer is a VCSAnnotate buffer
+already, the version number on the current line is used.
+
+For CVS buffers, the 'VCSCommandCVSAnnotateParent' option, if set to non-zero,
+will cause the above behavior to change. Instead of annotating the version on
+the current line, the parent revision is used instead, crossing branches if
+necessary.
+
+The filetype of the vcscommand scratch buffer is set to one of 'CVSAnnotate',
+'SVNAnnotate', or 'SVKAnnotate' as appropriate, to take advantage of the
+bundled syntax files.
+
+:VCSBlame *:VCSBlame*
+
+Alias for |:VCSAnnotate|.
+
+:VCSCommit[!] *:VCSCommit*
+
+This command commits changes to the current file to source control.
+
+If called with arguments, the arguments are the log message.
+
+If '!' is used, an empty log message is committed.
+
+If called with no arguments, this is a two-step command. The first step opens
+a buffer to accept a log message. When that buffer is written, it is
+automatically closed and the file is committed using the information from that
+log message. The commit can be abandoned if the log message buffer is deleted
+or wiped before being written.
+
+Alternatively, the mapping that is used to invoke :VCSCommit (by default
+<Leader>cc) can be used in the log message buffer to immediately commit. This
+is useful if the |VCSCommandCommitOnWrite| variable is set to 0 to disable the
+normal commit-on-write behavior.
+
+:VCSDelete *:VCSDelete*
+
+Deletes the current file and removes it from source control. All parameters
+to the command are passed to the underlying VCS.
+
+:VCSDiff *:VCSDiff*
+
+With no arguments, this displays the differences between the current file and
+its parent version under source control in a new scratch buffer.
+
+With one argument, the diff is performed on the current file against the
+specified revision.
+
+With two arguments, the diff is performed between the specified revisions of
+the current file.
+
+For CVS, this command uses the |VCSCommandCVSDiffOpt| variable to specify diff
+options. If that variable does not exist, a plugin-specific default is used.
+If you wish to have no options, then set it to the empty string.
+
+For SVN, this command uses the |VCSCommandSVNDiffOpt| variable to specify diff
+options. If that variable does not exist, the SVN default is used.
+Additionally, |VCSCommandSVNDiffExt| can be used to select an external diff
+application.
+
+:VCSGotoOriginal *:VCSGotoOriginal*
+
+This command jumps to the source buffer if the current buffer is a VCS scratch
+buffer.
+
+:VCSGotoOriginal!
+
+Like ":VCSGotoOriginal" but also executes :bufwipeout on all VCS scrach
+buffers associated with the original file.
+
+:VCSInfo *:VCSInfo*
+
+This command displays extended information about the current file in a new
+scratch buffer.
+
+:VCSLock *:VCSLock*
+
+This command locks the current file in order to prevent other users from
+concurrently modifying it. The exact semantics of this command depend on the
+underlying VCS. This does nothing in CVS. All parameters are passed to the
+underlying VCS.
+
+:VCSLog *:VCSLog*
+
+Displays the version history of the current file in a new scratch buffer. If
+there is one parameter supplied, it is taken as as a revision parameters to be
+passed through to the underlying VCS. Otherwise, all parameters are passed to
+the underlying VCS.
+
+:VCSRemove *:VCSRemove*
+
+Alias for |:VCSDelete|.
+
+:VCSRevert *:VCSRevert*
+
+This command replaces the current file with the most recent version from the
+repository in order to wipe out any undesired changes.
+
+:VCSReview *:VCSReview*
+
+Displays a particular version of the current file in a new scratch buffer. If
+no argument is given, the most recent version of the file on the current
+branch is retrieved.
+
+:VCSStatus *:VCSStatus*
+
+Displays versioning information about the current file in a new scratch
+buffer. All parameters are passed to the underlying VCS.
+
+
+:VCSUnlock *:VCSUnlock*
+
+Unlocks the current file in order to allow other users from concurrently
+modifying it. The exact semantics of this command depend on the underlying
+VCS. All parameters are passed to the underlying VCS.
+
+:VCSUpdate *:VCSUpdate*
+
+Updates the current file with any relevant changes from the repository. This
+intentionally does not automatically reload the current buffer, though vim
+should prompt the user to do so if the underlying file is altered by this
+command.
+
+:VCSVimDiff *:VCSVimDiff*
+
+Uses vimdiff to display differences between versions of the current file.
+
+If no revision is specified, the most recent version of the file on the
+current branch is used. With one argument, that argument is used as the
+revision as above. With two arguments, the differences between the two
+revisions is displayed using vimdiff.
+
+With either zero or one argument, the original buffer is used to perform the
+vimdiff. When the scratch buffer is closed, the original buffer will be
+returned to normal mode.
+
+Once vimdiff mode is started using the above methods, additional vimdiff
+buffers may be added by passing a single version argument to the command.
+There may be up to 4 vimdiff buffers total.
+
+Using the 2-argument form of the command resets the vimdiff to only those 2
+versions. Additionally, invoking the command on a different file will close
+the previous vimdiff buffers.
+
+:CVSEdit *:CVSEdit*
+
+This command performs "cvs edit" on the current file. Yes, the output buffer
+in this case is almost completely useless.
+
+:CVSEditors *:CVSEditors*
+
+This command performs "cvs edit" on the current file.
+
+:CVSUnedit *:CVSUnedit*
+
+Performs "cvs unedit" on the current file. Again, yes, the output buffer here
+is basically useless.
+
+:CVSWatch *:CVSWatch*
+
+This command takes an argument which must be one of [on|off|add|remove]. The
+command performs "cvs watch" with the given argument on the current file.
+
+:CVSWatchAdd *:CVSWatchAdd*
+
+This command is an alias for ":CVSWatch add"
+
+:CVSWatchOn *:CVSWatchOn*
+
+This command is an alias for ":CVSWatch on"
+
+:CVSWatchOff *:CVSWatchOff*
+
+This command is an alias for ":CVSWatch off"
+
+:CVSWatchRemove *:CVSWatchRemove*
+
+This command is an alias for ":CVSWatch remove"
+
+:CVSWatchers *:CVSWatchers*
+
+This command performs "cvs watchers" on the current file.
+
+4.2 Mappings *vcscommand-mappings*
+
+By default, a mapping is defined for each command. These mappings execute the
+default (no-argument) form of each command.
+
+<Leader>ca VCSAdd
+<Leader>cn VCSAnnotate
+<Leader>cc VCSCommit
+<Leader>cD VCSDelete
+<Leader>cd VCSDiff
+<Leader>cg VCSGotoOriginal
+<Leader>cG VCSGotoOriginal!
+<Leader>ci VCSInfo
+<Leader>cl VCSLog
+<Leader>cL VCSLock
+<Leader>cr VCSReview
+<Leader>cs VCSStatus
+<Leader>cu VCSUpdate
+<Leader>cU VCSUnlock
+<Leader>cv VCSVimDiff
+
+Only for CVS buffers:
+
+<Leader>ce CVSEdit
+<Leader>cE CVSEditors
+<Leader>ct CVSUnedit
+<Leader>cwv CVSWatchers
+<Leader>cwa CVSWatchAdd
+<Leader>cwn CVSWatchOn
+<Leader>cwf CVSWatchOff
+<Leader>cwf CVSWatchRemove
+
+ *vcscommand-mappings-override*
+
+The default mappings can be overriden by user-provided instead by mapping to
+<Plug>CommandName. This is especially useful when these mappings collide with
+other existing mappings (vim will warn of this during plugin initialization,
+but will not clobber the existing mappings).
+
+For instance, to override the default mapping for :VCSAdd to set it to '\add',
+add the following to the vimrc:
+
+nmap \add <Plug>VCSAdd
+
+4.3 Automatic buffer variables *vcscommand-buffer-variables*
+
+Several buffer variables are defined in each vcscommand result buffer. These
+may be useful for additional customization in callbacks defined in the event
+handlers (please see |vcscommand-events|).
+
+The following variables are automatically defined:
+
+b:VCSCommandOriginalBuffer *b:VCSCommandOriginalBuffer*
+
+This variable is set to the buffer number of the source file.
+
+b:VCSCommandCommand *b:VCSCommandCommand*
+
+This variable is set to the name of the vcscommand that created the result
+buffer.
+
+b:VCSCommandSourceFile *b:VCSCommandSourceFile*
+
+This variable is set to the name of the original file under source control.
+
+b:VCSCommandVCSType *b:VCSCommandVCSType*
+
+This variable is set to the type of the source control. This variable is also
+set on the original file itself.
+==============================================================================
+
+5. Configuration and customization *vcscommand-customize*
+ *vcscommand-config*
+
+The vcscommand plugin can be configured in several ways: by setting
+configuration variables (see |vcscommand-options|) or by defining vcscommand
+event handlers (see |vcscommand-events|). Additionally, the vcscommand plugin
+supports a customized status line (see |vcscommand-statusline| and
+|vcscommand-buffer-management|).
+
+5.1 vcscommand configuration variables *vcscommand-options*
+
+Several variables affect the plugin's behavior. These variables are checked
+at time of execution, and may be defined at the window, buffer, or global
+level and are checked in that order of precedence.
+
+
+The following variables are available:
+
+|VCSCommandCommitOnWrite|
+|VCSCommandCVSDiffOpt|
+|VCSCommandCVSExec|
+|VCSCommandDeleteOnHide|
+|VCSCommandDiffSplit|
+|VCSCommandDisableMappings|
+|VCSCommandDisableExtensionMappings|
+|VCSCommandEdit|
+|VCSCommandEnableBufferSetup|
+|VCSCommandResultBufferNameExtension|
+|VCSCommandResultBufferNameFunction|
+|VCSCommandSplit|
+|VCSCommandSVKExec|
+|VCSCommandSVNDiffExt|
+|VCSCommandSVNDiffOpt|
+|VCSCommandSVNExec|
+
+VCSCommandCommitOnWrite *VCSCommandCommitOnWrite*
+
+This variable, if set to a non-zero value, causes the pending commit
+to take place immediately as soon as the log message buffer is written.
+If set to zero, only the VCSCommit mapping will cause the pending commit to
+occur. If not set, it defaults to 1.
+
+VCSCommandCVSExec *VCSCommandCVSExec*
+
+This variable controls the executable used for all CVS commands If not set,
+it defaults to "cvs".
+
+VCSCommandDeleteOnHide *VCSCommandDeleteOnHide*
+
+This variable, if set to a non-zero value, causes the temporary result buffers
+to automatically delete themselves when hidden.
+
+VCSCommandCVSDiffOpt *VCSCommandCVSDiffOpt*
+
+This variable, if set, determines the options passed to the diff command of
+CVS. If not set, it defaults to 'u'.
+
+VCSCommandDiffSplit *VCSCommandDiffSplit*
+
+This variable overrides the |VCSCommandSplit| variable, but only for buffers
+created with |:VCSVimDiff|.
+
+VCSCommandDisableMappings *VCSCommandDisableMappings*
+
+This variable, if set to a non-zero value, prevents the default command
+mappings from being set. This supercedes
+|VCSCommandDisableExtensionMappings|.
+
+VCSCommandDisableExtensionMappings *VCSCommandDisableExtensionMappings*
+
+This variable, if set to a non-zero value, prevents the default command
+mappings from being set for commands specific to an individual VCS.
+
+VCSCommandEdit *VCSCommandEdit*
+
+This variable controls whether the original buffer is replaced ('edit') or
+split ('split'). If not set, it defaults to 'split'.
+
+VCSCommandEnableBufferSetup *VCSCommandEnableBufferSetup*
+
+This variable, if set to a non-zero value, activates VCS buffer management
+mode see (|vcscommand-buffer-management|). This mode means that the
+'VCSCommandBufferInfo' variable is filled with version information if the file
+is VCS-controlled. This is useful for displaying version information in the
+status bar.
+
+VCSCommandResultBufferNameExtension *VCSCommandResultBufferNameExtension*
+
+This variable, if set to a non-blank value, is appended to the name of the VCS
+command output buffers. For example, '.vcs'. Using this option may help
+avoid problems caused by autocommands dependent on file extension.
+
+VCSCommandResultBufferNameFunction *VCSCommandResultBufferNameFunction*
+
+This variable, if set, specifies a custom function for naming VCS command
+output buffers. This function is expected to return the new buffer name, and
+will be passed the following arguments:
+
+ command - name of the VCS command being executed (such as 'Log' or
+ 'Diff').
+
+ originalBuffer - buffer number of the source file.
+
+ vcsType - type of VCS controlling this file (such as 'CVS' or 'SVN').
+
+ statusText - extra text associated with the VCS action (such as version
+ numbers).
+
+VCSCommandSplit *VCSCommandSplit*
+
+This variable controls the orientation of the various window splits that
+may occur.
+
+If set to 'horizontal', the resulting windows will be on stacked on top of
+one another. If set to 'vertical', the resulting windows will be
+side-by-side. If not set, it defaults to 'horizontal' for all but
+VCSVimDiff windows.
+
+VCSCommandSVKExec *VCSCommandSVKExec*
+
+This variable controls the executable used for all SVK commands If not set,
+it defaults to "svk".
+
+VCSCommandSVNDiffExt *VCSCommandSVNDiffExt*
+
+This variable, if set, is passed to SVN via the --diff-cmd command to select
+an external application for performing the diff.
+
+VCSCommandSVNDiffOpt *VCSCommandSVNDiffOpt*
+
+This variable, if set, determines the options passed with the '-x' parameter
+to the SVN diff command. If not set, no options are passed.
+
+VCSCommandSVNExec *VCSCommandSVNExec*
+
+This variable controls the executable used for all SVN commands If not set,
+it defaults to "svn".
+
+5.2 VCSCommand events *vcscommand-events*
+
+For additional customization, vcscommand can trigger user-defined events.
+Event handlers are provided by defining User event autocommands (see
+|autocommand|, |User|) in the vcscommand group with patterns matching the
+event name.
+
+For instance, the following could be added to the vimrc to provide a 'q'
+mapping to quit a vcscommand scratch buffer:
+
+augroup VCSCommand
+ au User VCSBufferCreated silent! nmap <unique> <buffer> q: bwipeout<cr>
+augroup END
+
+The following hooks are available:
+
+VCSBufferCreated This event is fired just after a vcscommand
+ result buffer is created and populated. It is
+ executed within the context of the vcscommand
+ buffer. The vcscommand buffer variables may
+ be useful for handlers of this event (please
+ see |vcscommand-buffer-variables|).
+
+VCSBufferSetup This event is fired just after vcscommand buffer
+ setup occurs, if enabled.
+
+VCSPluginInit This event is fired when the vcscommand plugin
+ first loads.
+
+VCSPluginFinish This event is fired just after the vcscommand
+ plugin loads.
+
+VCSVimDiffFinish This event is fired just after the VCSVimDiff
+ command executes to allow customization of,
+ for instance, window placement and focus.
+
+Additionally, there is another hook which is used internally to handle loading
+the multiple scripts in order. This hook should probably not be used by an
+end user without a good idea of how it works. Among other things, any events
+associated with this hook are cleared after they are executed (during
+vcscommand.vim script initialization).
+
+VCSLoadExtensions This event is fired just before the
+ VCSPluginFinish. It is used internally to
+ execute any commands from the VCS
+ implementation plugins that needs to be
+ deferred until the primary plugin is
+ initialized.
+
+5.3 vcscommand buffer naming *vcscommand-naming*
+
+vcscommand result buffers use the following naming convention:
+[{VCS type} {VCS command} {Source file name}]
+
+If additional buffers are created that would otherwise conflict, a
+distinguishing number is added:
+
+[{VCS type} {VCS command} {Source file name}] (1,2, etc)
+
+5.4 vcscommand status line support *vcscommand-statusline*
+
+It is intended that the user will customize the |'statusline'| option to
+include vcscommand result buffer attributes. A sample function that may be
+used in the |'statusline'| option is provided by the plugin,
+VCSCommandGetStatusLine(). In order to use that function in the status line, do
+something like the following:
+
+set statusline=%<%f\ %{VCSCommandGetStatusLine()}\ %h%m%r%=%l,%c%V\ %P
+
+of which %{VCSCommandGetStatusLine()} is the relevant portion.
+
+The sample VCSCommandGetStatusLine() function handles both vcscommand result
+buffers and VCS-managed files if vcscommand buffer management is enabled
+(please see |vcscommand-buffer-management|).
+
+5.5 vcscommand buffer management *vcscommand-buffer-management*
+
+The vcscommand plugin can operate in buffer management mode, which means that
+it attempts to set a buffer variable ('VCSCommandBufferInfo') upon entry into
+a buffer. This is rather slow because it means that the VCS will be invoked
+at each entry into a buffer (during the |BufEnter| autocommand).
+
+This mode is disabled by default. In order to enable it, set the
+|VCSCommandEnableBufferSetup| variable to a true (non-zero) value. Enabling
+this mode simply provides the buffer variable mentioned above. The user must
+explicitly include information from the variable in the |'statusline'| option
+if they are to appear in the status line (but see |vcscommand-statusline| for
+a simple way to do that).
+
+The 'VCSCommandBufferInfo' variable is a list which contains, in order, the
+revision of the current file, the latest revision of the file in the
+repository, and (for CVS) the name of the branch. If those values cannot be
+determined, the list is a single element: 'Unknown'.
+
+==============================================================================
+
+6. SSH "integration" *vcscommand-ssh*
+
+The following instructions are intended for use in integrating the
+vcscommand.vim plugin with an SSH-based CVS environment.
+
+Familiarity with SSH and CVS are assumed.
+
+These instructions assume that the intent is to have a message box pop up in
+order to allow the user to enter a passphrase. If, instead, the user is
+comfortable using certificate-based authentication, then only instructions
+6.1.1 and 6.1.2 (and optionally 6.1.4) need to be followed; ssh should then
+work transparently.
+
+6.1 Environment settings *vcscommand-ssh-env*
+
+6.1.1 CVSROOT should be set to something like:
+
+ :ext:user@host:/path_to_repository
+
+6.1.2 CVS_RSH should be set to:
+
+ ssh
+
+ Together, those settings tell CVS to use ssh as the transport when
+ performing CVS calls.
+
+6.1.3 SSH_ASKPASS should be set to the password-dialog program. In my case,
+ running gnome, it's set to:
+
+ /usr/libexec/openssh/gnome-ssh-askpass
+
+ This tells SSH how to get passwords if no input is available.
+
+6.1.4 OPTIONAL. You may need to set SSH_SERVER to the location of the cvs
+ executable on the remote (server) machine.
+
+6.2 CVS wrapper program *vcscommand-ssh-wrapper*
+
+Now you need to convince SSH to use the password-dialog program. This means
+you need to execute SSH (and therefore CVS) without standard input. The
+following script is a simple perl wrapper that dissasociates the CVS command
+from the current terminal. Specific steps to do this may vary from system to
+system; the following example works for me on linux.
+
+#!/usr/bin/perl -w
+use strict;
+use POSIX qw(setsid);
+open STDIN, '/dev/null';
+fork and do {wait; exit;};
+setsid;
+exec('cvs', @ARGV);
+
+6.3 Configuring vcscommand.vim *vcscommand-ssh-config*
+
+At this point, you should be able to use your wrapper script to invoke CVS with
+various commands, and get the password dialog. All that's left is to make CVS
+use your newly-created wrapper script.
+
+6.3.1 Tell vcscommand.vim what CVS executable to use. The easiest way to do this
+ is globally, by putting the following in your .vimrc:
+
+ let VCSCommandCVSExec=/path/to/cvs/wrapper/script
+
+6.4 Where to go from here *vcscommand-ssh-other*
+
+The script given above works even when non-SSH CVS connections are used,
+except possibly when interactively entering the message for CVS commit log
+(depending on the editor you use... VIM works fine). Since the vcscommand.vim
+plugin handles that message without a terminal, the wrapper script can be used
+all the time.
+
+This allows mixed-mode operation, where some work is done with SSH-based CVS
+repositories, and others with pserver or local access.
+
+It is possible, though beyond the scope of the plugin, to dynamically set the
+CVS executable based on the CVSROOT for the file being edited. The user
+events provided (such as VCSBufferCreated and VCSBufferSetup) can be used to
+set a buffer-local value (b:VCSCommandCVSExec) to override the CVS executable
+on a file-by-file basis. Alternatively, much the same can be done (less
+automatically) by the various project-oriented plugins out there.
+
+It is highly recommended for ease-of-use that certificates with no passphrase
+or ssh-agent are employed so that the user is not given the password prompt
+too often.
+
+==============================================================================
+
+7. Changes from cvscommandi *cvscommand-changes*
+
+1. Require Vim 7 in order to leverage several convenient features; also
+because I wanted to play with Vim 7.
+
+2. Renamed commands to start with 'VCS' instead of 'CVS'. The exceptions are
+the 'CVSEdit' and 'CVSWatch' family of commands, which are specific to CVS.
+
+3. Renamed options, events to start with 'VCSCommand'.
+
+4. Removed option to jump to the parent version of the current line in an
+annotated buffer, as opposed to the version on the current line. This made
+little sense in the branching scheme used by subversion, where jumping to a
+parent branch required finding a different location in the repository. It
+didn't work consistently in CVS anyway.
+
+5. Removed option to have nameless scratch buffers.
+
+6. Changed default behavior of scratch buffers to split the window instead of
+displaying in the current window. This may still be overridden using the
+'VCSCommandEdit' option.
+
+7. Split plugin into multiple plugins.
+
+8. Added 'VCSLock' and 'VCSUnlock' commands. These are implemented for
+subversion but not for CVS. These were not kept specific to subversion as they
+seemed more general in nature and more likely to be supported by any future VCS
+supported by this plugin.
+
+9. Changed name of buffer variables set by commands.
+
+'b:cvsOrigBuffNR' became 'b:VCSCommandOriginalBuffer'
+'b:cvscmd' became 'b:VCSCommandCommand'
+
+10. Added new automatic variables to command result buffers.
+
+'b:VCSCommandSourceFile'
+'b:VCSCommandVCSType'
+
+==============================================================================
+
+8. Known bugs *vcscommand-bugs*
+
+Please let me know if you run across any.
+
+CVSUnedit may, if a file is changed from the repository, provide prompt text
+to determine whether the changes should be thrown away. Currently, that text
+shows up in the CVS result buffer as information; there is no way for the user
+to actually respond to the prompt and the CVS unedit command does nothing. If
+this really bothers anyone, please let me know.
+
+VCSVimDiff, when using the original (real) source buffer as one of the diff
+buffers, uses some hacks to try to restore the state of the original buffer
+when the scratch buffer containing the other version is destroyed. There may
+still be bugs in here, depending on many configuration details.
+
+vim:tw=78:ts=8:ft=help
--- /dev/null
+"=============================================================================
+" fuzzyfinder.vim : Fuzzy/Partial pattern explorer for
+" buffer/file/MRU/command/favorite/tag/etc.
+"=============================================================================
+"
+" Author: Takeshi NISHIDA <
[email protected]>
+" Version: 2.13, for Vim 7.1
+" Licence: MIT Licence
+" URL: http://www.vim.org/scripts/script.php?script_id=1984
+"
+" GetLatestVimScripts: 1984 1 :AutoInstall: fuzzyfinder.vim
+"
+"=============================================================================
+" DOCUMENT: {{{1
+" Japanese: http://vim.g.hatena.ne.jp/keyword/fuzzyfinder.vim
+"
+"-----------------------------------------------------------------------------
+" Description:
+" Fuzzyfinder provides convenient ways to quickly reach the buffer/file you
+" want. Fuzzyfinder finds matching files/buffers with a fuzzy/partial
+" pattern to which it converted the entered pattern.
+"
+" E.g.: entered pattern -> fuzzy pattern / partial pattern
+" abc -> *a*b*c* / *abc*
+" a?c -> *a?c* / *a?c*
+" dir/file -> dir/*f*i*l*e* / dir/*file*
+" d*r/file -> d*r/*f*i*l*e* / d*r/*file*
+" ../**/s -> ../**/*s* / ../**/*s*
+"
+" (** allows searching a directory tree.)
+"
+" You will be happy when:
+" "./OhLongLongLongLongLongFile.txt"
+" "./AhLongLongLongLongLongName.txt"
+" "./AhLongLongLongLongLongFile.txt" <- you want :O
+" Type "AF" and "AhLongLongLongLongLongFile.txt" will be select. :D
+"
+" Fuzzyfinder has some modes:
+" - Buffer mode
+" - File mode
+" - Directory mode (yet another :cd command)
+" - MRU-file mode (most recently used files)
+" - MRU-command mode (most recently used command-lines)
+" - Favorite-file mode
+" - Tag mode (yet another :tag command)
+" - Tagged-file mode (files which are included in current tags)
+"
+" Fuzzyfinder supports the multibyte.
+"
+"-----------------------------------------------------------------------------
+" Installation:
+" Drop this file in your plugin directory.
+"
+"-----------------------------------------------------------------------------
+" Usage:
+" Starting Fuzzyfinder:
+" You can start Fuzzyfinder by the following commands:
+"
+" :FuzzyFinderBuffer - launchs buffer-mode Fuzzyfinder.
+" :FuzzyFinderFile - launchs file-mode Fuzzyfinder.
+" :FuzzyFinderDir - launchs directory-mode Fuzzyfinder.
+" :FuzzyFinderMruFile - launchs MRU-file-mode Fuzzyfinder.
+" :FuzzyFinderMruCmd - launchs MRU-command-mode Fuzzyfinder.
+" :FuzzyFinderFavFile - launchs favorite-file-mode Fuzzyfinder.
+" :FuzzyFinderTag - launchs tag-mode Fuzzyfinder.
+" :FuzzyFinderTaggedFile - launchs tagged-file-mode Fuzzyfinder.
+"
+" It is recommended to map these commands. These commands can take initial
+" text as a command argument. The text will be entered after Fuzzyfinder
+" launched. If a command was executed with a ! modifier (e.g.
+" :FuzzyFinderTag!), it enables the partial matching instead of the fuzzy
+" matching.
+"
+"
+" In Fuzzyfinder:
+" The entered pattern is converted to the fuzzy pattern and buffers/files
+" which match the pattern is shown in a completion menu.
+"
+" A completion menu is shown when you type at the end of the line and the
+" length of entered pattern is more than setting value. By default, it is
+" shown at the beginning.
+"
+" If too many items (200, by default) were matched, the completion is
+" aborted to reduce nonresponse.
+"
+" If an item were matched with entered pattern exactly, it is shown first.
+" The item whose file name has longer prefix matching is placed upper.
+" Also, an item which matched more sequentially is placed upper. The item
+" whose index were matched with a number suffixed with entered pattern is
+" placed lower. the first item in the completion menu will be selected
+" automatically.
+"
+" You can open a selected item in various ways:
+" <CR> - opens in a previous window.
+" <C-j> - opens in a split window.
+" <C-k> - opens in a vertical-split window.
+" <C-]> - opens in a new tab page.
+" In MRU-command mode, <CR> executes a selected command and others just
+" put it into a command-line. These key mappings are customizable.
+"
+" To cancel and return to previous window, leave Insert mode.
+"
+" To Switch the mode without leaving Insert mode, use <C-l> or <C-o>.
+" This key mapping is customizable.
+"
+" If you want to temporarily change whether or not to ignore case, use
+" <C-t>. This key mapping is customizable.
+"
+" To Hide The Completion Temporarily Menu In Fuzzyfinder:
+" You can close it by <C-e> and reopen it by <C-x><C-u>.
+"
+" About Highlighting:
+" Fuzzyfinder highlights the buffer with "Error" group when the completion
+" item was not found or the completion process was aborted.
+"
+" About Alternative Approach For Tag Jump:
+" Following mappings are replacements for :tag and <C-]>:
+"
+" nnoremap <silent> <C-f><C-t> :FuzzyFinderTag!<CR>
+" nnoremap <silent> <C-]> :FuzzyFinderTag! <C-r>=expand('<cword>')<CR><CR>
+"
+" In the tag mode, it is recommended to use partial matching instead of
+" fuzzy matching.
+"
+" About Tagged File Mode:
+" The files which are included in the current tags are the ones which are
+" related to the current working environment. So this mode is a pseudo
+" project mode.
+"
+" About Usage Of Command Argument:
+" As an example, if you want to launch file-mode Fuzzyfinder with the full
+" path of current directory, map like below:
+"
+" nnoremap <C-p> :FuzzyFinderFile <C-r>=fnamemodify(getcwd(), ':p')<CR><CR>
+"
+" Instead, if you want the directory of current buffer and not current
+" directory:
+"
+" nnoremap <C-p> :FuzzyFinderFile <C-r>=expand('%:~:.')[:-1-len(expand('%:~:.:t'))]<CR><CR>
+"
+" About Abbreviations And Multiple Search:
+" You can use abbreviations and multiple search in each mode. For example,
+" set as below:
+"
+" let g:FuzzyFinderOptions.Base.abbrev_map = {
+" \ "^WORK" : [
+" \ "~/project/**/src/",
+" \ ".vim/plugin/",
+" \ ],
+" \ }
+"
+" And type "WORKtxt" in file-mode Fuzzyfinder, then it searches by
+" following patterns:
+"
+" "~/project/**/src/*t*x*t*"
+" ".vim/plugin/*t*x*t*"
+"
+" Adding Favorite Files:
+" You can add a favorite file by the following commands:
+"
+" :FuzzyFinderAddFavFile {filename}
+"
+" If you do not specify the filename, current file name is used.
+"
+" About Information File:
+" Fuzzyfinder writes information of the MRU, favorite, etc to the file by
+" default (~/.vimfuzzyfinder).
+
+" :FuzzyFinderEditInfo command is helpful in editing your information
+" file. This command reads the information file in new unnamed buffer.
+" Write the buffer and the information file will be updated.
+"
+" About Cache:
+" Once a cache was created, It is not updated automatically to improve
+" response by default. To update it, use :FuzzyFinderRemoveCache command.
+"
+" About Migemo:
+" Migemo is a search method for Japanese language.
+"
+"-----------------------------------------------------------------------------
+" Options:
+" You can set options via g:FuzzyFinderOptions which is a dictionary. See
+" the folded section named "GLOBAL OPTIONS:" for details. To easily set
+" options for customization, put necessary entries from GLOBAL OPTIONS into
+" your vimrc file and edit those values.
+"
+"-----------------------------------------------------------------------------
+" Setting Example:
+" let g:FuzzyFinderOptions = { 'Base':{}, 'Buffer':{}, 'File':{}, 'Dir':{}, 'MruFile':{}, 'MruCmd':{}, 'FavFile':{}, 'Tag':{}, 'TaggedFile':{}}
+" let g:FuzzyFinderOptions.Base.ignore_case = 1
+" let g:FuzzyFinderOptions.Base.abbrev_map = {
+" \ '\C^VR' : [
+" \ '$VIMRUNTIME/**',
+" \ '~/.vim/**',
+" \ '$VIM/.vim/**',
+" \ '$VIM/vimfiles/**',
+" \ ],
+" \ }
+" let g:FuzzyFinderOptions.MruFile.max_item = 200
+" let g:FuzzyFinderOptions.MruCmd.max_item = 200
+" nnoremap <silent> <C-n> :FuzzyFinderBuffer<CR>
+" nnoremap <silent> <C-m> :FuzzyFinderFile <C-r>=expand('%:~:.')[:-1-len(expand('%:~:.:t'))]<CR><CR>
+" nnoremap <silent> <C-j> :FuzzyFinderMruFile<CR>
+" nnoremap <silent> <C-k> :FuzzyFinderMruCmd<CR>
+" nnoremap <silent> <C-p> :FuzzyFinderDir <C-r>=expand('%:p:~')[:-1-len(expand('%:p:~:t'))]<CR><CR>
+" nnoremap <silent> <C-f><C-d> :FuzzyFinderDir<CR>
+" nnoremap <silent> <C-f><C-f> :FuzzyFinderFavFile<CR>
+" nnoremap <silent> <C-f><C-t> :FuzzyFinderTag!<CR>
+" nnoremap <silent> <C-f><C-g> :FuzzyFinderTaggedFile<CR>
+" noremap <silent> g] :FuzzyFinderTag! <C-r>=expand('<cword>')<CR><CR>
+" nnoremap <silent> <C-f>F :FuzzyFinderAddFavFile<CR>
+" nnoremap <silent> <C-f><C-e> :FuzzyFinderEditInfo<CR>
+"
+"-----------------------------------------------------------------------------
+" Special Thanks:
+" Vincent Wang
+" Ingo Karkat
+" Nikolay Golubev
+" Brian Doyle
+" id:secondlife
+" Matt Tolton
+"
+"-----------------------------------------------------------------------------
+" ChangeLog:
+" 2.13:
+" - Fixed a bug that a directory disappeared when a file in that directroy
+" was being opened in File/Mru-File mode.
+"
+" 2.12:
+" - Changed to be able to show completion items in the order of recently
+" used in Buffer mode.
+" - Added g:FuzzyFinderOptions.Buffer.mru_order option.
+"
+" 2.11:
+" - Changed that a dot sequence of entered pattern is expanded to parent
+" directroies in File/Dir mode.
+" E.g.: "foo/...bar" -> "foo/../../bar"
+" - Fixed a bug that a prompt string was excessively inserted.
+"
+" 2.10:
+" - Changed not to show a current buffer in a completion menu.
+" - Fixed a bug that a filename to open was not been escaped.
+" - Added 'prompt' option.
+" - Added 'prompt_highlight' option.
+" - Removed g:FuzzyFinderOptions.MruFile.no_special_buffer option.
+"
+" 2.9:
+" - Enhanced <BS> behavior in Fuzzyfinder and added 'smart_bs' option.
+" - Fixed a bug that entered pattern was not been escaped.
+" - Fixed not to insert "zv" with "c/pattern<CR>" command in Normal mode.
+" - Avoid the slow down problem caused by filereadable() check for the MRU
+" information in BufEnter/BufWritePost.
+"
+" 2.8.1:
+" - Fixed a bug caused by the non-escaped buffer name "[Fuzzyfinder]".
+" - Fixed a command to open in a new tab page in Buffer mode.
+" 2.8:
+" - Added 'trim_length' option.
+" - Added 'switch_order' option.
+" - Fixed a bug that entered command did not become the newest in the
+" history.
+" - Fixed a bug that folds could not open with <CR> in a command-line when
+" searching.
+" - Removed 'excluded_indicator' option. Now a completion list in Buffer
+" mode is the same as a result of :buffers.
+"
+" 2.7:
+" - Changed to find an item whose index is matched with the number
+" suffixed with entered pattern.
+" - Fixed the cache bug after changing current directroy in File mode.
+"
+" 2.6.2:
+" - Fixed not to miss changes in options when updates the MRU information.
+"
+" 2.6.1:
+" - Fixed a bug related to floating-point support.
+" - Added support for GetLatestVimScripts.
+"
+" 2.6:
+" - Revived MRU-command mode. The problem with a command-line abbreviation
+" was solved.
+" - Changed the specification of the information file.
+" - Added :FuzzyFinderEditInfo command.
+
+" 2.5.1:
+" - Fixed to be able to match "foo/./bar" by "foo/**/bar" in File mode.
+" - Fixed to be able to open a space-containing file in File mode.
+" - Fixed to honor the current working directory properly in File mode.
+"
+" 2.5:
+" - Fixed the bug that a wrong initial text is entered after switching to a
+" next mode.
+" - Fixed the bug that it does not return to previous window after leaving
+" Fuzzyfinder one.
+"
+" 2.4:
+" - Fixed the bug that Fuzzyfinder fails to open a file caused by auto-cd
+" plugin/script.
+"
+" 2.3:
+" - Added a key mapping to open items in a new tab page and
+" g:FuzzyFinderOptions.Base.key_open_tab opton.
+" - Changed to show Fuzzyfinder window above last window even if
+" 'splitbelow' was set.
+" - Changed to set nocursorline and nocursorcolumn in Fuzzyfinder.
+" - Fixed not to push up a buffer number unlimitedly.
+"
+" 2.2:
+" - Added new feature, which is the partial matching.
+" - Fixed the bug that an error occurs when "'" was entered.
+"
+" 2.1:
+" - Restructured the option system AGAIN. Sorry :p
+" - Changed to inherit a typed text when switching a mode without leaving
+" Insert mode.
+" - Changed commands which launch explorers to be able to take a argument
+" for initial text.
+" - Changed to complete file names by relative path and not full path in
+" the buffer/mru-file/tagged-file mode.
+" - Changed to highlight a typed text when the completion item was not
+" found or the completion process was aborted.
+" - Changed to create caches for each tag file and not working directory
+" in the tag/tagged-file mode.
+" - Fixed the bug that the buffer mode couldn't open a unnamed buffer.
+" - Added 'matching_limit' option.
+" - Removed 'max_match' option. Use 'matching_limit' option instead.
+" - Removed 'initial_text' option. Use command argument instead.
+" - Removed the MRU-command mode.
+"
+" 2.0:
+" - Added the tag mode.
+" - Added the tagged-file mode.
+" - Added :FuzzyFinderRemoveCache command.
+" - Restructured the option system. many options are changed names or
+" default values of some options.
+" - Changed to hold and reuse caches of completion lists by default.
+" - Changed to set filetype 'fuzzyfinder'.
+" - Disabled the MRU-command mode by default because there are problems.
+" - Removed FuzzyFinderAddMode command.
+"
+" 1.5:
+" - Added the directory mode.
+" - Fixed the bug that it caused an error when switch a mode in Insert
+" mode.
+" - Changed g:FuzzyFinder_KeySwitchMode type to a list.
+"
+" 1.4:
+" - Changed the specification of the information file.
+" - Added the MRU-commands mode.
+" - Renamed :FuzzyFinderAddFavorite command to :FuzzyFinderAddFavFile.
+" - Renamed g:FuzzyFinder_MruModeVars option to
+" g:FuzzyFinder_MruFileModeVars.
+" - Renamed g:FuzzyFinder_FavoriteModeVars option to
+" g:FuzzyFinder_FavFileModeVars.
+" - Changed to show registered time of each item in MRU/favorite mode.
+" - Added 'timeFormat' option for MRU/favorite modes.
+"
+" 1.3:
+" - Fixed a handling of multi-byte characters.
+"
+" 1.2:
+" - Added support for Migemo. (Migemo is Japanese search method.)
+"
+" 1.1:
+" - Added the favorite mode.
+" - Added new features, which are abbreviations and multiple search.
+" - Added 'abbrevMap' option for each mode.
+" - Added g:FuzzyFinder_MruModeVars['ignoreSpecialBuffers'] option.
+" - Fixed the bug that it did not work correctly when a user have mapped
+" <C-p> or <Down>.
+"
+" 1.0:
+" - Added the MRU mode.
+" - Added commands to add and use original mode.
+" - Improved the sorting algorithm for completion items.
+" - Added 'initialInput' option to automatically insert a text at the
+" beginning of a mode.
+" - Changed that 'excludedPath' option works for the entire path.
+" - Renamed some options.
+" - Changed default values of some options.
+" - Packed the mode-specific options to dictionaries.
+" - Removed some options.
+"
+" 0.6:
+" - Fixed some bugs.
+
+" 0.5:
+" - Improved response by aborting processing too many items.
+" - Changed to be able to open a buffer/file not only in previous window
+" but also in new window.
+" - Fixed a bug that recursive searching with '**' does not work.
+" - Added g:FuzzyFinder_CompletionItemLimit option.
+" - Added g:FuzzyFinder_KeyOpen option.
+"
+" 0.4:
+" - Improved response of the input.
+" - Improved the sorting algorithm for completion items. It is based on
+" the matching level. 1st is perfect matching, 2nd is prefix matching,
+" and 3rd is fuzzy matching.
+" - Added g:FuzzyFinder_ExcludePattern option.
+" - Removed g:FuzzyFinder_WildIgnore option.
+" - Removed g:FuzzyFinder_EchoPattern option.
+" - Removed g:FuzzyFinder_PathSeparator option.
+" - Changed the default value of g:FuzzyFinder_MinLengthFile from 1 to 0.
+"
+" 0.3:
+" - Added g:FuzzyFinder_IgnoreCase option.
+" - Added g:FuzzyFinder_KeyToggleIgnoreCase option.
+" - Added g:FuzzyFinder_EchoPattern option.
+" - Changed the open command in a buffer mode from ":edit" to ":buffer" to
+" avoid being reset cursor position.
+" - Changed the default value of g:FuzzyFinder_KeyToggleMode from
+" <C-Space> to <F12> because <C-Space> does not work on some CUI
+" environments.
+" - Changed to avoid being loaded by Vim before 7.0.
+" - Fixed a bug with making a fuzzy pattern which has '\'.
+"
+" 0.2:
+" - A bug it does not work on Linux is fixed.
+"
+" 0.1:
+" - First release.
+"
+" }}}1
+"=============================================================================
+" INCLUDE GUARD: {{{1
+if exists('loaded_fuzzyfinder') || v:version < 701
+ finish
+endif
+let loaded_fuzzyfinder = 1
+
+" }}}1
+"=============================================================================
+" FUNCTION: {{{1
+"-----------------------------------------------------------------------------
+" LIST FUNCTIONS:
+
+function! s:Unique(in)
+ let sorted = sort(a:in)
+ if len(sorted) < 2
+ return sorted
+ endif
+ let last = remove(sorted, 0)
+ let result = [last]
+ for item in sorted
+ if item != last
+ call add(result, item)
+ let last = item
+ endif
+ endfor
+ return result
+endfunction
+
+" [ [0], [1,2], [3] ] -> [ 0, 1, 2, 3 ]
+function! s:Concat(in)
+ let result = []
+ for l in a:in
+ let result += l
+ endfor
+ return result
+endfunction
+
+" [ [ 0, 1 ], [ 2, 3, 4 ], ] -> [ [0,2], [0,3], [0,4], [1,2], [1,3], [1,4] ]
+function! s:CartesianProduct(lists)
+ if empty(a:lists)
+ return []
+ endif
+ "let result = map((a:lists[0]), '[v:val]')
+ let result = [ [] ]
+ for l in a:lists
+ let temp = []
+ for r in result
+ let temp += map(copy(l), 'add(copy(r), v:val)')
+ endfor
+ let result = temp
+ endfor
+ return result
+endfunction
+
+" copy + filter + limit
+function! s:FilterEx(in, expr, limit)
+ if a:limit <= 0
+ return filter(copy(a:in), a:expr)
+ endif
+ let result = []
+ let stride = a:limit * 3 / 2 " x1.5
+ for i in range(0, len(a:in) - 1, stride)
+ let result += filter(a:in[i : i + stride - 1], a:expr)
+ if len(result) >= a:limit
+ return remove(result, 0, a:limit - 1)
+ endif
+ endfor
+ return result
+endfunction
+
+"
+function! s:FilterMatching(entries, key, pattern, index, limit)
+ return s:FilterEx(a:entries, 'v:val[''' . a:key . '''] =~ ' . string(a:pattern) . ' || v:val.index == ' . a:index, a:limit)
+endfunction
+
+function! s:ExtendIndexToEach(in, offset)
+ for i in range(len(a:in))
+ let a:in[i].index = i + a:offset
+ endfor
+ return a:in
+endfunction
+
+function! s:UpdateMruList(mrulist, new_item, key, max_item, excluded)
+ let result = copy(a:mrulist)
+ let result = filter(result,'v:val[a:key] != a:new_item[a:key]')
+ let result = insert(result, a:new_item)
+ let result = filter(result, 'v:val[a:key] !~ a:excluded')
+ return result[0 : a:max_item - 1]
+endfunction
+
+"-----------------------------------------------------------------------------
+" STRING FUNCTIONS:
+
+" trims a:str and add a:mark if a length of a:str is more than a:len
+function! s:TrimLast(str, len)
+ if a:len <= 0 || len(a:str) <= a:len
+ return a:str
+ endif
+ return a:str[:(a:len - len(s:ABBR_TRIM_MARK) - 1)] . s:ABBR_TRIM_MARK
+endfunction
+
+" takes suffix numer. if no digits, returns -1
+function! s:SuffixNumber(str)
+ let s = matchstr(a:str, '\d\+$')
+ return (len(s) ? str2nr(s) : -1)
+endfunction
+
+function! s:ConvertWildcardToRegexp(expr)
+ let re = escape(a:expr, '\')
+ for [pat, sub] in [ [ '*', '\\.\\*' ], [ '?', '\\.' ], [ '[', '\\[' ], ]
+ let re = substitute(re, pat, sub, 'g')
+ endfor
+ return '\V' . re
+endfunction
+
+" "foo/bar/hoge" -> { head: "foo/bar/", tail: "hoge" }
+function! s:SplitPath(path)
+ let dir = matchstr(a:path, '^.*[/\\]')
+ return {
+ \ 'head' : dir,
+ \ 'tail' : a:path[strlen(dir):]
+ \ }
+endfunction
+
+function! s:EscapeFilename(fn)
+ return escape(a:fn, " \t\n*?[{`$%#'\"|!<")
+endfunction
+
+" "foo/.../bar/...hoge" -> "foo/.../bar/../../hoge"
+function! s:ExpandTailDotSequenceToParentDir(base)
+ return substitute(a:base, '^\(.*[/\\]\)\?\zs\.\(\.\+\)\ze[^/\\]*$',
+ \ '\=repeat(".." . s:PATH_SEPARATOR, len(submatch(2)))', '')
+endfunction
+
+"-----------------------------------------------------------------------------
+" FUNCTIONS FOR COMPLETION ITEM:
+
+function! s:FormatCompletionItem(expr, number, abbr, trim_len, time, base_pattern, evals_path_tail)
+ if a:evals_path_tail
+ let rate = s:EvaluateMatchingRate(s:SplitPath(matchstr(a:expr, '^.*[^/\\]')).tail,
+ \ s:SplitPath(a:base_pattern).tail)
+ else
+ let rate = s:EvaluateMatchingRate(a:expr, a:base_pattern)
+ endif
+ return {
+ \ 'word' : a:expr,
+ \ 'abbr' : s:TrimLast((a:number >= 0 ? printf('%2d: ', a:number) : '') . a:abbr, a:trim_len),
+ \ 'menu' : printf('%s[%s]', (len(a:time) ? a:time . ' ' : ''), s:MakeRateStar(rate, 5)),
+ \ 'ranks' : [-rate, (a:number >= 0 ? a:number : a:expr)]
+ \ }
+endfunction
+
+function! s:EvaluateMatchingRate(expr, pattern)
+ if a:expr == a:pattern
+ return s:MATCHING_RATE_BASE
+ endif
+ let rate = 0
+ let rate_increment = (s:MATCHING_RATE_BASE * 9) / (len(a:pattern) * 10) " zero divide ok
+ let matched = 1
+ let i_pattern = 0
+ for i_expr in range(len(a:expr))
+ if a:expr[i_expr] == a:pattern[i_pattern]
+ let rate += rate_increment
+ let matched = 1
+ let i_pattern += 1
+ if i_pattern >= len(a:pattern)
+ break
+ endif
+ elseif matched
+ let rate_increment = rate_increment / 2
+ let matched = 0
+ endif
+ endfor
+ return rate
+endfunction
+
+function! s:MakeRateStar(rate, base)
+ let len = (a:base * a:rate) / s:MATCHING_RATE_BASE
+ return repeat('*', len) . repeat('.', a:base - len)
+endfunction
+
+"-----------------------------------------------------------------------------
+" MISC FUNCTIONS:
+
+function! s:IsAvailableMode(mode)
+ return exists('a:mode.mode_available') && a:mode.mode_available
+endfunction
+
+function! s:GetAvailableModes()
+ return filter(values(g:FuzzyFinderMode), 's:IsAvailableMode(v:val)')
+endfunction
+
+function! s:GetSortedAvailableModes()
+ let modes = filter(items(g:FuzzyFinderMode), 's:IsAvailableMode(v:val[1])')
+ let modes = map(modes, 'extend(v:val[1], { "ranks" : [v:val[1].switch_order, v:val[0]] })')
+ return sort(modes, 's:CompareRanks')
+endfunction
+
+function! s:GetSidPrefix()
+ return matchstr(expand('<sfile>'), '<SNR>\d\+_')
+endfunction
+
+function! s:OnCmdCR()
+ for m in s:GetAvailableModes()
+ call m.extend_options()
+ call m.on_command_pre(getcmdtype() . getcmdline())
+ endfor
+ " lets last entry become the newest in the history
+ if getcmdtype() =~ '[:/=@]'
+ call histadd(getcmdtype(), getcmdline())
+ endif
+
+ " this is not mapped again (:help recursive_mapping)
+ return "\<CR>"
+endfunction
+
+function! s:ExpandAbbrevMap(base, abbrev_map)
+ let result = [a:base]
+
+ " expand
+ for [pattern, sub_list] in items(a:abbrev_map)
+ let exprs = result
+ let result = []
+ for expr in exprs
+ let result += map(copy(sub_list), 'substitute(expr, pattern, v:val, "g")')
+ endfor
+ endfor
+
+ return s:Unique(result)
+endfunction
+
+" "**" is expanded to ["**", "."]. E.g.: "foo/**/bar" -> [ "foo/./bar", "foo/**/bar" ]
+function! s:ExpandEx(dir)
+ if a:dir !~ '\S'
+ return ['']
+ endif
+
+ " [ ["foo/"], ["**/", "./" ], ["bar/"] ]
+ let lists = []
+ for i in split(a:dir, '[/\\]\zs')
+ let m = matchlist(i, '^\*\{2,}\([/\\]*\)$')
+ call add(lists, (empty(m) ? [i] : [i, '.' . m[1]]))
+ endfor
+
+ " expand wlidcards
+ return split(join(map(s:CartesianProduct(lists), 'expand(join(v:val, ""))'), "\n"), "\n")
+endfunction
+
+function! s:EnumExpandedDirsEntries(dir, excluded)
+ let dirs = s:ExpandEx(a:dir)
+ let entries = s:Concat(map(copy(dirs), 'split(glob(v:val . ".*"), "\n") + ' .
+ \ 'split(glob(v:val . "*" ), "\n")'))
+ if len(dirs) <= 1
+ call map(entries, 'extend(s:SplitPath(v:val), { "suffix" : (isdirectory(v:val) ? s:PATH_SEPARATOR : ""), "head" : a:dir })')
+ else
+ call map(entries, 'extend(s:SplitPath(v:val), { "suffix" : (isdirectory(v:val) ? s:PATH_SEPARATOR : "") })')
+ endif
+ if len(a:excluded)
+ call filter(entries, '(v:val.head . v:val.tail . v:val.suffix) !~ a:excluded')
+ endif
+ return entries
+endfunction
+
+function! s:GetTagList(tagfile)
+ return map(readfile(a:tagfile), 'matchstr(v:val, ''^[^!\t][^\t]*'')')
+endfunction
+
+function! s:GetTaggedFileList(tagfile)
+ execute 'cd ' . fnamemodify(a:tagfile, ':h')
+ let result = map(readfile(a:tagfile), 'fnamemodify(matchstr(v:val, ''^[^!\t][^\t]*\t\zs[^\t]\+''), '':p:~'')')
+ cd -
+ return result
+endfunction
+
+function! s:HighlightPrompt(prompt, highlight)
+ syntax clear
+ execute printf('syntax match %s /^\V%s/', a:highlight, escape(a:prompt, '\'))
+endfunction
+
+function! s:HighlightError()
+ syntax clear
+ syntax match Error /^.*$/
+endfunction
+
+function! s:CompareTimeDescending(i1, i2)
+ return a:i1.time == a:i2.time ? 0 : a:i1.time > a:i2.time ? -1 : +1
+endfunction
+
+function! s:CompareRanks(i1, i2)
+ if exists('a:i1.ranks') && exists('a:i2.ranks')
+ for i in range(min([len(a:i1.ranks), len(a:i2.ranks)]))
+ if a:i1.ranks[i] > a:i2.ranks[i]
+ return +1
+ elseif a:i1.ranks[i] < a:i2.ranks[i]
+ return -1
+ endif
+ endfor
+ endif
+ return 0
+endfunction
+
+function! s:GetCurrentTagFiles()
+ return sort(filter(map(tagfiles(), 'fnamemodify(v:val, '':p'')'), 'filereadable(v:val)'))
+endfunction
+
+" }}}1
+"=============================================================================
+" OBJECT: {{{1
+"-----------------------------------------------------------------------------
+let g:FuzzyFinderMode = { 'Base' : {} }
+
+function! g:FuzzyFinderMode.Base.launch(initial_text, partial_matching, prev_bufnr, tag_files)
+ " initializes this object
+ call self.extend_options()
+ let self.partial_matching = a:partial_matching
+ let self.prev_bufnr = a:prev_bufnr
+ let self.tag_files = a:tag_files " to get local value of current buffer
+ let self.last_col = -1
+ call s:InfoFileManager.load()
+ if !s:IsAvailableMode(self)
+ echo 'This mode is not available: ' . self.to_str()
+ return
+ endif
+
+ call s:WindowManager.activate(self.make_complete_func('CompleteFunc'))
+ call s:OptionManager.set('completeopt', 'menuone')
+ call s:OptionManager.set('ignorecase', self.ignore_case)
+
+ " local autocommands
+ augroup FuzzyfinderLocal
+ autocmd!
+ execute 'autocmd CursorMovedI <buffer> call ' . self.to_str('on_cursor_moved_i()')
+ execute 'autocmd InsertLeave <buffer> nested call ' . self.to_str('on_insert_leave()' )
+ augroup END
+
+ " local mapping
+ for [lhs, rhs] in [
+ \ [ self.key_open , self.to_str('on_cr(0, 0)' ) ],
+ \ [ self.key_open_split , self.to_str('on_cr(1, 0)' ) ],
+ \ [ self.key_open_vsplit, self.to_str('on_cr(2, 0)' ) ],
+ \ [ self.key_open_tab , self.to_str('on_cr(3, 0)' ) ],
+ \ [ '<BS>' , self.to_str('on_bs()' ) ],
+ \ [ '<C-h>' , self.to_str('on_bs()' ) ],
+ \ [ self.key_next_mode , self.to_str('on_switch_mode(+1)' ) ],
+ \ [ self.key_prev_mode , self.to_str('on_switch_mode(-1)' ) ],
+ \ [ self.key_ignore_case, self.to_str('on_switch_ignore_case()') ],
+ \ ]
+ " hacks to be able to use feedkeys().
+ execute printf('inoremap <buffer> <silent> %s <C-r>=%s ? "" : ""<CR>', lhs, rhs)
+ endfor
+
+ call self.on_mode_enter()
+
+ " Starts Insert mode and makes CursorMovedI event now. Command prompt is
+ " needed to forces a completion menu to update every typing.
+ call setline(1, self.prompt . a:initial_text)
+ call feedkeys("A", 'n') " startinsert! does not work in InsertLeave handler
+endfunction
+
+function! g:FuzzyFinderMode.Base.on_cursor_moved_i()
+ let ln = getline('.')
+ let cl = col('.')
+ if !self.exists_prompt(ln)
+ " if command prompt is removed
+ "call setline('.', self.prompt . ln)
+ call setline('.', self.restore_prompt(ln))
+ call feedkeys(repeat("\<Right>", len(getline('.')) - len(ln)), 'n')
+ elseif cl <= len(self.prompt)
+ " if the cursor is moved before command prompt
+ call feedkeys(repeat("\<Right>", len(self.prompt) - cl + 1), 'n')
+ elseif cl > strlen(ln) && cl != self.last_col
+ " if the cursor is placed on the end of the line and has been actually moved.
+ let self.last_col = cl
+ call feedkeys("\<C-x>\<C-u>", 'n')
+ endif
+endfunction
+
+function! g:FuzzyFinderMode.Base.on_insert_leave()
+ let text = getline('.')
+ call self.on_mode_leave()
+ call self.empty_cache_if_existed(0)
+ call s:OptionManager.restore_all()
+ call s:WindowManager.deactivate()
+
+ " switchs to next mode, or finishes fuzzyfinder.
+ if exists('s:reserved_switch_mode')
+ let m = self.next_mode(s:reserved_switch_mode < 0)
+ call m.launch(self.remove_prompt(text), self.partial_matching, self.prev_bufnr, self.tag_files)
+ unlet s:reserved_switch_mode
+ else
+ if exists('s:reserved_command')
+ call feedkeys(self.on_open(s:reserved_command[0], s:reserved_command[1]), 'n')
+ unlet s:reserved_command
+ endif
+ endif
+endfunction
+
+function! g:FuzzyFinderMode.Base.on_buf_enter()
+endfunction
+
+function! g:FuzzyFinderMode.Base.on_buf_write_post()
+endfunction
+
+function! g:FuzzyFinderMode.Base.on_command_pre(cmd)
+endfunction
+
+function! g:FuzzyFinderMode.Base.on_cr(index, check_dir)
+ if pumvisible()
+ call feedkeys(printf("\<C-y>\<C-r>=%s(%d, 1) ? '' : ''\<CR>", self.to_str('on_cr'), a:index), 'n')
+ elseif !a:check_dir || getline('.') !~ '[/\\]$'
+ let s:reserved_command = [self.remove_prompt(getline('.')), a:index]
+ call feedkeys("\<Esc>", 'n')
+ endif
+endfunction
+
+function! g:FuzzyFinderMode.Base.on_bs()
+ let bs_count = 1
+ if self.smart_bs && col('.') > 2 && getline('.')[col('.') - 2] =~ '[/\\]'
+ let bs_count = len(matchstr(getline('.')[:col('.') - 3], '[^/\\]*$')) + 1
+ endif
+ call feedkeys((pumvisible() ? "\<C-e>" : "") . repeat("\<BS>", bs_count), 'n')
+endfunction
+
+function! g:FuzzyFinderMode.Base.on_mode_enter()
+endfunction
+
+function! g:FuzzyFinderMode.Base.on_mode_leave()
+endfunction
+
+function! g:FuzzyFinderMode.Base.on_open(expr, mode)
+ return [
+ \ ':edit ',
+ \ ':split ',
+ \ ':vsplit ',
+ \ ':tabedit ',
+ \ ][a:mode] . s:EscapeFilename(a:expr) . "\<CR>"
+endfunction
+
+function! g:FuzzyFinderMode.Base.on_switch_mode(next_prev)
+ let s:reserved_switch_mode = a:next_prev
+ call feedkeys("\<Esc>", 'n')
+endfunction
+
+function! g:FuzzyFinderMode.Base.on_switch_ignore_case()
+ let &ignorecase = !&ignorecase
+ echo "ignorecase = " . &ignorecase
+ let self.last_col = -1
+ call self.on_cursor_moved_i()
+endfunction
+
+" export string list
+function! g:FuzzyFinderMode.Base.serialize_info()
+ let header = self.to_key() . "\t"
+ return map(copy(self.info), 'header . string(v:val)')
+endfunction
+
+" import related items from string list
+function! g:FuzzyFinderMode.Base.deserialize_info(lines)
+ let header = self.to_key() . "\t"
+ let self.info = map(filter(copy(a:lines), 'v:val[: len(header) - 1] ==# header'),
+ \ 'eval(v:val[len(header) :])')
+endfunction
+
+function! g:FuzzyFinderMode.Base.complete(findstart, base)
+ if a:findstart
+ return 0
+ elseif !self.exists_prompt(a:base) || len(self.remove_prompt(a:base)) < self.min_length
+ return []
+ endif
+ call s:HighlightPrompt(self.prompt, self.prompt_highlight)
+ " FIXME: ExpandAbbrevMap duplicates index
+ let result = []
+ for expanded_base in s:ExpandAbbrevMap(self.remove_prompt(a:base), self.abbrev_map)
+ let result += self.on_complete(expanded_base)
+ endfor
+ call sort(result, 's:CompareRanks')
+ if empty(result)
+ call s:HighlightError()
+ else
+ call feedkeys("\<C-p>\<Down>", 'n')
+ endif
+ return result
+endfunction
+
+" This function is set to 'completefunc' which doesn't accept dictionary-functions.
+function! g:FuzzyFinderMode.Base.make_complete_func(name)
+ execute printf("function! s:%s(findstart, base)\n" .
+ \ " return %s.complete(a:findstart, a:base)\n" .
+ \ "endfunction", a:name, self.to_str())
+ return s:GetSidPrefix() . a:name
+endfunction
+
+" fuzzy : 'str' -> {'base':'str', 'wi':'*s*t*r*', 're':'\V\.\*s\.\*t\.\*r\.\*'}
+" partial: 'str' -> {'base':'str', 'wi':'*str*', 're':'\V\.\*str\.\*'}
+function! g:FuzzyFinderMode.Base.make_pattern(base)
+ if self.partial_matching
+ let wi = (a:base !~ '^[*?]' ? '*' : '') . a:base .
+ \ (a:base =~ '[^*?]$' ? '*' : '')
+ let re = s:ConvertWildcardToRegexp(wi)
+ return { 'base': a:base, 'wi':wi, 're': re }
+ else
+ let wi = ''
+ for char in split(a:base, '\zs')
+ if wi !~ '[*?]$' && char !~ '[*?]'
+ let wi .= '*'. char
+ else
+ let wi .= char
+ endif
+ endfor
+
+ if wi !~ '[*?]$'
+ let wi .= '*'
+ endif
+
+ let re = s:ConvertWildcardToRegexp(wi)
+
+ if self.migemo_support && a:base !~ '[^\x01-\x7e]'
+ let re .= '\|\m.*' . substitute(migemo(a:base), '\\_s\*', '.*', 'g') . '.*'
+ endif
+
+ return { 'base': a:base, 'wi':wi, 're': re }
+ endif
+endfunction
+
+" glob with caching-feature, etc.
+function! g:FuzzyFinderMode.Base.glob_ex(dir, file, excluded, index, matching_limit)
+ let key = fnamemodify(a:dir, ':p')
+ call extend(self, { 'cache' : {} }, 'keep')
+ if !exists('self.cache[key]')
+ echo 'Caching file list...'
+ let self.cache[key] = s:EnumExpandedDirsEntries(key, a:excluded)
+ call s:ExtendIndexToEach(self.cache[key], 1)
+ endif
+ echo 'Filtering file list...'
+ "return map(s:FilterEx(self.cache[key], 'v:val.tail =~ ' . string(a:file), a:matching_limit),
+ return map(s:FilterMatching(self.cache[key], 'tail', a:file, a:index, a:matching_limit),
+ \ '{ "index" : v:val.index, "path" : (v:val.head == key ? a:dir : v:val.head) . v:val.tail . v:val.suffix }')
+endfunction
+
+function! g:FuzzyFinderMode.Base.glob_dir_ex(dir, file, excluded, index, matching_limit)
+ let key = fnamemodify(a:dir, ':p')
+ call extend(self, { 'cache' : {} }, 'keep')
+ if !exists('self.cache[key]')
+ echo 'Caching file list...'
+ let self.cache[key] = filter(s:EnumExpandedDirsEntries(key, a:excluded), 'len(v:val.suffix)')
+ call insert(self.cache[key], { 'head' : key, 'tail' : '..', 'suffix' : s:PATH_SEPARATOR })
+ call insert(self.cache[key], { 'head' : key, 'tail' : '.' , 'suffix' : '' })
+ call s:ExtendIndexToEach(self.cache[key], 1)
+ endif
+ echo 'Filtering file list...'
+ "return map(s:FilterEx(self.cache[key], 'v:val.tail =~ ' . string(a:file), a:matching_limit),
+ return map(s:FilterMatching(self.cache[key], 'tail', a:file, a:index, a:matching_limit),
+ \ '{ "index" : v:val.index, "path" : (v:val.head == key ? a:dir : v:val.head) . v:val.tail . v:val.suffix }')
+endfunction
+
+function! g:FuzzyFinderMode.Base.empty_cache_if_existed(force)
+ if exists('self.cache') && (a:force || !exists('self.lasting_cache') || !self.lasting_cache)
+ unlet self.cache
+ "let self.cache = (type(self.cache) == type({}) ? {} :
+ " \ type(self.cache) == type([]) ? [] :
+ " \ type(self.cache) == type('') ? '' : 0)
+ endif
+endfunction
+
+function! g:FuzzyFinderMode.Base.to_key()
+ return filter(keys(g:FuzzyFinderMode), 'g:FuzzyFinderMode[v:val] is self')[0]
+endfunction
+
+" returns 'g:FuzzyFinderMode.{key}{.argument}'
+function! g:FuzzyFinderMode.Base.to_str(...)
+ return 'g:FuzzyFinderMode.' . self.to_key() . (a:0 > 0 ? '.' . a:1 : '')
+endfunction
+
+" takes in g:FuzzyFinderOptions
+function! g:FuzzyFinderMode.Base.extend_options()
+ let n = filter(keys(g:FuzzyFinderMode), 'g:FuzzyFinderMode[v:val] is self')[0]
+ call extend(self, g:FuzzyFinderOptions.Base, 'force')
+ call extend(self, g:FuzzyFinderOptions[self.to_key()], 'force')
+endfunction
+
+function! g:FuzzyFinderMode.Base.next_mode(rev)
+ let modes = (a:rev ? s:GetSortedAvailableModes() : reverse(s:GetSortedAvailableModes()))
+ let m_last = modes[-1]
+ for m in modes
+ if m is self
+ break
+ endif
+ let m_last = m
+ endfor
+ return m_last
+ " vim crashed using map()
+endfunction
+
+function! g:FuzzyFinderMode.Base.exists_prompt(in)
+ return strlen(a:in) >= strlen(self.prompt) && a:in[:strlen(self.prompt) -1] ==# self.prompt
+endfunction
+
+function! g:FuzzyFinderMode.Base.remove_prompt(in)
+ return a:in[(self.exists_prompt(a:in) ? strlen(self.prompt) : 0):]
+endfunction
+
+function! g:FuzzyFinderMode.Base.restore_prompt(in)
+ let i = 0
+ while i < len(self.prompt) && i < len(a:in) && self.prompt[i] ==# a:in[i]
+ let i += 1
+ endwhile
+ return self.prompt . a:in[i : ]
+endfunction
+
+"-----------------------------------------------------------------------------
+let g:FuzzyFinderMode.Buffer = copy(g:FuzzyFinderMode.Base)
+
+function! g:FuzzyFinderMode.Buffer.on_complete(base)
+ let patterns = self.make_pattern(a:base)
+ let result = s:FilterMatching(self.cache, 'path', patterns.re, s:SuffixNumber(patterns.base), 0)
+ return map(result, 's:FormatCompletionItem(v:val.path, v:val.index, v:val.path, self.trim_length, v:val.time, a:base, 1)')
+endfunction
+
+function! g:FuzzyFinderMode.Buffer.on_open(expr, mode)
+ " attempts to convert the path to the number for handling unnamed buffer
+ return printf([
+ \ ':%sbuffer',
+ \ ':%ssbuffer',
+ \ ':vertical :%ssbuffer',
+ \ ':tab :%ssbuffer',
+ \ ][a:mode] . "\<CR>", filter(self.cache, 'v:val.path == a:expr')[0].buf_nr)
+endfunction
+
+function! g:FuzzyFinderMode.Buffer.on_mode_enter()
+ let self.cache = map(filter(range(1, bufnr('$')), 'buflisted(v:val) && v:val != self.prev_bufnr'),
+ \ 'self.make_item(v:val)')
+ if self.mru_order
+ call s:ExtendIndexToEach(sort(self.cache, 's:CompareTimeDescending'), 1)
+ endif
+endfunction
+
+function! g:FuzzyFinderMode.Buffer.on_buf_enter()
+ call self.update_buf_times()
+endfunction
+
+function! g:FuzzyFinderMode.Buffer.on_buf_write_post()
+ call self.update_buf_times()
+endfunction
+
+function! g:FuzzyFinderMode.Buffer.update_buf_times()
+ if !exists('self.buf_times')
+ let self.buf_times = {}
+ endif
+ let self.buf_times[bufnr('%')] = localtime()
+endfunction
+
+function! g:FuzzyFinderMode.Buffer.make_item(nr)
+ return {
+ \ 'index' : a:nr,
+ \ 'buf_nr' : a:nr,
+ \ 'path' : empty(bufname(a:nr)) ? '[No Name]' : fnamemodify(bufname(a:nr), ':~:.'),
+ \ 'time' : (exists('self.buf_times[a:nr]') ? strftime(self.time_format, self.buf_times[a:nr]) : ''),
+ \ }
+endfunction
+
+"-----------------------------------------------------------------------------
+let g:FuzzyFinderMode.File = copy(g:FuzzyFinderMode.Base)
+
+function! g:FuzzyFinderMode.File.on_complete(base)
+ let base = s:ExpandTailDotSequenceToParentDir(a:base)
+ let patterns = map(s:SplitPath(base), 'self.make_pattern(v:val)')
+ let result = self.glob_ex(patterns.head.base, patterns.tail.re, self.excluded_path, s:SuffixNumber(patterns.tail.base), self.matching_limit)
+ let result = filter(result, 'bufnr("^" . v:val.path . "$") != self.prev_bufnr')
+ if len(result) >= self.matching_limit
+ call s:HighlightError()
+ endif
+ return map(result, 's:FormatCompletionItem(v:val.path, v:val.index, v:val.path, self.trim_length, "", base, 1)')
+endfunction
+
+"-----------------------------------------------------------------------------
+let g:FuzzyFinderMode.Dir = copy(g:FuzzyFinderMode.Base)
+
+function! g:FuzzyFinderMode.Dir.on_complete(base)
+ let base = s:ExpandTailDotSequenceToParentDir(a:base)
+ let patterns = map(s:SplitPath(base), 'self.make_pattern(v:val)')
+ let result = self.glob_dir_ex(patterns.head.base, patterns.tail.re, self.excluded_path, s:SuffixNumber(patterns.tail.base), 0)
+ return map(result, 's:FormatCompletionItem(v:val.path, v:val.index, v:val.path, self.trim_length, "", base, 1)')
+endfunction
+
+function! g:FuzzyFinderMode.Dir.on_open(expr, mode)
+ return ':cd ' . escape(a:expr, ' ') . [
+ \ "\<CR>",
+ \ "",
+ \ "",
+ \ "",
+ \ ][a:mode]
+endfunction
+
+"-----------------------------------------------------------------------------
+let g:FuzzyFinderMode.MruFile = copy(g:FuzzyFinderMode.Base)
+
+function! g:FuzzyFinderMode.MruFile.on_complete(base)
+ let patterns = self.make_pattern(a:base)
+ let result = s:FilterMatching(self.cache, 'path', patterns.re, s:SuffixNumber(patterns.base), 0)
+ return map(result, 's:FormatCompletionItem(v:val.path, v:val.index, v:val.path, self.trim_length, v:val.time, a:base, 1)')
+endfunction
+
+function! g:FuzzyFinderMode.MruFile.on_mode_enter()
+ let self.cache = copy(self.info)
+ let self.cache = filter(self.cache, 'bufnr("^" . v:val.path . "$") != self.prev_bufnr')
+ let self.cache = filter(self.cache, 'filereadable(v:val.path)')
+ let self.cache = map(self.cache, '{ "path" : fnamemodify(v:val.path, ":~:."), "time" : strftime(self.time_format, v:val.time) }')
+ let self.cache = s:ExtendIndexToEach(self.cache, 1)
+endfunction
+
+function! g:FuzzyFinderMode.MruFile.on_buf_enter()
+ call self.update_info()
+endfunction
+
+function! g:FuzzyFinderMode.MruFile.on_buf_write_post()
+ call self.update_info()
+endfunction
+
+function! g:FuzzyFinderMode.MruFile.update_info()
+ "if !empty(&buftype) || !filereadable(expand('%'))
+ if !empty(&buftype)
+ return
+ endif
+ call s:InfoFileManager.load()
+ let self.info = s:UpdateMruList(self.info, { 'path' : expand('%:p'), 'time' : localtime() },
+ \ 'path', self.max_item, self.excluded_path)
+ call s:InfoFileManager.save()
+endfunction
+
+"-----------------------------------------------------------------------------
+let g:FuzzyFinderMode.MruCmd = copy(g:FuzzyFinderMode.Base)
+
+function! g:FuzzyFinderMode.MruCmd.on_complete(base)
+ let patterns = self.make_pattern(a:base)
+ let result = s:FilterMatching(self.cache, 'command', patterns.re, s:SuffixNumber(patterns.base), 0)
+ return map(result, 's:FormatCompletionItem(v:val.command, v:val.index, v:val.command, self.trim_length, v:val.time, a:base, 0)')
+endfunction
+
+function! g:FuzzyFinderMode.MruCmd.on_open(expr, mode)
+ redraw
+ " use feedkeys to remap <CR>
+ return a:expr . [
+ \ "\<C-r>=feedkeys(\"\\<CR>\", 'm')?'':''\<CR>",
+ \ "",
+ \ "",
+ \ "",
+ \ ][a:mode]
+endfunction
+
+function! g:FuzzyFinderMode.MruCmd.on_mode_enter()
+ let self.cache = s:ExtendIndexToEach(map(copy(self.info),
+ \ '{ "command" : v:val.command, "time" : strftime(self.time_format, v:val.time) }'), 1)
+endfunction
+
+function! g:FuzzyFinderMode.MruCmd.on_command_pre(cmd)
+ call self.update_info(a:cmd)
+endfunction
+
+function! g:FuzzyFinderMode.MruCmd.update_info(cmd)
+ call s:InfoFileManager.load()
+ let self.info = s:UpdateMruList(self.info, { 'command' : a:cmd, 'time' : localtime() },
+ \ 'command', self.max_item, self.excluded_command)
+ call s:InfoFileManager.save()
+endfunction
+
+"-----------------------------------------------------------------------------
+let g:FuzzyFinderMode.FavFile = copy(g:FuzzyFinderMode.Base)
+
+function! g:FuzzyFinderMode.FavFile.on_complete(base)
+ let patterns = self.make_pattern(a:base)
+ let result = s:FilterMatching(self.cache, 'path', patterns.re, s:SuffixNumber(patterns.base), 0)
+ return map(result, 's:FormatCompletionItem(v:val.path, v:val.index, v:val.path, self.trim_length, v:val.time, a:base, 1)')
+endfunction
+
+function! g:FuzzyFinderMode.FavFile.on_mode_enter()
+ let self.cache = copy(self.info)
+ let self.cache = filter(self.cache, 'bufnr("^" . v:val.path . "$") != self.prev_bufnr')
+ let self.cache = map(self.cache, '{ "path" : fnamemodify(v:val.path, ":~:."), "time" : strftime(self.time_format, v:val.time) }')
+ let self.cache = s:ExtendIndexToEach(self.cache, 1)
+endfunction
+
+function! g:FuzzyFinderMode.FavFile.add(in_file, adds)
+ call s:InfoFileManager.load()
+
+ let file = fnamemodify((empty(a:in_file) ? expand('%') : a:in_file), ':p:~')
+
+ call filter(self.info, 'v:val.path != file')
+ if a:adds
+ call add(self.info, { 'path' : file, 'time' : localtime() })
+ endif
+
+ call s:InfoFileManager.save()
+endfunction
+
+"-----------------------------------------------------------------------------
+let g:FuzzyFinderMode.Tag = copy(g:FuzzyFinderMode.Base)
+
+function! g:FuzzyFinderMode.Tag.on_complete(base)
+ let patterns = self.make_pattern(a:base)
+ let result = self.find_tag(patterns.re, self.matching_limit)
+ if len(result) >= self.matching_limit
+ call s:HighlightError()
+ endif
+ return map(result, 's:FormatCompletionItem(v:val, -1, v:val, self.trim_length, "", a:base, 1)')
+endfunction
+
+function! g:FuzzyFinderMode.Tag.on_open(expr, mode)
+ return [
+ \ ':tjump ',
+ \ ':stjump ',
+ \ ':vertical :stjump ',
+ \ ':tab :stjump ',
+ \ ][a:mode] . a:expr . "\<CR>"
+endfunction
+
+function! g:FuzzyFinderMode.Tag.find_tag(pattern, matching_limit)
+ if !len(self.tag_files)
+ return []
+ endif
+
+ let key = join(self.tag_files, "\n")
+
+ " cache not created or tags file updated?
+ call extend(self, { 'cache' : {} }, 'keep')
+ if !exists('self.cache[key]') || max(map(copy(self.tag_files), 'getftime(v:val) >= self.cache[key].time'))
+ echo 'Caching tag list...'
+ let self.cache[key] = {
+ \ 'time' : localtime(),
+ \ 'data' : s:Unique(s:Concat(map(copy(self.tag_files), 's:GetTagList(v:val)'))),
+ \ }
+ endif
+
+ echo 'Filtering tag list...'
+ return s:FilterEx(self.cache[key].data, 'v:val =~ ' . string(a:pattern), a:matching_limit)
+endfunction
+
+"-----------------------------------------------------------------------------
+let g:FuzzyFinderMode.TaggedFile = copy(g:FuzzyFinderMode.Base)
+
+function! g:FuzzyFinderMode.TaggedFile.on_complete(base)
+ let patterns = self.make_pattern(a:base)
+ echo 'Making tagged file list...'
+ let result = self.find_tagged_file(patterns.re, self.matching_limit)
+ if len(result) >= self.matching_limit
+ call s:HighlightError()
+ endif
+ return map(result, 's:FormatCompletionItem(v:val, -1, v:val, self.trim_length, "", a:base, 1)')
+endfunction
+
+function! g:FuzzyFinderMode.TaggedFile.find_tagged_file(pattern, matching_limit)
+ if !len(self.tag_files)
+ return []
+ endif
+
+ let key = join(self.tag_files, "\n")
+
+ " cache not created or tags file updated?
+ call extend(self, { 'cache' : {} }, 'keep')
+ if !exists('self.cache[key]') || max(map(copy(self.tag_files), 'getftime(v:val) >= self.cache[key].time'))
+ echo 'Caching tagged-file list...'
+ let self.cache[key] = {
+ \ 'time' : localtime(),
+ \ 'data' : s:Unique(s:Concat(map(copy(self.tag_files), 's:GetTaggedFileList(v:val)'))),
+ \ }
+ endif
+
+ echo 'Filtering tagged-file list...'
+ return s:FilterEx(map(self.cache[key].data, 'fnamemodify(v:val, '':.'')'),
+ \ 'v:val =~ ' . string(a:pattern),
+ \ a:matching_limit)
+
+endfunction
+
+"-----------------------------------------------------------------------------
+" sets or restores temporary options
+let s:OptionManager = { 'originals' : {} }
+
+function! s:OptionManager.set(name, value)
+ call extend(self.originals, { a:name : eval('&' . a:name) }, 'keep')
+ execute printf('let &%s = a:value', a:name)
+endfunction
+
+function! s:OptionManager.restore_all()
+ for [name, value] in items(self.originals)
+ execute printf('let &%s = value', name)
+ endfor
+ let self.originals = {}
+endfunction
+
+"-----------------------------------------------------------------------------
+" manages buffer/window for fuzzyfinder
+let s:WindowManager = { 'buf_nr' : -1 }
+
+function! s:WindowManager.activate(complete_func)
+ let self.prev_winnr = winnr()
+ let cwd = getcwd()
+
+ if !bufexists(self.buf_nr)
+ leftabove 1new
+ file `='[Fuzzyfinder]'`
+ let self.buf_nr = bufnr('%')
+ elseif bufwinnr(self.buf_nr) == -1
+ leftabove 1split
+ execute self.buf_nr . 'buffer'
+ delete _
+ elseif bufwinnr(self.buf_nr) != bufwinnr('%')
+ execute bufwinnr(self.buf_nr) . 'wincmd w'
+ endif
+
+ " countermeasure for auto-cd script
+ execute ':lcd ' . cwd
+
+ setlocal filetype=fuzzyfinder
+ setlocal bufhidden=delete
+ setlocal buftype=nofile
+ setlocal noswapfile
+ setlocal nobuflisted
+ setlocal modifiable
+ setlocal nocursorline " for highlighting
+ setlocal nocursorcolumn " for highlighting
+ let &l:completefunc = a:complete_func
+
+ redraw " for 'lazyredraw'
+
+ " suspend autocomplpop.vim
+ if exists(':AutoComplPopLock')
+ :AutoComplPopLock
+ endif
+endfunction
+
+function! s:WindowManager.deactivate()
+ " resume autocomplpop.vim
+ if exists(':AutoComplPopUnlock')
+ :AutoComplPopUnlock
+ endif
+
+ close
+ execute self.prev_winnr . 'wincmd w'
+endfunction
+
+"-----------------------------------------------------------------------------
+let s:InfoFileManager = { 'originals' : {} }
+
+function! s:InfoFileManager.load()
+ for m in s:GetAvailableModes()
+ let m.info = []
+ endfor
+
+ try
+ let lines = readfile(expand(self.get_info_file()))
+ catch /.*/
+ return
+ endtry
+
+ " compatibility check
+ if !count(lines, self.get_info_version_line())
+ call self.warn_old_info()
+ let g:FuzzyFinderOptions.Base.info_file = ''
+ return
+ endif
+
+ for m in s:GetAvailableModes()
+ call m.deserialize_info(lines)
+ endfor
+endfunction
+
+function! s:InfoFileManager.save()
+ let lines = [ self.get_info_version_line() ]
+ for m in s:GetAvailableModes()
+ let lines += m.serialize_info()
+ endfor
+
+ try
+ call writefile(lines, expand(self.get_info_file()))
+ catch /.*/
+ endtry
+endfunction
+
+function! s:InfoFileManager.edit()
+
+ new
+ file `='[FuzzyfinderInfo]'`
+ let self.bufnr = bufnr('%')
+
+ setlocal filetype=vim
+ setlocal bufhidden=delete
+ setlocal buftype=acwrite
+ setlocal noswapfile
+
+ augroup FuzzyfinderInfo
+ autocmd!
+ autocmd BufWriteCmd <buffer> call s:InfoFileManager.on_buf_write_cmd()
+ augroup END
+
+ execute '0read ' . expand(self.get_info_file())
+ setlocal nomodified
+
+endfunction
+
+function! s:InfoFileManager.on_buf_write_cmd()
+ for m in s:GetAvailableModes()
+ call m.deserialize_info(getline(1, '$'))
+ endfor
+ call self.save()
+ setlocal nomodified
+ execute printf('%dbdelete! ', self.bufnr)
+ echo "Information file updated"
+endfunction
+
+function! s:InfoFileManager.get_info_version_line()
+ return "VERSION\t206"
+endfunction
+
+function! s:InfoFileManager.get_info_file()
+ return g:FuzzyFinderOptions.Base.info_file
+endfunction
+
+function! s:InfoFileManager.warn_old_info()
+ echohl WarningMsg
+ echo printf("==================================================\n" .
+ \ " Your Fuzzyfinder information file is no longer \n" .
+ \ " supported. Please remove \n" .
+ \ " %-48s\n" .
+ \ "==================================================\n" ,
+ \ '"' . expand(self.get_info_file()) . '".')
+ echohl None
+endfunction
+
+" }}}1
+"=============================================================================
+" GLOBAL OPTIONS: {{{1
+" stores user-defined g:FuzzyFinderOptions ------------------------------ {{{2
+let user_options = (exists('g:FuzzyFinderOptions') ? g:FuzzyFinderOptions : {})
+" }}}2
+
+" Initializes g:FuzzyFinderOptions.
+let g:FuzzyFinderOptions = { 'Base':{}, 'Buffer':{}, 'File':{}, 'Dir':{}, 'MruFile':{}, 'MruCmd':{}, 'FavFile':{}, 'Tag':{}, 'TaggedFile':{}}
+"-----------------------------------------------------------------------------
+" [All Mode] This is mapped to select completion item or finish input and
+" open a buffer/file in previous window.
+let g:FuzzyFinderOptions.Base.key_open = '<CR>'
+" [All Mode] This is mapped to select completion item or finish input and
+" open a buffer/file in split new window
+let g:FuzzyFinderOptions.Base.key_open_split = '<C-j>'
+" [All Mode] This is mapped to select completion item or finish input and
+" open a buffer/file in vertical-split new window.
+let g:FuzzyFinderOptions.Base.key_open_vsplit = '<C-k>'
+" [All Mode] This is mapped to select completion item or finish input and
+" open a buffer/file in a new tab page.
+let g:FuzzyFinderOptions.Base.key_open_tab = '<C-]>'
+" [All Mode] This is mapped to switch to the next mode.
+let g:FuzzyFinderOptions.Base.key_next_mode = '<C-l>'
+" [All Mode] This is mapped to switch to the previous mode.
+let g:FuzzyFinderOptions.Base.key_prev_mode = '<C-o>'
+" [All Mode] This is mapped to temporarily switch whether or not to ignore
+" case.
+let g:FuzzyFinderOptions.Base.key_ignore_case = '<C-t>'
+" [All Mode] This is the file name to write information of the MRU, etc. If
+" "" was set, Fuzzyfinder does not write to the file.
+let g:FuzzyFinderOptions.Base.info_file = '~/.vimfuzzyfinder'
+" [All Mode] Fuzzyfinder does not start a completion if a length of entered
+" text is less than this.
+let g:FuzzyFinderOptions.Base.min_length = 0
+" [All Mode] This is a dictionary. Each value must be a list. All matchs of a
+" key in entered text is expanded with the value.
+let g:FuzzyFinderOptions.Base.abbrev_map = {}
+" [All Mode] Fuzzyfinder ignores case in search patterns if non-zero is set.
+let g:FuzzyFinderOptions.Base.ignore_case = 1
+" [All Mode] This is a string to format time string. See :help strftime() for
+" details.
+let g:FuzzyFinderOptions.Base.time_format = '(%x %H:%M:%S)'
+" [All Mode] If a length of completion item is more than this, it is trimmed
+" when shown in completion menu.
+let g:FuzzyFinderOptions.Base.trim_length = 80
+" [All Mode] Fuzzyfinder does not remove caches of completion lists at the end
+" of explorer to reuse at the next time if non-zero was set.
+let g:FuzzyFinderOptions.Base.lasting_cache = 1
+" [All Mode] Fuzzyfinder uses Migemo if non-zero is set.
+let g:FuzzyFinderOptions.Base.migemo_support = 0
+"-----------------------------------------------------------------------------
+" [Buffer Mode] This disables all functions of this mode if zero was set.
+let g:FuzzyFinderOptions.Buffer.mode_available = 1
+" [Buffer Mode] The prompt string.
+let g:FuzzyFinderOptions.Buffer.prompt = '>Buffer>'
+" [Buffer Mode] The highlight group name for a prompt string.
+let g:FuzzyFinderOptions.Buffer.prompt_highlight = 'Question'
+" [Buffer Mode] Pressing <BS> after a path separator deletes one directory
+" name if non-zero is set.
+let g:FuzzyFinderOptions.Buffer.smart_bs = 1
+" [Buffer Mode] The completion items is sorted in the order of recently used
+" if non-zero is set.
+let g:FuzzyFinderOptions.Buffer.mru_order = 1
+" [Buffer Mode] This is used to sort modes for switching to the next/previous
+" mode.
+let g:FuzzyFinderOptions.Buffer.switch_order = 10
+"-----------------------------------------------------------------------------
+" [File Mode] This disables all functions of this mode if zero was set.
+let g:FuzzyFinderOptions.File.mode_available = 1
+" [File Mode] The prompt string.
+let g:FuzzyFinderOptions.File.prompt = '>File>'
+" [File Mode] The highlight group name for a prompt string.
+let g:FuzzyFinderOptions.File.prompt_highlight = 'Question'
+" [File Mode] Pressing <BS> after a path separator deletes one directory name
+" if non-zero is set.
+let g:FuzzyFinderOptions.File.smart_bs = 1
+" [File Mode] This is used to sort modes for switching to the next/previous
+" mode.
+let g:FuzzyFinderOptions.File.switch_order = 20
+" [File Mode] The items matching this are excluded from the completion list.
+let g:FuzzyFinderOptions.File.excluded_path = '\v\~$|\.o$|\.exe$|\.bak$|\.swp$|((^|[/\\])\.[/\\]$)'
+" [File Mode] If a number of matched items was over this, the completion
+" process is aborted.
+let g:FuzzyFinderOptions.File.matching_limit = 200
+"-----------------------------------------------------------------------------
+" [Directory Mode] This disables all functions of this mode if zero was set.
+let g:FuzzyFinderOptions.Dir.mode_available = 1
+" [Directory Mode] The prompt string.
+let g:FuzzyFinderOptions.Dir.prompt = '>Dir>'
+" [Directory Mode] The highlight group name for a prompt string.
+let g:FuzzyFinderOptions.Dir.prompt_highlight = 'Question'
+" [Directory Mode] Pressing <BS> after a path separator deletes one directory
+" name if non-zero is set.
+let g:FuzzyFinderOptions.Dir.smart_bs = 1
+" [Directory Mode] This is used to sort modes for switching to the
+" next/previous mode.
+let g:FuzzyFinderOptions.Dir.switch_order = 30
+" [Directory Mode] The items matching this are excluded from the completion
+" list.
+let g:FuzzyFinderOptions.Dir.excluded_path = '\v(^|[/\\])\.{1,2}[/\\]$'
+"-----------------------------------------------------------------------------
+" [Mru-File Mode] This disables all functions of this mode if zero was set.
+let g:FuzzyFinderOptions.MruFile.mode_available = 1
+" [Mru-File Mode] The prompt string.
+let g:FuzzyFinderOptions.MruFile.prompt = '>MruFile>'
+" [Mru-File Mode] The highlight group name for a prompt string.
+let g:FuzzyFinderOptions.MruFile.prompt_highlight = 'Question'
+" [Mru-File Mode] Pressing <BS> after a path separator deletes one directory
+" name if non-zero is set.
+let g:FuzzyFinderOptions.MruFile.smart_bs = 1
+" [Mru-File Mode] This is used to sort modes for switching to the
+" next/previous mode.
+let g:FuzzyFinderOptions.MruFile.switch_order = 40
+" [Mru-File Mode] The items matching this are excluded from the completion
+" list.
+let g:FuzzyFinderOptions.MruFile.excluded_path = '\v\~$|\.bak$|\.swp$'
+" [Mru-File Mode] This is an upper limit of MRU items to be stored.
+let g:FuzzyFinderOptions.MruFile.max_item = 99
+"-----------------------------------------------------------------------------
+" [Mru-Cmd Mode] This disables all functions of this mode if zero was set.
+let g:FuzzyFinderOptions.MruCmd.mode_available = 1
+" [Mru-Cmd Mode] The prompt string.
+let g:FuzzyFinderOptions.MruCmd.prompt = '>MruCmd>'
+" [Mru-Cmd Mode] The highlight group name for a prompt string.
+let g:FuzzyFinderOptions.MruCmd.prompt_highlight = 'Question'
+" [Mru-Cmd Mode] Pressing <BS> after a path separator deletes one directory
+" name if non-zero is set.
+let g:FuzzyFinderOptions.MruCmd.smart_bs = 0
+" [Mru-Cmd Mode] This is used to sort modes for switching to the next/previous
+" mode.
+let g:FuzzyFinderOptions.MruCmd.switch_order = 50
+" [Mru-Cmd Mode] The items matching this are excluded from the completion
+" list.
+let g:FuzzyFinderOptions.MruCmd.excluded_command = '^$'
+" [Mru-Cmd Mode] This is an upper limit of MRU items to be stored.
+let g:FuzzyFinderOptions.MruCmd.max_item = 99
+"-----------------------------------------------------------------------------
+" [Favorite-File Mode] This disables all functions of this mode if zero was
+" set.
+let g:FuzzyFinderOptions.FavFile.mode_available = 1
+" [Favorite-File Mode] The prompt string.
+let g:FuzzyFinderOptions.FavFile.prompt = '>FavFile>'
+" [Favorite-File Mode] The highlight group name for a prompt string.
+let g:FuzzyFinderOptions.FavFile.prompt_highlight = 'Question'
+" [Favorite-File Mode] Pressing <BS> after a path separator deletes one
+" directory name if non-zero is set.
+let g:FuzzyFinderOptions.FavFile.smart_bs = 1
+" [Favorite-File Mode] This is used to sort modes for switching to the
+" next/previous mode.
+let g:FuzzyFinderOptions.FavFile.switch_order = 60
+"-----------------------------------------------------------------------------
+" [Tag Mode] This disables all functions of this mode if zero was set.
+let g:FuzzyFinderOptions.Tag.mode_available = 1
+" [Tag Mode] The prompt string.
+let g:FuzzyFinderOptions.Tag.prompt = '>Tag>'
+" [Tag Mode] The highlight group name for a prompt string.
+let g:FuzzyFinderOptions.Tag.prompt_highlight = 'Question'
+" [Tag Mode] Pressing <BS> after a path separator deletes one directory name
+" if non-zero is set.
+let g:FuzzyFinderOptions.Tag.smart_bs = 0
+" [Tag Mode] This is used to sort modes for switching to the next/previous
+" mode.
+let g:FuzzyFinderOptions.Tag.switch_order = 70
+" [Tag Mode] The items matching this are excluded from the completion list.
+let g:FuzzyFinderOptions.Tag.excluded_path = '\v\~$|\.bak$|\.swp$'
+" [Tag Mode] If a number of matched items was over this, the completion
+" process is aborted.
+let g:FuzzyFinderOptions.Tag.matching_limit = 200
+"-----------------------------------------------------------------------------
+" [Tagged-File Mode] This disables all functions of this mode if zero was set.
+let g:FuzzyFinderOptions.TaggedFile.mode_available = 1
+" [Tagged-File Mode] The prompt string.
+let g:FuzzyFinderOptions.TaggedFile.prompt = '>TaggedFile>'
+" [Tagged-File Mode] The highlight group name for a prompt string.
+let g:FuzzyFinderOptions.TaggedFile.prompt_highlight = 'Question'
+" [Tagged-File Mode] Pressing <BS> after a path separator deletes one
+" directory name if non-zero is set.
+let g:FuzzyFinderOptions.TaggedFile.smart_bs = 0
+" [Tagged-File Mode] This is used to sort modes for switching to the
+" next/previous mode.
+let g:FuzzyFinderOptions.TaggedFile.switch_order = 80
+" [Tagged-File Mode] If a number of matched items was over this, the
+" completion process is aborted.
+let g:FuzzyFinderOptions.TaggedFile.matching_limit = 200
+
+" overwrites default values of g:FuzzyFinderOptions with user-defined values - {{{2
+call map(user_options, 'extend(g:FuzzyFinderOptions[v:key], v:val, ''force'')')
+call map(copy(g:FuzzyFinderMode), 'v:val.extend_options()')
+" }}}2
+
+" }}}1
+"=============================================================================
+" COMMANDS/AUTOCOMMANDS/MAPPINGS/ETC.: {{{1
+
+let s:PATH_SEPARATOR = (has('win32') || has('win64') ? '\' : '/')
+let s:MATCHING_RATE_BASE = 10000000
+let s:ABBR_TRIM_MARK = '...'
+
+augroup FuzzyfinderGlobal
+ autocmd!
+ autocmd BufEnter * for m in s:GetAvailableModes() | call m.extend_options() | call m.on_buf_enter() | endfor
+ autocmd BufWritePost * for m in s:GetAvailableModes() | call m.extend_options() | call m.on_buf_write_post() | endfor
+augroup END
+
+" cnoremap has a problem, which doesn't expand cabbrev.
+cmap <silent> <expr> <CR> <SID>OnCmdCR()
+
+command! -bang -narg=? -complete=buffer FuzzyFinderBuffer call g:FuzzyFinderMode.Buffer.launch (<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles())
+command! -bang -narg=? -complete=file FuzzyFinderFile call g:FuzzyFinderMode.File.launch (<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles())
+command! -bang -narg=? -complete=dir FuzzyFinderDir call g:FuzzyFinderMode.Dir.launch (<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles())
+command! -bang -narg=? -complete=file FuzzyFinderMruFile call g:FuzzyFinderMode.MruFile.launch (<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles())
+command! -bang -narg=? -complete=file FuzzyFinderMruCmd call g:FuzzyFinderMode.MruCmd.launch (<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles())
+command! -bang -narg=? -complete=file FuzzyFinderFavFile call g:FuzzyFinderMode.FavFile.launch (<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles())
+command! -bang -narg=? -complete=tag FuzzyFinderTag call g:FuzzyFinderMode.Tag.launch (<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles())
+command! -bang -narg=? -complete=file FuzzyFinderTaggedFile call g:FuzzyFinderMode.TaggedFile.launch(<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles())
+command! -bang -narg=? -complete=file FuzzyFinderEditInfo call s:InfoFileManager.edit()
+command! -bang -narg=? -complete=file FuzzyFinderAddFavFile call g:FuzzyFinderMode.FavFile.add(<q-args>, 1)
+command! -bang -narg=0 FuzzyFinderRemoveCache for m in s:GetAvailableModes() | call m.empty_cache_if_existed(1) | endfor
+
+" }}}1
+"=============================================================================
+" vim: set fdm=marker:
--- /dev/null
+if has("ruby")
+
+" ====================================================================================
+" COPIED FROM FUZZYFINDER.VIM {{{
+" since they can't be called from outside fuzzyfinder.vim
+" ====================================================================================
+function! s:GetCurrentTagFiles()
+ return sort(filter(map(tagfiles(), 'fnamemodify(v:val, '':p'')'), 'filereadable(v:val)'))
+endfunction
+
+function! s:HighlightPrompt(prompt, highlight)
+ syntax clear
+ execute printf('syntax match %s /^\V%s/', a:highlight, escape(a:prompt, '\'))
+endfunction
+
+function! s:HighlightError()
+ syntax clear
+ syntax match Error /^.*$/
+endfunction
+" ------------------------------------------------------------------------------------
+" }}}
+" ====================================================================================
+
+command! -bang -narg=? -complete=file FuzzyFinderTextMate call FuzzyFinderTextMateLauncher(<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles())
+
+function! InstantiateTextMateMode() "{{{
+ruby << RUBY
+ $LOAD_PATH << "#{ENV['HOME']}/.vim/ruby"
+
+ begin
+ require 'rubygems'
+ gem 'fuzzy_file_finder'
+ rescue LoadError
+ end
+
+ require 'fuzzy_file_finder'
+RUBY
+
+ ruby def finder; @finder ||= FuzzyFileFinder.new; end
+
+ let g:FuzzyFinderMode.TextMate = copy(g:FuzzyFinderMode.Base)
+
+ " ================================================================================
+ " This function is copied almost whole-sale from fuzzyfinder.vim. Ideally, I could
+ " used the on_complete callback to more cleanly add the new behavior, but the
+ " TextMate-style completion broke a few of fuzzyfinder.vim's assumptions, and the
+ " only way to patch that up was to override Base.complete...which required me to
+ " copy-and-paste much of the original implementation.
+ "
+ " Ugly. But effective.
+ " ================================================================================
+ function! g:FuzzyFinderMode.TextMate.complete(findstart, base)
+ if a:findstart
+ return 0
+ elseif !self.exists_prompt(a:base) || len(self.remove_prompt(a:base)) < self.min_length
+ return []
+ endif
+ call s:HighlightPrompt(self.prompt, self.prompt_highlight)
+
+ let result = []
+ ruby << RUBY
+ matches = finder.find(VIM.evaluate('self.remove_prompt(a:base)'), VIM.evaluate('self.matching_limit').to_i + 1)
+ matches.sort_by { |a| [-a[:score], a[:path]] }.each_with_index do |match, index|
+ word = match[:path]
+ abbr = "%2d: %s" % [index+1, match[:abbr]]
+ menu = "[%5d]" % [match[:score] * 10000]
+ VIM.evaluate("add(result, { 'word' : #{word.inspect}, 'abbr' : #{abbr.inspect}, 'menu' : #{menu.inspect} })")
+ end
+RUBY
+ if empty(result) || len(result) >= self.matching_limit
+ call s:HighlightError()
+ endif
+
+ if !empty(result)
+ call feedkeys("\<C-p>\<Down>", 'n')
+ endif
+
+ return result
+ endfunction
+
+ function! FuzzyFinderTextMateLauncher(initial_text, partial_matching, prev_bufnr, tag_files)
+ call g:FuzzyFinderMode.TextMate.launch(a:initial_text, a:partial_matching, a:prev_bufnr, a:tag_files)
+ endfunction
+
+ let g:FuzzyFinderOptions.TextMate = copy(g:FuzzyFinderOptions.File)
+endfunction "}}}
+
+if !exists('loaded_fuzzyfinder') "{{{
+ function! FuzzyFinderTextMateLauncher(initial_text, partial_matching, prev_bufnr, tag_files)
+ call InstantiateTextMateMode()
+ function! FuzzyFinderTextMateLauncher(initial_text, partial_matching, prev_bufnr, tag_files)
+ call g:FuzzyFinderMode.TextMate.launch(a:initial_text, a:partial_matching, a:prev_bufnr, a:tag_files)
+ endfunction
+ call g:FuzzyFinderMode.TextMate.launch(a:initial_text, a:partial_matching, a:prev_bufnr, a:tag_files)
+ endfunction
+ finish
+end "}}}
+
+call InstantiateTextMateMode()
+
+endif
--- /dev/null
+" genutils: Useful buffer, file and window related functions.
+" Author: Hari Krishna Dara (hari_vim at yahoo dot com)
+" Last Change: 08-Jun-2007 @ 17:36
+" Requires: Vim-7.0
+" Version: 2.4.0
+" Licence: This program is free software; you can redistribute it and/or
+" modify it under the terms of the GNU General Public License.
+" See http://www.gnu.org/copyleft/gpl.txt
+" Acknowledgements:
+" - The genutils#GetNextWinnrInStack() function is based on the WinStackMv()
+" function posted by Charles E. Campbell, Jr. on vim mailing list on Jul
+" 14, 2004.
+" - The genutils#CommonPath() function is based on the thread,
+" "computing relative path" on Jul 29, 2002.
+" - The genutils#ShowLinesWithSyntax() function is based on a posting by
+" Gary Holloway (gary at castandcrew dot com) on Jan, 16 2002.
+" - Robert Webb for the original "quick sort" algorithm from eval.txt.
+" - Peit Delport's (pjd at 303 dot za dot net) for his original BISort()
+" algorithm on which the genutils#BinInsertSort() and
+" genutils#BinInsertSort2() functions are based on.
+" Download From:
+" http://www.vim.org/script.php?script_id=197
+" See Also: autoload/genutils.vim
+"
+" Description:
+" - Read the "Documentation With Function Prototypes" section below.
+" - Misc. window/buffer related functions, genutils#NumberOfWindows(),
+" genutils#FindBufferForName(), genutils#MoveCursorToWindow(),
+" genutils#MoveCurLineToWinLine(), genutils#SetupScratchBuffer(),
+" genutils#MapAppendCascaded()
+" - Save/Restore all the window height/width settings to be restored later.
+" - Save/Restore position in the buffer to be restored later. Works like the
+" built-in marks feature, but has more to it.
+" - genutils#AddNotifyWindowClose() to get notifications *after* a window
+" with the specified buffer has been closed or the buffer is unloaded. The
+" built-in autocommands can only notify you *before* the window is closed.
+" You can use this with the Save/Restore window settings feature to
+" restore the dimensions of existing windows, after your window is closed
+" (just like how Vim does while closing help windows). See selectbuf.vim
+" or perforce.vim for examples.
+" There is also a test function called RunNotifyWindowCloseTest() that
+" demos the usage (you need to uncomment RunNotifyWindowCloseTest and
+" NotifyWindowCloseF functions).
+" - genutils#ShowLinesWithSyntax() function to echo lines with syntax coloring.
+" - genutils#ShiftWordInSpace(), genutils#CenterWordInSpace() and
+" genutils#AlignWordWithWordInPreviousLine() utility functions to move
+" words in the space without changing the width of the field. A
+" genutils#GetSpacer() function to return a spacer of specified width.
+" - Binary search function genutils#BinSearchList() for sorted lists, to
+" find the index after which a given item can be inserted to keep the list
+" in sorted order. You can also use these functions to just search for
+" boundaries.
+" There are also a couple of functions genutils#BinSearchForInsert() and
+" genutils#BinSearchForInsert2() to find the location for a newline to be
+" inserted in an already sorted buffer or arbitrary data.
+" There are also a few comparison functions that can be used with sort() or
+" the above functions.
+" - ExecMap function has now been separated as a plugin called execmap.vim.
+" - New genutils#CommonPath() function to extract the common part of two
+" paths, and genutils#RelPathFromFile() and genutils#RelPathFromDir() to
+" find relative paths (useful HTML href's). A side effect is the
+" genutils#CommonString() function to find the common string of two
+" strings.
+" - genutils#UnEscape() and genutils#DeEscape() functions to reverse and
+" genutils#Escape() to compliment what built-in escape() does. There is
+" also an genutils#EscapeCommand() function to escape external command
+" strings.
+" - Utility functions genutils#CurLineHasSign() and genutils#ClearAllSigns()
+" to fill in the gaps left by Vim.
+" - genutils#GetVimCmdOutput() function to capture the output of Vim built-in
+" commands, in a safe manner.
+" - genutils#OptClearBuffer() function to clear the contents and undo
+" history of the current buffer in an optimal manner. Ideal to be used
+" when plugins need to refresh their windows and don't care about
+" preserving the current contents (which is the most usual case).
+" - genutils#GetPreviewWinnr() function.
+" - Functions to have persistent data, genutils#PutPersistentVar() and
+" genutils#GetPersistentVar(). You don't need to worry about saving in
+" files and reading them back. To disable, set g:genutilsNoPersist in your
+" vimrc.
+" - A function to emulate the default Vim behavior for |timestamp| changes.
+" It also provides hooks to get call backs before and after handling the
+" default FileChangedShell autocommand (effectively splitting it into a
+" Pre and a Post event). Suggested usage is to use
+" genutils#AddToFCShellPre() and either install a default event handling
+" mechanism for all files by calling genutils#DefFCShellInstall() or
+" create your own autocommand on a matching pattern to call
+" genutils#DefFileChangedShell() function. Most useful for the source
+" control plugins to conditionally reload a file, while being able to
+" default to the Vim's standard behavior of asking the user. See
+" perforce.vim for usage examples.
+" - Utility function genutils#ExtractFuncListing() that is useful to to
+" create snippets (see breakpts.vim, ntservices.vim and ntprocesses.vim
+" for interesting ideas on how to use this function).
+"
+" Function Prototypes:
+" The types in prototypes of the functions mimic Java.
+" This is just a full list for a quick reference, see
+" "Documentation With Function Prototypes" for more information on the
+" functions.
+"
+" void genutils#DebugShowArgs(...)
+" String genutils#ExtractFuncListing(String funcName, String hLines, String tLines)
+" int genutils#NumberOfWindows()
+" int genutils#FindBufferForName(String fileName)
+" String genutils#GetBufNameForAu(String bufName)
+" void genutils#MoveCursorToWindow(int winno)
+" void genutils#MoveCurLineToWinLine(int winLine)
+" void genutils#CloseWindow(int winnr, boolean force)
+" void genutils#MarkActiveWindow()
+" void genutils#RestoreActiveWindow()
+" void genutils#IsOnlyVerticalWindow()
+" void genutils#IsOnlyHorizontalWindow()
+" int genutils#GetNextWinnrInStack(char dir)
+" int genutils#GetLastWinnrInStack(char dir)
+" void genutils#MoveCursorToNextInWinStack(char dir)
+" void genutils#MoveCursorToLastInWinStack(char dir)
+" void genutils#OpenWinNoEa(String openWinCmd)
+" void genutils#CloseWinNoEa(int winnr, boolean force)
+" void genutils#SetupScratchBuffer()
+" void genutils#CleanDiffOptions()
+" boolean genutils#ArrayVarExists(String varName, int index)
+" void genutils#MapAppendCascaded(String lhs, String rhs, String mapMode)
+" void genutils#SaveWindowSettings()
+" void genutils#RestoreWindowSettings()
+" void genutils#ResetWindowSettings()
+" void genutils#SaveWindowSettings2(String id, boolean overwrite)
+" void genutils#RestoreWindowSettings2(String id)
+" void genutils#ResetWindowSettings2(String id)
+" void genutils#SaveVisualSelection(String id)
+" void genutils#RestoreVisualSelection(String id)
+" void genutils#SaveSoftPosition(String id)
+" void genutils#RestoreSoftPosition(String id)
+" void genutils#ResetSoftPosition(String id)
+" void genutils#SaveHardPosition(String id)
+" void genutils#RestoreHardPosition(String id)
+" void genutils#ResetHardPosition(String id)
+" int genutils#GetLinePosition(String id)
+" int genutils#GetColPosition(String id)
+" boolean genutils#IsPositionSet(String id)
+" String genutils#CleanupFileName(String fileName)
+" String genutils#CleanupFileName2(String fileName, String win32ProtectedChars)
+" boolean genutils#OnMS()
+" boolean genutils#PathIsAbsolute(String path)
+" boolean genutils#PathIsFileNameOnly(String path)
+" void genutils#AddNotifyWindowClose(String windowTitle, String functionName)
+" void genutils#RemoveNotifyWindowClose(String windowTitle)
+" void genutils#CheckWindowClose()
+" void genutils#ShowLinesWithSyntax() range
+" void genutils#ShiftWordInSpace(int direction)
+" void genutils#CenterWordInSpace()
+" int genutils#BinSearchList(List list, int start, int end, Object item,
+" [Funcref|String] cmp, int direction)
+" int genutils#BinSearchForInsert(int start, int end, String line,
+" String cmp, int direction)
+" int genutils#BinSearchForInsert2(int start, int end, line, String cmp,
+" int direction, String accessor, String context)
+" String genutils#CommonPath(String path1, String path2)
+" String genutils#CommonString(String str1, String str2)
+" String genutils#RelPathFromFile(String srcFile, String tgtFile)
+" String genutils#RelPathFromDir(String srcDir, String tgtFile)
+" String genutils#Roman2Decimal(String str)
+" String genutils#Escape(String str, String chars)
+" String genutils#UnEscape(String str, String chars)
+" String genutils#DeEscape(String str)
+" String genutils#CrUnProtectedCharsPattern(String chars)
+" String genutils#EscapeCommand(String cmd, List/String args, List/String pipe)
+" int genutils#GetShellEnvType()
+" String genutils#ExpandStr(String str)
+" String genutils#QuoteStr(String str)
+" boolean genutils#CurLineHasSign()
+" void genutils#ClearAllSigns()
+" String genutils#UserFileComplete(String ArgLead, String CmdLine,
+" String CursorPos, String smartSlash, String searchPath)
+" String genutils#UserFileExpand(String fileArgs)
+" String genutils#GetVimCmdOutput(String cmd)
+" void genutils#OptClearBuffer()
+" int genutils#GetPreviewWinnr()
+" void genutils#PutPersistentVar(String pluginName, String persistentVar,
+" String value)
+" void genutils#GetPersistentVar(String pluginName, String persistentVar,
+" String default)
+" void genutils#AddToFCShellPre(String funcName)
+" void genutils#RemoveFromFCShellPre(String funcName)
+" void genutils#DefFCShellInstall()
+" void genutils#DefFCShellUninstall()
+" boolean genutils#DefFileChangedShell()
+" void genutils#SilentSubstitute(String pat, String cmd)
+" void genutils#SilentDelete(String pat)
+" void genutils#SilentDelete(String range, String pat)
+" String genutils#GetSpacer(int width)
+" String genutils#PromptForElement(List array,
+" [String defaultValue | int defaultIndex], String msg,
+" String skip, boolean useDialog, int nCols)
+" int genutils#GetSelectedIndex()
+"
+" Documentation With Function Prototypes:
+" -----------------------
+" Useful function to debug passing arguments to functions. See exactly what
+" you would receive on the other side.
+" Ex: :exec 'call genutils#DebugShowArgs('. genutils#CreateArgString("a 'b' c", ' ') . ')'
+"
+" void genutils#DebugShowArgs(...)
+" -----------------------
+" This function returns the body of the specified function ( the name should be
+" complete, including any scriptid prefix in case of a script local
+" function), without the function header and tail. You can also pass in the
+" number of additional lines to be removed from the head and or tail of the
+" function.
+"
+" String genutils#ExtractFuncListing(String funcName, String hLines, String tLines)
+" -----------------------
+" -----------------------
+" Return the number of windows open currently.
+"
+" int genutils#NumberOfWindows()
+" -----------------------
+" Returns the buffer number of the given fileName if it is already loaded.
+" The fileName argument is treated literally, unlike the bufnr() which treats
+" the argument as a filename-pattern. The function first escape all the
+" |filename-pattern| characters before passing it to bufnr(). It should work
+" in most of the cases, except when backslashes are used in non-windows
+" platforms, when the result could be unpredictable.
+"
+" Note: The function removes protections for "#%" characters because, these
+" are special characters on Vim commandline, and so are usually escaped
+" themselves, but bufnr() wouldn't like them.
+"
+" int genutils#FindBufferForName(String fileName)
+" -----------------------
+" Returns the transformed buffer name that is suitable to be used in
+" autocommands.
+"
+" String genutils#GetBufNameForAu(String bufName)
+" -----------------------
+" Given the window number, moves the cursor to that window.
+"
+" void genutils#MoveCursorToWindow(int winno)
+" -----------------------
+" Moves the current line such that it is going to be the nth line in the window
+" without changing the column position.
+"
+" void genutils#MoveCurLineToWinLine(int winLine)
+" -----------------------
+" Closes the given window and returns to the original window. It the simplest,
+" this is equivalent to:
+"
+" let curWin = winnr()
+" exec winnr 'wincmd w'
+" close
+" exec curWin 'wincmd w'
+"
+" But the function keeps track of the change in window numbers and restores
+" the current window correctly. It also restores the previous window (the
+" window that the cursor would jump to when executing "wincmd p" command).
+" This is something that all plugins should do while moving around in the
+" windows, behind the scenes.
+"
+" Pass 1 to force closing the window (:close!).
+"
+" void genutils#CloseWindow(int winnr, boolean force)
+" -----------------------
+" Remembers the number of the current window as well as the previous-window
+" (the one the cursor would jump to when executing "wincmd p" command). To
+" determine the window number of the previous-window, the function temporarily
+" jumps to the previous-window, so if your script intends to avoid generating
+" unnecessary window events, consider disabling window events before calling
+" this function (see :h 'eventignore').
+"
+" void genutils#MarkActiveWindow()
+" -----------------------
+" Restore the cursor to the window that was previously marked as "active", as
+" well as its previous-window (the one the cursor would jump to when executing
+" "wincmd p" command). To restore the window number of the previous-window,
+" the function temporarily jumps to the previous-window, so if your script
+" intends to avoid generating unnecessary window events, consider disabling
+" window events before calling this function (see :h 'eventignore').
+"
+" void genutils#RestoreActiveWindow()
+" -----------------------
+" Returns 1 if the current window is the only window vertically.
+"
+" void genutils#IsOnlyVerticalWindow()
+" -----------------------
+" Returns 1 if the current window is the only window horizontally.
+"
+" void genutils#IsOnlyHorizontalWindow()
+" -----------------------
+" Returns the window number of the next window while remaining in the same
+" horizontal or vertical window stack (or 0 when there are no more). Pass
+" hjkl characters to indicate direction.
+" Usage:
+" let wn = genutils#GetNextWinnrInStack('h') left window number in stack.
+" let wn = genutils#GetNextWinnrInStack('l') right window number in stack.
+" let wn = genutils#GetNextWinnrInStack('j') upper window number in stack.
+" let wn = genutils#GetNextWinnrInStack('k') lower window number in stack.
+"
+" int genutils#GetNextWinnrInStack(char dir)
+" -----------------------
+" Returns the window number of the last window while remaining in the same
+" horizontal or vertical window stack (or 0 when there are no more, or it is
+" already the last window). Pass hjkl characters to indicate direction.
+" Usage:
+" let wn = genutils#GetLastWinnrInStack('h') leftmost window number in stack.
+" let wn = genutils#GetLastWinnrInStack('l') rightmost window number in stack.
+" let wn = genutils#GetLastWinnrInStack('j') top window number in stack.
+" let wn = genutils#GetLastWinnrInStack('k') bottom window number in stack.
+"
+" int genutils#GetLastWinnrInStack(char dir)
+" -----------------------
+" Move cursor to the next window in stack. See genutils#GetNextWinnrInStack()
+" for more information.
+"
+" void genutils#MoveCursorToNextInWinStack(char dir)
+" -----------------------
+" Move cursor to the last window in stack. See genutils#GetLastWinnrInStack()
+" for more information.
+"
+" void genutils#MoveCursorToLastInWinStack(char dir)
+" -----------------------
+" This function, which stands for "execute the given command that creates a
+" window, while disabling the 'equalalways' setting", is a means for plugins
+" to create new windows without disturbing the existing window dimensions as
+" much as possible. This function would not be required if 'equalalways' is
+" not set by the user. Even if set, the below code, though intuitive,
+" wouldn't work:
+" let _equalalways = &equalalways
+" set noequalalways
+" " open window now.
+" let &equalalways = _equalalways
+"
+" The problem is that while restoring the value of equalalways, if the user
+" originally had it set, Vim would immediately try to equalize all the
+" window dimensions, which is exactly what we tried to avoid by setting
+" 'noequalalways'. The function works around the problem by temporarily
+" setting 'winfixheight' in all the existing windows and restoring them
+" after done.
+" Usage:
+" call genutils#OpenWinNoEa('sb ' pluginBuf)
+"
+" Note: The function doesn't catch any exceptions that are generated by the
+" operations, so it is advisable to catch them by the caller itself.
+"
+" void genutils#OpenWinNoEa(String openWinCmd)
+" -----------------------
+" This is for the same purpose as described for genutils#OpenWinNoEa()
+" function, except that it is used to close a given window. This is just a
+" convenience function.
+"
+" void genutils#CloseWinNoEa(int winnr, boolean force)
+" -----------------------
+" Turn on some buffer settings that make it suitable to be a scratch buffer.
+"
+" void genutils#SetupScratchBuffer()
+" -----------------------
+" Turns off those options that are set by diff to the current window.
+" Also removes the 'hor' option from scrollopt (which is a global option).
+" Better alternative would be to close the window and reopen the buffer in a
+" new window.
+"
+" void genutils#CleanDiffOptions()
+" -----------------------
+" This function is an alternative to exists() function, for those odd array
+" index names for which the built-in function fails. The var should be
+" accessible to this functions, so it shouldn't be a local or script local
+" variable.
+" if genutils#ArrayVarExists("array", id)
+" let val = array{id}
+" endif
+"
+" boolean genutils#ArrayVarExists(String varName, int index)
+" -----------------------
+" If lhs is already mapped, this function makes sure rhs is appended to it
+" instead of overwriting it. If you are rhs has any script local functions,
+" make sure you use the <SNR>\d\+_ prefix instead of the <SID> prefix (or the
+" <SID> will be replaced by the SNR number of genutils script, instead of
+" yours).
+" mapMode is used to prefix to "oremap" and used as the map command. E.g., if
+" mapMode is 'n', then the function call results in the execution of noremap
+" command.
+"
+" void genutils#MapAppendCascaded(String lhs, String rhs, String mapMode)
+" -----------------------
+" -----------------------
+" Saves the heights and widths of the currently open windows for restoring
+" later.
+"
+" void genutils#SaveWindowSettings()
+" -----------------------
+" Restores the heights of the windows from the information that is saved by
+" genutils#SaveWindowSettings(). Works only when the number of windows
+" haven't changed since the genutils#SaveWindowSettings is called.
+"
+" void genutils#RestoreWindowSettings()
+" -----------------------
+" Reset the previously saved window settings using genutils#SaveWindowSettings.
+"
+" void genutils#ResetWindowSettings()
+" -----------------------
+" Same as genutils#SaveWindowSettings, but uses the passed in id to create a
+" private copy for the calling script. Pass in a unique id to avoid
+" conflicting with other callers. If overwrite is zero and if the settings
+" are already stored for the passed in id, it will overwrite previously
+" saved settings.
+"
+" void genutils#SaveWindowSettings2(String id, boolean overwrite)
+" -----------------------
+" Same as genutils#RestoreWindowSettings, but uses the passed in id to get the
+" settings. The settings must have been previously saved using this
+" id. Call genutils#ResetWindowSettings2() to explicitly reset the saved
+" settings.
+"
+" void genutils#RestoreWindowSettings2(String id)
+" -----------------------
+" Reset the previously saved window settings using genutils#SaveWindowSettings2.
+" Releases the variables.
+"
+" void genutils#ResetWindowSettings2(String id)
+" -----------------------
+" -----------------------
+" Save the current/last visual selection such that it can be later restored
+" using genutils#RestoreVisualSelection(). Pass a unique id such that it will
+" not interfere with the other callers to this function. Saved selections
+" are not associated with the window so you can later restore the selection
+" in any window, provided there are enough lines/columns.
+"
+" void genutils#SaveVisualSelection(String id)
+" -----------------------
+" Restore the visual selection that was previuosly saved using
+" genutils#SaveVisualSelection().
+"
+" void genutils#RestoreVisualSelection(String id)
+" -----------------------
+" -----------------------
+" This method tries to save the hard position along with the line context This
+" is like the vim builtin marker. Pass in a unique id to avoid
+" conflicting with other callers.
+"
+" void genutils#SaveSoftPosition(String id)
+" -----------------------
+" Restore the cursor position using the information saved by the previous call
+" to genutils#SaveSoftPosition. This first calls
+" genutils#RestoreHardPosition() and then searches for the original line
+" first in the forward direction and then in the backward and positions the
+" cursor on the line if found. If the original line is not found it still
+" behaves like a call to genutils#RestoreHardPosition. This is similar to
+" the functionality of the built-in marker, as Vim is capable of maintaining
+" the marker even when the line is moved up or down. However, if there are
+" identical lines in the buffer and the original line has moved, this
+" function might get confused.
+"
+" void genutils#RestoreSoftPosition(String id)
+" -----------------------
+" Reset the previously cursor position using genutils#SaveSoftPosition.
+" Releases the variables.
+"
+" void genutils#ResetSoftPosition(String id)
+" -----------------------
+" Useful when you want to go to the exact (line, col), but marking will not
+" work, or if you simply don't want to disturb the marks. Pass in a unique
+" id.
+"
+" void genutils#SaveHardPosition(String id)
+" -----------------------
+" Restore the cursor position using the information saved by the previous call
+" to genutils#SaveHardPosition.
+"
+" void genutils#RestoreHardPosition(String id)
+" -----------------------
+" Reset the previously cursor position using genutils#SaveHardPosition.
+" Releases the variables.
+"
+" void genutils#ResetHardPosition(String id)
+" -----------------------
+" Return the line number of the previously saved position for the id.
+" This is like calling line() builtin function for a mark.
+"
+" int genutils#GetLinePosition(String id)
+" -----------------------
+" Return the column number of the previously saved position for the id.
+" This is like calling col() builtin function for a mark.
+"
+" int genutils#GetColPosition(String id)
+" -----------------------
+" A convenience function to check if a position has been saved (and not reset)
+" using the id given.
+"
+" boolean genutils#IsPositionSet(String id)
+" -----------------------
+" -----------------------
+" Cleanup file name such that two *cleaned up* file names are easy to be
+" compared. This probably works only on windows and unix platforms. Also
+" recognizes UNC paths. Always returns paths with forward slashes only,
+" irrespective of what your 'shellslash' setting is. The return path will
+" always be a valid path for use in Vim, provided the original path itself
+" was valid for the platform (a valid cygwin path after the cleanup will
+" still be valid in a cygwin vim). The CleanupFileName2() variant is meant
+" for win32, to avoid translating some backslash protections to be treated
+" as regular path separators. Pass the characters that are protected, and
+" the backslashes infront of them are preserved.
+"
+" String genutils#CleanupFileName(String fileName)
+" String genutils#CleanupFileName2(String fileName, String win32ProtectedChars)
+" -----------------------
+" Returns true if the current OS is any of the Microsoft OSes. Most useful to
+" know if the path separator is "\".
+"
+" boolean genutils#OnMS()
+" -----------------------
+" Returns true if the given path could be an absolute path. Probably works
+" only on Unix and Windows platforms.
+"
+" boolean genutils#PathIsAbsolute(String path)
+" -----------------------
+" Returns true if the given path doesn't have any directory components.
+" Probably works only on Unix and Windows platforms.
+"
+" boolean genutils#PathIsFileNameOnly(String path)
+" -----------------------
+" -----------------------
+" Add a notification to know when a buffer with the given name (referred to as
+" windowTitle) is no longer visible in any window. This by functionality is
+" like a BufWinLeavePost event. The function functionName is called back
+" with the title (buffer name) as an argument. The notification gets removed
+" after excuting it, so for future notifications, you need to reregister
+" your function. You can only have one notification for any buffer. The
+" function should be accessible from the script's local context.
+"
+" void genutils#AddNotifyWindowClose(String windowTitle, String functionName)
+" -----------------------
+" Remove the notification previously added using genutils#AddNotifyWindowClose
+" function.
+"
+" void genutils#RemoveNotifyWindowClose(String windowTitle)
+" -----------------------
+" Normally the plugin checks for closed windows for every WinEnter event, but
+" you can force a check at anytime by calling this function.
+"
+" void genutils#CheckWindowClose()
+" -----------------------
+" -----------------------
+" Displays the given line(s) from the current file in the command area (i.e.,
+" echo), using that line's syntax highlighting (i.e., WYSIWYG). If no line
+" number is given, display the current line.
+" Originally,
+" From: Gary Holloway "gary at castandcrew dot com"
+" Date: Wed, 16 Jan 2002 14:31:56 -0800
+"
+" void genutils#ShowLinesWithSyntax() range
+" -----------------------
+" This function shifts the current word in the space without changing the
+" column position of the next word. Doesn't work for tabs.
+"
+" void genutils#ShiftWordInSpace(int direction)
+" -----------------------
+" This function centers the current word in the space without changing the
+" column position of the next word. Doesn't work for tabs.
+"
+" void genutils#CenterWordInSpace()
+" -----------------------
+" -----------------------
+" Find common path component of two filenames.
+" Based on the thread, "computing relative path".
+" Date: Mon, 29 Jul 2002 21:30:56 +0200 (CEST)
+" The last two arguments are optional and default to 0 (false), but you can
+" pass a value of 1 (true) to indicate that the path represents a directory.
+" Ex:
+" genutils#CommonPath('/a/b/c/d.e', '/a/b/f/g/h.i') => '/a/b/'
+" genutils#CommonPath('/a/b/c/d.e', '/a/b/') => '/a/b'
+" genutils#CommonPath('/a/b/c/d.e', '/a/b/', 0, 1) => '/a/b/'
+"
+" String genutils#CommonPath(String path1, String path2 [, boolean path1IsDir, boolean path2IsDir])
+" -----------------------
+" Find common string component of two strings.
+" Based on the tread, "computing relative path".
+" Date: Mon, 29 Jul 2002 21:30:56 +0200 (CEST)
+" Ex:
+" genutils#CommonString('abcde', 'abfghi') => 'ab'
+"
+" String genutils#CommonString(String str1, String str2)
+" -----------------------
+" Find the relative path of tgtFile from the directory of srcFile.
+" Based on the tread, "computing relative path".
+" Date: Mon, 29 Jul 2002 21:30:56 +0200 (CEST)
+" Ex:
+" genutils#RelPathFromFile('/a/b/c/d.html', '/a/b/e/f.html') => '../f/g.html'
+"
+" String genutils#RelPathFromFile(String srcFile, String tgtFile)
+" -----------------------
+" Find the relative path of tgtFile from the srcDir.
+" Based on the tread, "computing relative path".
+" Date: Mon, 29 Jul 2002 21:30:56 +0200 (CEST)
+" Ex:
+" genutils#RelPathFromDir('/a/b/c/d', '/a/b/e/f/g.html') => '../../e/f/g.html'
+"
+" String genutils#RelPathFromDir(String srcDir, String tgtFile)
+" -----------------------
+" -----------------------
+" Convert Roman numerals to decimal. Doesn't detect format errors.
+" Originally,
+" From: "Preben Peppe Guldberg" <
[email protected]>
+" Date: Fri, 10 May 2002 14:28:19 +0200
+"
+" String genutils#Roman2Decimal(String str)
+" -----------------------
+" -----------------------
+" Works like the built-in escape(), except that it escapes the specified
+" characters only if they are not already escaped, so something like
+" genutils#Escape('a\bc\\bd', 'b') would give 'a\bc\\\bd'. The chars value
+" directly goes into the [] collection, so it can be anything that is
+" accepted in [].
+"
+" String genutils#Escape(String str, String chars)
+" -----------------------
+" Works like the reverse of the builtin escape() function, but un-escapes the
+" specified characters only if they are already escaped (essentially the
+" opposite of genutils#Escape()). The chars value directly goes into the []
+" collection, so it can be anything that is acceptable to [].
+"
+" String genutils#UnEscape(String str, String chars)
+" -----------------------
+" Works like the reverse of the built-in escape() function. De-escapes all the
+" escaped characters. Essentially removes one level of escaping from the
+" string, so something like: 'a\b\\\\c\\d' would become 'ab\\c\d'.
+"
+" String genutils#DeEscape(String str)
+" -----------------------
+" This function creates a pattern that avoids the given protected characters'
+" from getting treated as separators, when used with split(). The argument
+" goes directly into the [] atom, so make sure you pass in a valid string.
+" When optional argument capture is true, the characters are placed in a
+" capturing group.
+" Ex:
+" let paths = split(&path, genutils#CrUnProtectedCharsPattern(','))
+"
+" String genutils#CrUnProtectedCharsPattern(String chars, [boolean capture = false])
+" -----------------------
+" genutils#Escape the passed in shell command with quotes and backslashes such
+" a way that the arguments reach the command literally (avoids shell
+" interpretations). See the function header for the kind of escapings that
+" are done. The first argument is the actual command name, the second
+" argument is the arguments to the command and third argument is any pipe
+" command that should be appended to the command. The reason the function
+" requires them to be passed separately is that the escaping is minimized
+" for the first and third arguments. It is preferable to pass args as a Vim7
+" List, but it can be passed as a single string with spaces separating the
+" arguments (spaces in side each argument then needs to be protected)
+" Usage:
+" let fullCmd = genutils#EscapeCommand('ls', ['-u', expand('%:h')], ['|', 'grep', 'xxx'])
+" Note:
+" If the escaped command is used on Vim command-line (such as with ":w !",
+" ":r !" and ":!"), you need to further protect '%', '#' and '!' chars,
+" even if they are in quotes, to avoid getting expanded by Vim before
+" invoking external cmd. However this is not required for using it with
+" system() function. The easiest way to escape them is by using the
+" genutils#Escape() function as in "Escape(fullCmd, '%#!')".
+" String genutils#EscapeCommand(String cmd, List/String args, List/String pipe)
+" -----------------------
+" Returns the global ST_* constants (g:ST_WIN_CMD, g:ST_WIN_SH, g:ST_UNIX)
+" based on the values of shell related settings and the OS on which Vim is
+" running.
+"
+" int genutils#GetShellEnvType()
+" -----------------------
+"
+" Expands the string for the special characters. The return value should
+" essentially be what you would see if it was a string constant with
+" double-quotes.
+" Ex:
+" genutils#ExpandStr('a\tA') => 'a A'
+" String genutils#ExpandStr(String str)
+" -----------------------
+" Quotes the passed in string such that it can be used as a string expression
+" in :execute. It sorrounds the passed in string with single-quotes while
+" escaping any existing single-quotes in the string.
+"
+" String genutils#QuoteStr(String str)
+" -----------------------
+" -----------------------
+" Returns true if the current line has a sign placed.
+"
+" boolean genutils#CurLineHasSign()
+" -----------------------
+" Clears all signs in the current buffer.
+"
+" void genutils#ClearAllSigns()
+" -----------------------
+" -----------------------
+" This function is suitable to be used by custom command completion functions
+" for expanding filenames conditionally. The function could based on the
+" context, decide whether to do a file completion or a different custom
+" completion. See breakpts.vim and perforce.vim for examples.
+" If you pass non-zero value to smartSlash, the function decides to use
+" backslash or forwardslash as the path separator based on the user settings
+" and the ArgLead, but if you always want to use only forwardslash as the
+" path separator, then pass 0. If you pass in a comma separated list of
+" directories as searchPath, then the file expansion is limited to the files
+" under these directories. This means, you can implement your own commands
+" that don't expect the user to type in the full path name to the file
+" (e.g., if the user types in the command while in the explorer window, you
+" could assume that the path is relative to the directory being viewed). Most
+" useful with a single directory, but also useful in combination with vim
+" 'runtimepath' in loading scripts etc. (see Runtime command in
+" breakpts.vim).
+"
+" String genutils#UserFileComplete(String ArgLead, String CmdLine, String
+" CursorPos, String smartSlash, String searchPath)
+" -----------------------
+" This is a convenience function to expand filename meta-sequences in the
+" given arguments just as Vim would have if given to a user-defined command
+" as arguments with completion mode set to "file". Useful
+" if you set the completion mode of your command to anything
+" other than the "file", and later conditionally expand arguments (for
+" characters such as % and # and other sequences such as #10 and <cword>)
+" after deciding which arguments represent filenames/patterns.
+"
+" String genutils#UserFileExpand(String fileArgs)
+" -----------------------
+" This returns the output of the vim command as a string, without corrupting
+" any registers. Returns empty string on errors. Check for v:errmsg after
+" calling this function for any error messages.
+"
+" String genutils#GetVimCmdOutput(String cmd)
+" -----------------------
+" Clear the contents of the current buffer in an optimum manner. For plugins
+" that keep redrawing the contents of its buffer, executing "1,$d" or its
+" equivalents result in overloading Vim's undo mechanism. Using this function
+" avoids that problem.
+"
+" void genutils#OptClearBuffer()
+" -----------------------
+" Returns the window number of the preview window if open or -1 if not.
+" int genutils#GetPreviewWinnr()
+" -----------------------
+" -----------------------
+" These functions provide a persistent storage mechanism.
+"
+" Example: Put the following in a file called t.vim in your plugin
+" directory and watch the magic. You can set new value using SetVar() and
+" see that it returns the same value across session when GetVar() is
+" called.
+" >>>>t.vim<<<<
+" au VimEnter * call LoadSettings()
+" au VimLeavePre * call SaveSettings()
+"
+" function! LoadSettings()
+" let s:tVar = genutils#GetPersistentVar("T", "tVar", "defVal")
+" endfunction
+"
+" function! SaveSettings()
+" call genutils#PutPersistentVar("T", "tVar", s:tVar)
+" endfunction
+"
+" function! SetVar(val)
+" let s:tVar = a:val
+" endfunction
+"
+" function! GetVar()
+" return s:tVar
+" endfunction
+" <<<<t.vim>>>>
+"
+" The pluginName and persistentVar have to be unique and are case insensitive.
+" Ideally called from your VimLeavePre autocommand handler of your plugin.
+" This simply creates a global variable which will be persisted by Vim
+" through viminfo. The variable can be read back in the next session by the
+" plugin using genutils#GetPersistentVar() function, ideally from your
+" VimEnter autocommand handler. The pluginName is to provide a name space
+" for different plugins, and avoid conflicts in using the same persistentVar
+" name.
+" This feature uses the '!' option of viminfo, to avoid storing all the
+" temporary and other plugin specific global variables getting saved.
+"
+" void genutils#PutPersistentVar(String pluginName, String persistentVar,
+" String value)
+" -----------------------
+" Ideally called from VimEnter, this simply reads the value of the global
+" variable for the persistentVar that is saved in the viminfo in a previous
+" session using genutils#PutPersistentVar() and returns it (and default if
+" the variable is not found). It removes the variable from global space
+" before returning the value, so can be called only once. It also means that
+" genutils#PutPersistentVar should be called again in the next VimLeavePre
+" if the variable continues to be persisted.
+"
+" void genutils#GetPersistentVar(String pluginName, String persistentVar,
+" String default)
+" -----------------------
+" -----------------------
+" These functions channel the FileChangedShell autocommand and extend it to
+" create an additional fictitious FileChangedShellPre and FileChangedShellPost
+" events.
+"
+" Add the given noarg function to the list of functions that need to be
+" notified before processing the FileChangedShell event. The function when
+" called can expand "<abuf>" or "<afile>" to get the details of the buffer
+" for which this autocommand got executed. It should return 0 to mean
+" noautoread and 1 to mean autoread the current buffer. It can also return
+" -1 to make its return value ignored and use default autoread mechanism
+" (which could still be overridden by the return value of other functions).
+" The return value of all the functions is ORed to determine the effective
+" autoread value.
+"
+" void genutils#AddToFCShellPre(String funcName)
+" -----------------------
+" Remove the given function previously added by calling
+" genutils#AddToFCShellPre.
+"
+" void genutils#RemoveFromFCShellPre(String funcName)
+" -----------------------
+" Same as genutils#AddToFCShellPre except that the function is called after
+" the event is processed, so this is like a fictitious FileChangedShellPost
+" event.
+"
+" void genutils#DefFCShellInstall()
+" -----------------------
+" Uninstall the default autocommand handler that was previously installed
+" using genutils#DefFCShellInstall. Calling this function may not actually
+" result in removing the handler, in case there are other callers still
+" dependent on it (which is kept track of by the number of times
+" genutils#DefFCShellInstall has been called).
+"
+" void genutils#DefFCShellUninstall()
+" -----------------------
+" This function emulates the Vim's default behavior when a |timestamp| change
+" is detected. Register your functions by calling genutils#AddToFCShellPre
+" and have this function called during the FileChangedShell event (or just
+" install the default handler by calling genutils#DefFCShellInstall). From
+" your callbacks, return 1 to mean autoread, 0 to mean noautoread and -1 to
+" mean system default (or ignore). The return value of this method is 1 if
+" the file was reloaded and 0 otherwise. The return value of all the
+" functions is ORed to determine the effective autoread value. See my
+" perforce plugin for usage example.
+"
+" boolean genutils#DefFileChangedShell()
+" -----------------------
+" Execute a substitute command silently and without corrupting the search
+" register. It also preserves the cursor position.
+" Ex:
+" To insert a tab infrontof all lines:
+" call genutils#SilentSubstitute('^', '%s//\t/e')
+" To remote all carriage returns at the line ending:
+" call genutils#SilentSubstitute("\<CR>$", '%s///e')
+"
+" void genutils#SilentSubstitute(String pat, String cmd)
+" -----------------------
+" Delete all lines matching the given pattern silently and without corrupting
+" the search register. The range argument if passed should be a valid prefix
+" for the :global command. It also preserves the cursor position.
+" Ex:
+" To delete all lines that are empty:
+" call genutils#SilentDelete('^\s*$')
+" To delete all lines that are empty only in the range 10 to 100:
+" call genutils#SilentDelete('10,100', '^\s*$')
+"
+" void genutils#SilentDelete(String pat)
+" void genutils#SilentDelete(String range, String pat)
+" -----------------------
+" Can return a spacer from 0 to 80 characters width.
+"
+" String genutils#GetSpacer(int width)
+" -----------------------
+" Function to prompt user for an element out of the passed in array. The
+" user will be prompted with a list of choices to make. The elements will be
+" formatted in to the given number of columns. Each element will be given a
+" number that the user can enter to indicate the selection. This is very
+" much like the inputlist() method, but better for a large number of options
+" formatted into multiple columns (instead of one per row). However, if the
+" formatted options run for multiple pages, no special handling is done.
+" Params:
+" default - The default value for the selection. Default can be the
+" element-index or the element itself. If number (type() returns
+" 0), it is treated as an index.
+" msg - The message that should appear in the prompt (passed to input()).
+" skip - The element that needs to be skipped from selection (pass a
+" non-existent element to disable this, such as an empty value '').
+" useDialog - if true, uses dialogs for prompts, instead of the command-line(
+" inputdialog() instead of input()). But personally, I don't
+" like this because the power user then can't use the
+" expression register.
+" nCols - Number of columns to use for formatting the options. Using "1"
+" will make the output look very like that of inputlist()
+" Returns:
+" the selected element or empty string, "" if nothing is selected. Call
+" genutils#GetSelectedIndex() for the index entered by the user.
+"
+" Ex:
+" echo genutils#PromptForElement(map(range(0,25),
+" \ "nr2char(char2nr('a')+v:val)") , 'd', 'Enter: ', 'x', 1, 5)
+" String genutils#PromptForElement(List array,
+" [String defaultValue | int defaultIndex], String msg,
+" String skip, boolean useDialog, int nCols)
+"
+" Returns the index of the element selected by the user in the previous
+" genutils#PromptForElement call. Returns -1 when the user didn't select
+" any element (aborted the selection). This function is useful if there are
+" empty or duplicate elements in the selection.
+" int genutils#GetSelectedIndex()
+" -----------------------
+" Deprecations:
+" - CleanDiffOptions() is deprecated as Vim now has the :diffoff command.
+" - MakeArgumentString, MakeArgumentList and CreateArgString are deprecated.
+" Vim7 now includes call() function to receive and pass argument lists
+" around.
+" - The g:makeArgumentString and g:makeArgumentList are obsolete and are
+" deprecated, please use MakeArgumentString() and MakeArgumentList()
+" instead.
+" - FindWindowForBuffer() function is now deprecated, as the corresponding
+" Vim bugs are fixed. Use the below expr instead:
+" bufwinnr(genutils#FindBufferForName(fileName))
+" - QSort(), QSort2(), BinInsertSort() and BinInsertSort2() functions are
+" now deprecated in favor of sort() function.
+"
+"
+" Sample Usages Or Tips:
+" - Add the following commands to create simple sort commands.
+" command! -nargs=0 -range=% SortByLength <line1>,<line2>call
+" \ genutils#QSort('genutils#CmpByLineLengthNname', 1)
+" command! -nargs=0 -range=% RSortByLength <line1>,<line2>call
+" \ genutils#QSort('genutils#CmpByLineLengthNname', -1)
+" command! -nargs=0 -range=% SortJavaImports <line1>,<line2>call
+" \ genutils#QSort('genutils#CmpJavaImports', 1)
+"
+" - You might like the following mappings to adjust spacing:
+" nnoremap <silent> <C-Space> :call genutils#ShiftWordInSpace(1)<CR>
+" nnoremap <silent> <C-BS> :call genutils#ShiftWordInSpace(-1)<CR>
+" nnoremap <silent> \cw :call genutils#CenterWordInSpace()<CR>
+" nnoremap <silent> \va :call
+" \ genutils#AlignWordWithWordInPreviousLine()<CR>
+"
+" - The :find command is very useful to search for a file in path, but it
+" doesn't support file completion. Add the following command in your vimrc
+" to add this functionality:
+" command! -nargs=1 -bang -complete=custom,<SID>PathComplete FindInPath
+" \ :find<bang> <args>
+" function! s:PathComplete(ArgLead, CmdLine, CursorPos)
+" return genutils#UserFileComplete(a:ArgLead, a:CmdLine, a:CursorPos, 1,
+" \ &path)
+" endfunction
+"
+" - If you are running commands that generate multiple pages of output, you
+" might find it useful to redirect the output to a new buffer. Put the
+" following command in your vimrc:
+" command! -nargs=* -complete=command Redir
+" \ :new | put! =genutils#GetVimCmdOutput('<args>') |
+" \ setl bufhidden=wipe | setl nomodified
+"
+" Changes in 2.4:
+" - Fixed some corner cases in RelPathFromDir()/RelPathFromFile().
+" - Made the default comparators sort() function friendly.
+" Changes in 2.3:
+" - SilentSubstitute() and SilentDelete() should preserve cursor position.
+" - CleanupFileName() should also remove any leading or trailing whitespace.
+" Changes in 2.2:
+" - EscapeCommand() now supports Lists as arguments.
+" - CrUnProtectedCharsPattern() now accepts an optional "capture" argument.
+" - Renamed PromptForElement2 to PromptForElement. It was a typo.
+" Changes in 2.1:
+" - Fixed a typo in AddNotifyWindowClose() in the previous release.
+" - Added BinSearchList() function.
+" Changes in 2.0:
+" - Converted to Vim7 autoload script. Since there is no common prefix to
+" find all the usages of genutils functions in your script, Use the
+" pattern \<\(:\|>\|#\)\@<!\zs\u\w\+( to find all the global functions and
+" prefix the ones from genutils with genutils#.
+" - The new version is not backwards compatible with prior versions. If you
+" have plugins that depend on the older versions of genutils, you should try
+" to request the author to port their plugin to use the new genutils. If
+" having them to coexist is a must, then use the below trick:
+" - Install the latest version of genutils first. Overwriting all existing
+" files.
+" - Open the plugin/genutils.vim file and note the value set to
+" loaded_genutils variable.
+" - Install the older version of genutils (non autoload version) in to
+" plugin directory, overwriting the existing file.
+" - Open the plugin/genutils.vim again and change the value of
+" loaded_genutils variable to the value you noted before and save it.
+" - Fix for Save/RestoreHardPosition() not working right when there are
+" wrapped lines in the window.
+" - Dropped the AddToFCShell and RemoveFromFCShell functions as these can't be
+" implemented in Vim7 because of new restrictions on FileChangedShell
+" autocommand. Use AddToFcShellPre and RemoveFromFCShellPre functions
+" instead.
+" - No longer depends on multvals plugin. Inherits some useful functions from
+" multvals to make way for it to be retired. New functions are:
+" genutils#CrUnProtectedCharsPattern
+" PromptForElement/GetSelectedIndex
+
+if exists('loaded_genutils')
+ finish
+endif
+if v:version < 700
+ echomsg 'genutils: You need at least Vim 7.0'
+ finish
+endif
+
+let loaded_genutils = 204
--- /dev/null
+" lookupfile.vim: Lookup filenames by pattern
+" Author: Hari Krishna Dara (hari.vim at gmail dot com)
+" Last Change: 14-Jun-2007 @ 18:30
+" Created: 11-May-2006
+" Requires: Vim-7.1, genutils.vim(2.3)
+" Version: 1.8.0
+" Licence: This program is free software; you can redistribute it and/or
+" modify it under the terms of the GNU General Public License.
+" See http://www.gnu.org/copyleft/gpl.txt
+" Download From:
+" http://www.vim.org//script.php?script_id=1581
+" Usage:
+" See :help lookupfile.txt
+
+if exists('loaded_lookupfile')
+ finish
+endif
+if v:version < 701
+ echomsg 'lookupfile: You need at least Vim 7.1'
+ finish
+endif
+if !exists('loaded_genutils')
+ runtime plugin/genutils.vim
+endif
+if !exists('loaded_genutils') || loaded_genutils < 203
+ echomsg 'lookupfile: You need a newer version of genutils.vim plugin'
+ finish
+endif
+
+let g:loaded_lookupfile = 108
+
+" Make sure line-continuations won't cause any problem. This will be restored
+" at the end
+let s:save_cpo = &cpo
+set cpo&vim
+
+if !exists('g:LookupFile_TagExpr')
+ let g:LookupFile_TagExpr = '&tags'
+endif
+
+if !exists('g:LookupFile_LookupFunc')
+ let g:LookupFile_LookupFunc = ''
+endif
+
+if !exists('g:LookupFile_LookupNotifyFunc')
+ let g:LookupFile_LookupNotifyFunc = ''
+endif
+
+if !exists('g:LookupFile_LookupAcceptFunc')
+ let g:LookupFile_LookupAcceptFunc = ''
+endif
+
+if !exists('g:LookupFile_MinPatLength')
+ let g:LookupFile_MinPatLength = 4
+endif
+
+if !exists('g:LookupFile_PreservePatternHistory')
+ let g:LookupFile_PreservePatternHistory = 1
+endif
+
+if !exists('g:LookupFile_PreserveLastPattern')
+ let g:LookupFile_PreserveLastPattern = 1
+endif
+
+if !exists('g:LookupFile_ShowFiller')
+ let g:LookupFile_ShowFiller = 1
+endif
+
+if !exists('g:LookupFile_AlwaysAcceptFirst')
+ let g:LookupFile_AlwaysAcceptFirst = 0
+endif
+
+if !exists('g:LookupFile_FileFilter')
+ let g:LookupFile_FileFilter = ''
+endif
+
+if !exists('g:LookupFile_AllowNewFiles')
+ let g:LookupFile_AllowNewFiles = 1
+endif
+
+if !exists('g:LookupFile_SortMethod')
+ let g:LookupFile_SortMethod = 'alpha'
+endif
+
+if !exists('g:LookupFile_Bufs_BufListExpr')
+ let g:LookupFile_Bufs_BufListExpr = ''
+endif
+
+if !exists('g:LookupFile_Bufs_SkipUnlisted')
+ let g:LookupFile_Bufs_SkipUnlisted = 1
+endif
+
+if !exists('g:LookupFile_Bufs_LikeBufCmd')
+ let g:LookupFile_Bufs_LikeBufCmd = 1
+endif
+
+if !exists('g:LookupFile_UsingSpecializedTags')
+ let g:LookupFile_UsingSpecializedTags = 0
+endif
+
+if !exists('g:LookupFile_DefaultCmd')
+ let g:LookupFile_DefaultCmd = ':LUTags'
+endif
+
+if !exists('g:LookupFile_EnableRemapCmd')
+ let g:LookupFile_EnableRemapCmd = 1
+endif
+
+if !exists('g:LookupFile_DisableDefaultMap')
+ let g:LookupFile_DisableDefaultMap = 0
+endif
+
+if !exists('g:LookupFile_UpdateTime')
+ let g:LookupFile_UpdateTime = 300
+endif
+
+if !exists('g:LookupFile_OnCursorMovedI')
+ let g:LookupFile_OnCursorMovedI = 0
+endif
+
+if !exists('g:LookupFile_EscCancelsPopup')
+ let g:LookupFile_EscCancelsPopup = 1
+endif
+
+if !exists('g:LookupFile_SearchForBufsInTabs')
+ let g:LookupFile_SearchForBufsInTabs = 1
+endif
+
+if !exists('g:LookupFile_TagsExpandCamelCase')
+ let g:LookupFile_TagsExpandCamelCase = 1
+endif
+
+if !exists('g:LookupFile_RecentFileListSize')
+ let g:LookupFile_RecentFileListSize = 20
+endif
+
+if (! exists("no_plugin_maps") || ! no_plugin_maps) &&
+ \ (! exists("no_lookupfile_maps") || ! no_lookupfile_maps)
+ noremap <script> <silent> <Plug>LookupFile :LookupFile<CR>
+
+ if ! g:LookupFile_DisableDefaultMap
+ if !hasmapto('<Plug>LookupFile', 'n')
+ nmap <unique> <silent> <F5> <Plug>LookupFile
+ endif
+ if !hasmapto('<Plug>LookupFile', 'i')
+ inoremap <Plug>LookupFileCE <C-E>
+ imap <unique> <expr> <silent> <F5> (pumvisible() ? "\<Plug>LookupFileCE" :
+ \ "")."\<Esc>\<Plug>LookupFile"
+ endif
+ endif
+endif
+
+command! -nargs=? -bang -complete=file LookupFile :call
+ \ <SID>LookupUsing('lookupfile', "<bang>", <q-args>, 0)
+
+command! -nargs=? -bang -complete=tag LUTags :call
+ \ <SID>LookupUsing('Tags', "<bang>", <q-args>, 0)
+command! -nargs=? -bang -complete=file LUPath :call
+ \ <SID>LookupUsing('Path', "<bang>", <q-args>, g:LookupFile_MinPatLength)
+command! -nargs=? -bang -complete=file LUArgs :call
+ \ <SID>LookupUsing('Args', "<bang>", <q-args>, 0)
+command! -nargs=? -bang -complete=file LUBufs :call
+ \ <SID>LookupUsing('Bufs', "<bang>", <q-args>, 0)
+command! -nargs=? -bang -complete=dir LUWalk :call
+ \ <SID>LookupUsing('Walk', "<bang>", <q-args>, 0)
+
+function! s:RemapLookupFile(cmd)
+ let cmd = (a:cmd != '') ? a:cmd : ':LUTags'
+ " It is not straight-forward to determine the right completion method.
+ exec 'command! -nargs=? -bang -complete=file LookupFile' cmd
+endfunction
+call s:RemapLookupFile(g:LookupFile_DefaultCmd)
+
+let s:mySNR = ''
+function! s:SNR()
+ if s:mySNR == ''
+ let s:mySNR = matchstr(expand('<sfile>'), '<SNR>\d\+_\zeSNR$')
+ endif
+ return s:mySNR
+endfun
+
+let s:baseBufNr = 0
+function! s:LookupUsing(ftr, bang, initPat, minPatLen)
+ let cmd = ':LUTags'
+ if a:ftr != 'Tags'
+ call s:SaveSett('LookupFunc')
+ call s:SaveSett('LookupNotifyFunc')
+ call s:SaveSett('MinPatLength')
+ unlet! g:LookupFile_LookupFunc g:LookupFile_LookupNotifyFunc
+ let g:LookupFile_LookupFunc = function(s:SNR().'Lookup'.a:ftr)
+ let g:LookupFile_LookupNotifyFunc = function(s:SNR().'LookupReset')
+ let g:LookupFile_MinPatLength = a:minPatLen
+ let s:baseBufNr = bufnr('%')
+ let cmd = ':LU'.a:ftr
+ endif
+ if g:LookupFile_EnableRemapCmd
+ call s:RemapLookupFile(cmd)
+ endif
+ call lookupfile#OpenWindow(a:bang, a:initPat)
+
+ if exists('*s:Config'.a:ftr)
+ call s:Config{a:ftr}()
+ endif
+
+ aug LookupReset
+ au!
+ au BufHidden <buffer> call <SID>LookupReset()
+ aug END
+endfunction
+
+function! s:LookupReset()
+ if exists('s:saved')
+ for sett in keys(s:saved)
+ unlet! g:LookupFile_{sett}
+ let g:LookupFile_{sett} = s:saved[sett]
+ endfor
+ unlet s:saved
+ endif
+ if exists('s:cleanup')
+ for cmd in s:cleanup
+ try
+ exec cmd
+ catch
+ echoerr v:exception . ', while executing cleanup command: ' . cmd
+ endtry
+ endfor
+ unlet s:cleanup
+ endif
+ aug ConfigIdo
+ au!
+ aug END
+endfunction
+
+function! s:SaveSett(sett)
+ if !exists('s:saved')
+ let s:saved = {}
+ endif
+ " Avoid overwriting the original value.
+ if !has_key(s:saved, a:sett)
+ let s:saved[a:sett] = g:LookupFile_{a:sett}
+ endif
+endfunction
+
+function! s:AddCleanup(cmd)
+ if !exists('s:cleanup')
+ let s:cleanup = []
+ endif
+ if index(s:cleanup, a:cmd) == -1
+ call add(s:cleanup, a:cmd)
+ endif
+endfunction
+
+function! s:LookupPath(pattern)
+ let filePat = a:pattern
+ let matchingExactCase = s:MatchingExactCase(filePat)
+ " Remove leading or trailing '*'s as we add a star anyway. This also removes
+ " '**' unless it is followed by a slash.
+ let filePat = substitute(filePat, '^\*\+\|\*\+$', '', 'g')
+ " On windows, the case is anyway ignored.
+ if !genutils#OnMS() && !matchingExactCase
+ let filePat = s:FilePatIgnoreCase(filePat)
+ endif
+ let fl = split(globpath(&path, (filePat != '') ? '*'.filePat.'*' : '*'),
+ \ "\n")
+ let regexPat = s:TranslateFileRegex(filePat)
+ " This is a psuedo case-sensitive match for windows, when 'smartcase' is
+ " set.
+ if genutils#OnMS() && matchingExactCase
+ set verbose=15
+ call filter(fl, 'v:val =~# regexPat')
+ set verbose=0
+ endif
+ return map(fl,
+ \ '{'.
+ \ ' "word": v:val,'.
+ \ ' "abbr": fnamemodify(v:val, ":t"), '.
+ \ ' "menu": fnamemodify(v:val, ":h"), '.
+ \ ' "dup": 1'.
+ \ '}')
+endfunction
+
+function! s:LookupArgs(pattern)
+ return map(filter(argv(), 'v:val =~ a:pattern'),
+ \ '{'.
+ \ ' "word":fnamemodify(v:val, ":p"), '.
+ \ ' "abbr": v:val, '.
+ \ ' "menu": substitute(v:val, a:pattern, "[&]", ""), '.
+ \ ' "dup": 1'.
+ \ '}')
+endfunction
+
+let s:bufList = [1]
+function! s:LookupBufs(pattern)
+ let results = []
+
+ if g:LookupFile_Bufs_BufListExpr != ''
+ let buflist = eval(g:LookupFile_Bufs_BufListExpr)
+ else
+ " Since we need to generate the same range again and again, it is better to
+ " cache the list.
+ if s:bufList[-1] != bufnr('$')
+ call extend(s:bufList, range(s:bufList[-1], bufnr('$')))
+ endif
+ let buflist = s:bufList
+ endif
+ let lastBufNr = bufnr('$')
+ let i = 1
+ if g:LookupFile_Bufs_LikeBufCmd
+ let pattern = s:TranslateFileRegex(a:pattern)
+ else
+ let pattern = a:pattern
+ endif
+ for bufNr in buflist
+ if ! bufexists(bufNr)
+ call remove(buflist, i)
+ continue
+ endif
+ try
+ if g:LookupFile_Bufs_SkipUnlisted && ! buflisted(bufNr)
+ continue
+ endif
+ let fname = expand('#'.bufNr.':p')
+ if g:LookupFile_Bufs_LikeBufCmd
+ let bname = bufname(bufNr)
+ let dir = ''
+ else
+ let bname = fnamemodify(bufname(bufNr), ':t')
+ let dir = fnamemodify(bufname(bufNr), ':h').'/'
+ endif
+ if bname =~ pattern
+ call add(results, {
+ \ 'word': fname,
+ \ 'abbr': bname,
+ \ 'menu': dir.substitute(bname, pattern, '[&]', ''),
+ \ 'dup': 1,
+ \ })
+ endif
+ finally
+ let i = i + 1
+ endtry
+ endfor
+ return results
+endfunction
+
+function! s:LookupWalk(pattern)
+ " We will wait till '/' is typed
+ if a:pattern =~ '\*\*$'
+ return []
+ endif
+ let showOnlyDirs = 0
+ " Determine the parent dir.
+ if a:pattern =~ '//$'
+ let parent = strpart(a:pattern, 0, strlen(a:pattern)-1)
+ let filePat = ''
+ if parent ==# g:lookupfile#lastPattern
+ return filter(g:lookupfile#lastResults, 'v:val["kind"] == "/"')
+ endif
+ let showOnlyDirs = 1
+ else
+ let parent = matchstr(a:pattern, '^.*/')
+ let filePat = strpart(a:pattern, len(parent))
+ endif
+
+ let matchingExactCase = s:MatchingExactCase(filePat)
+
+ " Remove leading or trailing '*'s as we add a star anyway. This also makes
+ " '**' as '', but we rule this case out already.
+ let filePat = substitute(filePat, '^\*\+\|\*\+$', '', 'g')
+ " On windows, the case is anyway ignored.
+ if !genutils#OnMS() && !matchingExactCase
+ let filePat = s:FilePatIgnoreCase(filePat)
+ endif
+ "exec BPBreak(1)
+ let _shellslash = &shellslash
+ set shellslash
+ try
+ let files = glob(parent.((filePat != '') ? '*'.filePat.'*' : '*'))
+ catch
+ " Ignore errors in patterns.
+ let files = ''
+ finally
+ let &shellslash = _shellslash
+ endtry
+ let fl = split(files, "\<NL>")
+ let regexPat = s:TranslateFileRegex(filePat)
+ " This is a psuedo case-sensitive match for windows, when 'smartcase' is
+ " set.
+ if genutils#OnMS() && matchingExactCase
+ call filter(fl, 'fnamemodify(v:val, ":t") =~# regexPat')
+ endif
+ " Find the start of path component that uses any of the *, [], ? or {
+ " wildcard. Path until this is unambiguously common to all, so we can strip
+ " it off, for brevity.
+ let firstWildIdx = match(a:pattern, '[^/]*\%(\*\|\[\|?\|{\)')
+ return s:FormatFileResults(fl, firstWildIdx!=-1 ? firstWildIdx :
+ \ strlen(parent), regexPat, matchingExactCase, showOnlyDirs)
+endfunction
+
+function! s:FormatFileResults(fl, parentLen, matchPat, matchingCase, dirsOnly)
+ let entries = []
+ for f in a:fl
+ if isdirectory(f)
+ let suffx = '/'
+ else
+ if a:dirsOnly
+ continue
+ endif
+ let suffx = ''
+ endif
+ let word = f.suffx
+ let fname = matchstr(f, '[^/]*$')
+ let dir = fnamemodify(f, ':h').'/'
+ if dir != '/' && a:parentLen != -1
+ let dir = strpart(dir, a:parentLen)
+ else
+ let dir = ''
+ endif
+ "let dir = (dir == '/'?'':dir)
+ call add(entries, {
+ \ 'word': word,
+ \ 'abbr': fname.suffx,
+ \ 'menu': (a:matchPat!='') ? dir.substitute(fname,
+ \ (a:matchingCase?'\C':'\c').a:matchPat, '[&]', '') :
+ \ dir.fname,
+ \ 'kind': suffx,
+ \ 'dup': 1
+ \ })
+ endfor
+ return entries
+endfunction
+
+function! s:ConfigBufs()
+ " Allow switching to file mode.
+ inoremap <expr> <buffer> <C-F> <SID>IdoSwitchTo('file')
+ call s:AddCleanup('iunmap <buffer> <C-F>')
+ if g:LookupFile_Bufs_BufListExpr != ''
+ call s:SaveSett('SortMethod')
+ let g:LookupFile_SortMethod = ''
+ endif
+endfunction
+
+function! s:ConfigWalk()
+ call s:SaveSett('LookupAcceptFunc')
+ unlet! g:LookupFile_LookupAcceptFunc
+ let g:LookupFile_LookupAcceptFunc = function(s:SNR().'IdoAccept')
+ " Make sure we have the right slashes, in case user passed in init path
+ " with wrong slashes.
+ call setline('.', substitute(getline('.'), '\\', '/', 'g'))
+
+ inoremap <buffer> <expr> <BS> <SID>IdoBS()
+ inoremap <buffer> <expr> <S-BS> <SID>IdoBS()
+ call s:AddCleanup('iunmap <buffer> <BS>')
+ imap <buffer> <expr> <Tab> <SID>IdoTab()
+ call s:AddCleanup('iunmap <buffer> <Tab>')
+ inoremap <expr> <buffer> <C-B> <SID>IdoSwitchTo('buffer')
+ call s:AddCleanup('iunmap <buffer> <C-B>')
+endfunction
+
+function! s:IdoSwitchTo(mode)
+ call s:LookupReset()
+ if a:mode == 'buffer'
+ let tok = matchstr(getline('.'), '[^/]*$')
+ let cmd = 'LUBufs'.(tok == "" ? '!' : ' '.tok)
+ else
+ let cmd = 'LUWalk '.s:GetDefDir().getline('.')
+ endif
+ return (pumvisible()?"\<C-E>":'')."\<Esc>:".cmd."\<CR>"
+endfunction
+
+function! s:IdoAccept(splitWin, key)
+ let refreshCmd = "\<C-O>:call lookupfile#LookupFile(0)\<CR>\<C-O>:\<BS>"
+ if getline('.') !=# g:lookupfile#lastPattern && getline('.')[strlen(getline('.'))-1] == '/'
+ return refreshCmd
+ elseif getline('.') ==# g:lookupfile#lastPattern
+ \ && len(g:lookupfile#lastResults) > 0
+ \ && g:lookupfile#lastResults[0]['kind'] == '/'
+ " When the first entry is a directory, accept it, and trigger a fresh
+ " completion on that.
+ return "\<C-N>\<C-R>=(getline('.') == lookupfile#lastPattern)?\"\\<C-N>\":''\<CR>".refreshCmd
+ endif
+ return lookupfile#AcceptFile(a:splitWin, a:key)
+endfunction
+
+function! s:IdoBS()
+ if lookupfile#IsPopupHidden() == 1
+ return "\<BS>"
+ endif
+ if getline('.') !~ '/$'
+ return (pumvisible() ? "\<C-E>" : '')."\<BS>"
+ else
+ " Determine the number of <BS>'s required to remove the patch component.
+ let lastComp = matchstr(getline('.'), '[^/]*/$')
+ return (pumvisible() ? (getline('.') ==# g:lookupfile#lastPattern ?
+ \ "\<C-E>" : "\<C-Y>") : '') . repeat("\<BS>", strlen(lastComp))
+ endif
+endfunction
+
+function! s:IdoTab()
+ " When no pattern yet, fill up with current directory.
+ if !pumvisible() && getline('.') == ''
+ return s:GetDefDir()
+ else
+ return "\<Tab>"
+ endif
+endfunction
+
+function! s:GetDefDir()
+ return substitute(expand('#'.s:baseBufNr.':p:h'), '\\', '/', 'g').'/'
+endfunction
+
+" Convert file wildcards ("*", "?" etc. |file-pattern|) to a Vim string
+" regex metachars (see |pattern.txt|). Returns metachars that work in "very
+" nomagic" mode.
+let s:fileWild = {}
+function! s:TranslateFileWild(fileWild)
+ let strRegex = ''
+ if a:fileWild ==# '*'
+ let strRegex = '\[^/]\*'
+ elseif a:fileWild ==# '**'
+ let strRegex = '\.\*'
+ elseif a:fileWild ==# '?'
+ let strRegex = '\.'
+ elseif a:fileWild ==# '['
+ let strRegex = '\['
+ endif
+ return strRegex
+endfunction
+
+" Convert a |file-pattern| to a Vim string regex (see |pattern.txt|).
+" No error checks for now, for simplicity.
+function! s:TranslateFileRegex(filePat)
+ let pat = substitute(a:filePat, '\(\*\*\|\*\|\[\)',
+ \ '\=s:TranslateFileWild(submatch(1))', 'g')
+ let unprotectedMeta = genutils#CrUnProtectedCharsPattern('?,', 1)
+ let pat = substitute(pat, unprotectedMeta,
+ \ '\=s:TranslateFileWild(submatch(1))', 'g')
+ return (pat == '') ? pat : '\V'.pat
+endfunction
+
+" Translates the file pattern to ignore case on non-case-insensitive systems.
+function! s:FilePatIgnoreCase(filePat)
+ return substitute(a:filePat, '\(\[.\{-}]\)\|\(\a\)',
+ \ '\=s:TranslateAlpha(submatch(0))', 'g')
+endfunction
+
+function! s:TranslateAlpha(pat)
+ if a:pat =~"^["
+ return substitute(substitute(a:pat, '-\@<!\a-\@!', '&\u&', 'g'),
+ \ '\(\a\)-\(\a\)', '\1-\2\u\1-\u\2', 'g')
+ else
+ return substitute(a:pat, '\a', '[\l&\u&]', 'g')
+ endif
+endfunction
+
+function! s:MatchingExactCase(filePat)
+ if &ignorecase
+ if &smartcase && a:filePat =~# '\u'
+ let matchingExactCase = 1
+ else
+ let matchingExactCase = 0
+ endif
+ else
+ if genutils#OnMS()
+ let matchingExactCase = 0
+ else
+ let matchingExactCase = 1
+ endif
+ endif
+ return matchingExactCase
+endfunction
+
+" Restore cpo.
+let &cpo = s:save_cpo
+unlet s:save_cpo
+
+" vim6:fdm=marker et sw=2
--- /dev/null
+function Send_to_Screen(text)
+ if !exists("g:screen_sessionname") || !exists("g:screen_windowname")
+ call Screen_Vars()
+ end
+
+ echo system("screen -S " . g:screen_sessionname . " -p " . g:screen_windowname . " -X stuff '" . substitute(a:text, "'", "'\\\\''", 'g') . "'")
+endfunction
+
+function Screen_Session_Names(A,L,P)
+ return system("screen -ls | awk '/Attached/ {print $1}'")
+endfunction
+
+function Screen_Vars()
+ if !exists("g:screen_sessionname") || !exists("g:screen_windowname")
+ let g:screen_sessionname = ""
+ let g:screen_windowname = "0"
+ end
+
+ let g:screen_sessionname = input("session name: ", "", "custom,Screen_Session_Names")
+ let g:screen_windowname = input("window name: ", g:screen_windowname)
+endfunction
+
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+vmap <C-c><C-c> "ry :call Send_to_Screen(@r)<CR>
+nmap <C-c><C-c> vip<C-c><C-c>
+
+nmap <C-c>v :call Screen_Vars()<CR>
--- /dev/null
+" Author:
+" Original: Gergely Kontra <
[email protected]>
+" Current: Eric Van Dewoestine <
[email protected]> (as of version 0.4)
+" Please direct all correspondence to Eric.
+" Version: 0.45
+"
+" Description: {{{
+" Use your tab key to do all your completion in insert mode!
+" You can cycle forward and backward with the <Tab> and <S-Tab> keys
+" (<S-Tab> will not work in the console version)
+" Note: you must press <Tab> once to be able to cycle back
+"
+" http://www.vim.org/scripts/script.php?script_id=1643
+" }}}
+"
+" License: {{{
+" Software License Agreement (BSD License)
+"
+" Copyright (c) 2002 - 2007
+" All rights reserved.
+"
+" Redistribution and use of this software in source and binary forms, with
+" or without modification, are permitted provided that the following
+" conditions are met:
+"
+" * Redistributions of source code must retain the above
+" copyright notice, this list of conditions and the
+" following disclaimer.
+"
+" * Redistributions in binary form must reproduce the above
+" copyright notice, this list of conditions and the
+" following disclaimer in the documentation and/or other
+" materials provided with the distribution.
+"
+" * Neither the name of Gergely Kontra or Eric Van Dewoestine nor the names
+" of its contributors may be used to endorse or promote products derived
+" from this software without specific prior written permission of Gergely
+" Kontra or Eric Van Dewoestine.
+"
+" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+" IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+" THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+" PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+" }}}
+
+if exists('complType') "Integration with other completion functions.
+ finish
+endif
+
+" Global Variables {{{
+
+ " Used to set the default completion type.
+ " There is no need to escape this value as that will be done for you when
+ " the type is set.
+ " Ex. let g:SuperTabDefaultCompletionType = "<C-X><C-U>"
+ if !exists("g:SuperTabDefaultCompletionType")
+ let g:SuperTabDefaultCompletionType = "<C-P>"
+ endif
+
+ " Used to set a list of variable, completion type pairs used to determine
+ " the default completion type to use for the current buffer. If the
+ " variable is non-zero and non-empty then the associated completion type
+ " will be used.
+ " Ex. To use omni or user completion when available, but fall back to the
+ " global default otherwise.
+ " let g:SuperTabDefaultCompletionTypeDiscovery = "&omnifunc:<C-X><C-O>,&completefunc:<C-X><C-U>"
+ if !exists("g:SuperTabDefaultCompletionTypeDiscovery")
+ let g:SuperTabDefaultCompletionTypeDiscovery = ""
+ endif
+
+ " Determines if, and for how long, the current completion type is retained.
+ " The possible values include:
+ " 0 - The current completion type is only retained for the current completion.
+ " Once you have chosen a completion result or exited the completion
+ " mode, the default completion type is restored.
+ " 1 - The current completion type is saved for the duration of your vim
+ " session or until you enter a different completion mode.
+ " (SuperTab default).
+ " 2 - The current completion type is saved until you exit insert mode (via
+ " ESC). Once you exit insert mode the default completion type is
+ " restored.
+ if !exists("g:SuperTabRetainCompletionType")
+ let g:SuperTabRetainCompletionType = 1
+ endif
+
+ " Sets whether or not mid word completion is enabled.
+ " When enabled, <tab> will kick off completion when ever a word character is
+ " to the left of the cursor. When disabled, completion will only occur if
+ " the char to the left is a word char and the char to the right is not (you
+ " are at the end of the word).
+ if !exists("g:SuperTabMidWordCompletion")
+ let g:SuperTabMidWordCompletion = 1
+ endif
+
+ " The following two variables allow you to set the key mapping used to kick
+ " off the current completion. By default this is <tab> and <s-tab>. To
+ " change to something like <c-space> and <s-c-space>, you can add the
+ " following to your vimrc.
+ "
+ " let g:SuperTabMappingForward = '<c-space>'
+ " let g:SuperTabMappingBackward = '<s-c-space>'
+ "
+ " Note: if the above does not have the desired effect (which may happen in
+ " console version of vim), you can try the following mappings. Although the
+ " backwards mapping still doesn't seem to work in the console for me, your
+ " milage may vary.
+ "
+ " let g:SuperTabMappingForward = '<nul>'
+ " let g:SuperTabMappingBackward = '<s-nul>'
+ "
+ if !exists("g:SuperTabMappingForward")
+ let g:SuperTabMappingForward = '<tab>'
+ endif
+ if !exists("g:SuperTabMappingBackward")
+ let g:SuperTabMappingBackward = '<s-tab>'
+ endif
+
+ " Sets whether or not to pre-highlight first match when completeopt has
+ " the popup menu enabled and the 'longest' option as well.
+ " When enabled, <tab> will kick off completion and pre-select the first
+ " entry in the popup menu, allowing you to simply hit <enter> to use it.
+ if !exists("g:SuperTabLongestHighlight")
+ let g:SuperTabLongestHighlight = 0
+ endif
+
+" }}}
+
+" Script Variables {{{
+
+ " construct the help text.
+ let s:tabHelp =
+ \ "Hit <CR> or CTRL-] on the completion type you wish to switch to.\n" .
+ \ "Use :help ins-completion for more information.\n" .
+ \ "\n" .
+ \ "|<C-N>| - Keywords in 'complete' searching down.\n" .
+ \ "|<C-P>| - Keywords in 'complete' searching up (SuperTab default).\n" .
+ \ "|<C-X><C-L>| - Whole lines.\n" .
+ \ "|<C-X><C-N>| - Keywords in current file.\n" .
+ \ "|<C-X><C-K>| - Keywords in 'dictionary'.\n" .
+ \ "|<C-X><C-T>| - Keywords in 'thesaurus', thesaurus-style.\n" .
+ \ "|<C-X><C-I>| - Keywords in the current and included files.\n" .
+ \ "|<C-X><C-]>| - Tags.\n" .
+ \ "|<C-X><C-F>| - File names.\n" .
+ \ "|<C-X><C-D>| - Definitions or macros.\n" .
+ \ "|<C-X><C-V>| - Vim command-line."
+ if v:version >= 700
+ let s:tabHelp = s:tabHelp . "\n" .
+ \ "|<C-X><C-U>| - User defined completion.\n" .
+ \ "|<C-X><C-O>| - Omni completion.\n" .
+ \ "|<C-X>s| - Spelling suggestions."
+ endif
+
+ " set the available completion types and modes.
+ let s:types =
+ \ "\<C-E>\<C-Y>\<C-L>\<C-N>\<C-K>\<C-T>\<C-I>\<C-]>\<C-F>\<C-D>\<C-V>\<C-N>\<C-P>"
+ let s:modes = '/^E/^Y/^L/^N/^K/^T/^I/^]/^F/^D/^V/^P'
+ if v:version >= 700
+ let s:types = s:types . "\<C-U>\<C-O>\<C-N>\<C-P>s"
+ let s:modes = s:modes . '/^U/^O/s'
+ endif
+ let s:types = s:types . "np"
+ let s:modes = s:modes . '/n/p'
+
+" }}}
+
+" CtrlXPP() {{{
+" Handles entrance into completion mode.
+function! CtrlXPP()
+ if &smd
+ echo '' | echo '-- ^X++ mode (' . s:modes . ')'
+ endif
+ let complType = nr2char(getchar())
+ if stridx(s:types, complType) != -1
+ if stridx("\<C-E>\<C-Y>", complType) != -1 " no memory, just scroll...
+ return "\<C-x>" . complType
+ elseif stridx('np', complType) != -1
+ let complType = nr2char(char2nr(complType) - 96) " char2nr('n')-char2nr("\<C-n")
+ else
+ let complType="\<C-x>" . complType
+ endif
+
+ if g:SuperTabRetainCompletionType
+ let b:complType = complType
+ endif
+
+ return complType
+ else
+ echohl "Unknown mode"
+ return complType
+ endif
+endfunction " }}}
+
+" SuperTabSetCompletionType(type) {{{
+" Globally available function that user's can use to create mappings to
+" quickly switch completion modes. Useful when a user wants to restore the
+" default or switch to another mode without having to kick off a completion
+" of that type or use SuperTabHelp.
+" Example mapping to restore SuperTab default:
+" nmap <F6> :call SetSuperTabCompletionType("<C-P>")<cr>
+function! SuperTabSetCompletionType (type)
+ exec "let b:complType = \"" . escape(a:type, '<') . "\""
+endfunction " }}}
+
+" s:Init {{{
+" Global initilization when supertab is loaded.
+function! s:Init ()
+ augroup supertab_init
+ autocmd!
+ autocmd BufEnter * call <SID>InitBuffer()
+ augroup END
+ " ensure InitBuffer gets called for the first buffer.
+ call s:InitBuffer()
+
+ " Setup mechanism to restore orignial completion type upon leaving insert
+ " mode if g:SuperTabRetainCompletionType == 2
+ if g:SuperTabRetainCompletionType == 2
+ " pre vim 7, must map <esc>
+ if v:version < 700
+ im <silent> <ESC> <ESC>:call s:SetDefaultCompletionType()<cr>
+
+ " since vim 7, we can use InsertLeave autocmd.
+ else
+ augroup supertab_retain
+ autocmd!
+ autocmd InsertLeave * call s:SetDefaultCompletionType()
+ augroup END
+ endif
+ endif
+endfunction " }}}
+
+" s:InitBuffer {{{
+" Per buffer initilization.
+function! s:InitBuffer ()
+ if exists("b:complType")
+ return
+ endif
+
+ if !exists("b:SuperTabDefaultCompletionType")
+ " loop through discovery list to find the default
+ if g:SuperTabDefaultCompletionTypeDiscovery != ''
+ let dlist = g:SuperTabDefaultCompletionTypeDiscovery
+ while dlist != ''
+ let pair = substitute(dlist, '\(.\{-}\)\(,.*\|$\)', '\1', '')
+ let dlist = substitute(dlist, '.\{-}\(,.*\|$\)', '\1', '')
+ let dlist = substitute(dlist, '^,', '\1', '')
+
+ let var = substitute(pair, '\(.*\):.*', '\1', '')
+ let type = substitute(pair, '.*:\(.*\)', '\1', '')
+
+ exec 'let value = ' . var
+ if value !~ '^\s*$' && value != '0'
+ let b:SuperTabDefaultCompletionType = type
+ break
+ endif
+ endwhile
+ endif
+
+ " fallback to configured default.
+ if !exists("b:SuperTabDefaultCompletionType")
+ let b:SuperTabDefaultCompletionType = g:SuperTabDefaultCompletionType
+ endif
+ endif
+
+ " set the default completion type.
+ call SuperTabSetCompletionType(b:SuperTabDefaultCompletionType)
+endfunction " }}}
+
+" s:IsWordChar(char) {{{
+" Determines if the supplied character is a word character or matches value
+" defined by 'iskeyword'.
+function! s:IsWordChar (char)
+ if a:char =~ '\w'
+ return 1
+ endif
+
+ " check against 'iskeyword'
+ let values = &iskeyword
+ let index = stridx(values, ',')
+ while index > 0 || values != ''
+ if index > 0
+ let value = strpart(values, 0, index)
+ let values = strpart(values, index + 1)
+ else
+ let value = values
+ let values = ''
+ endif
+
+ " exception case for '^,'
+ if value == '^'
+ let value = '^,'
+
+ " execption case for ','
+ elseif value =~ '^,,'
+ let values .= strpart(value, 2)
+ let value = ','
+
+ " execption case after a ^,
+ elseif value =~ '^,'
+ let value = strpart(value, 1)
+ endif
+
+ " keyword values is an ascii number range
+ if value =~ '[0-9]\+-[0-9]\+'
+ let charnum = char2nr(a:char)
+ exec 'let start = ' . substitute(value, '\([0-9]\+\)-.*', '\1', '')
+ exec 'let end = ' . substitute(value, '.*-\([0-9]\+\)', '\1', '')
+
+ if charnum >= start && charnum <= end
+ return 1
+ endif
+
+ " keyword value is a set of include or exclude characters
+ else
+ let include = 1
+ if value =~ '^\^'
+ let value = strpart(value, 1)
+ let include = 0
+ endif
+
+ if a:char =~ '[' . escape(value, '[]') . ']'
+ return include
+ endif
+ endif
+ let index = stridx(values, ',')
+ endwhile
+
+ return 0
+endfunction " }}}
+
+" s:SetCompletionType() {{{
+" Sets the completion type based on what the user has chosen from the help
+" buffer.
+function! s:SetCompletionType ()
+ let chosen = substitute(getline('.'), '.*|\(.*\)|.*', '\1', '')
+ if chosen != getline('.')
+ let winnr = b:winnr
+ close
+ exec winnr . 'winc w'
+ call SuperTabSetCompletionType(chosen)
+ endif
+endfunction " }}}
+
+" s:SetDefaultCompletionType () {{{
+function! s:SetDefaultCompletionType ()
+ if exists('b:SuperTabDefaultCompletionType')
+ call SuperTabSetCompletionType(b:SuperTabDefaultCompletionType)
+ endif
+endfunction " }}}
+
+" s:SuperTab(command) {{{
+" Used to perform proper cycle navigtion as the user requests the next or
+" previous entry in a completion list, and determines whether or not to simply
+" retain the normal usage of <tab> based on the cursor position.
+function! s:SuperTab(command)
+ if s:WillComplete()
+ let key = ''
+ " highlight first result if longest enabled
+ if g:SuperTabLongestHighlight && !pumvisible() && &completeopt =~ 'longest'
+ let key = (b:complType == "\<C-P>") ? "\<C-P>" : "\<C-N>"
+ endif
+
+ " exception: if in <c-p> mode, then <c-n> should move up the list, and
+ " <c-p> down the list.
+ if a:command == 'p' && b:complType == "\<C-P>"
+ return "\<C-N>"
+ endif
+ return b:complType . key
+ endif
+
+ return "\<Tab>"
+endfunction " }}}
+
+" s:SuperTabHelp() {{{
+" Opens a help window where the user can choose a completion type to enter.
+function! s:SuperTabHelp()
+ let winnr = winnr()
+ if bufwinnr("SuperTabHelp") == -1
+ botright split SuperTabHelp
+
+ setlocal noswapfile
+ setlocal buftype=nowrite
+ setlocal bufhidden=delete
+
+ let saved = @"
+ let @" = s:tabHelp
+ silent put
+ call cursor(1, 1)
+ silent 1,delete
+ call cursor(4, 1)
+ let @" = saved
+ exec "resize " . line('$')
+
+ syntax match Special "|.\{-}|"
+
+ setlocal readonly
+ setlocal nomodifiable
+
+ nmap <silent> <buffer> <cr> :call <SID>SetCompletionType()<cr>
+ nmap <silent> <buffer> <c-]> :call <SID>SetCompletionType()<cr>
+ else
+ exec bufwinnr("SuperTabHelp") . "winc w"
+ endif
+ let b:winnr = winnr
+endfunction " }}}
+
+" s:WillComplete () {{{
+" Determines if completion should be kicked off at the current location.
+function! s:WillComplete ()
+ let line = getline('.')
+ let cnum = col('.')
+
+ " Start of line.
+ let prev_char = strpart(line, cnum - 2, 1)
+ if prev_char =~ '^\s*$'
+ return 0
+ endif
+
+ " Within a word, but user does not have mid word completion enabled.
+ let next_char = strpart(line, cnum - 1, 1)
+ if !g:SuperTabMidWordCompletion && s:IsWordChar(next_char)
+ return 0
+ endif
+
+ " In keyword completion mode and no preceding word characters.
+ "if (b:complType == "\<C-N>" || b:complType == "\<C-P>") && !s:IsWordChar(prev_char)
+ " return 0
+ "endif
+
+ return 1
+endfunction " }}}
+
+" Key Mappings {{{
+ im <C-X> <C-r>=CtrlXPP()<CR>
+
+ " From the doc |insert.txt| improved
+ exec 'im ' . g:SuperTabMappingForward . ' <C-n>'
+ exec 'im ' . g:SuperTabMappingBackward . ' <C-p>'
+
+ " After hitting <Tab>, hitting it once more will go to next match
+ " (because in XIM mode <C-n> and <C-p> mappings are ignored)
+ " and wont start a brand new completion
+ " The side effect, that in the beginning of line <C-n> and <C-p> inserts a
+ " <Tab>, but I hope it may not be a problem...
+ ino <C-n> <C-R>=<SID>SuperTab('n')<CR>
+ ino <C-p> <C-R>=<SID>SuperTab('p')<CR>
+" }}}
+
+" Command Mappings {{{
+ if !exists(":SuperTabHelp")
+ command SuperTabHelp :call <SID>SuperTabHelp()
+ endif
+" }}}
+
+call <SID>Init()
+
+" vim:ft=vim:fdm=marker
--- /dev/null
+" surround.vim - Surroundings
+" Author: Tim Pope <
[email protected]>
+" GetLatestVimScripts: 1697 1 :AutoInstall: surround.vim
+" $Id: surround.vim,v 1.34 2008-02-15 21:43:42 tpope Exp $
+"
+" See surround.txt for help. This can be accessed by doing
+"
+" :helptags ~/.vim/doc
+" :help surround
+"
+" Licensed under the same terms as Vim itself.
+
+" ============================================================================
+
+" Exit quickly when:
+" - this plugin was already loaded or disabled
+" - when 'compatible' is set
+if (exists("g:loaded_surround") && g:loaded_surround) || &cp
+ finish
+endif
+let g:loaded_surround = 1
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" Input functions {{{1
+
+function! s:getchar()
+ let c = getchar()
+ if c =~ '^\d\+$'
+ let c = nr2char(c)
+ endif
+ return c
+endfunction
+
+function! s:inputtarget()
+ let c = s:getchar()
+ while c =~ '^\d\+$'
+ let c = c . s:getchar()
+ endwhile
+ if c == " "
+ let c = c . s:getchar()
+ endif
+ if c =~ "\<Esc>\|\<C-C>\|\0"
+ return ""
+ else
+ return c
+ endif
+endfunction
+
+function! s:inputreplacement()
+ "echo '-- SURROUND --'
+ let c = s:getchar()
+ if c == " "
+ let c = c . s:getchar()
+ endif
+ if c =~ "\<Esc>" || c =~ "\<C-C>"
+ return ""
+ else
+ return c
+ endif
+endfunction
+
+function! s:beep()
+ exe "norm! \<Esc>"
+ return ""
+endfunction
+
+function! s:redraw()
+ redraw
+ return ""
+endfunction
+
+" }}}1
+
+" Wrapping functions {{{1
+
+function! s:extractbefore(str)
+ if a:str =~ '\r'
+ return matchstr(a:str,'.*\ze\r')
+ else
+ return matchstr(a:str,'.*\ze\n')
+ endif
+endfunction
+
+function! s:extractafter(str)
+ if a:str =~ '\r'
+ return matchstr(a:str,'\r\zs.*')
+ else
+ return matchstr(a:str,'\n\zs.*')
+ endif
+endfunction
+
+function! s:repeat(str,count)
+ let cnt = a:count
+ let str = ""
+ while cnt > 0
+ let str = str . a:str
+ let cnt = cnt - 1
+ endwhile
+ return str
+endfunction
+
+function! s:fixindent(str,spc)
+ let str = substitute(a:str,'\t',s:repeat(' ',&sw),'g')
+ let spc = substitute(a:spc,'\t',s:repeat(' ',&sw),'g')
+ let str = substitute(str,'\(\n\|\%^\).\@=','\1'.spc,'g')
+ if ! &et
+ let str = substitute(str,'\s\{'.&ts.'\}',"\t",'g')
+ endif
+ return str
+endfunction
+
+function! s:process(string)
+ let i = 0
+ while i < 7
+ let i = i + 1
+ let repl_{i} = ''
+ let m = matchstr(a:string,nr2char(i).'.\{-\}\ze'.nr2char(i))
+ if m != ''
+ let m = substitute(strpart(m,1),'\r.*','','')
+ let repl_{i} = input(substitute(m,':\s*$','','').': ')
+ endif
+ endwhile
+ let s = ""
+ let i = 0
+ while i < strlen(a:string)
+ let char = strpart(a:string,i,1)
+ if char2nr(char) < 8
+ let next = stridx(a:string,char,i+1)
+ if next == -1
+ let s = s . char
+ else
+ let insertion = repl_{char2nr(char)}
+ let subs = strpart(a:string,i+1,next-i-1)
+ let subs = matchstr(subs,'\r.*')
+ while subs =~ '^\r.*\r'
+ let sub = matchstr(subs,"^\r\\zs[^\r]*\r[^\r]*")
+ let subs = strpart(subs,strlen(sub)+1)
+ let r = stridx(sub,"\r")
+ let insertion = substitute(insertion,strpart(sub,0,r),strpart(sub,r+1),'')
+ endwhile
+ let s = s . insertion
+ let i = next
+ endif
+ else
+ let s = s . char
+ endif
+ let i = i + 1
+ endwhile
+ return s
+endfunction
+
+function! s:wrap(string,char,type,...)
+ let keeper = a:string
+ let newchar = a:char
+ let type = a:type
+ let linemode = type ==# 'V' ? 1 : 0
+ let special = a:0 ? a:1 : 0
+ let before = ""
+ let after = ""
+ if type == "V"
+ let initspaces = matchstr(keeper,'\%^\s*')
+ else
+ let initspaces = matchstr(getline('.'),'\%^\s*')
+ endif
+ " Duplicate b's are just placeholders (removed)
+ let pairs = "b()B{}r[]a<>"
+ let extraspace = ""
+ if newchar =~ '^ '
+ let newchar = strpart(newchar,1)
+ let extraspace = ' '
+ endif
+ let idx = stridx(pairs,newchar)
+ if newchar == ' '
+ let before = ''
+ let after = ''
+ elseif exists("b:surround_".char2nr(newchar))
+ let all = s:process(b:surround_{char2nr(newchar)})
+ let before = s:extractbefore(all)
+ let after = s:extractafter(all)
+ elseif exists("g:surround_".char2nr(newchar))
+ let all = s:process(g:surround_{char2nr(newchar)})
+ let before = s:extractbefore(all)
+ let after = s:extractafter(all)
+ elseif newchar ==# "p"
+ let before = "\n"
+ let after = "\n\n"
+ elseif newchar =~# "[tT\<C-T><,]"
+ let dounmapp = 0
+ let dounmapb = 0
+ if !maparg(">","c")
+ let dounmapb= 1
+ " Hide from AsNeeded
+ exe "cn"."oremap > <CR>"
+ exe "cn"."oremap % %<C-V>"
+ "cm ap > <C-R>=getcmdline() =~ '^[^%?].*[%?]$' ? "\026\076" : "\026\076\015"<CR>
+ endif
+ let default = ""
+ if !maparg("%","c")
+ " This is to help when typing things like
+ " <a href="/images/<%= @image.filename %>">
+ " The downside is it breaks backspace, so lets disable it for now
+ "let dounmapp= 1
+ "exe "cn"."oremap % %<C-V>"
+ endif
+ if newchar ==# "T"
+ if !exists("s:lastdel")
+ let s:lastdel = ""
+ endif
+ let default = matchstr(s:lastdel,'<\zs.\{-\}\ze>')
+ endif
+ let tag = input("<",default)
+ echo "<".substitute(tag,'>*$','>','')
+ "if dounmapr
+ "silent! cunmap <CR>
+ "endif
+ if dounmapb
+ silent! cunmap >
+ endif
+ if dounmapp
+ silent! cunmap %
+ endif
+ if tag != ""
+ let tag = substitute(tag,'>*$','','')
+ let before = '<'.tag.'>'
+ if tag =~ '/$'
+ let after = ''
+ else
+ let after = '</'.substitute(tag,' .*','','').'>'
+ endif
+ if newchar == "\<C-T>" || newchar == ","
+ if type ==# "v" || type ==# "V"
+ let before = before . "\n\t"
+ endif
+ if type ==# "v"
+ let after = "\n". after
+ endif
+ endif
+ endif
+ elseif newchar ==# 'l' || newchar == '\'
+ " LaTeX
+ let env = input('\begin{')
+ let env = '{' . env
+ let env = env . s:closematch(env)
+ echo '\begin'.env
+ if env != ""
+ let before = '\begin'.env
+ let after = '\end'.matchstr(env,'[^}]*').'}'
+ endif
+ "if type ==# 'v' || type ==# 'V'
+ "let before = before ."\n\t"
+ "endif
+ "if type ==# 'v'
+ "let after = "\n".initspaces.after
+ "endif
+ elseif newchar ==# 'f' || newchar ==# 'F'
+ let fnc = input('function: ')
+ if fnc != ""
+ let before = substitute(fnc,'($','','').'('
+ let after = ')'
+ if newchar ==# 'F'
+ let before = before . ' '
+ let after = ' ' . after
+ endif
+ endif
+ elseif idx >= 0
+ let spc = (idx % 3) == 1 ? " " : ""
+ let idx = idx / 3 * 3
+ let before = strpart(pairs,idx+1,1) . spc
+ let after = spc . strpart(pairs,idx+2,1)
+ elseif newchar == "\<C-[>" || newchar == "\<C-]>"
+ let before = "{\n\t"
+ let after = "\n}"
+ elseif newchar !~ '\a'
+ let before = newchar
+ let after = newchar
+ else
+ let before = ''
+ let after = ''
+ endif
+ "let before = substitute(before,'\n','\n'.initspaces,'g')
+ let after = substitute(after ,'\n','\n'.initspaces,'g')
+ "let after = substitute(after,"\n\\s*\<C-U>\\s*",'\n','g')
+ if type ==# 'V' || (special && type ==# "v")
+ let before = substitute(before,' \+$','','')
+ let after = substitute(after ,'^ \+','','')
+ if after !~ '^\n'
+ let after = initspaces.after
+ endif
+ if keeper !~ '\n$' && after !~ '^\n'
+ let keeper = keeper . "\n"
+ elseif keeper =~ '\n$' && after =~ '^\n'
+ let after = strpart(after,1)
+ endif
+ if before !~ '\n\s*$'
+ let before = before . "\n"
+ if special
+ let before = before . "\t"
+ endif
+ endif
+ endif
+ if type ==# 'V'
+ let before = initspaces.before
+ endif
+ if before =~ '\n\s*\%$'
+ if type ==# 'v'
+ let keeper = initspaces.keeper
+ endif
+ let padding = matchstr(before,'\n\zs\s\+\%$')
+ let before = substitute(before,'\n\s\+\%$','\n','')
+ let keeper = s:fixindent(keeper,padding)
+ endif
+ if type ==# 'V'
+ let keeper = before.keeper.after
+ elseif type =~ "^\<C-V>"
+ " Really we should be iterating over the buffer
+ let repl = substitute(before,'[\\~]','\\&','g').'\1'.substitute(after,'[\\~]','\\&','g')
+ let repl = substitute(repl,'\n',' ','g')
+ let keeper = substitute(keeper."\n",'\(.\{-\}\)\('.(special ? '\s\{-\}' : '').'\n\)',repl.'\n','g')
+ let keeper = substitute(keeper,'\n\%$','','')
+ else
+ let keeper = before.extraspace.keeper.extraspace.after
+ endif
+ return keeper
+endfunction
+
+function! s:wrapreg(reg,char,...)
+ let orig = getreg(a:reg)
+ let type = substitute(getregtype(a:reg),'\d\+$','','')
+ let special = a:0 ? a:1 : 0
+ let new = s:wrap(orig,a:char,type,special)
+ call setreg(a:reg,new,type)
+endfunction
+" }}}1
+
+function! s:insert(...) " {{{1
+ " Optional argument causes the result to appear on 3 lines, not 1
+ "call inputsave()
+ let linemode = a:0 ? a:1 : 0
+ let char = s:inputreplacement()
+ while char == "\<CR>" || char == "\<C-S>"
+ " TODO: use total count for additional blank lines
+ let linemode = linemode + 1
+ let char = s:inputreplacement()
+ endwhile
+ "call inputrestore()
+ if char == ""
+ return ""
+ endif
+ "call inputsave()
+ let cb_save = &clipboard
+ let reg_save = @@
+ call setreg('"',"\r",'v')
+ call s:wrapreg('"',char,linemode)
+ " If line mode is used and the surrounding consists solely of a suffix,
+ " remove the initial newline. This fits a use case of mine but is a
+ " little inconsistent. Is there anyone that would prefer the simpler
+ " behavior of just inserting the newline?
+ if linemode && match(getreg('"'),'^\n\s*\zs.*') == 0
+ call setreg('"',matchstr(getreg('"'),'^\n\s*\zs.*'),getregtype('"'))
+ endif
+ " This can be used to append a placeholder to the end
+ if exists("g:surround_insert_tail")
+ call setreg('"',g:surround_insert_tail,"a".getregtype('"'))
+ endif
+ "if linemode
+ "call setreg('"',substitute(getreg('"'),'^\s\+','',''),'c')
+ "endif
+ if col('.') >= col('$')
+ norm! ""p
+ else
+ norm! ""P
+ endif
+ if linemode
+ call s:reindent()
+ endif
+ norm! `]
+ call search('\r','bW')
+ let @@ = reg_save
+ let &clipboard = cb_save
+ return "\<Del>"
+endfunction " }}}1
+
+function! s:reindent() " {{{1
+ if exists("b:surround_indent") ? b:surround_indent : (exists("g:surround_indent") && g:surround_indent)
+ silent norm! '[=']
+ endif
+endfunction " }}}1
+
+function! s:dosurround(...) " {{{1
+ let scount = v:count1
+ let char = (a:0 ? a:1 : s:inputtarget())
+ let spc = ""
+ if char =~ '^\d\+'
+ let scount = scount * matchstr(char,'^\d\+')
+ let char = substitute(char,'^\d\+','','')
+ endif
+ if char =~ '^ '
+ let char = strpart(char,1)
+ let spc = 1
+ endif
+ if char == 'a'
+ let char = '>'
+ endif
+ if char == 'r'
+ let char = ']'
+ endif
+ let newchar = ""
+ if a:0 > 1
+ let newchar = a:2
+ if newchar == "\<Esc>" || newchar == "\<C-C>" || newchar == ""
+ return s:beep()
+ endif
+ endif
+ let cb_save = &clipboard
+ set clipboard-=unnamed
+ let append = ""
+ let original = getreg('"')
+ let otype = getregtype('"')
+ call setreg('"',"")
+ let strcount = (scount == 1 ? "" : scount)
+ if char == '/'
+ exe 'norm '.strcount.'[/d'.strcount.']/'
+ else
+ exe 'norm d'.strcount.'i'.char
+ endif
+ let keeper = getreg('"')
+ let okeeper = keeper " for reindent below
+ if keeper == ""
+ call setreg('"',original,otype)
+ let &clipboard = cb_save
+ return ""
+ endif
+ let oldline = getline('.')
+ let oldlnum = line('.')
+ if char ==# "p"
+ call setreg('"','','V')
+ elseif char ==# "s" || char ==# "w" || char ==# "W"
+ " Do nothing
+ call setreg('"','')
+ elseif char =~ "[\"'`]"
+ exe "norm! i \<Esc>d2i".char
+ call setreg('"',substitute(getreg('"'),' ','',''))
+ elseif char == '/'
+ norm! "_x
+ call setreg('"','/**/',"c")
+ let keeper = substitute(substitute(keeper,'^/\*\s\=','',''),'\s\=\*$','','')
+ else
+ " One character backwards
+ call search('.','bW')
+ exe "norm da".char
+ endif
+ let removed = getreg('"')
+ let rem2 = substitute(removed,'\n.*','','')
+ let oldhead = strpart(oldline,0,strlen(oldline)-strlen(rem2))
+ let oldtail = strpart(oldline, strlen(oldline)-strlen(rem2))
+ let regtype = getregtype('"')
+ if char =~# '[\[({<T]' || spc
+ let keeper = substitute(keeper,'^\s\+','','')
+ let keeper = substitute(keeper,'\s\+$','','')
+ endif
+ if col("']") == col("$") && col('.') + 1 == col('$')
+ if oldhead =~# '^\s*$' && a:0 < 2
+ let keeper = substitute(keeper,'\%^\n'.oldhead.'\(\s*.\{-\}\)\n\s*\%$','\1','')
+ endif
+ let pcmd = "p"
+ else
+ let pcmd = "P"
+ endif
+ if line('.') < oldlnum && regtype ==# "V"
+ let pcmd = "p"
+ endif
+ call setreg('"',keeper,regtype)
+ if newchar != ""
+ call s:wrapreg('"',newchar)
+ endif
+ silent exe 'norm! ""'.pcmd.'`['
+ if removed =~ '\n' || okeeper =~ '\n' || getreg('"') =~ '\n'
+ call s:reindent()
+ endif
+ if getline('.') =~ '^\s\+$' && keeper =~ '^\s*\n'
+ silent norm! cc
+ endif
+ call setreg('"',removed,regtype)
+ let s:lastdel = removed
+ let &clipboard = cb_save
+ if newchar == ""
+ silent! call repeat#set("\<Plug>Dsurround".char,scount)
+ else
+ silent! call repeat#set("\<Plug>Csurround".char.newchar,scount)
+ endif
+endfunction " }}}1
+
+function! s:changesurround() " {{{1
+ let a = s:inputtarget()
+ if a == ""
+ return s:beep()
+ endif
+ let b = s:inputreplacement()
+ if b == ""
+ return s:beep()
+ endif
+ call s:dosurround(a,b)
+endfunction " }}}1
+
+function! s:opfunc(type,...) " {{{1
+ let char = s:inputreplacement()
+ if char == ""
+ return s:beep()
+ endif
+ let reg = '"'
+ let sel_save = &selection
+ let &selection = "inclusive"
+ let cb_save = &clipboard
+ set clipboard-=unnamed
+ let reg_save = getreg(reg)
+ let reg_type = getregtype(reg)
+ "call setreg(reg,"\n","c")
+ let type = a:type
+ if a:type == "char"
+ silent exe 'norm! v`[o`]"'.reg.'y'
+ let type = 'v'
+ elseif a:type == "line"
+ silent exe 'norm! `[V`]"'.reg.'y'
+ let type = 'V'
+ elseif a:type ==# "v" || a:type ==# "V" || a:type ==# "\<C-V>"
+ silent exe 'norm! gv"'.reg.'y'
+ elseif a:type =~ '^\d\+$'
+ let type = 'v'
+ silent exe 'norm! ^v'.a:type.'$h"'.reg.'y'
+ if mode() == 'v'
+ norm! v
+ return s:beep()
+ endif
+ else
+ let &selection = sel_save
+ let &clipboard = cb_save
+ return s:beep()
+ endif
+ let keeper = getreg(reg)
+ if type == "v" && a:type != "v"
+ let append = matchstr(keeper,'\_s\@<!\s*$')
+ let keeper = substitute(keeper,'\_s\@<!\s*$','','')
+ endif
+ call setreg(reg,keeper,type)
+ call s:wrapreg(reg,char,a:0)
+ if type == "v" && a:type != "v" && append != ""
+ call setreg(reg,append,"ac")
+ endif
+ silent exe 'norm! gv'.(reg == '"' ? '' : '"' . reg).'p`['
+ if type == 'V' || (getreg(reg) =~ '\n' && type == 'v')
+ call s:reindent()
+ endif
+ call setreg(reg,reg_save,reg_type)
+ let &selection = sel_save
+ let &clipboard = cb_save
+ if a:type =~ '^\d\+$'
+ silent! call repeat#set("\<Plug>Y".(a:0 ? "S" : "s")."surround".char,a:type)
+ endif
+endfunction
+
+function! s:opfunc2(arg)
+ call s:opfunc(a:arg,1)
+endfunction " }}}1
+
+function! s:closematch(str) " {{{1
+ " Close an open (, {, [, or < on the command line.
+ let tail = matchstr(a:str,'.[^\[\](){}<>]*$')
+ if tail =~ '^\[.\+'
+ return "]"
+ elseif tail =~ '^(.\+'
+ return ")"
+ elseif tail =~ '^{.\+'
+ return "}"
+ elseif tail =~ '^<.+'
+ return ">"
+ else
+ return ""
+ endif
+endfunction " }}}1
+
+nnoremap <silent> <Plug>Dsurround :<C-U>call <SID>dosurround(<SID>inputtarget())<CR>
+nnoremap <silent> <Plug>Csurround :<C-U>call <SID>changesurround()<CR>
+nnoremap <silent> <Plug>Yssurround :<C-U>call <SID>opfunc(v:count1)<CR>
+nnoremap <silent> <Plug>YSsurround :<C-U>call <SID>opfunc2(v:count1)<CR>
+" <C-U> discards the numerical argument but there's not much we can do with it
+nnoremap <silent> <Plug>Ysurround :<C-U>set opfunc=<SID>opfunc<CR>g@
+nnoremap <silent> <Plug>YSurround :<C-U>set opfunc=<SID>opfunc2<CR>g@
+vnoremap <silent> <Plug>Vsurround :<C-U>call <SID>opfunc(visualmode())<CR>
+vnoremap <silent> <Plug>VSurround :<C-U>call <SID>opfunc2(visualmode())<CR>
+inoremap <silent> <Plug>Isurround <C-R>=<SID>insert()<CR>
+inoremap <silent> <Plug>ISurround <C-R>=<SID>insert(1)<CR>
+
+if !exists("g:surround_no_mappings") || ! g:surround_no_mappings
+ nmap ds <Plug>Dsurround
+ nmap cs <Plug>Csurround
+ nmap ys <Plug>Ysurround
+ nmap yS <Plug>YSurround
+ nmap yss <Plug>Yssurround
+ nmap ySs <Plug>YSsurround
+ nmap ySS <Plug>YSsurround
+ if !hasmapto("<Plug>Vsurround","v")
+ if exists(":xmap")
+ xmap s <Plug>Vsurround
+ else
+ vmap s <Plug>Vsurround
+ endif
+ endif
+ if !hasmapto("<Plug>VSurround","v")
+ if exists(":xmap")
+ xmap S <Plug>VSurround
+ else
+ vmap S <Plug>VSurround
+ endif
+ endif
+ if !hasmapto("<Plug>Isurround","i") && "" == mapcheck("<C-S>","i")
+ imap <C-S> <Plug>Isurround
+ endif
+ imap <C-G>s <Plug>Isurround
+ imap <C-G>S <Plug>ISurround
+ "Implemented internally instead
+ "imap <C-S><C-S> <Plug>ISurround
+endif
+
+let &cpo = s:cpo_save
+
+" vim:set ft=vim sw=4 sts=4 et:
--- /dev/null
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+" svndiff (C) 2007 Ico Doornekamp
+"
+" 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.
+"
+" This program is distributed in the hope that it will be useful, but WITHOUT
+" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+" more details.
+"
+" Introduction
+" ------------
+"
+" NOTE: This plugin is unix-only!
+"
+" An small vim 7.0 plugin for showing svn diff information in a file while
+" editing. This plugin runs a diff between the current buffer and the original
+" subversion file, and shows coloured signs indicating where the buffer
+" differs from the original file from the subversion repository. The original
+" text is not shown, only signs are used to indicate where changes were made.
+"
+" The following symbols and syntax highlight groups are used for the signs:
+"
+" > DiffAdd: Newly added lines. (default=blue)
+"
+" ! DiffChange: Lines which are changed from the original. (default=cyan)
+"
+" < DiffDel: Applied to the lines directly above and below a deleted block
+" (default=magenta)
+" Usage
+" -----
+"
+" The plugin defines one function: Svndiff(). This function figures out the
+" difference between the current buffer and it's subversion original, and adds
+" the signs at the places where the buffer differs from the original file from
+" subversion. You'll need to call this function after making changes to update
+" the highlighting.
+"
+" The function takes one argument specifying an additional action to perform:
+"
+" "prev" : jump to the previous different block
+" "next" : jump to the next different block
+" "clear" : clean up all signs
+"
+" You might want to map some keys to run the Svndiff function. For
+" example, add to your .vimrc:
+"
+" noremap <F3> :call Svndiff("prev")<CR>
+" noremap <F4> :call Svndiff("next")<CR>
+" noremap <F5> :call Svndiff("clear")<CR>
+"
+"
+" Configuration
+" -------------
+"
+" The following configuration variables are availabe:
+"
+" * g:svndiff_autoupdate
+"
+" If this variable is defined, svndiff will automatically update the signs
+" when the user stops typing for a short while, and when leaving insert
+" mode. This might slow things down on large files, so use with caution.
+" The vim variable 'updatetime' can be used to set the auto-update intervar,
+" but not that changing this variable other effects as well. (refer to the
+" vim docs for more info)
+" To use, add to your .vimrc:
+"
+" let g:svndiff_autoupdate = 1
+"
+" * g:svndiff_one_sign_delete
+"
+" Normally, two 'delete' signs are placed around the location where
+" text was deleted. When this variable is defined, only one sign is
+" placed, above the location of the deleted text.
+" To use, add to your .vimrc:
+"
+" let g:svndiff_one_sign_delete = 1
+"
+" Colors
+" ------
+"
+" Personally, I find the following colours more intuitive for diff colours:
+" red=deleted, green=added, yellow=changed. If you want to use these colours,
+" try adding the following lines to your .vimrc
+"
+" hi DiffAdd ctermfg=0 ctermbg=2 guibg='green'
+" hi DiffDelete ctermfg=0 ctermbg=1 guibg='red'
+" hi DiffChange ctermfg=0 ctermbg=3 guibg='yellow'
+"
+" Changelog
+" ---------
+"
+" 1.0 2007-04-02 Initial version
+"
+" 1.1 2007-04-02 Added goto prev/next diffblock commands
+"
+" 1.2 2007-06-14 Updated diff arguments from -u0 (obsolete) to -U0
+"
+" 2.0 2007-08-16 Changed from syntax highlighting to using signs, thanks
+" to Noah Spurrier for the idea. NOTE: the name of the
+" function changed from Svndiff_show() to Svndiff(), so
+" you might need to update your .vimrc mappings!
+"
+" 3.0 2008-02-02 Redesign with some ideas from Jan Bezdekovsky. The
+" diff is only updated when the buffer actually changes,
+" cleanup of signs is now done properly and some info
+" about each diff block is printed in the status line.
+"
+" 3.1 2008-02-04 Fixed bug that broke plugin in non-english locales, thanks
+" to Bernhard Walle for the patch
+"
+" 3.2 2008-02-27 The latest rewrite broke vim 6 compatiblity. The plugin
+" is now simply disabled for older vim versions to avoid
+" a lot of warnings when loading.
+"
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+if v:version < 700
+ finish
+endif
+
+
+let s:sign_base = 200000 " Base for our sign id's, hoping to avoid colisions
+let s:is_active = {} " dictionary with buffer names that have svndiff active
+let s:diff_signs = {} " dict with list of ids of all signs, per file
+let s:diff_blocks = {} " dict with list of ids of first line of each diff block, per file
+let s:changedtick = {} " dict with changedticks of each buffer since last invocation
+
+"
+" Do the diff and update signs.
+"
+
+function s:Svndiff_update(...)
+
+ let fname = bufname("%")
+
+ if ! exists("s:is_active[fname]")
+ return 0
+ end
+
+ " Check if this file is managed by subversion, exit otherwise
+
+ let info = system("LANG=C svn info " . fname)
+ if match(info, "Path") == -1
+ echom "Svndiff: Warning, file " . fname . " is not managed by subversion, or error running svn."
+ unlet s:is_active[fname]
+ return 0
+ end
+
+ " Check if the changedticks changed since the last invocation of this
+ " function. If nothing changed, there's no need to update the signs.
+
+ if exists("s:changedtick[fname]") && s:changedtick[fname] == b:changedtick
+ return 1
+ end
+ let s:changedtick[fname] = b:changedtick
+
+ " The diff has changed since the last time, so we need to update the signs.
+ " This is where the magic happens: pipe the current buffer contents to a
+ " shell command calculating the diff in a friendly parsable format.
+
+ let contents = join(getbufline("%", 1, "$"), "\n")
+ let diff = system("diff -U0 <(svn cat " . fname . ") <(cat;echo)", contents)
+
+ " clear the old signs
+
+ call s:Svndiff_clear()
+
+ " Parse the output of the diff command and put signs at changed, added and
+ " removed lines
+
+ for line in split(diff, '\n')
+
+ let part = matchlist(line, '@@ -\([0-9]*\),*\([0-9]*\) +\([0-9]*\),*\([0-9]*\) @@')
+
+ if ! empty(part)
+ let old_from = part[1]
+ let old_count = part[2] == '' ? 1 : part[2]
+ let new_from = part[3]
+ let new_count = part[4] == '' ? 1 : part[4]
+
+ " Figure out if text was added, removed or changed.
+
+ if old_count == 0
+ let from = new_from
+ let to = new_from + new_count - 1
+ let name = 'svndiff_add'
+ let info = new_count . " lines added"
+ elseif new_count == 0
+ let from = new_from
+ let to = new_from
+ let name = 'svndiff_delete'
+ let info = old_count . " lines deleted"
+ if ! exists("g:svndiff_one_sign_delete")
+ let to += 1
+ endif
+ else
+ let from = new_from
+ let to = new_from + new_count - 1
+ let name = 'svndiff_change'
+ let info = new_count . " lines changed"
+ endif
+
+ let id = from + s:sign_base
+ let s:diff_blocks[fname] += [{ 'id': id, 'info': info }]
+
+ " Add signs to mark the changed lines
+
+ let line = from
+ while line <= to
+ let id = line + s:sign_base
+ exec 'sign place ' . id . ' line=' . line . ' name=' . name . ' file=' . fname
+ let s:diff_signs[fname] += [id]
+ let line = line + 1
+ endwhile
+
+ endif
+ endfor
+
+endfunction
+
+
+
+"
+" Remove all signs we placed earlier
+"
+
+function s:Svndiff_clear(...)
+ let fname = bufname("%")
+ if exists("s:diff_signs[fname]")
+ for id in s:diff_signs[fname]
+ exec 'sign unplace ' . id . ' file=' . fname
+ endfor
+ end
+ let s:diff_blocks[fname] = []
+ let s:diff_signs[fname] = []
+endfunction
+
+
+"
+" Jump to previous diff block sign above the current line
+"
+
+function s:Svndiff_prev(...)
+ let fname = bufname("%")
+ let diff_blocks_reversed = reverse(copy(s:diff_blocks[fname]))
+ for block in diff_blocks_reversed
+ let line = block.id - s:sign_base
+ if line < line(".")
+ call setpos(".", [ 0, line, 1, 0 ])
+ echom 'svndiff: ' . block.info
+ return
+ endif
+ endfor
+ echom 'svndiff: no more diff blocks above cursor'
+endfunction
+
+
+"
+" Jump to next diff block sign below the current line
+"
+
+function s:Svndiff_next(...)
+ let fname = bufname("%")
+ for block in s:diff_blocks[fname]
+ let line = block.id - s:sign_base
+ if line > line(".")
+ call setpos(".", [ 0, line, 1, 0 ])
+ echom 'svndiff: ' . block.info
+ return
+ endif
+ endfor
+ echom 'svndiff: no more diff blocks below cursor'
+endfunction
+
+
+"
+" Wrapper function: Takes one argument, which is the action to perform:
+" {next|prev|clear}
+"
+
+function Svndiff(...)
+
+ let cmd = exists("a:1") ? a:1 : ''
+ let fname = bufname("%")
+ if fname == ""
+ echom "Buffer has no file name, can not do a svn diff"
+ return
+ endif
+
+ if cmd == 'clear'
+ let s:changedtick[fname] = 0
+ if exists("s:is_active[fname]")
+ unlet s:is_active[fname]
+ endif
+ call s:Svndiff_clear()
+ end
+
+ if cmd == 'prev'
+ let s:is_active[fname] = 1
+ let ok = s:Svndiff_update()
+ if ok
+ call s:Svndiff_prev()
+ endif
+ endif
+
+ if cmd == 'next'
+ let s:is_active[fname] = 1
+ let ok = s:Svndiff_update()
+ if ok
+ call s:Svndiff_next()
+ endif
+ endif
+
+endfunction
+
+
+" Define sign characters and colors
+
+sign define svndiff_add text=> texthl=diffAdd
+sign define svndiff_delete text=< texthl=diffDelete
+sign define svndiff_change text=! texthl=diffChange
+
+
+" Define autocmds if autoupdate is enabled
+
+if exists("g:svndiff_autoupdate")
+ autocmd CursorHold,CursorHoldI * call s:Svndiff_update()
+ autocmd InsertLeave * call s:Svndiff_update()
+endif
+
+" vi: ts=2 sw=2
+
--- /dev/null
+" vim600: set foldmethod=marker:
+"
+" Vim plugin to assist in working with files under control of CVS or SVN.
+"
+" Version: Beta 26
+" Maintainer: Bob Hiestand <
[email protected]>
+" License:
+" Copyright (c) 2008 Bob Hiestand
+"
+" 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.
+"
+" Section: Documentation {{{1
+"
+" Provides functions to invoke various source control commands on the current
+" file (either the current buffer, or, in the case of an directory buffer, the
+" directory and all subdirectories associated with the current buffer). The
+" output of the commands is captured in a new scratch window.
+"
+" This plugin needs additional extension plugins, each specific to a source
+" control system, to function. Those plugins should be placed in a
+" subdirectory of the standard plugin directory named 'vcscommand'. Several
+" options include the name of the version control system in the option name.
+" Such options use the placeholder text '{VCSType}', which would be replaced
+" in actual usage with 'CVS' or 'SVN', for instance.
+"
+" Command documentation {{{2
+"
+" VCSAdd Adds the current file to source control.
+"
+" VCSAnnotate Displays the current file with each line annotated with the
+" version in which it was most recently changed. If an
+" argument is given, the argument is used as a revision
+" number to display. If not given an argument, it uses the
+" most recent version of the file on the current branch.
+" Additionally, if the current buffer is a VCSAnnotate buffer
+" already, the version number on the current line is used.
+"
+" VCSBlame Alias for 'VCSAnnotate'.
+"
+" VCSCommit[!] Commits changes to the current file to source control.
+"
+" If called with arguments, the arguments are the log message.
+"
+" If '!' is used, an empty log message is committed.
+"
+" If called with no arguments, this is a two-step command.
+" The first step opens a buffer to accept a log message.
+" When that buffer is written, it is automatically closed and
+" the file is committed using the information from that log
+" message. The commit can be abandoned if the log message
+" buffer is deleted or wiped before being written.
+"
+" VCSDelete Deletes the current file and removes it from source control.
+"
+" VCSDiff With no arguments, this displays the differences between
+" the current file and its parent version under source
+" control in a new scratch buffer.
+"
+" With one argument, the diff is performed on the
+" current file against the specified revision.
+"
+" With two arguments, the diff is performed between the
+" specified revisions of the current file.
+"
+" This command uses the 'VCSCommand{VCSType}DiffOpt' variable
+" to specify diff options. If that variable does not exist,
+" a plugin-specific default is used. If you wish to have no
+" options, then set it to the empty string.
+"
+" VCSGotoOriginal Jumps to the source buffer if the current buffer is a VCS
+" scratch buffer. If VCSGotoOriginal[!] is used, remove all
+" VCS scratch buffers associated with the original file.
+"
+" VCSInfo Displays extended information about the current file in a
+" new scratch buffer.
+"
+" VCSLock Locks the current file in order to prevent other users from
+" concurrently modifying it. The exact semantics of this
+" command depend on the underlying VCS.
+"
+" VCSLog Displays the version history of the current file in a new
+" scratch buffer.
+"
+" VCSRemove Alias for 'VCSDelete'.
+"
+" VCSRevert Replaces the modified version of the current file with the
+" most recent version from the repository.
+"
+" VCSReview Displays a particular version of the current file in a new
+" scratch buffer. If no argument is given, the most recent
+" version of the file on the current branch is retrieved.
+"
+" VCSStatus Displays versioning information about the current file in a
+" new scratch buffer.
+"
+" VCSUnlock Unlocks the current file in order to allow other users from
+" concurrently modifying it. The exact semantics of this
+" command depend on the underlying VCS.
+"
+" VCSUpdate Updates the current file with any relevant changes from the
+" repository.
+"
+" VCSVimDiff Uses vimdiff to display differences between versions of the
+" current file.
+"
+" If no revision is specified, the most recent version of the
+" file on the current branch is used. With one argument,
+" that argument is used as the revision as above. With two
+" arguments, the differences between the two revisions is
+" displayed using vimdiff.
+"
+" With either zero or one argument, the original buffer is
+" used to perform the vimdiff. When the scratch buffer is
+" closed, the original buffer will be returned to normal
+" mode.
+"
+" Once vimdiff mode is started using the above methods,
+" additional vimdiff buffers may be added by passing a single
+" version argument to the command. There may be up to 4
+" vimdiff buffers total.
+"
+" Using the 2-argument form of the command resets the vimdiff
+" to only those 2 versions. Additionally, invoking the
+" command on a different file will close the previous vimdiff
+" buffers.
+"
+" Mapping documentation: {{{2
+"
+" By default, a mapping is defined for each command. User-provided mappings
+" can be used instead by mapping to <Plug>CommandName, for instance:
+"
+" nmap ,ca <Plug>VCSAdd
+"
+" The default mappings are as follow:
+"
+" <Leader>ca VCSAdd
+" <Leader>cn VCSAnnotate
+" <Leader>cc VCSCommit
+" <Leader>cD VCSDelete
+" <Leader>cd VCSDiff
+" <Leader>cg VCSGotoOriginal
+" <Leader>cG VCSGotoOriginal!
+" <Leader>ci VCSInfo
+" <Leader>cl VCSLog
+" <Leader>cL VCSLock
+" <Leader>cr VCSReview
+" <Leader>cs VCSStatus
+" <Leader>cu VCSUpdate
+" <Leader>cU VCSUnlock
+" <Leader>cv VCSVimDiff
+"
+" Options documentation: {{{2
+"
+" Several variables are checked by the script to determine behavior as follow:
+"
+" VCSCommandCommitOnWrite
+" This variable, if set to a non-zero value, causes the pending commit to
+" take place immediately as soon as the log message buffer is written. If
+" set to zero, only the VCSCommit mapping will cause the pending commit to
+" occur. If not set, it defaults to 1.
+"
+" VCSCommandDeleteOnHide
+" This variable, if set to a non-zero value, causes the temporary VCS result
+" buffers to automatically delete themselves when hidden.
+"
+" VCSCommand{VCSType}DiffOpt
+" This variable, if set, determines the options passed to the diff command
+" of the underlying VCS. Each VCS plugin defines a default value.
+"
+" VCSCommandDiffSplit
+" This variable overrides the VCSCommandSplit variable, but only for buffers
+" created with VCSVimDiff.
+"
+" VCSCommandDisableMappings
+" This variable, if set to a non-zero value, prevents the default command
+" mappings from being set.
+"
+" VCSCommandDisableExtensionMappings
+" This variable, if set to a non-zero value, prevents the default command
+" mappings from being set for commands specific to an individual VCS.
+"
+" VCSCommandEdit
+" This variable controls whether to split the current window to display a
+" scratch buffer ('split'), or to display it in the current buffer ('edit').
+" If not set, it defaults to 'split'.
+"
+" VCSCommandEnableBufferSetup
+" This variable, if set to a non-zero value, activates VCS buffer management
+" mode. This mode means that the buffer variable 'VCSRevision' is set if
+" the file is VCS-controlled. This is useful for displaying version
+" information in the status bar. Additional options may be set by
+" individual VCS plugins.
+"
+" VCSCommandResultBufferNameExtension
+" This variable, if set to a non-blank value, is appended to the name of the
+" VCS command output buffers. For example, '.vcs'. Using this option may
+" help avoid problems caused by autocommands dependent on file extension.
+"
+" VCSCommandResultBufferNameFunction
+" This variable, if set, specifies a custom function for naming VCS command
+" output buffers. This function will be passed the following arguments:
+"
+" command - name of the VCS command being executed (such as 'Log' or
+" 'Diff').
+"
+" originalBuffer - buffer number of the source file.
+"
+" vcsType - type of VCS controlling this file (such as 'CVS' or 'SVN').
+"
+" statusText - extra text associated with the VCS action (such as version
+" numbers).
+"
+" VCSCommandSplit
+" This variable controls the orientation of the various window splits that
+" may occur (such as with VCSVimDiff, when using a VCS command on a VCS
+" command buffer, or when the 'VCSCommandEdit' variable is set to 'split'.
+" If set to 'horizontal', the resulting windows will be on stacked on top of
+" one another. If set to 'vertical', the resulting windows will be
+" side-by-side. If not set, it defaults to 'horizontal' for all but
+" VCSVimDiff windows.
+"
+" Event documentation {{{2
+" For additional customization, VCSCommand.vim uses User event autocommand
+" hooks. Each event is in the VCSCommand group, and different patterns
+" match the various hooks.
+"
+" For instance, the following could be added to the vimrc to provide a 'q'
+" mapping to quit a VCS scratch buffer:
+"
+" augroup VCSCommand
+" au VCSCommand User VCSBufferCreated silent! nmap <unique> <buffer> q :bwipeout<cr>
+" augroup END
+"
+" The following hooks are available:
+"
+" VCSBufferCreated This event is fired just after a VCS command
+" output buffer is created. It is executed
+" within the context of the new buffer.
+"
+" VCSBufferSetup This event is fired just after VCS buffer setup
+" occurs, if enabled.
+"
+" VCSPluginInit This event is fired when the VCSCommand plugin
+" first loads.
+"
+" VCSPluginFinish This event is fired just after the VCSCommand
+" plugin loads.
+"
+" VCSVimDiffFinish This event is fired just after the VCSVimDiff
+" command executes to allow customization of,
+" for instance, window placement and focus.
+"
+" Section: Plugin header {{{1
+
+" loaded_VCSCommand is set to 1 when the initialization begins, and 2 when it
+" completes. This allows various actions to only be taken by functions after
+" system initialization.
+
+if exists('loaded_VCSCommand')
+ finish
+endif
+let loaded_VCSCommand = 1
+
+if v:version < 700
+ echohl WarningMsg|echomsg 'VCSCommand requires at least VIM 7.0'|echohl None
+ finish
+endif
+
+let s:save_cpo=&cpo
+set cpo&vim
+
+" Section: Event group setup {{{1
+
+augroup VCSCommand
+augroup END
+
+augroup VCSCommandCommit
+augroup END
+
+" Section: Plugin initialization {{{1
+silent do VCSCommand User VCSPluginInit
+
+" Section: Constants declaration {{{1
+
+let g:VCSCOMMAND_IDENTIFY_EXACT = 1
+let g:VCSCOMMAND_IDENTIFY_INEXACT = -1
+
+" Section: Script variable initialization {{{1
+
+" plugin-specific information: {vcs -> [script, {command -> function}, {key -> mapping}]}
+let s:plugins = {}
+
+" temporary values of overridden configuration variables
+let s:optionOverrides = {}
+
+" state flag used to vary behavior of certain automated actions
+let s:isEditFileRunning = 0
+
+" commands needed to restore diff buffers to their original state
+unlet! s:vimDiffRestoreCmd
+
+" original buffer currently reflected in vimdiff windows
+unlet! s:vimDiffSourceBuffer
+
+"
+unlet! s:vimDiffScratchList
+
+" Section: Utility functions {{{1
+
+" Function: s:ReportError(mapping) {{{2
+" Displays the given error in a consistent faction. This is intended to be
+" invoked from a catch statement.
+
+function! s:ReportError(error)
+ echohl WarningMsg|echomsg 'VCSCommand: ' . a:error|echohl None
+endfunction
+
+" Function: s:ExecuteExtensionMapping(mapping) {{{2
+" Invokes the appropriate extension mapping depending on the type of the
+" current buffer.
+
+function! s:ExecuteExtensionMapping(mapping)
+ let buffer = bufnr('%')
+ let vcsType = VCSCommandGetVCSType(buffer)
+ if !has_key(s:plugins, vcsType)
+ throw 'Unknown VCS type: ' . vcsType
+ endif
+ if !has_key(s:plugins[vcsType][2], a:mapping)
+ throw 'This extended mapping is not defined for ' . vcsType
+ endif
+ silent execute 'normal' ':' . s:plugins[vcsType][2][a:mapping] . "\<CR>"
+endfunction
+
+" Function: s:ExecuteVCSCommand(command, argList) {{{2
+" Calls the indicated plugin-specific VCS command on the current buffer.
+" Returns: buffer number of resulting output scratch buffer, or -1 if an error
+" occurs.
+
+function! s:ExecuteVCSCommand(command, argList)
+ try
+ let buffer = bufnr('%')
+
+ let vcsType = VCSCommandGetVCSType(buffer)
+ if !has_key(s:plugins, vcsType)
+ throw 'Unknown VCS type: ' . vcsType
+ endif
+
+ let originalBuffer = VCSCommandGetOriginalBuffer(buffer)
+ let bufferName = bufname(originalBuffer)
+
+ " It is already known that the directory is under VCS control. No further
+ " checks are needed. Otherwise, perform some basic sanity checks to avoid
+ " VCS-specific error messages from confusing things.
+ if !isdirectory(bufferName)
+ if !filereadable(bufferName)
+ throw 'No such file ' . bufferName
+ endif
+ endif
+
+ let functionMap = s:plugins[vcsType][1]
+ if !has_key(functionMap, a:command)
+ throw 'Command ''' . a:command . ''' not implemented for ' . vcsType
+ endif
+ return functionMap[a:command](a:argList)
+ catch
+ call s:ReportError(v:exception)
+ return -1
+ endtry
+endfunction
+
+" Function: s:GenerateResultBufferName(command, originalBuffer, vcsType, statusText) {{{2
+" Default method of generating the name for VCS result buffers. This can be
+" overridden with the VCSResultBufferNameFunction variable.
+
+function! s:GenerateResultBufferName(command, originalBuffer, vcsType, statusText)
+ let fileName = bufname(a:originalBuffer)
+ let bufferName = a:vcsType . ' ' . a:command
+ if strlen(a:statusText) > 0
+ let bufferName .= ' ' . a:statusText
+ endif
+ let bufferName .= ' ' . fileName
+ let counter = 0
+ let versionedBufferName = bufferName
+ while buflisted(versionedBufferName)
+ let counter += 1
+ let versionedBufferName = bufferName . ' (' . counter . ')'
+ endwhile
+ return versionedBufferName
+endfunction
+
+" Function: s:GenerateResultBufferNameWithExtension(command, originalBuffer, vcsType, statusText) {{{2
+" Method of generating the name for VCS result buffers that uses the original
+" file name with the VCS type and command appended as extensions.
+
+function! s:GenerateResultBufferNameWithExtension(command, originalBuffer, vcsType, statusText)
+ let fileName = bufname(a:originalBuffer)
+ let bufferName = a:vcsType . ' ' . a:command
+ if strlen(a:statusText) > 0
+ let bufferName .= ' ' . a:statusText
+ endif
+ let bufferName .= ' ' . fileName . VCSCommandGetOption('VCSCommandResultBufferNameExtension', '.vcs')
+ let counter = 0
+ let versionedBufferName = bufferName
+ while buflisted(versionedBufferName)
+ let counter += 1
+ let versionedBufferName = '(' . counter . ') ' . bufferName
+ endwhile
+ return versionedBufferName
+endfunction
+
+" Function: s:EditFile(command, originalBuffer, statusText) {{{2
+" Creates a new buffer of the given name and associates it with the given
+" original buffer.
+
+function! s:EditFile(command, originalBuffer, statusText)
+ let vcsType = getbufvar(a:originalBuffer, 'VCSCommandVCSType')
+
+ let nameExtension = VCSCommandGetOption('VCSCommandResultBufferNameExtension', '')
+ if nameExtension == ''
+ let nameFunction = VCSCommandGetOption('VCSCommandResultBufferNameFunction', 's:GenerateResultBufferName')
+ else
+ let nameFunction = VCSCommandGetOption('VCSCommandResultBufferNameFunction', 's:GenerateResultBufferNameWithExtension')
+ endif
+
+ let resultBufferName = call(nameFunction, [a:command, a:originalBuffer, vcsType, a:statusText])
+
+ " Protect against useless buffer set-up
+ let s:isEditFileRunning += 1
+ try
+ let editCommand = VCSCommandGetOption('VCSCommandEdit', 'split')
+ if editCommand == 'split'
+ if VCSCommandGetOption('VCSCommandSplit', 'horizontal') == 'horizontal'
+ rightbelow split
+ else
+ vert rightbelow split
+ endif
+ endif
+
+ enew
+
+ let b:VCSCommandCommand = a:command
+ let b:VCSCommandOriginalBuffer = a:originalBuffer
+ let b:VCSCommandSourceFile = bufname(a:originalBuffer)
+ let b:VCSCommandVCSType = vcsType
+
+ setlocal buftype=nofile
+ setlocal noswapfile
+ let &filetype = vcsType . a:command
+
+ if a:statusText != ''
+ let b:VCSCommandStatusText = a:statusText
+ endif
+
+ if VCSCommandGetOption('VCSCommandDeleteOnHide', 0)
+ setlocal bufhidden=delete
+ endif
+ silent noautocmd file `=resultBufferName`
+ finally
+ let s:isEditFileRunning -= 1
+ endtry
+endfunction
+
+" Function: s:SetupBuffer() {{{2
+" Attempts to set the b:VCSCommandBufferInfo variable
+
+function! s:SetupBuffer()
+ if (exists('b:VCSCommandBufferSetup') && b:VCSCommandBufferSetup)
+ " This buffer is already set up.
+ return
+ endif
+
+ if !isdirectory(@%) && (strlen(&buftype) > 0 || !filereadable(@%))
+ " No special status for special buffers other than directory buffers.
+ return
+ endif
+
+ if !VCSCommandGetOption('VCSCommandEnableBufferSetup', 0) || s:isEditFileRunning > 0
+ unlet! b:VCSCommandBufferSetup
+ return
+ endif
+
+ try
+ let vcsType = VCSCommandGetVCSType(bufnr('%'))
+ let b:VCSCommandBufferInfo = s:plugins[vcsType][1].GetBufferInfo()
+ silent do VCSCommand User VCSBufferSetup
+ catch /No suitable plugin/
+ " This is not a VCS-controlled file.
+ let b:VCSCommandBufferInfo = []
+ endtry
+
+ let b:VCSCommandBufferSetup = 1
+endfunction
+
+" Function: s:MarkOrigBufferForSetup(buffer) {{{2
+" Resets the buffer setup state of the original buffer for a given VCS scratch
+" buffer.
+" Returns: The VCS buffer number in a passthrough mode.
+
+function! s:MarkOrigBufferForSetup(buffer)
+ checktime
+ if a:buffer > 0
+ let origBuffer = VCSCommandGetOriginalBuffer(a:buffer)
+ " This should never not work, but I'm paranoid
+ if origBuffer != a:buffer
+ call setbufvar(origBuffer, 'VCSCommandBufferSetup', 0)
+ endif
+ endif
+ return a:buffer
+endfunction
+
+" Function: s:OverrideOption(option, [value]) {{{2
+" Provides a temporary override for the given VCS option. If no value is
+" passed, the override is disabled.
+
+function! s:OverrideOption(option, ...)
+ if a:0 == 0
+ call remove(s:optionOverrides[a:option], -1)
+ else
+ if !has_key(s:optionOverrides, a:option)
+ let s:optionOverrides[a:option] = []
+ endif
+ call add(s:optionOverrides[a:option], a:1)
+ endif
+endfunction
+
+" Function: s:WipeoutCommandBuffers() {{{2
+" Clears all current VCS output buffers of the specified type for a given source.
+
+function! s:WipeoutCommandBuffers(originalBuffer, VCSCommand)
+ let buffer = 1
+ while buffer <= bufnr('$')
+ if getbufvar(buffer, 'VCSCommandOriginalBuffer') == a:originalBuffer
+ if getbufvar(buffer, 'VCSCommandCommand') == a:VCSCommand
+ execute 'bw' buffer
+ endif
+ endif
+ let buffer = buffer + 1
+ endwhile
+endfunction
+
+" Function: s:VimDiffRestore(vimDiffBuff) {{{2
+" Checks whether the given buffer is one whose deletion should trigger
+" restoration of an original buffer after it was diffed. If so, it executes
+" the appropriate setting command stored with that original buffer.
+
+function! s:VimDiffRestore(vimDiffBuff)
+ let s:isEditFileRunning += 1
+ try
+ if exists('s:vimDiffSourceBuffer')
+ if a:vimDiffBuff == s:vimDiffSourceBuffer
+ " Original file is being removed.
+ unlet! s:vimDiffSourceBuffer
+ unlet! s:vimDiffRestoreCmd
+ unlet! s:vimDiffScratchList
+ else
+ let index = index(s:vimDiffScratchList, a:vimDiffBuff)
+ if index >= 0
+ call remove(s:vimDiffScratchList, index)
+ if len(s:vimDiffScratchList) == 0
+ if exists('s:vimDiffRestoreCmd')
+ " All scratch buffers are gone, reset the original.
+ " Only restore if the source buffer is still in Diff mode
+
+ let sourceWinNR = bufwinnr(s:vimDiffSourceBuffer)
+ if sourceWinNR != -1
+ " The buffer is visible in at least one window
+ let currentWinNR = winnr()
+ while winbufnr(sourceWinNR) != -1
+ if winbufnr(sourceWinNR) == s:vimDiffSourceBuffer
+ execute sourceWinNR . 'wincmd w'
+ if getwinvar(0, '&diff')
+ execute s:vimDiffRestoreCmd
+ endif
+ endif
+ let sourceWinNR = sourceWinNR + 1
+ endwhile
+ execute currentWinNR . 'wincmd w'
+ else
+ " The buffer is hidden. It must be visible in order to set the
+ " diff option.
+ let currentBufNR = bufnr('')
+ execute 'hide buffer' s:vimDiffSourceBuffer
+ if getwinvar(0, '&diff')
+ execute s:vimDiffRestoreCmd
+ endif
+ execute 'hide buffer' currentBufNR
+ endif
+
+ unlet s:vimDiffRestoreCmd
+ endif
+ " All buffers are gone.
+ unlet s:vimDiffSourceBuffer
+ unlet s:vimDiffScratchList
+ endif
+ endif
+ endif
+ endif
+ finally
+ let s:isEditFileRunning -= 1
+ endtry
+endfunction
+
+" Section: Generic VCS command functions {{{1
+
+" Function: s:VCSCommit() {{{2
+function! s:VCSCommit(bang, message)
+ try
+ let vcsType = VCSCommandGetVCSType(bufnr('%'))
+ if !has_key(s:plugins, vcsType)
+ throw 'Unknown VCS type: ' . vcsType
+ endif
+
+ let originalBuffer = VCSCommandGetOriginalBuffer(bufnr('%'))
+
+ " Handle the commit message being specified. If a message is supplied, it
+ " is used; if bang is supplied, an empty message is used; otherwise, the
+ " user is provided a buffer from which to edit the commit message.
+
+ if strlen(a:message) > 0 || a:bang == '!'
+ return s:VCSFinishCommit([a:message], originalBuffer)
+ endif
+
+ call s:EditFile('commitlog', originalBuffer, '')
+ setlocal ft=vcscommit
+
+ " Create a commit mapping.
+
+ nnoremap <silent> <buffer> <Plug>VCSCommit :call <SID>VCSFinishCommitWithBuffer()<CR>
+
+ silent 0put ='VCS: ----------------------------------------------------------------------'
+ silent put ='VCS: Please enter log message. Lines beginning with ''VCS:'' are removed automatically.'
+ silent put ='VCS: To finish the commit, Type <leader>cc (or your own <Plug>VCSCommit mapping)'
+
+ if VCSCommandGetOption('VCSCommandCommitOnWrite', 1) == 1
+ setlocal buftype=acwrite
+ au VCSCommandCommit BufWriteCmd <buffer> call s:VCSFinishCommitWithBuffer()
+ silent put ='VCS: or write this buffer'
+ endif
+
+ silent put ='VCS: ----------------------------------------------------------------------'
+ $
+ setlocal nomodified
+ catch
+ call s:ReportError(v:exception)
+ return -1
+ endtry
+endfunction
+
+" Function: s:VCSFinishCommitWithBuffer() {{{2
+" Wrapper for s:VCSFinishCommit which is called only from a commit log buffer
+" which removes all lines starting with 'VCS:'.
+
+function! s:VCSFinishCommitWithBuffer()
+ setlocal nomodified
+ let currentBuffer = bufnr('%')
+ let logMessageList = getbufline('%', 1, '$')
+ call filter(logMessageList, 'v:val !~ ''^\s*VCS:''')
+ let resultBuffer = s:VCSFinishCommit(logMessageList, b:VCSCommandOriginalBuffer)
+ if resultBuffer >= 0
+ execute 'bw' currentBuffer
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:VCSFinishCommit(logMessageList, originalBuffer) {{{2
+function! s:VCSFinishCommit(logMessageList, originalBuffer)
+ let shellSlashBak = &shellslash
+ try
+ set shellslash
+ let messageFileName = tempname()
+ call writefile(a:logMessageList, messageFileName)
+ try
+ let resultBuffer = s:ExecuteVCSCommand('Commit', [messageFileName])
+ if resultBuffer < 0
+ return resultBuffer
+ endif
+ return s:MarkOrigBufferForSetup(resultBuffer)
+ finally
+ call delete(messageFileName)
+ endtry
+ finally
+ let &shellslash = shellSlashBak
+ endtry
+endfunction
+
+" Function: s:VCSGotoOriginal(bang) {{{2
+function! s:VCSGotoOriginal(bang)
+ let originalBuffer = VCSCommandGetOriginalBuffer(bufnr('%'))
+ if originalBuffer > 0
+ let origWinNR = bufwinnr(originalBuffer)
+ if origWinNR == -1
+ execute 'buffer' originalBuffer
+ else
+ execute origWinNR . 'wincmd w'
+ endif
+ if a:bang == '!'
+ let buffnr = 1
+ let buffmaxnr = bufnr('$')
+ while buffnr <= buffmaxnr
+ if getbufvar(buffnr, 'VCSCommandOriginalBuffer') == originalBuffer
+ execute 'bw' buffnr
+ endif
+ let buffnr = buffnr + 1
+ endwhile
+ endif
+ endif
+endfunction
+
+" Function: s:VCSVimDiff(...) {{{2
+function! s:VCSVimDiff(...)
+ try
+ let vcsType = VCSCommandGetVCSType(bufnr('%'))
+ if !has_key(s:plugins, vcsType)
+ throw 'Unknown VCS type: ' . vcsType
+ endif
+ let originalBuffer = VCSCommandGetOriginalBuffer(bufnr('%'))
+ let s:isEditFileRunning = s:isEditFileRunning + 1
+ try
+ " If there's already a VimDiff'ed window, restore it.
+ " There may only be one VCSVimDiff original window at a time.
+
+ if exists('s:vimDiffSourceBuffer') && s:vimDiffSourceBuffer != originalBuffer
+ " Clear the existing vimdiff setup by removing the result buffers.
+ call s:WipeoutCommandBuffers(s:vimDiffSourceBuffer, 'vimdiff')
+ endif
+
+ " Split and diff
+ if(a:0 == 2)
+ " Reset the vimdiff system, as 2 explicit versions were provided.
+ if exists('s:vimDiffSourceBuffer')
+ call s:WipeoutCommandBuffers(s:vimDiffSourceBuffer, 'vimdiff')
+ endif
+ let resultBuffer = s:plugins[vcsType][1].Review([a:1])
+ if resultBuffer < 0
+ echomsg 'Can''t open revision ' . a:1
+ return resultBuffer
+ endif
+ let b:VCSCommandCommand = 'vimdiff'
+ diffthis
+ let s:vimDiffScratchList = [resultBuffer]
+ " If no split method is defined, cheat, and set it to vertical.
+ try
+ call s:OverrideOption('VCSCommandSplit', VCSCommandGetOption('VCSCommandDiffSplit', VCSCommandGetOption('VCSCommandSplit', 'vertical')))
+ let resultBuffer = s:plugins[vcsType][1].Review([a:2])
+ finally
+ call s:OverrideOption('VCSCommandSplit')
+ endtry
+ if resultBuffer < 0
+ echomsg 'Can''t open revision ' . a:1
+ return resultBuffer
+ endif
+ let b:VCSCommandCommand = 'vimdiff'
+ diffthis
+ let s:vimDiffScratchList += [resultBuffer]
+ else
+ " Add new buffer
+ call s:OverrideOption('VCSCommandEdit', 'split')
+ try
+ " Force splitting behavior, otherwise why use vimdiff?
+ call s:OverrideOption('VCSCommandSplit', VCSCommandGetOption('VCSCommandDiffSplit', VCSCommandGetOption('VCSCommandSplit', 'vertical')))
+ try
+ if(a:0 == 0)
+ let resultBuffer = s:plugins[vcsType][1].Review([])
+ else
+ let resultBuffer = s:plugins[vcsType][1].Review([a:1])
+ endif
+ finally
+ call s:OverrideOption('VCSCommandSplit')
+ endtry
+ finally
+ call s:OverrideOption('VCSCommandEdit')
+ endtry
+ if resultBuffer < 0
+ echomsg 'Can''t open current revision'
+ return resultBuffer
+ endif
+ let b:VCSCommandCommand = 'vimdiff'
+ diffthis
+
+ if !exists('s:vimDiffSourceBuffer')
+ " New instance of vimdiff.
+ let s:vimDiffScratchList = [resultBuffer]
+
+ " This could have been invoked on a VCS result buffer, not the
+ " original buffer.
+ wincmd W
+ execute 'buffer' originalBuffer
+ " Store info for later original buffer restore
+ let s:vimDiffRestoreCmd =
+ \ 'call setbufvar('.originalBuffer.', ''&diff'', '.getbufvar(originalBuffer, '&diff').')'
+ \ . '|call setbufvar('.originalBuffer.', ''&foldcolumn'', '.getbufvar(originalBuffer, '&foldcolumn').')'
+ \ . '|call setbufvar('.originalBuffer.', ''&foldenable'', '.getbufvar(originalBuffer, '&foldenable').')'
+ \ . '|call setbufvar('.originalBuffer.', ''&foldmethod'', '''.getbufvar(originalBuffer, '&foldmethod').''')'
+ \ . '|call setbufvar('.originalBuffer.', ''&foldlevel'', '''.getbufvar(originalBuffer, '&foldlevel').''')'
+ \ . '|call setbufvar('.originalBuffer.', ''&scrollbind'', '.getbufvar(originalBuffer, '&scrollbind').')'
+ \ . '|call setbufvar('.originalBuffer.', ''&wrap'', '.getbufvar(originalBuffer, '&wrap').')'
+ \ . '|if &foldmethod==''manual''|execute ''normal zE''|endif'
+ diffthis
+ wincmd w
+ else
+ " Adding a window to an existing vimdiff
+ let s:vimDiffScratchList += [resultBuffer]
+ endif
+ endif
+
+ let s:vimDiffSourceBuffer = originalBuffer
+
+ " Avoid executing the modeline in the current buffer after the autocommand.
+
+ let currentBuffer = bufnr('%')
+ let saveModeline = getbufvar(currentBuffer, '&modeline')
+ try
+ call setbufvar(currentBuffer, '&modeline', 0)
+ silent do VCSCommand User VCSVimDiffFinish
+ finally
+ call setbufvar(currentBuffer, '&modeline', saveModeline)
+ endtry
+ return resultBuffer
+ finally
+ let s:isEditFileRunning = s:isEditFileRunning - 1
+ endtry
+ catch
+ call s:ReportError(v:exception)
+ return -1
+ endtry
+endfunction
+
+" Section: Public functions {{{1
+
+" Function: VCSCommandGetVCSType() {{{2
+" Sets the b:VCSCommandVCSType variable in the given buffer to the
+" appropriate source control system name.
+"
+" This uses the Identify extension function to test the buffer. If the
+" Identify function returns VCSCOMMAND_IDENTIFY_EXACT, the match is considered
+" exact. If the Identify function returns VCSCOMMAND_IDENTIFY_INEXACT, the
+" match is considered inexact, and is only applied if no exact match is found.
+" Multiple inexact matches is currently considered an error.
+
+function! VCSCommandGetVCSType(buffer)
+ let vcsType = getbufvar(a:buffer, 'VCSCommandVCSType')
+ if strlen(vcsType) > 0
+ return vcsType
+ endif
+ let matches = []
+ for vcsType in keys(s:plugins)
+ let identified = s:plugins[vcsType][1].Identify(a:buffer)
+ if identified
+ if identified == g:VCSCOMMAND_IDENTIFY_EXACT
+ let matches = [vcsType]
+ break
+ else
+ let matches += [vcsType]
+ endif
+ endif
+ endfor
+ if len(matches) == 1
+ call setbufvar(a:buffer, 'VCSCommandVCSType', matches[0])
+ return matches[0]
+ elseif len(matches) == 0
+ throw 'No suitable plugin'
+ else
+ throw 'Too many matching VCS: ' . join(matches)
+ endif
+endfunction
+
+" Function: VCSCommandChdir(directory) {{{2
+" Changes the current directory, respecting :lcd changes.
+
+function! VCSCommandChdir(directory)
+ let command = 'cd'
+ if exists("*haslocaldir") && haslocaldir()
+ let command = 'lcd'
+ endif
+ execute command escape(a:directory, ' ')
+endfunction
+
+" Function: VCSCommandChangeToCurrentFileDir() {{{2
+" Go to the directory in which the given file is located.
+
+function! VCSCommandChangeToCurrentFileDir(fileName)
+ let oldCwd = getcwd()
+ let newCwd = fnamemodify(resolve(a:fileName), ':p:h')
+ if strlen(newCwd) > 0
+ call VCSCommandChdir(newCwd)
+ endif
+ return oldCwd
+endfunction
+
+" Function: VCSCommandGetOriginalBuffer(vcsBuffer) {{{2
+" Attempts to locate the original file to which VCS operations were applied
+" for a given buffer.
+
+function! VCSCommandGetOriginalBuffer(vcsBuffer)
+ let origBuffer = getbufvar(a:vcsBuffer, 'VCSCommandOriginalBuffer')
+ if origBuffer
+ if bufexists(origBuffer)
+ return origBuffer
+ else
+ " Original buffer no longer exists.
+ throw 'Original buffer for this VCS buffer no longer exists.'
+ endif
+ else
+ " No original buffer
+ return a:vcsBuffer
+ endif
+endfunction
+
+" Function: VCSCommandRegisterModule(name, file, commandMap) {{{2
+" Allows VCS modules to register themselves.
+
+function! VCSCommandRegisterModule(name, path, commandMap, mappingMap)
+ let s:plugins[a:name] = [a:path, a:commandMap, a:mappingMap]
+ if !empty(a:mappingMap)
+ \ && !VCSCommandGetOption('VCSCommandDisableMappings', 0)
+ \ && !VCSCommandGetOption('VCSCommandDisableExtensionMappings', 0)
+ for mapname in keys(a:mappingMap)
+ execute 'noremap <silent> <Leader>' . mapname ':call <SID>ExecuteExtensionMapping(''' . mapname . ''')<CR>'
+ endfor
+ endif
+endfunction
+
+" Function: VCSCommandDoCommand(cmd, cmdName, statusText, [options]) {{{2
+" General skeleton for VCS function execution. The given command is executed
+" after appending the current buffer name (or substituting it for
+" <VCSCOMMANDFILE>, if such a token is present). The output is captured in a
+" new buffer.
+"
+" The optional 'options' Dictionary may contain the following options:
+" allowNonZeroExit: if non-zero, if the underlying VCS command has a
+" non-zero exit status, the command is still considered
+" successfuly. This defaults to zero.
+" Returns: name of the new command buffer containing the command results
+
+function! VCSCommandDoCommand(cmd, cmdName, statusText, options)
+ let allowNonZeroExit = 0
+ if has_key(a:options, 'allowNonZeroExit')
+ let allowNonZeroExit = a:options.allowNonZeroExit
+ endif
+
+ let originalBuffer = VCSCommandGetOriginalBuffer(bufnr('%'))
+ if originalBuffer == -1
+ throw 'Original buffer no longer exists, aborting.'
+ endif
+
+ let path = resolve(bufname(originalBuffer))
+
+ " Work with netrw or other systems where a directory listing is displayed in
+ " a buffer.
+
+ if isdirectory(path)
+ let fileName = '.'
+ else
+ let fileName = fnamemodify(path, ':t')
+ endif
+
+ if match(a:cmd, '<VCSCOMMANDFILE>') > 0
+ let fullCmd = substitute(a:cmd, '<VCSCOMMANDFILE>', fileName, 'g')
+ else
+ let fullCmd = a:cmd . ' "' . fileName . '"'
+ endif
+
+ " Change to the directory of the current buffer. This is done for CVS, but
+ " is left in for other systems as it does not affect them negatively.
+
+ let oldCwd = VCSCommandChangeToCurrentFileDir(path)
+ try
+ let output = system(fullCmd)
+ finally
+ call VCSCommandChdir(oldCwd)
+ endtry
+
+ " HACK: if line endings in the repository have been corrupted, the output
+ " of the command will be confused.
+ let output = substitute(output, "\r", '', 'g')
+
+ if v:shell_error && !allowNonZeroExit
+ if strlen(output) == 0
+ throw 'Version control command failed'
+ else
+ let output = substitute(output, '\n', ' ', 'g')
+ throw 'Version control command failed: ' . output
+ endif
+ endif
+
+ if strlen(output) == 0
+ " Handle case of no output. In this case, it is important to check the
+ " file status, especially since cvs edit/unedit may change the attributes
+ " of the file with no visible output.
+
+ checktime
+ return 0
+ endif
+
+ call s:EditFile(a:cmdName, originalBuffer, a:statusText)
+
+ silent 0put=output
+
+ " The last command left a blank line at the end of the buffer. If the
+ " last line is folded (a side effect of the 'put') then the attempt to
+ " remove the blank line will kill the last fold.
+ "
+ " This could be fixed by explicitly detecting whether the last line is
+ " within a fold, but I prefer to simply unfold the result buffer altogether.
+
+ if has('folding')
+ normal zR
+ endif
+
+ $d
+ 1
+
+ " Define the environment and execute user-defined hooks.
+
+ silent do VCSCommand User VCSBufferCreated
+ return bufnr('%')
+endfunction
+
+" Function: VCSCommandGetOption(name, default) {{{2
+" Grab a user-specified option to override the default provided. Options are
+" searched in the window, buffer, then global spaces.
+
+function! VCSCommandGetOption(name, default)
+ if has_key(s:optionOverrides, a:name) && len(s:optionOverrides[a:name]) > 0
+ return s:optionOverrides[a:name][-1]
+ elseif exists('w:' . a:name)
+ return w:{a:name}
+ elseif exists('b:' . a:name)
+ return b:{a:name}
+ elseif exists('g:' . a:name)
+ return g:{a:name}
+ else
+ return a:default
+ endif
+endfunction
+
+" Function: VCSCommandDisableBufferSetup() {{{2
+" Global function for deactivating the buffer autovariables.
+
+function! VCSCommandDisableBufferSetup()
+ let g:VCSCommandEnableBufferSetup = 0
+ silent! augroup! VCSCommandPlugin
+endfunction
+
+" Function: VCSCommandEnableBufferSetup() {{{2
+" Global function for activating the buffer autovariables.
+
+function! VCSCommandEnableBufferSetup()
+ let g:VCSCommandEnableBufferSetup = 1
+ augroup VCSCommandPlugin
+ au!
+ au BufEnter * call s:SetupBuffer()
+ augroup END
+
+ " Only auto-load if the plugin is fully loaded. This gives other plugins a
+ " chance to run.
+ if g:loaded_VCSCommand == 2
+ call s:SetupBuffer()
+ endif
+endfunction
+
+" Function: VCSCommandGetStatusLine() {{{2
+" Default (sample) status line entry for VCS-controlled files. This is only
+" useful if VCS-managed buffer mode is on (see the VCSCommandEnableBufferSetup
+" variable for how to do this).
+
+function! VCSCommandGetStatusLine()
+ if exists('b:VCSCommandCommand')
+ " This is a result buffer. Return nothing because the buffer name
+ " contains information already.
+ return ''
+ endif
+
+ if exists('b:VCSCommandVCSType')
+ \ && exists('g:VCSCommandEnableBufferSetup')
+ \ && g:VCSCommandEnableBufferSetup
+ \ && exists('b:VCSCommandBufferInfo')
+ return '[' . join(extend([b:VCSCommandVCSType], b:VCSCommandBufferInfo), ' ') . ']'
+ else
+ return ''
+ endif
+endfunction
+
+" Section: Command definitions {{{1
+" Section: Primary commands {{{2
+com! -nargs=* VCSAdd call s:MarkOrigBufferForSetup(s:ExecuteVCSCommand('Add', [<f-args>]))
+com! -nargs=* VCSAnnotate call s:ExecuteVCSCommand('Annotate', [<f-args>])
+com! -nargs=* VCSBlame call s:ExecuteVCSCommand('Annotate', [<f-args>])
+com! -nargs=? -bang VCSCommit call s:VCSCommit(<q-bang>, <q-args>)
+com! -nargs=* VCSDelete call s:ExecuteVCSCommand('Delete', [<f-args>])
+com! -nargs=* VCSDiff call s:ExecuteVCSCommand('Diff', [<f-args>])
+com! -nargs=0 -bang VCSGotoOriginal call s:VCSGotoOriginal(<q-bang>)
+com! -nargs=* VCSInfo call s:ExecuteVCSCommand('Info', [<f-args>])
+com! -nargs=* VCSLock call s:MarkOrigBufferForSetup(s:ExecuteVCSCommand('Lock', [<f-args>]))
+com! -nargs=* VCSLog call s:ExecuteVCSCommand('Log', [<f-args>])
+com! -nargs=* VCSRemove call s:ExecuteVCSCommand('Delete', [<f-args>])
+com! -nargs=0 VCSRevert call s:MarkOrigBufferForSetup(s:ExecuteVCSCommand('Revert', []))
+com! -nargs=? VCSReview call s:ExecuteVCSCommand('Review', [<f-args>])
+com! -nargs=* VCSStatus call s:ExecuteVCSCommand('Status', [<f-args>])
+com! -nargs=* VCSUnlock call s:MarkOrigBufferForSetup(s:ExecuteVCSCommand('Unlock', [<f-args>]))
+com! -nargs=0 VCSUpdate call s:MarkOrigBufferForSetup(s:ExecuteVCSCommand('Update', []))
+com! -nargs=* VCSVimDiff call s:VCSVimDiff(<f-args>)
+
+" Section: VCS buffer management commands {{{2
+com! VCSCommandDisableBufferSetup call VCSCommandDisableBufferSetup()
+com! VCSCommandEnableBufferSetup call VCSCommandEnableBufferSetup()
+
+" Allow reloading VCSCommand.vim
+com! VCSReload let savedPlugins = s:plugins|let s:plugins = {}|aunmenu Plugin.VCS|unlet! g:loaded_VCSCommand|runtime plugin/vcscommand.vim|for plugin in values(savedPlugins)|execute 'source' plugin[0]|endfor|unlet savedPlugins
+
+" Section: Plugin command mappings {{{1
+nnoremap <silent> <Plug>VCSAdd :VCSAdd<CR>
+nnoremap <silent> <Plug>VCSAnnotate :VCSAnnotate<CR>
+nnoremap <silent> <Plug>VCSCommit :VCSCommit<CR>
+nnoremap <silent> <Plug>VCSDelete :VCSDelete<CR>
+nnoremap <silent> <Plug>VCSDiff :VCSDiff<CR>
+nnoremap <silent> <Plug>VCSGotoOriginal :VCSGotoOriginal<CR>
+nnoremap <silent> <Plug>VCSClearAndGotoOriginal :VCSGotoOriginal!<CR>
+nnoremap <silent> <Plug>VCSInfo :VCSInfo<CR>
+nnoremap <silent> <Plug>VCSLock :VCSLock<CR>
+nnoremap <silent> <Plug>VCSLog :VCSLog<CR>
+nnoremap <silent> <Plug>VCSRevert :VCSRevert<CR>
+nnoremap <silent> <Plug>VCSReview :VCSReview<CR>
+nnoremap <silent> <Plug>VCSStatus :VCSStatus<CR>
+nnoremap <silent> <Plug>VCSUnlock :VCSUnlock<CR>
+nnoremap <silent> <Plug>VCSUpdate :VCSUpdate<CR>
+nnoremap <silent> <Plug>VCSVimDiff :VCSVimDiff<CR>
+
+" Section: Default mappings {{{1
+
+if !VCSCommandGetOption('VCSCommandDisableMappings', 0)
+ if !hasmapto('<Plug>VCSAdd')
+ nmap <unique> <Leader>ca <Plug>VCSAdd
+ endif
+ if !hasmapto('<Plug>VCSAnnotate')
+ nmap <unique> <Leader>cn <Plug>VCSAnnotate
+ endif
+ if !hasmapto('<Plug>VCSClearAndGotoOriginal')
+ nmap <unique> <Leader>cG <Plug>VCSClearAndGotoOriginal
+ endif
+ if !hasmapto('<Plug>VCSCommit')
+ nmap <unique> <Leader>cc <Plug>VCSCommit
+ endif
+ if !hasmapto('<Plug>VCSDelete')
+ nmap <unique> <Leader>cD <Plug>VCSDelete
+ endif
+ if !hasmapto('<Plug>VCSDiff')
+ nmap <unique> <Leader>cd <Plug>VCSDiff
+ endif
+ if !hasmapto('<Plug>VCSGotoOriginal')
+ nmap <unique> <Leader>cg <Plug>VCSGotoOriginal
+ endif
+ if !hasmapto('<Plug>VCSInfo')
+ nmap <unique> <Leader>ci <Plug>VCSInfo
+ endif
+ if !hasmapto('<Plug>VCSLock')
+ nmap <unique> <Leader>cL <Plug>VCSLock
+ endif
+ if !hasmapto('<Plug>VCSLog')
+ nmap <unique> <Leader>cl <Plug>VCSLog
+ endif
+ if !hasmapto('<Plug>VCSRevert')
+ nmap <unique> <Leader>cq <Plug>VCSRevert
+ endif
+ if !hasmapto('<Plug>VCSReview')
+ nmap <unique> <Leader>cr <Plug>VCSReview
+ endif
+ if !hasmapto('<Plug>VCSStatus')
+ nmap <unique> <Leader>cs <Plug>VCSStatus
+ endif
+ if !hasmapto('<Plug>VCSUnlock')
+ nmap <unique> <Leader>cU <Plug>VCSUnlock
+ endif
+ if !hasmapto('<Plug>VCSUpdate')
+ nmap <unique> <Leader>cu <Plug>VCSUpdate
+ endif
+ if !hasmapto('<Plug>VCSVimDiff')
+ nmap <unique> <Leader>cv <Plug>VCSVimDiff
+ endif
+endif
+
+" Section: Menu items {{{1
+amenu <silent> &Plugin.VCS.&Add <Plug>VCSAdd
+amenu <silent> &Plugin.VCS.A&nnotate <Plug>VCSAnnotate
+amenu <silent> &Plugin.VCS.&Commit <Plug>VCSCommit
+amenu <silent> &Plugin.VCS.Delete <Plug>VCSDelete
+amenu <silent> &Plugin.VCS.&Diff <Plug>VCSDiff
+amenu <silent> &Plugin.VCS.&Info <Plug>VCSInfo
+amenu <silent> &Plugin.VCS.&Log <Plug>VCSLog
+amenu <silent> &Plugin.VCS.Revert <Plug>VCSRevert
+amenu <silent> &Plugin.VCS.&Review <Plug>VCSReview
+amenu <silent> &Plugin.VCS.&Status <Plug>VCSStatus
+amenu <silent> &Plugin.VCS.&Update <Plug>VCSUpdate
+amenu <silent> &Plugin.VCS.&VimDiff <Plug>VCSVimDiff
+
+" Section: Autocommands to restore vimdiff state {{{1
+augroup VimDiffRestore
+ au!
+ au BufUnload * call s:VimDiffRestore(str2nr(expand('<abuf>')))
+augroup END
+
+" Section: Optional activation of buffer management {{{1
+
+if VCSCommandGetOption('VCSCommandEnableBufferSetup', 0)
+ call VCSCommandEnableBufferSetup()
+endif
+
+" Section: VIM shutdown hook {{{1
+
+" Close all result buffers when VIM exits, to prevent them from being restored
+" via viminfo.
+
+" Function: s:CloseAllResultBuffers() {{{2
+" Closes all vcscommand result buffers.
+function! s:CloseAllResultBuffers()
+ " This avoids using bufdo as that may load buffers already loaded in another
+ " vim process, resulting in an error.
+ let buffnr = 1
+ let buffmaxnr = bufnr('$')
+ while buffnr <= buffmaxnr
+ if getbufvar(buffnr, 'VCSCommandOriginalBuffer') != ""
+ execute 'bw' buffnr
+ endif
+ let buffnr = buffnr + 1
+ endwhile
+endfunction
+
+augroup VCSCommandVIMShutdown
+ au!
+ au VimLeavePre * call s:CloseAllResultBuffers()
+augroup END
+
+" Section: Plugin completion {{{1
+
+let loaded_VCSCommand = 2
+
+silent do VCSCommand User VCSPluginFinish
+
+let &cpo = s:save_cpo
--- /dev/null
+" vim600: set foldmethod=marker:
+"
+" CVS extension for VCSCommand.
+"
+" Version: VCS development
+" Maintainer: Bob Hiestand <
[email protected]>
+" License:
+" Copyright (c) 2007 Bob Hiestand
+"
+" 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.
+"
+" Section: Documentation {{{1
+"
+" Command documentation {{{2
+"
+" The following commands only apply to files under CVS source control.
+"
+" CVSEdit Performs "cvs edit" on the current file.
+"
+" CVSEditors Performs "cvs editors" on the current file.
+"
+" CVSUnedit Performs "cvs unedit" on the current file.
+"
+" CVSWatch Takes an argument which must be one of [on|off|add|remove].
+" Performs "cvs watch" with the given argument on the current
+" file.
+"
+" CVSWatchers Performs "cvs watchers" on the current file.
+"
+" CVSWatchAdd Alias for "CVSWatch add"
+"
+" CVSWatchOn Alias for "CVSWatch on"
+"
+" CVSWatchOff Alias for "CVSWatch off"
+"
+" CVSWatchRemove Alias for "CVSWatch remove"
+"
+" Mapping documentation: {{{2
+"
+" By default, a mapping is defined for each command. User-provided mappings
+" can be used instead by mapping to <Plug>CommandName, for instance:
+"
+" nnoremap ,ce <Plug>CVSEdit
+"
+" The default mappings are as follow:
+"
+" <Leader>ce CVSEdit
+" <Leader>cE CVSEditors
+" <Leader>ct CVSUnedit
+" <Leader>cwv CVSWatchers
+" <Leader>cwa CVSWatchAdd
+" <Leader>cwn CVSWatchOn
+" <Leader>cwf CVSWatchOff
+" <Leader>cwr CVSWatchRemove
+"
+" Options documentation: {{{2
+"
+" VCSCommandCVSExec
+" This variable specifies the CVS executable. If not set, it defaults to
+" 'cvs' executed from the user's executable path.
+"
+" VCSCommandCVSDiffOpt
+" This variable, if set, determines the options passed to the cvs diff
+" command. If not set, it defaults to 'u'.
+
+" Section: Plugin header {{{1
+
+if v:version < 700
+ echohl WarningMsg|echomsg 'VCSCommand requires at least VIM 7.0'|echohl None
+ finish
+endif
+
+runtime plugin/vcscommand.vim
+
+if !executable(VCSCommandGetOption('VCSCommandCVSExec', 'cvs'))
+ " CVS is not installed
+ finish
+endif
+
+let s:save_cpo=&cpo
+set cpo&vim
+
+" Section: Variable initialization {{{1
+
+let s:cvsFunctions = {}
+
+" Section: Utility functions {{{1
+
+" Function: s:DoCommand(cmd, cmdName, statusText, options) {{{2
+" Wrapper to VCSCommandDoCommand to add the name of the CVS executable to the
+" command argument.
+function! s:DoCommand(cmd, cmdName, statusText, options)
+ if VCSCommandGetVCSType(expand('%')) == 'CVS'
+ let fullCmd = VCSCommandGetOption('VCSCommandCVSExec', 'cvs') . ' ' . a:cmd
+ return VCSCommandDoCommand(fullCmd, a:cmdName, a:statusText, a:options)
+ else
+ throw 'CVS VCSCommand plugin called on non-CVS item.'
+ endif
+endfunction
+
+" Function: GetRevision() {{{2
+" Function for retrieving the current buffer's revision number.
+" Returns: Revision number or an empty string if an error occurs.
+
+function! GetRevision()
+ if !exists('b:VCSCommandBufferInfo')
+ let b:VCSCommandBufferInfo = s:cvsFunctions.GetBufferInfo()
+ endif
+
+ if len(b:VCSCommandBufferInfo) > 0
+ return b:VCSCommandBufferInfo[0]
+ else
+ return ''
+ endif
+endfunction
+
+" Section: VCS function implementations {{{1
+
+" Function: s:cvsFunctions.Identify(buffer) {{{2
+function! s:cvsFunctions.Identify(buffer)
+ let fileName = resolve(bufname(a:buffer))
+ if isdirectory(fileName)
+ let directoryName = fileName
+ else
+ let directoryName = fnamemodify(fileName, ':h')
+ endif
+ if strlen(directoryName) > 0
+ let CVSRoot = directoryName . '/CVS/Root'
+ else
+ let CVSRoot = 'CVS/Root'
+ endif
+ if filereadable(CVSRoot)
+ return 1
+ else
+ return 0
+ endif
+endfunction
+
+" Function: s:cvsFunctions.Add(argList) {{{2
+function! s:cvsFunctions.Add(argList)
+ return s:DoCommand(join(['add'] + a:argList, ' '), 'add', join(a:argList, ' '), {})
+endfunction
+
+" Function: s:cvsFunctions.Annotate(argList) {{{2
+function! s:cvsFunctions.Annotate(argList)
+ if len(a:argList) == 0
+ if &filetype == 'CVSAnnotate'
+ " This is a CVSAnnotate buffer. Perform annotation of the version
+ " indicated by the current line.
+ let caption = matchstr(getline('.'),'\v^[0-9.]+')
+
+ if VCSCommandGetOption('VCSCommandCVSAnnotateParent', 0) != 0
+ if caption != '1.1'
+ let revmaj = matchstr(caption,'\v[0-9.]+\ze\.[0-9]+')
+ let revmin = matchstr(caption,'\v[0-9.]+\.\zs[0-9]+') - 1
+ if revmin == 0
+ " Jump to ancestor branch
+ let caption = matchstr(revmaj,'\v[0-9.]+\ze\.[0-9]+')
+ else
+ let caption = revmaj . "." . revmin
+ endif
+ endif
+ endif
+
+ let options = ['-r' . caption]
+ else
+ " CVS defaults to pulling HEAD, regardless of current branch.
+ " Therefore, always pass desired revision.
+ let caption = ''
+ let options = ['-r' . GetRevision()]
+ endif
+ elseif len(a:argList) == 1 && a:argList[0] !~ '^-'
+ let caption = a:argList[0]
+ let options = ['-r' . caption]
+ else
+ let caption = join(a:argList)
+ let options = a:argList
+ endif
+
+ let resultBuffer = s:DoCommand(join(['-q', 'annotate'] + options), 'annotate', caption, {})
+ if resultBuffer > 0
+ set filetype=CVSAnnotate
+ " Remove header lines from standard error
+ silent v/^\d\+\%(\.\d\+\)\+/d
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:cvsFunctions.Commit(argList) {{{2
+function! s:cvsFunctions.Commit(argList)
+ let resultBuffer = s:DoCommand('commit -F "' . a:argList[0] . '"', 'commit', '', {})
+ if resultBuffer == 0
+ echomsg 'No commit needed.'
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:cvsFunctions.Delete() {{{2
+" By default, use the -f option to remove the file first. If options are
+" passed in, use those instead.
+function! s:cvsFunctions.Delete(argList)
+ let options = ['-f']
+ let caption = ''
+ if len(a:argList) > 0
+ let options = a:argList
+ let caption = join(a:argList, ' ')
+ endif
+ return s:DoCommand(join(['remove'] + options, ' '), 'delete', caption, {})
+endfunction
+
+" Function: s:cvsFunctions.Diff(argList) {{{2
+function! s:cvsFunctions.Diff(argList)
+ if len(a:argList) == 0
+ let revOptions = []
+ let caption = ''
+ elseif len(a:argList) <= 2 && match(a:argList, '^-') == -1
+ let revOptions = ['-r' . join(a:argList, ' -r')]
+ let caption = '(' . a:argList[0] . ' : ' . get(a:argList, 1, 'current') . ')'
+ else
+ " Pass-through
+ let caption = join(a:argList, ' ')
+ let revOptions = a:argList
+ endif
+
+ let cvsDiffOpt = VCSCommandGetOption('VCSCommandCVSDiffOpt', 'u')
+ if cvsDiffOpt == ''
+ let diffOptions = []
+ else
+ let diffOptions = ['-' . cvsDiffOpt]
+ endif
+
+ let resultBuffer = s:DoCommand(join(['diff'] + diffOptions + revOptions), 'diff', caption, {'allowNonZeroExit': 1})
+ if resultBuffer > 0
+ set filetype=diff
+ else
+ echomsg 'No differences found'
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:cvsFunctions.GetBufferInfo() {{{2
+" Provides version control details for the current file. Current version
+" number and current repository version number are required to be returned by
+" the vcscommand plugin. This CVS extension adds branch name to the return
+" list as well.
+" Returns: List of results: [revision, repository, branch]
+
+function! s:cvsFunctions.GetBufferInfo()
+ let originalBuffer = VCSCommandGetOriginalBuffer(bufnr('%'))
+ let fileName = bufname(originalBuffer)
+ if isdirectory(fileName)
+ let tag = ''
+ if filereadable(fileName . '/CVS/Tag')
+ let tagFile = readfile(fileName . '/CVS/Tag')
+ if len(tagFile) == 1
+ let tag = substitute(tagFile[0], '^T', '', '')
+ endif
+ endif
+ return [tag]
+ endif
+ let realFileName = fnamemodify(resolve(fileName), ':t')
+ if !filereadable(fileName)
+ return ['Unknown']
+ endif
+ let oldCwd = VCSCommandChangeToCurrentFileDir(fileName)
+ try
+ let statusText=system(VCSCommandGetOption('VCSCommandCVSExec', 'cvs') . ' status "' . realFileName . '"')
+ if(v:shell_error)
+ return []
+ endif
+ let revision=substitute(statusText, '^\_.*Working revision:\s*\(\d\+\%(\.\d\+\)\+\|New file!\)\_.*$', '\1', '')
+
+ " We can still be in a CVS-controlled directory without this being a CVS
+ " file
+ if match(revision, '^New file!$') >= 0
+ let revision='New'
+ elseif match(revision, '^\d\+\.\d\+\%(\.\d\+\.\d\+\)*$') <0
+ return ['Unknown']
+ endif
+
+ let branch=substitute(statusText, '^\_.*Sticky Tag:\s\+\(\d\+\%(\.\d\+\)\+\|\a[A-Za-z0-9-_]*\|(none)\).*$', '\1', '')
+ let repository=substitute(statusText, '^\_.*Repository revision:\s*\(\d\+\%(\.\d\+\)\+\|New file!\|No revision control file\)\_.*$', '\1', '')
+ let repository=substitute(repository, '^New file!\|No revision control file$', 'New', '')
+ return [revision, repository, branch]
+ finally
+ call VCSCommandChdir(oldCwd)
+ endtry
+endfunction
+
+" Function: s:cvsFunctions.Log() {{{2
+function! s:cvsFunctions.Log(argList)
+ if len(a:argList) == 0
+ let options = []
+ let caption = ''
+ elseif len(a:argList) <= 2 && match(a:argList, '^-') == -1
+ let options = ['-r' . join(a:argList, ':')]
+ let caption = options[0]
+ else
+ " Pass-through
+ let options = a:argList
+ let caption = join(a:argList, ' ')
+ endif
+
+ let resultBuffer=s:DoCommand(join(['log'] + options), 'log', caption, {})
+ if resultBuffer > 0
+ set filetype=rcslog
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:cvsFunctions.Revert(argList) {{{2
+function! s:cvsFunctions.Revert(argList)
+ return s:DoCommand('update -C', 'revert', '', {})
+endfunction
+
+" Function: s:cvsFunctions.Review(argList) {{{2
+function! s:cvsFunctions.Review(argList)
+ if len(a:argList) == 0
+ let versiontag = '(current)'
+ let versionOption = ''
+ else
+ let versiontag = a:argList[0]
+ let versionOption = ' -r ' . versiontag . ' '
+ endif
+
+ let resultBuffer = s:DoCommand('-q update -p' . versionOption, 'review', versiontag, {})
+ if resultBuffer > 0
+ let &filetype=getbufvar(b:VCSCommandOriginalBuffer, '&filetype')
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:cvsFunctions.Status(argList) {{{2
+function! s:cvsFunctions.Status(argList)
+ return s:DoCommand(join(['status'] + a:argList, ' '), 'status', join(a:argList, ' '), {})
+endfunction
+
+" Function: s:cvsFunctions.Update(argList) {{{2
+function! s:cvsFunctions.Update(argList)
+ return s:DoCommand('update', 'update', '', {})
+endfunction
+
+" Section: CVS-specific functions {{{1
+
+" Function: s:CVSEdit() {{{2
+function! s:CVSEdit()
+ return s:DoCommand('edit', 'cvsedit', '', {})
+endfunction
+
+" Function: s:CVSEditors() {{{2
+function! s:CVSEditors()
+ return s:DoCommand('editors', 'cvseditors', '', {})
+endfunction
+
+" Function: s:CVSUnedit() {{{2
+function! s:CVSUnedit()
+ return s:DoCommand('unedit', 'cvsunedit', '', {})
+endfunction
+
+" Function: s:CVSWatch(onoff) {{{2
+function! s:CVSWatch(onoff)
+ if a:onoff !~ '^\c\%(on\|off\|add\|remove\)$'
+ echoerr 'Argument to CVSWatch must be one of [on|off|add|remove]'
+ return -1
+ end
+ return s:DoCommand('watch ' . tolower(a:onoff), 'cvswatch', '', {})
+endfunction
+
+" Function: s:CVSWatchers() {{{2
+function! s:CVSWatchers()
+ return s:DoCommand('watchers', 'cvswatchers', '', {})
+endfunction
+
+" Section: Command definitions {{{1
+" Section: Primary commands {{{2
+com! CVSEdit call s:CVSEdit()
+com! CVSEditors call s:CVSEditors()
+com! CVSUnedit call s:CVSUnedit()
+com! -nargs=1 CVSWatch call s:CVSWatch(<f-args>)
+com! CVSWatchAdd call s:CVSWatch('add')
+com! CVSWatchOn call s:CVSWatch('on')
+com! CVSWatchOff call s:CVSWatch('off')
+com! CVSWatchRemove call s:CVSWatch('remove')
+com! CVSWatchers call s:CVSWatchers()
+
+" Section: Plugin command mappings {{{1
+
+let s:cvsExtensionMappings = {}
+let mappingInfo = [
+ \['CVSEdit', 'CVSEdit', 'ce'],
+ \['CVSEditors', 'CVSEditors', 'cE'],
+ \['CVSUnedit', 'CVSUnedit', 'ct'],
+ \['CVSWatchers', 'CVSWatchers', 'cwv'],
+ \['CVSWatchAdd', 'CVSWatch add', 'cwa'],
+ \['CVSWatchOff', 'CVSWatch off', 'cwf'],
+ \['CVSWatchOn', 'CVSWatch on', 'cwn'],
+ \['CVSWatchRemove', 'CVSWatch remove', 'cwr']
+ \]
+
+for [pluginName, commandText, shortCut] in mappingInfo
+ execute 'nnoremap <silent> <Plug>' . pluginName . ' :' . commandText . '<CR>'
+ if !hasmapto('<Plug>' . pluginName)
+ let s:cvsExtensionMappings[shortCut] = commandText
+ endif
+endfor
+
+" Section: Menu items {{{1
+silent! aunmenu Plugin.VCS.CVS
+amenu <silent> &Plugin.VCS.CVS.&Edit <Plug>CVSEdit
+amenu <silent> &Plugin.VCS.CVS.Ed&itors <Plug>CVSEditors
+amenu <silent> &Plugin.VCS.CVS.Unedi&t <Plug>CVSUnedit
+amenu <silent> &Plugin.VCS.CVS.&Watchers <Plug>CVSWatchers
+amenu <silent> &Plugin.VCS.CVS.WatchAdd <Plug>CVSWatchAdd
+amenu <silent> &Plugin.VCS.CVS.WatchOn <Plug>CVSWatchOn
+amenu <silent> &Plugin.VCS.CVS.WatchOff <Plug>CVSWatchOff
+amenu <silent> &Plugin.VCS.CVS.WatchRemove <Plug>CVSWatchRemove
+
+" Section: Plugin Registration {{{1
+call VCSCommandRegisterModule('CVS', expand('<sfile>'), s:cvsFunctions, s:cvsExtensionMappings)
+
+let &cpo = s:save_cpo
--- /dev/null
+" vim600: set foldmethod=marker:
+"
+" git extension for VCSCommand.
+"
+" Version: VCS development
+" Maintainer: Bob Hiestand <
[email protected]>
+" License:
+" Copyright (c) 2008 Bob Hiestand
+"
+" 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.
+"
+" Section: Documentation {{{1
+"
+" Options documentation: {{{2
+"
+" VCSCommandGitExec
+" This variable specifies the git executable. If not set, it defaults to
+" 'git' executed from the user's executable path.
+"
+" VCSCommandGitDiffOpt
+" This variable, if set, determines the default options passed to the
+" VCSDiff command. If any options (starting with '-') are passed to the
+" command, this variable is not used.
+
+" Section: Plugin header {{{1
+
+if v:version < 700
+ echohl WarningMsg|echomsg 'VCSCommand requires at least VIM 7.0'|echohl None
+ finish
+endif
+
+runtime plugin/vcscommand.vim
+
+if !executable(VCSCommandGetOption('VCSCommandGitExec', 'git'))
+ " git is not installed
+ finish
+endif
+
+let s:save_cpo=&cpo
+set cpo&vim
+
+" Section: Variable initialization {{{1
+
+let s:gitFunctions = {}
+
+" Section: Utility functions {{{1
+
+" Function: s:DoCommand(cmd, cmdName, statusText, options) {{{2
+" Wrapper to VCSCommandDoCommand to add the name of the git executable to the
+" command argument.
+function! s:DoCommand(cmd, cmdName, statusText, options)
+ if VCSCommandGetVCSType(expand('%')) == 'git'
+ let fullCmd = VCSCommandGetOption('VCSCommandGitExec', 'git',) . ' ' . a:cmd
+ return VCSCommandDoCommand(fullCmd, a:cmdName, a:statusText, a:options)
+ else
+ throw 'git VCSCommand plugin called on non-git item.'
+ endif
+endfunction
+
+" Section: VCS function implementations {{{1
+
+" Function: s:gitFunctions.Identify(buffer) {{{2
+" This function only returns an inexact match due to the detection method used
+" by git, which simply traverses the directory structure upward.
+function! s:gitFunctions.Identify(buffer)
+ let oldCwd = VCSCommandChangeToCurrentFileDir(resolve(bufname(a:buffer)))
+ try
+ call system(VCSCommandGetOption('VCSCommandGitExec', 'git') . ' rev-parse --is-inside-work-tree')
+ if(v:shell_error)
+ return 0
+ else
+ return g:VCSCOMMAND_IDENTIFY_INEXACT
+ endif
+ finally
+ call VCSCommandChdir(oldCwd)
+ endtry
+endfunction
+
+" Function: s:gitFunctions.Add(argList) {{{2
+function! s:gitFunctions.Add(argList)
+ return s:DoCommand(join(['add'] + ['-v'] + a:argList, ' '), 'add', join(a:argList, ' '), {})
+endfunction
+
+" Function: s:gitFunctions.Annotate(argList) {{{2
+function! s:gitFunctions.Annotate(argList)
+ if len(a:argList) == 0
+ if &filetype == 'gitAnnotate'
+ " Perform annotation of the version indicated by the current line.
+ let options = matchstr(getline('.'),'^\x\+')
+ else
+ let options = ''
+ endif
+ elseif len(a:argList) == 1 && a:argList[0] !~ '^-'
+ let options = a:argList[0]
+ else
+ let options = join(a:argList, ' ')
+ endif
+
+ let resultBuffer = s:DoCommand('blame ' . options . ' -- ', 'annotate', options, {})
+ if resultBuffer > 0
+ normal 1G
+ set filetype=gitAnnotate
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:gitFunctions.Commit(argList) {{{2
+function! s:gitFunctions.Commit(argList)
+ let resultBuffer = s:DoCommand('commit -F "' . a:argList[0] . '"', 'commit', '', {})
+ if resultBuffer == 0
+ echomsg 'No commit needed.'
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:gitFunctions.Delete() {{{2
+" All options are passed through.
+function! s:gitFunctions.Delete(argList)
+ let options = a:argList
+ let caption = join(a:argList, ' ')
+ return s:DoCommand(join(['rm'] + options, ' '), 'delete', caption, {})
+endfunction
+
+" Function: s:gitFunctions.Diff(argList) {{{2
+" Pass-through call to git-diff. If no options (starting with '-') are found,
+" then the options in the 'VCSCommandGitDiffOpt' variable are added.
+function! s:gitFunctions.Diff(argList)
+ let gitDiffOpt = VCSCommandGetOption('VCSCommandGitDiffOpt', '')
+ if gitDiffOpt == ''
+ let diffOptions = []
+ else
+ let diffOptions = [gitDiffOpt]
+ for arg in a:argList
+ if arg =~ '^-'
+ let diffOptions = []
+ break
+ endif
+ endfor
+ endif
+
+ let resultBuffer = s:DoCommand(join(['diff'] + diffOptions + a:argList), 'diff', join(a:argList), {})
+ if resultBuffer > 0
+ set filetype=diff
+ else
+ echomsg 'No differences found'
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:gitFunctions.GetBufferInfo() {{{2
+" Provides version control details for the current file. Current version
+" number and current repository version number are required to be returned by
+" the vcscommand plugin. This CVS extension adds branch name to the return
+" list as well.
+" Returns: List of results: [revision, repository, branch]
+
+function! s:gitFunctions.GetBufferInfo()
+ let oldCwd = VCSCommandChangeToCurrentFileDir(resolve(bufname('%')))
+ try
+ let branch = substitute(system(VCSCommandGetOption('VCSCommandGitExec', 'git') . ' symbolic-ref -q HEAD'), '\n$', '', '')
+ if v:shell_error
+ let branch = 'DETACHED'
+ else
+ let branch = substitute(branch, '^refs/heads/', '', '')
+ endif
+
+ let info = [branch]
+
+ for method in split(VCSCommandGetOption('VCSCommandGitDescribeArgList', (',tags,all,always')), ',', 1)
+ if method != ''
+ let method = ' --' . method
+ endif
+ let tag = substitute(system(VCSCommandGetOption('VCSCommandGitExec', 'git') . ' describe' . method), '\n$', '', '')
+ if !v:shell_error
+ call add(info, tag)
+ break
+ endif
+ endfor
+
+ return info
+ finally
+ call VCSCommandChdir(oldCwd)
+ endtry
+endfunction
+
+" Function: s:gitFunctions.Log() {{{2
+function! s:gitFunctions.Log(argList)
+ let resultBuffer=s:DoCommand(join(['log'] + a:argList), 'log', join(a:argList, ' '), {})
+ if resultBuffer > 0
+ set filetype=gitlog
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:gitFunctions.Revert(argList) {{{2
+function! s:gitFunctions.Revert(argList)
+ return s:DoCommand('checkout', 'revert', '', {})
+endfunction
+
+" Function: s:gitFunctions.Review(argList) {{{2
+function! s:gitFunctions.Review(argList)
+ if len(a:argList) == 0
+ let revision = 'HEAD'
+ else
+ let revision = a:argList[0]
+ endif
+
+ let oldCwd = VCSCommandChangeToCurrentFileDir(resolve(bufname(VCSCommandGetOriginalBuffer('%'))))
+ try
+ let prefix = system(VCSCommandGetOption('VCSCommandGitExec', 'git') . ' rev-parse --show-prefix')
+ finally
+ call VCSCommandChdir(oldCwd)
+ endtry
+
+ let prefix = substitute(prefix, '\n$', '', '')
+ let blob = '"' . revision . ':' . prefix . '<VCSCOMMANDFILE>"'
+ let resultBuffer = s:DoCommand('show ' . blob, 'review', revision, {})
+ if resultBuffer > 0
+ let &filetype=getbufvar(b:VCSCommandOriginalBuffer, '&filetype')
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:gitFunctions.Status(argList) {{{2
+function! s:gitFunctions.Status(argList)
+ return s:DoCommand(join(['status'] + a:argList), 'status', join(a:argList), {'allowNonZeroExit': 1})
+endfunction
+
+" Function: s:gitFunctions.Update(argList) {{{2
+function! s:gitFunctions.Update(argList)
+ throw "This command is not implemented for git because file-by-file update doesn't make much sense in that context. If you have an idea for what it should do, please let me know."
+endfunction
+
+
+" Section: Plugin Registration {{{1
+call VCSCommandRegisterModule('git', expand('<sfile>'), s:gitFunctions, [])
+
+let &cpo = s:save_cpo
--- /dev/null
+" vim600: set foldmethod=marker:
+"
+" SVK extension for VCSCommand.
+"
+" Version: VCS development
+" Maintainer: Bob Hiestand <
[email protected]>
+" License:
+" Copyright (c) 2007 Bob Hiestand
+"
+" 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.
+"
+" Section: Documentation {{{1
+"
+" Options documentation: {{{2
+"
+" VCSCommandSVKExec
+" This variable specifies the SVK executable. If not set, it defaults to
+" 'svk' executed from the user's executable path.
+
+" Section: Plugin header {{{1
+
+if v:version < 700
+ echohl WarningMsg|echomsg 'VCSCommand requires at least VIM 7.0'|echohl None
+ finish
+endif
+
+runtime plugin/vcscommand.vim
+
+if !executable(VCSCommandGetOption('VCSCommandSVKExec', 'svk'))
+ " SVK is not installed
+ finish
+endif
+
+let s:save_cpo=&cpo
+set cpo&vim
+
+" Section: Variable initialization {{{1
+
+let s:svkFunctions = {}
+
+" Section: Utility functions {{{1
+
+" Function: s:DoCommand(cmd, cmdName, statusText, options) {{{2
+" Wrapper to VCSCommandDoCommand to add the name of the SVK executable to the
+" command argument.
+function! s:DoCommand(cmd, cmdName, statusText, options)
+ if VCSCommandGetVCSType(expand('%')) == 'SVK'
+ let fullCmd = VCSCommandGetOption('VCSCommandSVKExec', 'svk') . ' ' . a:cmd
+ return VCSCommandDoCommand(fullCmd, a:cmdName, a:statusText, a:options)
+ else
+ throw 'SVK VCSCommand plugin called on non-SVK item.'
+ endif
+endfunction
+
+" Section: VCS function implementations {{{1
+
+" Function: s:svkFunctions.Identify(buffer) {{{2
+function! s:svkFunctions.Identify(buffer)
+ let fileName = resolve(bufname(a:buffer))
+ if isdirectory(fileName)
+ let directoryName = fileName
+ else
+ let directoryName = fnamemodify(fileName, ':p:h')
+ endif
+ let statusText = system(VCSCommandGetOption('VCSCommandSVKExec', 'svk') . ' info "' . directoryName . '"')
+ if(v:shell_error)
+ return 0
+ else
+ return 1
+ endif
+endfunction
+
+" Function: s:svkFunctions.Add() {{{2
+function! s:svkFunctions.Add(argList)
+ return s:DoCommand(join(['add'] + a:argList, ' '), 'add', join(a:argList, ' '), {})
+endfunction
+
+" Function: s:svkFunctions.Annotate(argList) {{{2
+function! s:svkFunctions.Annotate(argList)
+ if len(a:argList) == 0
+ if &filetype == 'SVKAnnotate'
+ " Perform annotation of the version indicated by the current line.
+ let caption = matchstr(getline('.'),'\v^\s+\zs\d+')
+ let options = ' -r' . caption
+ else
+ let caption = ''
+ let options = ''
+ endif
+ elseif len(a:argList) == 1 && a:argList[0] !~ '^-'
+ let caption = a:argList[0]
+ let options = ' -r' . caption
+ else
+ let caption = join(a:argList, ' ')
+ let options = ' ' . caption
+ endif
+
+ let resultBuffer = s:DoCommand('blame' . options, 'annotate', caption, {})
+ if resultBuffer > 0
+ normal 1G2dd
+ set filetype=SVKAnnotate
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:svkFunctions.Commit(argList) {{{2
+function! s:svkFunctions.Commit(argList)
+ let resultBuffer = s:DoCommand('commit -F "' . a:argList[0] . '"', 'commit', '', {})
+ if resultBuffer == 0
+ echomsg 'No commit needed.'
+ endif
+endfunction
+
+" Function: s:svkFunctions.Delete() {{{2
+function! s:svkFunctions.Delete(argList)
+ return s:DoCommand(join(['delete'] + a:argList, ' '), 'delete', join(a:argList, ' '), {})
+endfunction
+
+" Function: s:svkFunctions.Diff(argList) {{{2
+function! s:svkFunctions.Diff(argList)
+ if len(a:argList) == 0
+ let revOptions = []
+ let caption = ''
+ elseif len(a:argList) <= 2 && match(a:argList, '^-') == -1
+ let revOptions = ['-r' . join(a:argList, ':')]
+ let caption = '(' . a:argList[0] . ' : ' . get(a:argList, 1, 'current') . ')'
+ else
+ " Pass-through
+ let caption = join(a:argList, ' ')
+ let revOptions = a:argList
+ endif
+
+ let resultBuffer = s:DoCommand(join(['diff'] + revOptions), 'diff', caption, {})
+ if resultBuffer > 0
+ set filetype=diff
+ else
+ echomsg 'No differences found'
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:svkFunctions.GetBufferInfo() {{{2
+" Provides version control details for the current file. Current version
+" number and current repository version number are required to be returned by
+" the vcscommand plugin.
+" Returns: List of results: [revision, repository]
+
+function! s:svkFunctions.GetBufferInfo()
+ let originalBuffer = VCSCommandGetOriginalBuffer(bufnr('%'))
+ let fileName = resolve(bufname(originalBuffer))
+ let statusText = system(VCSCommandGetOption('VCSCommandSVKExec', 'svk') . ' status -v "' . fileName . '"')
+ if(v:shell_error)
+ return []
+ endif
+
+ " File not under SVK control.
+ if statusText =~ '^?'
+ return ['Unknown']
+ endif
+
+ let [flags, revision, repository] = matchlist(statusText, '^\(.\{3}\)\s\+\(\S\+\)\s\+\(\S\+\)\s\+\(\S\+\)\s')[1:3]
+ if revision == ''
+ " Error
+ return ['Unknown']
+ elseif flags =~ '^A'
+ return ['New', 'New']
+ else
+ return [revision, repository]
+ endif
+endfunction
+
+" Function: s:svkFunctions.Info(argList) {{{2
+function! s:svkFunctions.Info(argList)
+ return s:DoCommand(join(['info'] + a:argList, ' '), 'info', join(a:argList, ' '), {})
+endfunction
+
+" Function: s:svkFunctions.Lock(argList) {{{2
+function! s:svkFunctions.Lock(argList)
+ return s:DoCommand(join(['lock'] + a:argList, ' '), 'lock', join(a:argList, ' '), {})
+endfunction
+
+" Function: s:svkFunctions.Log() {{{2
+function! s:svkFunctions.Log(argList)
+ if len(a:argList) == 0
+ let options = []
+ let caption = ''
+ elseif len(a:argList) <= 2 && match(a:argList, '^-') == -1
+ let options = ['-r' . join(a:argList, ':')]
+ let caption = options[0]
+ else
+ " Pass-through
+ let options = a:argList
+ let caption = join(a:argList, ' ')
+ endif
+
+ let resultBuffer = s:DoCommand(join(['log', '-v'] + options), 'log', caption, {})
+ return resultBuffer
+endfunction
+
+" Function: s:svkFunctions.Revert(argList) {{{2
+function! s:svkFunctions.Revert(argList)
+ return s:DoCommand('revert', 'revert', '', {})
+endfunction
+
+" Function: s:svkFunctions.Review(argList) {{{2
+function! s:svkFunctions.Review(argList)
+ if len(a:argList) == 0
+ let versiontag = '(current)'
+ let versionOption = ''
+ else
+ let versiontag = a:argList[0]
+ let versionOption = ' -r ' . versiontag . ' '
+ endif
+
+ let resultBuffer = s:DoCommand('cat' . versionOption, 'review', versiontag, {})
+ if resultBuffer > 0
+ let &filetype=getbufvar(b:VCSCommandOriginalBuffer, '&filetype')
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:svkFunctions.Status(argList) {{{2
+function! s:svkFunctions.Status(argList)
+ let options = ['-v']
+ if len(a:argList) == 0
+ let options = a:argList
+ endif
+ return s:DoCommand(join(['status'] + options, ' '), 'status', join(options, ' '), {})
+endfunction
+
+" Function: s:svkFunctions.Unlock(argList) {{{2
+function! s:svkFunctions.Unlock(argList)
+ return s:DoCommand(join(['unlock'] + a:argList, ' '), 'unlock', join(a:argList, ' '), {})
+endfunction
+" Function: s:svkFunctions.Update(argList) {{{2
+function! s:svkFunctions.Update(argList)
+ return s:DoCommand('update', 'update', '', {})
+endfunction
+
+" Section: Plugin Registration {{{1
+call VCSCommandRegisterModule('SVK', expand('<sfile>'), s:svkFunctions, [])
+
+let &cpo = s:save_cpo
--- /dev/null
+" vim600: set foldmethod=marker:
+"
+" SVN extension for VCSCommand.
+"
+" Version: VCS development
+" Maintainer: Bob Hiestand <
[email protected]>
+" License:
+" Copyright (c) 2007 Bob Hiestand
+"
+" 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.
+"
+" Section: Documentation {{{1
+"
+" Options documentation: {{{2
+"
+" VCSCommandSVNExec
+" This variable specifies the SVN executable. If not set, it defaults to
+" 'svn' executed from the user's executable path.
+"
+" VCSCommandSVNDiffExt
+" This variable, if set, sets the external diff program used by Subversion.
+"
+" VCSCommandSVNDiffOpt
+" This variable, if set, determines the options passed to the svn diff
+" command (such as 'u', 'w', or 'b').
+
+" Section: Plugin header {{{1
+
+if v:version < 700
+ echohl WarningMsg|echomsg 'VCSCommand requires at least VIM 7.0'|echohl None
+ finish
+endif
+
+runtime plugin/vcscommand.vim
+
+if !executable(VCSCommandGetOption('VCSCommandSVNExec', 'svn'))
+ " SVN is not installed
+ finish
+endif
+
+let s:save_cpo=&cpo
+set cpo&vim
+
+" Section: Variable initialization {{{1
+
+let s:svnFunctions = {}
+
+" Section: Utility functions {{{1
+
+" Function: s:DoCommand(cmd, cmdName, statusText, options) {{{2
+" Wrapper to VCSCommandDoCommand to add the name of the SVN executable to the
+" command argument.
+function! s:DoCommand(cmd, cmdName, statusText, options)
+ if VCSCommandGetVCSType(expand('%')) == 'SVN'
+ let fullCmd = VCSCommandGetOption('VCSCommandSVNExec', 'svn') . ' ' . a:cmd
+ return VCSCommandDoCommand(fullCmd, a:cmdName, a:statusText, a:options)
+ else
+ throw 'SVN VCSCommand plugin called on non-SVN item.'
+ endif
+endfunction
+
+" Section: VCS function implementations {{{1
+
+" Function: s:svnFunctions.Identify(buffer) {{{2
+function! s:svnFunctions.Identify(buffer)
+ let fileName = resolve(bufname(a:buffer))
+ if isdirectory(fileName)
+ let directoryName = fileName
+ else
+ let directoryName = fnamemodify(fileName, ':h')
+ endif
+ if strlen(directoryName) > 0
+ let svnDir = directoryName . '/.svn'
+ else
+ let svnDir = '.svn'
+ endif
+ if isdirectory(svnDir)
+ return 1
+ else
+ return 0
+ endif
+endfunction
+
+" Function: s:svnFunctions.Add() {{{2
+function! s:svnFunctions.Add(argList)
+ return s:DoCommand(join(['add'] + a:argList, ' '), 'add', join(a:argList, ' '), {})
+endfunction
+
+" Function: s:svnFunctions.Annotate(argList) {{{2
+function! s:svnFunctions.Annotate(argList)
+ if len(a:argList) == 0
+ if &filetype == 'SVNAnnotate'
+ " Perform annotation of the version indicated by the current line.
+ let caption = matchstr(getline('.'),'\v^\s+\zs\d+')
+ let options = ' -r' . caption
+ else
+ let caption = ''
+ let options = ''
+ endif
+ elseif len(a:argList) == 1 && a:argList[0] !~ '^-'
+ let caption = a:argList[0]
+ let options = ' -r' . caption
+ else
+ let caption = join(a:argList, ' ')
+ let options = ' ' . caption
+ endif
+
+ let resultBuffer = s:DoCommand('blame' . options, 'annotate', caption, {})
+ if resultBuffer > 0
+ set filetype=SVNAnnotate
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:svnFunctions.Commit(argList) {{{2
+function! s:svnFunctions.Commit(argList)
+ let resultBuffer = s:DoCommand('commit -F "' . a:argList[0] . '"', 'commit', '', {})
+ if resultBuffer == 0
+ echomsg 'No commit needed.'
+ endif
+endfunction
+
+" Function: s:svnFunctions.Delete() {{{2
+function! s:svnFunctions.Delete(argList)
+ return s:DoCommand(join(['delete'] + a:argList, ' '), 'delete', join(a:argList, ' '), {})
+endfunction
+
+" Function: s:svnFunctions.Diff(argList) {{{2
+function! s:svnFunctions.Diff(argList)
+ if len(a:argList) == 0
+ let revOptions = []
+ let caption = ''
+ elseif len(a:argList) <= 2 && match(a:argList, '^-') == -1
+ let revOptions = ['-r' . join(a:argList, ':')]
+ let caption = '(' . a:argList[0] . ' : ' . get(a:argList, 1, 'current') . ')'
+ else
+ " Pass-through
+ let caption = join(a:argList, ' ')
+ let revOptions = a:argList
+ endif
+
+ let svnDiffExt = VCSCommandGetOption('VCSCommandSVNDiffExt', '')
+ if svnDiffExt == ''
+ let diffExt = []
+ else
+ let diffExt = ['--diff-cmd ' . svnDiffExt]
+ endif
+
+ let svnDiffOpt = VCSCommandGetOption('VCSCommandSVNDiffOpt', '')
+ if svnDiffOpt == ''
+ let diffOptions = []
+ else
+ let diffOptions = ['-x -' . svnDiffOpt]
+ endif
+
+ let resultBuffer = s:DoCommand(join(['diff'] + diffExt + diffOptions + revOptions), 'diff', caption, {})
+ if resultBuffer > 0
+ set filetype=diff
+ else
+ if svnDiffExt == ''
+ echomsg 'No differences found'
+ endif
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:svnFunctions.GetBufferInfo() {{{2
+" Provides version control details for the current file. Current version
+" number and current repository version number are required to be returned by
+" the vcscommand plugin.
+" Returns: List of results: [revision, repository, branch]
+
+function! s:svnFunctions.GetBufferInfo()
+ let originalBuffer = VCSCommandGetOriginalBuffer(bufnr('%'))
+ let fileName = bufname(originalBuffer)
+ let statusText = system(VCSCommandGetOption('VCSCommandSVNExec', 'svn') . ' status -vu "' . fileName . '"')
+ if(v:shell_error)
+ return []
+ endif
+
+ " File not under SVN control.
+ if statusText =~ '^?'
+ return ['Unknown']
+ endif
+
+ let [flags, revision, repository] = matchlist(statusText, '^\(.\{8}\)\s\+\(\S\+\)\s\+\(\S\+\)\s\+\(\S\+\)\s')[1:3]
+ if revision == ''
+ " Error
+ return ['Unknown']
+ elseif flags =~ '^A'
+ return ['New', 'New']
+ else
+ return [revision, repository]
+ endif
+endfunction
+
+" Function: s:svnFunctions.Info(argList) {{{2
+function! s:svnFunctions.Info(argList)
+ return s:DoCommand(join(['info'] + a:argList, ' '), 'info', join(a:argList, ' '), {})
+endfunction
+
+" Function: s:svnFunctions.Lock(argList) {{{2
+function! s:svnFunctions.Lock(argList)
+ return s:DoCommand(join(['lock'] + a:argList, ' '), 'lock', join(a:argList, ' '), {})
+endfunction
+
+" Function: s:svnFunctions.Log(argList) {{{2
+function! s:svnFunctions.Log(argList)
+ if len(a:argList) == 0
+ let options = []
+ let caption = ''
+ elseif len(a:argList) <= 2 && match(a:argList, '^-') == -1
+ let options = ['-r' . join(a:argList, ':')]
+ let caption = options[0]
+ else
+ " Pass-through
+ let options = a:argList
+ let caption = join(a:argList, ' ')
+ endif
+
+ let resultBuffer = s:DoCommand(join(['log', '-v'] + options), 'log', caption, {})
+ return resultBuffer
+endfunction
+
+" Function: s:svnFunctions.Revert(argList) {{{2
+function! s:svnFunctions.Revert(argList)
+ return s:DoCommand('revert', 'revert', '', {})
+endfunction
+
+" Function: s:svnFunctions.Review(argList) {{{2
+function! s:svnFunctions.Review(argList)
+ if len(a:argList) == 0
+ let versiontag = '(current)'
+ let versionOption = ''
+ else
+ let versiontag = a:argList[0]
+ let versionOption = ' -r ' . versiontag . ' '
+ endif
+
+ let resultBuffer = s:DoCommand('cat' . versionOption, 'review', versiontag, {})
+ if resultBuffer > 0
+ let &filetype = getbufvar(b:VCSCommandOriginalBuffer, '&filetype')
+ endif
+ return resultBuffer
+endfunction
+
+" Function: s:svnFunctions.Status(argList) {{{2
+function! s:svnFunctions.Status(argList)
+ let options = ['-u', '-v']
+ if len(a:argList) == 0
+ let options = a:argList
+ endif
+ return s:DoCommand(join(['status'] + options, ' '), 'status', join(options, ' '), {})
+endfunction
+
+" Function: s:svnFunctions.Unlock(argList) {{{2
+function! s:svnFunctions.Unlock(argList)
+ return s:DoCommand(join(['unlock'] + a:argList, ' '), 'unlock', join(a:argList, ' '), {})
+endfunction
+" Function: s:svnFunctions.Update(argList) {{{2
+function! s:svnFunctions.Update(argList)
+ return s:DoCommand('update', 'update', '', {})
+endfunction
+
+" Section: Plugin Registration {{{1
+call VCSCommandRegisterModule('SVN', expand('<sfile>'), s:svnFunctions, [])
+
+let &cpo = s:save_cpo
--- /dev/null
+" Vim syntax file
+" Language: CVS annotate output
+" Maintainer: Bob Hiestand <
[email protected]>
+" Remark: Used by the cvscommand plugin. Originally written by Mathieu
+" Clabaut
+" License:
+" Copyright (c) 2007 Bob Hiestand
+"
+" 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 version < 600
+ syntax clear
+elseif exists("b:current_syntax")
+ finish
+endif
+
+syn match cvsDate /\d\d-...-\d\d/ contained
+syn match cvsName /(\S* /hs=s+1,he=e-1 contained nextgroup=cvsDate
+syn match cvsVer /^\d\+\(\.\d\+\)\+/ contained nextgroup=cvsName
+syn region cvsHead start="^\d\+\.\d\+" end="):" contains=cvsVer,cvsName,cvsDate
+
+if !exists("did_cvsannotate_syntax_inits")
+ let did_cvsannotate_syntax_inits = 1
+ hi link cvsDate Comment
+ hi link cvsName Type
+ hi link cvsVer Statement
+endif
+
+let b:current_syntax="CVSAnnotate"
--- /dev/null
+" Vim syntax file
+" Language: SVK annotate output
+" Maintainer: Bob Hiestand <
[email protected]>
+" Remark: Used by the vcscommand plugin.
+" License:
+" Copyright (c) 2007 Bob Hiestand
+"
+" 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("b:current_syntax")
+ finish
+endif
+
+syn match svkDate /\d\{4}-\d\{1,2}-\d\{1,2}/ skipwhite contained
+syn match svkName /(\s*\zs\S\+/ contained nextgroup=svkDate skipwhite
+syn match svkVer /^\s*\d\+/ contained nextgroup=svkName skipwhite
+syn region svkHead start=/^/ end="):" contains=svkVer,svkName,svkDate oneline
+
+if !exists("did_svkannotate_syntax_inits")
+ let did_svkannotate_syntax_inits = 1
+ hi link svkName Type
+ hi link svkDate Comment
+ hi link svkVer Statement
+endif
+
+let b:current_syntax="svkAnnotate"
--- /dev/null
+" Vim syntax file
+" Language: SVN annotate output
+" Maintainer: Bob Hiestand <
[email protected]>
+" Remark: Used by the vcscommand plugin.
+" License:
+" Copyright (c) 2007 Bob Hiestand
+"
+" 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("b:current_syntax")
+ finish
+endif
+
+syn match svnName /\S\+/ contained
+syn match svnVer /^\s\+\zs\d\+/ contained nextgroup=svnName skipwhite
+syn match svnHead /^\s\+\d\+\s\+\S\+/ contains=svnVer,svnName
+
+if !exists("did_svnannotate_syntax_inits")
+ let did_svnannotate_syntax_inits = 1
+ hi link svnName Type
+ hi link svnVer Statement
+endif
+
+let b:current_syntax="svnAnnotate"
--- /dev/null
+" Vim syntax file
+" Language: VCS commit file
+" Maintainer: Bob Hiestand (
[email protected])
+" License:
+" Copyright (c) 2007 Bob Hiestand
+"
+" 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("b:current_syntax")
+ finish
+endif
+
+syntax region vcsComment start="^VCS: " end="$"
+highlight link vcsComment Comment
+let b:current_syntax = "vcscommit"