diff options
| author | Silvio Rhatto <rhatto@riseup.net> | 2013-02-01 01:25:10 -0200 | 
|---|---|---|
| committer | Silvio Rhatto <rhatto@riseup.net> | 2013-02-01 01:25:10 -0200 | 
| commit | 6b9187673ee62d11042832f938913f15131592a7 (patch) | |
| tree | 9e70016667efe273a72ab351aafaddbdb099e123 /modules/vim/vim.dot.link/plugin | |
| parent | 25235935e6c90557a4d6791c8d8f3a5cdf89681a (diff) | |
| download | metadot-6b9187673ee62d11042832f938913f15131592a7.tar.gz metadot-6b9187673ee62d11042832f938913f15131592a7.tar.bz2  | |
Adding metadot script
Diffstat (limited to 'modules/vim/vim.dot.link/plugin')
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/Rename.vim | 27 | ||||
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/bufexplorer.vim | 1157 | ||||
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/git.vim | 372 | ||||
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/indexer.vim.disabled | 672 | ||||
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/project.vim | 1293 | ||||
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/snipMate.vim | 247 | ||||
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/startshell_mapping.vim.disabled | 36 | ||||
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/taglist.vim | 4546 | ||||
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/vcsbzr.vim | 262 | ||||
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/vcscommand.vim | 1427 | ||||
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/vcscvs.vim | 449 | ||||
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/vcsgit.vim | 247 | ||||
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/vcshg.vim | 273 | ||||
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/vcssvk.vim | 257 | ||||
| -rw-r--r-- | modules/vim/vim.dot.link/plugin/vcssvn.vim | 284 | 
15 files changed, 11549 insertions, 0 deletions
diff --git a/modules/vim/vim.dot.link/plugin/Rename.vim b/modules/vim/vim.dot.link/plugin/Rename.vim new file mode 100644 index 0000000..b56c516 --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/Rename.vim @@ -0,0 +1,27 @@ +" Rename.vim  -  Rename a buffer within Vim and on the disk +" +" Copyright June 2007 by Christian J. Robinson <infynity@onewest.net> +" +" Distributed under the terms of the Vim license.  See ":help license". +" +" Usage: +" +" :Rename[!] {newname} + +command! -nargs=* -complete=file -bang Rename :call Rename("<args>", "<bang>") + +function! Rename(name, bang) +	let l:curfile = expand("%:p") +	let v:errmsg = "" +	silent! exe "saveas" . a:bang . " " . a:name +	if v:errmsg =~# '^$\|^E329' +		if expand("%:p") !=# l:curfile && filewritable(expand("%:p")) +			silent exe "bwipe! " . l:curfile +			if delete(l:curfile) +				echoerr "Could not delete " . l:curfile +			endif +		endif +	else +		echoerr v:errmsg +	endif +endfunction diff --git a/modules/vim/vim.dot.link/plugin/bufexplorer.vim b/modules/vim/vim.dot.link/plugin/bufexplorer.vim new file mode 100644 index 0000000..de957d8 --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/bufexplorer.vim @@ -0,0 +1,1157 @@ +"============================================================================= +"    Copyright: Copyright (C) 2001-2012 Jeff Lanzarotta +"               Permission is hereby granted to use and distribute this code, +"               with or without modifications, provided that this copyright +"               notice is copied with it. Like anything else that's free, +"               bufexplorer.vim is provided *as is* and comes with no +"               warranty of any kind, either expressed or implied. In no +"               event will the copyright holder be liable for any damages +"               resulting from the use of this software. +" Name Of File: bufexplorer.vim +"  Description: Buffer Explorer Vim Plugin +"   Maintainer: Jeff Lanzarotta (delux256-vim at yahoo dot com) +" Last Changed: Sunday, 23 Dec 2012 +"      Version: See g:bufexplorer_version for version number. +"        Usage: This file should reside in the plugin directory and be +"               automatically sourced. +" +"               You may use the default keymappings of +" +"                 <Leader>be  - Opens BufExplorer +"                 <Leader>bs  - Opens horizontally split window BufExplorer +"                 <Leader>bv  - Opens vertically split window BufExplorer +" +"               Or you can override the defaults and define your own mapping +"               in your vimrc file, for example: +" +"                   noremap <silent> <F11> :BufExplorer<CR> +"                   noremap <silent> <m-F11> :BufExplorerHorizontalSplit<CR> +"                   noremap <silent> <c-F11> :BufExplorerVerticalSplit<CR> +" +"               Or you can use +" +"                 ":BufExplorer"                - Opens BufExplorer +"                 ":BufExplorerHorizontalSplit" - Opens horizontally window BufExplorer +"                 ":BufExplorerVerticalSplit"   - Opens vertically split window BufExplorer +" +"               For more help see supplied documentation. +"      History: See supplied documentation. +"      Issues: 'D' and 'd' remove the buffer from the list but the list is not +"              displayed correctly. +"              - Add ability to open a buffer in a new split when \be is used. +"============================================================================= + +" Plugin Code {{{1 +" Exit quickly if already running or when 'compatible' is set. {{{2 +if exists("g:bufexplorer_version") || &cp +    finish +endif +"2}}} + +" Version number +let g:bufexplorer_version = "7.3.2" + +" Check for Vim version {{{2 +if v:version < 700 +    echohl WarningMsg +    echo "Sorry, bufexplorer ".g:bufexplorer_version." required Vim 7.0 and greater." +    echohl None +    finish +endif + +" Create commands {{{2 +command! BufExplorer :call BufExplorer(has ("gui") ? "drop" : "hide edit") +command! BufExplorerHorizontalSplit :call BufExplorerHorizontalSplit() +command! BufExplorerVerticalSplit :call BufExplorerVerticalSplit() + +" Set {{{2 +function! s:Set(var, default) +    if !exists(a:var) +        if type(a:default) +            exec "let" a:var "=" string(a:default) +        else +            exec "let" a:var "=" a:default +        endif + +        return 1 +    endif + +    return 0 +endfunction + +" Script variables {{{2 +let s:MRU_Exclude_List = ["[BufExplorer]","__MRU_Files__"] +let s:MRUList = [] +let s:name = '[BufExplorer]' +let s:originBuffer = 0 +let s:running = 0 +let s:sort_by = ["number", "name", "fullpath", "mru", "extension"] +let s:splitMode = "" +let s:tabSpace = [] +let s:types = {"fullname": ':p', "path": ':p:h', "relativename": ':~:.', "relativepath": ':~:.:h', "shortname": ':t'} + +" Setup the autocommands that handle the MRUList and other stuff. {{{2 +autocmd VimEnter * call s:Setup() + +" Setup {{{2 +function! s:Setup() +    call s:Reset() + +    " Now that the MRUList is created, add the other autocmds. +    augroup BufExplorer +        autocmd! +        autocmd BufEnter,BufNew * call s:ActivateBuffer() +        autocmd BufWipeOut * call s:DeactivateBuffer(1) +        autocmd BufDelete * call s:DeactivateBuffer(0) + +        autocmd BufWinEnter \[BufExplorer\] call s:Initialize() +        autocmd BufWinLeave \[BufExplorer\] call s:Cleanup() + +        autocmd TabEnter * call s:TabEnter() + +        autocmd SessionLoadPost * call s:Reset() +    augroup END +endfunction + +" Reset {{{2 +function! s:Reset() +    " Build initial MRUList. This makes sure all the files specified on the +    " command line are picked up correctly. +    let s:MRUList = range(1, bufnr('$')) + +    " Initialize one tab space array, ignore zero-based tabpagenr +    " since all tabpagenr's start at 1. +    " -1 signifies this is the first time we are referencing this +    " tabpagenr. +    " If Vim has been loaded with mksession, then it is possible for +    " more tabs to exist.  So use tabpagenr() to determine how large +    " to make the array. If there are 4 tabs, there should be 5 +    " elements in this array. +    " Each element will hold a CSV list of buffers viewed in +    " that tab.  So on the 3rd tab, if there user has viewed +    " 4 different buffers in that tab, the value would be: +    "    echo s:tabSpace[3] +    "    [4, 9, 1, 10] +    "    echo s:tabSpace +    "    [[-1], [-1], [-1], [4, 9, 1, 10], [-1]] +    let s:tabSpace = [] +    let i = 0 + +    while( tabpagenr('$') > 0 && i <= tabpagenr('$') ) +        call add(s:tabSpace, [-1]) +        let i = i + 1 +    endwhile +endfunction + +" ActivateBuffer {{{2 +function! s:ActivateBuffer() +    " Verify the current tabpage exists in the +    " current s:tabSpace array.  This can be missing +    " entries when restoring sessions. +    let i = 0 +    while( tabpagenr('$') > 0 && i <= tabpagenr() ) +        " Number:     0 +        " String:     1 +        " Funcref:    2 +        " List:       3 +        " Dictionary: 4 +        " Float:      5 +        if type(get(s:tabSpace, i)) == 0 +            call add(s:tabSpace, [-1]) +        endif + +        let i = i + 1 +    endwhile + +    let _bufnr = bufnr("%") +    let list = get(s:tabSpace, tabpagenr(), [-1]) + +    if !empty(list) && list[0] == '-1' +        " The first time we add a tab, Vim uses the current buffer +        " as it's starting page.  Even though we are about to +        " edit a new page (BufEnter is triggered after), so +        " remove the -1 entry indicating we have covered this case. +        let list = [] +        call add(list, _bufnr) +        let s:tabSpace[tabpagenr()] = list +    elseif empty(list) || index(list, _bufnr) == -1 +        " Add new buffer to this tab's buffer list. +        call add(list, _bufnr) +        let s:tabSpace[tabpagenr()] = list + +        if g:bufExplorerOnlyOneTab == 1 +            " If a buffer can only be available in 1 tab page ensure this +            " buffer is not present in any other tabs +            let tabidx = 1 +            while tabidx < len(s:tabSpace) +                if tabidx != tabpagenr() +                    let bufidx = index(s:tabSpace[tabidx], _bufnr) +                    if bufidx != -1 +                        call remove(s:tabSpace[tabidx], bufidx) +                    endif +                endif +                let tabidx = tabidx + 1 +            endwhile +        endif +    endif + +    call s:MRUPush(_bufnr) +endfunction + +" DeactivateBuffer {{{2 +function! s:DeactivateBuffer(remove) +    let _bufnr = str2nr(expand("<abuf>")) +    call s:MRUPop(_bufnr) +endfunction + +" TabEnter {{{2 +function! s:TabEnter() +    " Make s:tabSpace 1-based +    if empty(s:tabSpace) || len(s:tabSpace) < (tabpagenr() + 1) +        call add(s:tabSpace, [-1]) +    endif +endfunction + +" MRUPop {{{2 +function! s:MRUPop(bufnr) +    call filter(s:MRUList, 'v:val != '.a:bufnr) +endfunction + +" MRUPush {{{2 +function! s:MRUPush(buf) +    " Skip temporary buffer with buftype set. Don't add the BufExplorer window to the +    " list. +    if s:ShouldIgnore(a:buf) == 1 +        return +    endif + +    " Remove the buffer number from the list if it already exists. +    call s:MRUPop(a:buf) + +    " Add the buffer number to the head of the list. +    call insert(s:MRUList, a:buf) +endfunction + +" ShouldIgnore {{{2 +function! s:ShouldIgnore(buf) +    " Ignore temporary buffers with buftype set. +    if empty(getbufvar(a:buf, "&buftype") == 0) +        return 1 +    endif + +    " Ignore unlisted buffers. +    if buflisted(a:buf) == 0 +        return 1 +    endif + +    " Ignore buffers with no name. +    if empty(bufname(a:buf)) == 1 +        return 1 +    endif + +    " Ignore the BufExplorer buffer. +    if fnamemodify(bufname(a:buf), ":t") == s:name +        return 1 +    endif + +    " Ignore any buffers in the exclude list. +    if index(s:MRU_Exclude_List, bufname(a:buf)) >= 0 +        return 1 +    endif + +    " Else return 0 to indicate that the buffer was not ignored. +    return 0 +endfunction + +" Initialize {{{2 +function! s:Initialize() +    let s:_insertmode = &insertmode +    set noinsertmode + +    let s:_showcmd = &showcmd +    set noshowcmd + +    let s:_cpo = &cpo +    set cpo&vim + +    let s:_report = &report +    let &report = 10000 + +    let s:_list = &list +    set nolist + +    setlocal nonumber +    setlocal foldcolumn=0 +    setlocal nofoldenable +    setlocal cursorline +    setlocal nospell + +    setlocal nobuflisted + +    let s:running = 1 +endfunction + +" Cleanup {{{2 +function! s:Cleanup() +    if exists("s:_insertmode") +        let &insertmode = s:_insertmode +    endif + +    if exists("s:_showcmd") +        let &showcmd = s:_showcmd +    endif + +    if exists("s:_cpo") +        let &cpo = s:_cpo +    endif + +    if exists("s:_report") +        let &report = s:_report +    endif + +    if exists("s:_list") +        let &list = s:_list +    endif + +    let s:running = 0 +    let s:splitMode = "" + +    delmarks! +endfunction + +" BufExplorerHorizontalSplit {{{2 +function! BufExplorerHorizontalSplit() +    let s:splitMode = "sp" +    exec "BufExplorer" +endfunction + +" BufExplorerVerticalSplit {{{2 +function! BufExplorerVerticalSplit() +    let s:splitMode = "vsp" +    exec "BufExplorer" +endfunction + +" BufExplorer {{{2 +function! BufExplorer(open) +    let name = s:name + +    if !has("win32") +        " On non-Windows boxes, escape the name so that is shows up correctly. +        let name = escape(name, "[]") +    endif + +    " Make sure there is only one explorer open at a time. +    if s:running == 1 +        " Go to the open buffer. +        if has("gui") +            exec "drop" name +        endif + +        return +    endif + +    " Add zero to ensure the variable is treated as a number. +    let s:originBuffer = bufnr("%") + 0 + +    silent let s:raw_buffer_listing = s:GetBufferInfo(0) + +    let buffer_listing_copy = copy(s:raw_buffer_listing) + +    if (g:bufExplorerShowUnlisted == 0) +        call filter(buffer_listing_copy, 'v:val.attributes !~ "u"') +    endif + +    if (!empty(buffer_listing_copy)) +        call filter(buffer_listing_copy, 'v:val.shortname !~ "\\\[No Name\\\]"') +    endif + +"   if len(buffer_listing_copy) <= 1 +"       call s:Warning("Sorry, there are no more buffers to explore") +"       return +"   endif + +    " We may have to split the current window. +    if (s:splitMode != "") +        " Save off the original settings. +        let [_splitbelow, _splitright] = [&splitbelow, &splitright] + +        " Set the setting to ours. +        let [&splitbelow, &splitright] = [g:bufExplorerSplitBelow, g:bufExplorerSplitRight] + +        " Do it. +        exe 'keepalt '.s:splitMode + +        " Restore the original settings. +        let [&splitbelow, &splitright] = [_splitbelow, _splitright] +    endif + +    if !exists("b:displayMode") || b:displayMode != "winmanager" +        " Do not use keepalt when opening bufexplorer to allow the buffer that +        " we are leaving to become the new alternate buffer +        exec "silent keepjumps ".a:open." ".name +    endif + +    call s:DisplayBufferList() + +    " Position the cursor in the newly displayed list on the line representing +    " the active buffer.  The active buffer is the line with the '%' character +    " in it. +    execute search("%") +endfunction + +" DisplayBufferList {{{2 +function! s:DisplayBufferList() +    " Do not set bufhidden since it wipes out the data if we switch away from +    " the buffer using CTRL-^. +    setlocal buftype=nofile +    setlocal modifiable +    setlocal noswapfile +    setlocal nowrap + +    call s:SetupSyntax() +    call s:MapKeys() +    call setline(1, s:CreateHelp()) +    call s:BuildBufferList() +    call cursor(s:firstBufferLine, 1) + +    if !g:bufExplorerResize +        normal! zz +    endif + +    setlocal nomodifiable +endfunction + +" MapKeys {{{2 +function! s:MapKeys() +    if exists("b:displayMode") && b:displayMode == "winmanager" +        nnoremap <buffer> <silent> <tab> :call <SID>SelectBuffer()<CR> +    endif + +    nnoremap <script> <silent> <buffer> <2-leftmouse> :call <SID>SelectBuffer()<CR> +    nnoremap <script> <silent> <buffer> <CR>          :call <SID>SelectBuffer()<CR> +    nnoremap <script> <silent> <buffer> <F1>          :call <SID>ToggleHelp()<CR> +    nnoremap <script> <silent> <buffer> <s-cr>        :call <SID>SelectBuffer("tab")<CR> +    nnoremap <script> <silent> <buffer> B             :call <SID>ToggleOnlyOneTab()<CR> +    nnoremap <script> <silent> <buffer> d             :call <SID>RemoveBuffer("delete")<CR> +    nnoremap <script> <silent> <buffer> D             :call <SID>RemoveBuffer("wipe")<CR> +    nnoremap <script> <silent> <buffer> f             :call <SID>ToggleFindActive()<CR> +    nnoremap <script> <silent> <buffer> m             :call <SID>MRUListShow()<CR> +    nnoremap <script> <silent> <buffer> o             :call <SID>SelectBuffer()<CR> +    nnoremap <script> <silent> <buffer> p             :call <SID>ToggleSplitOutPathName()<CR> +    nnoremap <script> <silent> <buffer> q             :call <SID>Close()<CR> +    nnoremap <script> <silent> <buffer> r             :call <SID>SortReverse()<CR> +    nnoremap <script> <silent> <buffer> R             :call <SID>ToggleShowRelativePath()<CR> +    nnoremap <script> <silent> <buffer> s             :call <SID>SortSelect()<CR> +    nnoremap <script> <silent> <buffer> S             :call <SID>ReverseSortSelect()<CR> +    nnoremap <script> <silent> <buffer> t             :call <SID>SelectBuffer("tab")<CR> +    nnoremap <script> <silent> <buffer> T             :call <SID>ToggleShowTabBuffer()<CR> +    nnoremap <script> <silent> <buffer> u             :call <SID>ToggleShowUnlisted()<CR> + +    for k in ["G", "n", "N", "L", "M", "H"] +        exec "nnoremap <buffer> <silent>" k ":keepjumps normal!" k."<CR>" +    endfor +endfunction + +" SetupSyntax {{{2 +function! s:SetupSyntax() +    if has("syntax") +        syn match bufExplorerHelp     "^\".*" contains=bufExplorerSortBy,bufExplorerMapping,bufExplorerTitle,bufExplorerSortType,bufExplorerToggleSplit,bufExplorerToggleOpen +        syn match bufExplorerOpenIn   "Open in \w\+ window" contained +        syn match bufExplorerSplit    "\w\+ split" contained +        syn match bufExplorerSortBy   "Sorted by .*" contained contains=bufExplorerOpenIn,bufExplorerSplit +        syn match bufExplorerMapping  "\" \zs.\+\ze :" contained +        syn match bufExplorerTitle    "Buffer Explorer.*" contained +        syn match bufExplorerSortType "'\w\{-}'" contained +        syn match bufExplorerBufNbr   /^\s*\d\+/ +        syn match bufExplorerToggleSplit  "toggle split type" contained +        syn match bufExplorerToggleOpen   "toggle open mode" contained + +        syn match bufExplorerModBuf    /^\s*\d\+.\{4}+.*/ +        syn match bufExplorerLockedBuf /^\s*\d\+.\{3}[\-=].*/ +        syn match bufExplorerHidBuf    /^\s*\d\+.\{2}h.*/ +        syn match bufExplorerActBuf    /^\s*\d\+.\{2}a.*/ +        syn match bufExplorerCurBuf    /^\s*\d\+.%.*/ +        syn match bufExplorerAltBuf    /^\s*\d\+.#.*/ +        syn match bufExplorerUnlBuf    /^\s*\d\+u.*/ + +        hi def link bufExplorerBufNbr Number +        hi def link bufExplorerMapping NonText +        hi def link bufExplorerHelp Special +        hi def link bufExplorerOpenIn Identifier +        hi def link bufExplorerSortBy String +        hi def link bufExplorerSplit NonText +        hi def link bufExplorerTitle NonText +        hi def link bufExplorerSortType bufExplorerSortBy +        hi def link bufExplorerToggleSplit bufExplorerSplit +        hi def link bufExplorerToggleOpen bufExplorerOpenIn + +        hi def link bufExplorerActBuf Identifier +        hi def link bufExplorerAltBuf String +        hi def link bufExplorerCurBuf Type +        hi def link bufExplorerHidBuf Constant +        hi def link bufExplorerLockedBuf Special +        hi def link bufExplorerModBuf Exception +        hi def link bufExplorerUnlBuf Comment +    endif +endfunction + +" ToggleHelp {{{2 +function! s:ToggleHelp() +    let g:bufExplorerDetailedHelp = !g:bufExplorerDetailedHelp + +    setlocal modifiable + +    " Save position. +    normal! ma + +    " Remove old header. +    if (s:firstBufferLine > 1) +        exec "keepjumps 1,".(s:firstBufferLine - 1) "d _" +    endif + +    call append(0, s:CreateHelp()) + +    silent! normal! g`a +    delmarks a + +    setlocal nomodifiable + +    if exists("b:displayMode") && b:displayMode == "winmanager" +        call WinManagerForceReSize("BufExplorer") +    endif +endfunction + +" GetHelpStatus {{{2 +function! s:GetHelpStatus() +    let ret = '" Sorted by '.((g:bufExplorerReverseSort == 1) ? "reverse " : "").g:bufExplorerSortBy +    let ret .= ' | '.((g:bufExplorerFindActive == 0) ? "Don't " : "")."Locate buffer" +    let ret .= ((g:bufExplorerShowUnlisted == 0) ? "" : " | Show unlisted") +    let ret .= ((g:bufExplorerShowTabBuffer == 0) ? "" : " | Show buffers/tab") +    let ret .= ((g:bufExplorerOnlyOneTab == 1) ? "" : " | One tab/buffer") +    let ret .= ' | '.((g:bufExplorerShowRelativePath == 0) ? "Absolute" : "Relative") +    let ret .= ' '.((g:bufExplorerSplitOutPathName == 0) ? "Full" : "Split")." path" + +    return ret +endfunction + +" CreateHelp {{{2 +function! s:CreateHelp() +    if g:bufExplorerDefaultHelp == 0 && g:bufExplorerDetailedHelp == 0 +        let s:firstBufferLine = 1 +        return [] +    endif + +    let header = [] + +    if g:bufExplorerDetailedHelp == 1 +        call add(header, '" Buffer Explorer ('.g:bufexplorer_version.')') +        call add(header, '" --------------------------') +        call add(header, '" <F1> : toggle this help') +        call add(header, '" <enter> or o or Mouse-Double-Click : open buffer under cursor') +        call add(header, '" <shift-enter> or t : open buffer in another tab') +        call add(header, '" B : toggle if to save/use recent tab or not') +        call add(header, '" d : delete buffer') +        call add(header, '" D : wipe buffer') +        call add(header, '" f : toggle find active buffer') +        call add(header, '" p : toggle spliting of file and path name') +        call add(header, '" q : quit') +        call add(header, '" r : reverse sort') +        call add(header, '" R : toggle showing relative or full paths') +        call add(header, '" s : cycle thru "sort by" fields '.string(s:sort_by).'') +        call add(header, '" S : reverse cycle thru "sort by" fields') +        call add(header, '" T : toggle if to show only buffers for this tab or not') +        call add(header, '" u : toggle showing unlisted buffers') +    else +        call add(header, '" Press <F1> for Help') +    endif + +    if (!exists("b:displayMode") || b:displayMode != "winmanager") || (b:displayMode == "winmanager" && g:bufExplorerDetailedHelp == 1) +        call add(header, s:GetHelpStatus()) +        call add(header, '"=') +    endif + +    let s:firstBufferLine = len(header) + 1 + +    return header +endfunction + +" GetBufferInfo {{{2 +function! s:GetBufferInfo(bufnr) +    redir => bufoutput +    buffers! +    redir END + +    if (a:bufnr > 0) +        " Since we are only interested in this specified buffer +        " remove the other buffers listed +        let bufoutput = substitute(bufoutput."\n", '^.*\n\(\s*'.a:bufnr.'\>.\{-}\)\n.*', '\1', '') +    endif + +    let [all, allwidths, listedwidths] = [[], {}, {}] + +    for n in keys(s:types) +        let allwidths[n] = [] +        let listedwidths[n] = [] +    endfor + +    " Loop over each line in the buffer. +    for buf in split(bufoutput, '\n') +        let bits = split(buf, '"') +        let b = {"attributes": bits[0], "line": substitute(bits[2], '\s*', '', '')} + +        for [key, val] in items(s:types) +            let b[key] = fnamemodify(bits[1], val) +        endfor + +        if getftype(b.fullname) == "dir" && g:bufExplorerShowDirectories == 1 +            let b.shortname = "<DIRECTORY>" +        endif + +        call add(all, b) + +        for n in keys(s:types) +            call add(allwidths[n], len(b[n])) + +            if b.attributes !~ "u" +                call add(listedwidths[n], len(b[n])) +            endif +        endfor +    endfor + +    let [s:allpads, s:listedpads] = [{}, {}] + +    for n in keys(s:types) +        let s:allpads[n] = repeat(' ', max(allwidths[n])) +        let s:listedpads[n] = repeat(' ', max(listedwidths[n])) +    endfor + +    return all +endfunction + +" BuildBufferList {{{2 +function! s:BuildBufferList() +    let lines = [] + +    " Loop through every buffer. +    for buf in s:raw_buffer_listing +        " Skip unlisted buffers if we are not to show them. +        if (!g:bufExplorerShowUnlisted && buf.attributes =~ "u") +            " Skip unlisted buffers if we are not to show them. +            continue +        endif + +        " Ignore buffers with no name. +        if empty(bufname(str2nr(buf.attributes))) == 1 +            continue +        endif + +        if (g:bufExplorerShowTabBuffer) +            let show_buffer = 0 + +            for bufnr in s:tabSpace[tabpagenr()] +                if (buf.attributes =~ '^\s*'.bufnr.'\>') +                    " Only buffers shown on the current tabpagenr +                    let show_buffer = 1 +                    break +                endif +            endfor + +            if show_buffer == 0 +                continue +            endif +        endif + +        let line = buf.attributes." " + +        if g:bufExplorerSplitOutPathName +            let type = (g:bufExplorerShowRelativePath) ? "relativepath" : "path" +            let path = buf[type] +            let pad  = (g:bufExplorerShowUnlisted) ? s:allpads.shortname : s:listedpads.shortname +            let line .= buf.shortname." ".strpart(pad.path, len(buf.shortname)) +        else +            let type = (g:bufExplorerShowRelativePath) ? "relativename" : "fullname" +            let path = buf[type] +            let line .= path +        endif + +        let pads = (g:bufExplorerShowUnlisted) ? s:allpads : s:listedpads + +        if !empty(pads[type]) +            let line .= strpart(pads[type], len(path))." " +        endif + +        let line .= buf.line + +        call add(lines, line) +    endfor + +    call setline(s:firstBufferLine, lines) + +    call s:SortListing() +endfunction + +" SelectBuffer {{{2 +function! s:SelectBuffer(...) +    " Sometimes messages are not cleared when we get here so it looks like an +    " error has occurred when it really has not. +" 3/25/2012    echo "" + +    " Are we on a line with a file name? +    if line('.') < s:firstBufferLine +        exec "normal! \<CR>" +        return +    endif + +    let _bufNbr = str2nr(getline('.')) + +    " Check and see if we are running BufferExplorer via WinManager. +    if exists("b:displayMode") && b:displayMode == "winmanager" +        let _bufName = expand("#"._bufNbr.":p") + +        if (a:0 == 1) && (a:1 == "tab") +            call WinManagerFileEdit(_bufName, 1) +        else +            call WinManagerFileEdit(_bufName, 0) +        endif + +        return +    endif + +    if bufexists(_bufNbr) +        if bufnr("#") == _bufNbr && !exists("g:bufExplorerChgWin") +            return s:Close() +        endif + +        " Are we suppose to open the selected buffer in a tab? +        if (a:0 == 1) && (a:1 == "tab") +            " Yes, we are to open the selected buffer in a tab. + +            " Restore [BufExplorer] buffer. +            exec "keepjumps silent buffer!".s:originBuffer + +            " Get the tab nmber where this bufer is located in. +            let tabNbr = s:GetTabNbr(_bufNbr) + +            " Was the tab found? +            if tabNbr == 0 +                " _bufNbr is not opened in any tabs. Open a new tab with the selected buffer in it. +                exec "999tab split +buffer" . _bufNbr +            else +                " The _bufNbr is already opened in a tab, go to that tab. +                exec tabNbr . "tabnext" + +                " Focus window. +                exec s:GetWinNbr(tabNbr, _bufNbr) . "wincmd w" +            endif +        else +            " No, the user did not ask to open the selected buffer in a tab. + +            " Are we suppose to move to the tab where the active buffer is? +            if exists("g:bufExplorerChgWin") +                exe g:bufExplorerChgWin."wincmd w" +            elseif bufloaded(_bufNbr) && g:bufExplorerFindActive +                call s:Close() + +                " Get the tab number where this buffer is located in. +                let tabNbr = s:GetTabNbr(_bufNbr) + +                " Was the tab found? +                if tabNbr != 0 +                    " Yes, the buffer is located in a tab. Go to that tab number. +                    exec tabNbr . "tabnext" +                else +                    "Nope, the buffer is not in a tab. Simply switch to that +                    "buffer. +                    let _bufName = expand("#"._bufNbr.":p") +                    exec _bufName ? "drop ".escape(_bufName, " ") : "buffer "._bufNbr +                endif +            endif + +            " Switch to the buffer. +            exec "keepalt keepjumps silent b!" _bufNbr +        endif + +        " Make the buffer 'listed' again. +        call setbufvar(_bufNbr, "&buflisted", "1") + +        " Call any associated function references. g:bufExplorerFuncRef may be +        " an individual function reference or it may be a list containing +        " function references. It will ignore anything that's not a function +        " reference. +        " +        " See  :help FuncRef  for more on function references. +        if exists("g:BufExplorerFuncRef") +            if type(g:BufExplorerFuncRef) == 2 +                keepj call g:BufExplorerFuncRef() +            elseif type(g:BufExplorerFuncRef) == 3 +                for FncRef in g:BufExplorerFuncRef +                    if type(FncRef) == 2 +                        keepj call FncRef() +                    endif +                endfor +            endif +        endif +    else +        call s:Error("Sorry, that buffer no longer exists, please select another") +        call s:DeleteBuffer(_bufNbr, "wipe") +    endif +endfunction + +" RemoveBuffer {{{2 +function! s:RemoveBuffer(mode) +    " Are we on a line with a file name? +    if line('.') < s:firstBufferLine +        return +    endif + +    " Do not allow this buffer to be deleted if it is the last one. +    if len(s:MRUList) == 1 +        call s:Error("Sorry, you are not allowed to delete the last buffer") +        return +    endif + +    " These commands are to temporarily suspend the activity of winmanager. +    if exists("b:displayMode") && b:displayMode == "winmanager" +        call WinManagerSuspendAUs() +    end + +    let _bufNbr = str2nr(getline('.')) + +    if getbufvar(_bufNbr, '&modified') == 1 +        call s:Error("Sorry, no write since last change for buffer "._bufNbr.", unable to delete") +        return +    else +        " Okay, everything is good, delete or wipe the buffer. +        call s:DeleteBuffer(_bufNbr, a:mode) +    endif + +    " Reactivate winmanager autocommand activity. +    if exists("b:displayMode") && b:displayMode == "winmanager" +        call WinManagerForceReSize("BufExplorer") +        call WinManagerResumeAUs() +    end +endfunction + +" DeleteBuffer {{{2 +function! s:DeleteBuffer(buf, mode) +    " This routine assumes that the buffer to be removed is on the current line. +    try +        " Wipe/Delete buffer from Vim. +        if a:mode == "wipe" +            exe "silent bwipe" a:buf +        else +            exe "silent bdelete" a:buf +        endif + +        " Delete the buffer from the list on screen. +        setlocal modifiable +        normal! "_dd +        setlocal nomodifiable + +        " Delete the buffer from the raw buffer list. +        call filter(s:raw_buffer_listing, 'v:val.attributes !~ " '.a:buf.' "') +    catch +        call s:Error(v:exception) +    endtry +endfunction + +" Close {{{2 +function! s:Close() +    " Get only the listed buffers. +    let listed = filter(copy(s:MRUList), "buflisted(v:val)") + +    " If we needed to split the main window, close the split one. +    if (s:splitMode != "") +        exec "wincmd c" +    endif + +    " Check to see if there are anymore buffers listed. +    if len(listed) == 0 +        " Since there are no buffers left to switch to, open a new empty +        " buffers. +        exe "enew" +    else +        " Since there are buffers left to switch to, swith to them... +        for b in reverse(listed[0:1]) +            exec "keepjumps silent b ".b +        endfor +    endif + +    " Clear any messages. +    echo +endfunction + +" ToggleSplitOutPathName {{{2 +function! s:ToggleSplitOutPathName() +    let g:bufExplorerSplitOutPathName = !g:bufExplorerSplitOutPathName +    call s:RebuildBufferList() +    call s:UpdateHelpStatus() +endfunction + +" ToggleShowRelativePath {{{2 +function! s:ToggleShowRelativePath() +    let g:bufExplorerShowRelativePath = !g:bufExplorerShowRelativePath +    call s:RebuildBufferList() +    call s:UpdateHelpStatus() +endfunction + +" ToggleShowTabBuffer {{{2 +function! s:ToggleShowTabBuffer() +    let g:bufExplorerShowTabBuffer = !g:bufExplorerShowTabBuffer +    call s:RebuildBufferList(g:bufExplorerShowTabBuffer) +    call s:UpdateHelpStatus() +endfunction + +" ToggleOnlyOneTab {{{2 +function! s:ToggleOnlyOneTab() +    let g:bufExplorerOnlyOneTab = !g:bufExplorerOnlyOneTab +    call s:RebuildBufferList() +    call s:UpdateHelpStatus() +endfunction + +" ToggleShowUnlisted {{{2 +function! s:ToggleShowUnlisted() +    let g:bufExplorerShowUnlisted = !g:bufExplorerShowUnlisted +    let num_bufs = s:RebuildBufferList(g:bufExplorerShowUnlisted == 0) +    call s:UpdateHelpStatus() +endfunction + +" ToggleFindActive {{{2 +function! s:ToggleFindActive() +    let g:bufExplorerFindActive = !g:bufExplorerFindActive +    call s:UpdateHelpStatus() +endfunction + +" RebuildBufferList {{{2 +function! s:RebuildBufferList(...) +    setlocal modifiable + +    let curPos = getpos('.') + +    if a:0 +        " Clear the list first. +        exec "keepjumps ".s:firstBufferLine.',$d "_' +    endif + +    let num_bufs = s:BuildBufferList() + +    call setpos('.', curPos) + +    setlocal nomodifiable + +    return num_bufs +endfunction + +" UpdateHelpStatus {{{2 +function! s:UpdateHelpStatus() +    setlocal modifiable + +    let text = s:GetHelpStatus() +    call setline(s:firstBufferLine - 2, text) + +    setlocal nomodifiable +endfunction + +" MRUCmp {{{2 +function! s:MRUCmp(line1, line2) +    return index(s:MRUList, str2nr(a:line1)) - index(s:MRUList, str2nr(a:line2)) +endfunction + +" SortReverse {{{2 +function! s:SortReverse() +    let g:bufExplorerReverseSort = !g:bufExplorerReverseSort +    call s:ReSortListing() +endfunction + +" SortSelect {{{2 +function! s:SortSelect() +    let g:bufExplorerSortBy = get(s:sort_by, index(s:sort_by, g:bufExplorerSortBy) + 1, s:sort_by[0]) +    call s:ReSortListing() +endfunction + +" ReverseSortSelect {{{2 +function! s:ReverseSortSelect() +    let g:bufExplorerSortBy = get(s:sort_by, index(s:sort_by, g:bufExplorerSortBy) - 1, s:sort_by[-1]) +    call s:ReSortListing() +endfunction + +" ReSortListing {{{2 +function! s:ReSortListing() +    setlocal modifiable + +    let curPos = getpos('.') + +    call s:SortListing() +    call s:UpdateHelpStatus() + +    call setpos('.', curPos) + +    setlocal nomodifiable +endfunction + +" SortListing {{{2 +function! s:SortListing() +    let sort = s:firstBufferLine.",$sort".((g:bufExplorerReverseSort == 1) ? "!": "") + +    if g:bufExplorerSortBy == "number" +        " Easiest case. +        exec sort 'n' +    elseif g:bufExplorerSortBy == "name" +        if g:bufExplorerSplitOutPathName +            exec sort 'ir /\d.\{7}\zs\f\+\ze/' +        else +            exec sort 'ir /\zs[^\/\\]\+\ze\s*line/' +        endif +    elseif g:bufExplorerSortBy == "fullpath" +        if g:bufExplorerSplitOutPathName +            " Sort twice - first on the file name then on the path. +            exec sort 'ir /\d.\{7}\zs\f\+\ze/' +        endif + +        exec sort 'ir /\zs\f\+\ze\s\+line/' +    elseif g:bufExplorerSortBy == "extension" +        exec sort 'ir /\.\zs\w\+\ze\s/' +    elseif g:bufExplorerSortBy == "mru" +        let l = getline(s:firstBufferLine, "$") + +        call sort(l, "<SID>MRUCmp") + +        if g:bufExplorerReverseSort +            call reverse(l) +        endif + +        call setline(s:firstBufferLine, l) +    endif +endfunction + +" MRUListShow {{{2 +function! s:MRUListShow() +    echomsg "MRUList=".string(s:MRUList) +endfunction + +" Error {{{2 +" Display a message using ErrorMsg highlight group. +function! s:Error(msg) +    echohl ErrorMsg +    echomsg a:msg +    echohl None +endfunction + +" Warning {{{2 +" Display a message using WarningMsg highlight group. +function! s:Warning(msg) +    echohl WarningMsg +    echomsg a:msg +    echohl None +endfunction + +" GetTabNbr {{{2 +function! s:GetTabNbr(bufNbr) +    " Searching buffer bufno, in tabs. +    for i in range(tabpagenr("$")) +        if index(tabpagebuflist(i + 1), a:bufNbr) != -1 +            return i + 1 +        endif +    endfor + +    return 0 +endfunction + +" GetWinNbr" {{{2 +function! s:GetWinNbr(tabNbr, bufNbr) +    " window number in tabpage. +    let tablist = tabpagebuflist(a:tabNbr) +    " Number:     0 +    " String:     1 +    " Funcref:    2 +    " List:       3 +    " Dictionary: 4 +    " Float:      5 +    if type(tablist) == 3 +        return index(tabpagebuflist(a:tabNbr), a:bufNbr) + 1 +    else +        return 1 +    endif +endfunction + +" Winmanager Integration {{{2 +let g:BufExplorer_title = "\[Buf\ List\]" +call s:Set("g:bufExplorerResize", 1) +call s:Set("g:bufExplorerMaxHeight", 25) " Handles dynamic resizing of the window. + +" function! to start display. Set the mode to 'winmanager' for this buffer. +" This is to figure out how this plugin was called. In a standalone fashion +" or by winmanager. +function! BufExplorer_Start() +    let b:displayMode = "winmanager" +    call BufExplorer("e") +endfunction + +" Returns whether the display is okay or not. +function! BufExplorer_IsValid() +    return 0 +endfunction + +" Handles dynamic refreshing of the window. +function! BufExplorer_Refresh() +    let b:displayMode = "winmanager" +    call BufExplorer("e") +endfunction + +function! BufExplorer_ReSize() +    if !g:bufExplorerResize +        return +    end + +    let nlines = min([line("$"), g:bufExplorerMaxHeight]) + +    exe nlines." wincmd _" + +    " The following lines restore the layout so that the last file line is also +    " the last window line. Sometimes, when a line is deleted, although the +    " window size is exactly equal to the number of lines in the file, some of +    " the lines are pushed up and we see some lagging '~'s. +    let pres = getpos(".") + +    exe $ + +    let _scr = &scrolloff +    let &scrolloff = 0 + +    normal! z- + +    let &scrolloff = _scr + +    call setpos(".", pres) +endfunction + +" Default key mapping {{{1 +if !hasmapto('BufExplorer') +    noremap <script> <silent> <unique> <Leader>be :BufExplorer<CR> +endif + +if !hasmapto('BufExplorerHorizontalSplit') +    noremap <script> <silent> <unique> <Leader>bs :BufExplorerHorizontalSplit<CR> +endif + +if !hasmapto('BufExplorerVerticalSplit') +    noremap <script> <silent> <unique> <Leader>bv :BufExplorerVerticalSplit<CR> +endif + +" Default values {{{1 +call s:Set("g:bufExplorerDefaultHelp", 1)           " Show default help? +call s:Set("g:bufExplorerDetailedHelp", 0)          " Show detailed help? +call s:Set("g:bufExplorerFindActive", 1)            " When selecting an active buffer, take you to the window where it is active? +call s:Set("g:bufExplorerOnlyOneTab", 1)            " If ShowTabBuffer = 1, only store the most recent tab for this buffer. +call s:Set("g:bufExplorerReverseSort", 0)           " Sort in reverse order by default? +call s:Set("g:bufExplorerShowDirectories", 1)       " (Dir's are added by commands like ':e .') +call s:Set("g:bufExplorerShowRelativePath", 0)      " Show listings with relative or absolute paths? +call s:Set("g:bufExplorerShowTabBuffer", 0)         " Show only buffer(s) for this tab? +call s:Set("g:bufExplorerShowUnlisted", 0)          " Show unlisted buffers? +call s:Set("g:bufExplorerSortBy", "mru")            " Sorting methods are in s:sort_by: +call s:Set("g:bufExplorerSplitBelow", &splitbelow)  " Should horizontal splits be below or above current window? +call s:Set("g:bufExplorerSplitOutPathName", 1)      " Split out path and file name? +call s:Set("g:bufExplorerSplitRight", &splitright)  " Should vertical splits be on the right or left of current window? +"1}}} + +" vim:ft=vim foldmethod=marker sw=4 diff --git a/modules/vim/vim.dot.link/plugin/git.vim b/modules/vim/vim.dot.link/plugin/git.vim new file mode 100644 index 0000000..bd0b053 --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/git.vim @@ -0,0 +1,372 @@ +" Author:  motemen <motemen@gmail.com> +" License: The MIT License +" URL:     http://github.com/motemen/git-vim/ + +if !exists('g:git_command_edit') +    let g:git_command_edit = 'new' +endif + +if !exists('g:git_bufhidden') +    let g:git_bufhidden = '' +endif + +if !exists('g:git_bin') +    let g:git_bin = 'git' +endif + +if !exists('g:git_author_highlight') +    let g:git_author_highlight = { } +endif + +if !exists('g:git_highlight_blame') +    let g:git_highlight_blame = 0 +endif + +if !exists('g:git_no_map_default') || !g:git_no_map_default +    nnoremap <Leader>gd :GitDiff<Enter> +    nnoremap <Leader>gD :GitDiff --cached<Enter> +    nnoremap <Leader>gs :GitStatus<Enter> +    nnoremap <Leader>gl :GitLog<Enter> +    nnoremap <Leader>ga :GitAdd<Enter> +    nnoremap <Leader>gA :GitAdd <cfile><Enter> +    nnoremap <Leader>gc :GitCommit<Enter> +    nnoremap <Leader>gp :GitPullRebase<Enter> +endif + +" Ensure b:git_dir exists. +function! s:GetGitDir() +    if !exists('b:git_dir') +        let b:git_dir = s:SystemGit('rev-parse --git-dir') +        if !v:shell_error +            let b:git_dir = fnamemodify(split(b:git_dir, "\n")[0], ':p') . '/' +        endif +    endif +    return b:git_dir +endfunction + +" Returns current git branch. +" Call inside 'statusline' or 'titlestring'. +function! GitBranch() +    let git_dir = <SID>GetGitDir() + +    if strlen(git_dir) && filereadable(git_dir . '/HEAD') +        let lines = readfile(git_dir . '/HEAD') +        if !len(lines) +            return '' +        else +            return matchstr(lines[0], 'refs/heads/\zs.\+$') +        endif +    else +        return '' +    endif +endfunction + +" List all git local branches. +function! ListGitBranches(arg_lead, cmd_line, cursor_pos) +    let branches = split(s:SystemGit('branch'), '\n') +    if v:shell_error +        return [] +    endif + +    return map(branches, 'matchstr(v:val, ''^[* ] \zs.*'')') +endfunction + +" List all git commits. +function! ListGitCommits(arg_lead, cmd_line, cursor_pos) +    let commits = split(s:SystemGit('log --pretty=format:%h')) +    if v:shell_error +        return [] +    endif + +    let commits = ['HEAD'] + ListGitBranches(a:arg_lead, a:cmd_line, a:cursor_pos) + commits + +    if a:cmd_line =~ '^GitDiff' +        " GitDiff accepts <commit>..<commit> +        if a:arg_lead =~ '\.\.' +            let pre = matchstr(a:arg_lead, '.*\.\.\ze') +            let commits = map(commits, 'pre . v:val') +        endif +    endif + +    return filter(commits, 'match(v:val, ''\v'' . a:arg_lead) == 0') +endfunction + +" Show diff. +function! GitDiff(args) +    let git_output = s:SystemGit('diff ' . a:args . ' -- ' . s:Expand('%')) +    if !strlen(git_output) +        echo "No output from git command" +        return +    endif + +    call <SID>OpenGitBuffer(git_output) +    setlocal filetype=git-diff +endfunction + +" Show Status. +function! GitStatus() +    let git_output = s:SystemGit('status') +    call <SID>OpenGitBuffer(git_output) +    setlocal filetype=git-status +    nnoremap <buffer> <Enter> :GitAdd <cfile><Enter>:call <SID>RefreshGitStatus()<Enter> +    nnoremap <buffer> -       :silent !git reset HEAD -- =expand('<cfile>')<Enter><Enter>:call <SID>RefreshGitStatus()<Enter> +endfunction + +function! s:RefreshGitStatus() +    let pos_save = getpos('.') +    GitStatus +    call setpos('.', pos_save) +endfunction + +" Show Log. +function! GitLog(args) +    let git_output = s:SystemGit('log ' . a:args . ' -- ' . s:Expand('%')) +    call <SID>OpenGitBuffer(git_output) +    setlocal filetype=git-log +endfunction + +" Add file to index. +function! GitAdd(expr) +    let file = s:Expand(strlen(a:expr) ? a:expr : '%') + +    call GitDoCommand('add ' . file) +endfunction + +" Commit. +function! GitCommit(args) +    let git_dir = <SID>GetGitDir() + +    let args = a:args + +    if args !~ '\v\k@<!(-a|--all)>' && s:SystemGit('diff --cached --stat') =~ '^\(\s\|\n\)*$' +        let args .= ' -a' +    endif + +    " Create COMMIT_EDITMSG file +    let editor_save = $EDITOR +    let $EDITOR = '' +    let git_output = s:SystemGit('commit ' . args) +    let $EDITOR = editor_save + +    let cur_dir = getcwd() +    execute printf('%s %sCOMMIT_EDITMSG', g:git_command_edit, git_dir) +    execute printf("lcd %s", cur_dir) + +    setlocal filetype=git-status bufhidden=wipe +    augroup GitCommit +        autocmd BufWritePre  <buffer> g/^#\|^\s*$/d | setlocal fileencoding=utf-8 +        execute printf("autocmd BufEnter <buffer> lcd %s", cur_dir) +        execute printf("autocmd BufWritePost <buffer> call GitDoCommand('commit %s -F ' . expand('%%')) | autocmd! GitCommit * <buffer>", args) +    augroup END +endfunction + +" Checkout. +function! GitCheckout(args) +    call GitDoCommand('checkout ' . a:args) +endfunction + +" Push. +function! GitPush(args) +"   call GitDoCommand('push ' . a:args) +    " Wanna see progress... +    let args = a:args +    if args =~ '^\s*$' +        let args = 'origin ' . GitBranch() +    endif +    execute '!' g:git_bin 'push' args +endfunction + +" Pull. +function! GitPull(args) +"   call GitDoCommand('pull ' . a:args) +    " Wanna see progress... +    execute '!' g:git_bin 'pull' a:args +endfunction + +" Show commit, tree, blobs. +function! GitCatFile(file) +    let file = s:Expand(a:file) +    let git_output = s:SystemGit('cat-file -p ' . file) +    if !strlen(git_output) +        echo "No output from git command" +        return +    endif + +    call <SID>OpenGitBuffer(git_output) +endfunction + +" Show revision and author for each line. +function! GitBlame(...) +    let l:git_blame_width = 20 +    let git_output = s:SystemGit('blame -- ' . expand('%')) +    if !strlen(git_output) +        echo "No output from git command" +        return +    endif + +    if strlen(a:1) +        let l:git_blame_width = a:1 +    endif + +    setlocal noscrollbind + +    " :/ +    let git_command_edit_save = g:git_command_edit +    let g:git_command_edit = 'leftabove vnew' +    call <SID>OpenGitBuffer(git_output) +    let g:git_command_edit = git_command_edit_save + +    setlocal modifiable +    silent %s/\d\d\d\d\zs \+\d\+).*// +    exe 'vertical resize ' . git_blame_width +    setlocal nomodifiable +    setlocal nowrap scrollbind + +    if g:git_highlight_blame +        call s:DoHighlightGitBlame() +    endif + +    wincmd p +    setlocal nowrap scrollbind + +    syncbind +endfunction + + + + +" Experimental +function! s:DoHighlightGitBlame() +    for l in range(1, line('$')) +        let line = getline(l) +        let [commit, author] = matchlist(line, '\(\x\+\) (\(.\{-}\)\s* \d\d\d\d-\d\d-\d\d')[1:2] +        call s:LoadSyntaxRuleFor({ 'author': author }) +    endfor +endfunction + +function! s:LoadSyntaxRuleFor(params) +    let author = a:params.author +    let name = 'gitBlameAuthor_' . substitute(author, '\s', '_', 'g') +    if (!hlID(name)) +        if has_key(g:git_author_highlight, author) +            execute 'highlight' name g:git_author_highlight[author] +        else +            let [n1, n2] = [0, 1] +            for c in split(author, '\zs') +                let n1 = (n1 + char2nr(c))     % 8 +                let n2 = (n2 + char2nr(c) * 3) % 8 +            endfor +            if n1 == n2 +                let n1 = (n2 + 1) % 8 +            endif +            execute 'highlight' name printf('ctermfg=%d ctermbg=%d', n1, n2) +        endif +        execute 'syntax match' name '"\V\^\x\+ (' . escape(author, '\') . '\.\*"' +    endif +endfunction + +function! GitDoCommand(args) +    let git_output = s:SystemGit(a:args) +    let git_output = substitute(git_output, '\n*$', '', '') +    if v:shell_error +        echohl Error +        echo git_output +        echohl None +    else +        echo git_output +    endif +endfunction + +function! s:SystemGit(args) +    " workardound for MacVim, on which shell does not inherit environment +    " variables +    if has('mac') && &shell =~ 'sh$' +        return system('EDITOR="" '. g:git_bin . ' ' . a:args) +    else +        return system(g:git_bin . ' ' . a:args) +    endif +endfunction + +" Show vimdiff for merge. (experimental) +function! GitVimDiffMerge() +    let file = s:Expand('%') +    let filetype = &filetype +    let t:git_vimdiff_original_bufnr = bufnr('%') +    let t:git_vimdiff_buffers = [] + +    topleft new +    setlocal buftype=nofile +    file `=':2:' . file` +    call add(t:git_vimdiff_buffers, bufnr('%')) +    execute 'silent read!git show :2:' . file +    0d +    diffthis +    let &filetype = filetype + +    rightbelow vnew +    setlocal buftype=nofile +    file `=':3:' . file` +    call add(t:git_vimdiff_buffers, bufnr('%')) +    execute 'silent read!git show :3:' . file +    0d +    diffthis +    let &filetype = filetype +endfunction + +function! GitVimDiffMergeDone() +    if exists('t:git_vimdiff_original_bufnr') && exists('t:git_vimdiff_buffers') +        if getbufline(t:git_vimdiff_buffers[0], 1, '$') == getbufline(t:git_vimdiff_buffers[1], 1, '$') +            execute 'sbuffer ' . t:git_vimdiff_original_bufnr +            0put=getbufline(t:git_vimdiff_buffers[0], 1, '$') +            normal! jdG +            update +            execute 'bdelete ' . t:git_vimdiff_buffers[0] +            execute 'bdelete ' . t:git_vimdiff_buffers[1] +            close +        else +            echohl Error +            echo 'There still remains conflict' +            echohl None +        endif +    endif +endfunction + +function! s:OpenGitBuffer(content) +    if exists('b:is_git_msg_buffer') && b:is_git_msg_buffer +        enew! +    else +        execute g:git_command_edit +    endif + +    setlocal buftype=nofile readonly modifiable +    execute 'setlocal bufhidden=' . g:git_bufhidden + +    silent put=a:content +    keepjumps 0d +    setlocal nomodifiable + +    let b:is_git_msg_buffer = 1 +endfunction + +function! s:Expand(expr) +    if has('win32') +        return substitute(expand(a:expr), '\', '/', 'g') +    else +        return expand(a:expr) +    endif +endfunction + +command! -nargs=1 -complete=customlist,ListGitCommits GitCheckout call GitCheckout(<q-args>) +command! -nargs=* -complete=customlist,ListGitCommits GitDiff     call GitDiff(<q-args>) +command!          GitStatus           call GitStatus() +command! -nargs=? GitAdd              call GitAdd(<q-args>) +command! -nargs=* GitLog              call GitLog(<q-args>) +command! -nargs=* GitCommit           call GitCommit(<q-args>) +command! -nargs=1 GitCatFile          call GitCatFile(<q-args>) +command! -nargs=? GitBlame            call GitBlame(<q-args>) +command! -nargs=+ Git                 call GitDoCommand(<q-args>) +command!          GitVimDiffMerge     call GitVimDiffMerge() +command!          GitVimDiffMergeDone call GitVimDiffMergeDone() +command! -nargs=* GitPull             call GitPull(<q-args>) +command!          GitPullRebase       call GitPull('--rebase') +command! -nargs=* GitPush             call GitPush(<q-args>) diff --git a/modules/vim/vim.dot.link/plugin/indexer.vim.disabled b/modules/vim/vim.dot.link/plugin/indexer.vim.disabled new file mode 100644 index 0000000..28c9472 --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/indexer.vim.disabled @@ -0,0 +1,672 @@ +"============================================================================= +" File:        indexer.vim +" Author:      Dmitry Frank (dimon.frank@gmail.com) +" Last Change: 26 Sep 2010 +" Version:     1.8 +"============================================================================= +" See documentation in accompanying help file +" You may use this code in whatever way you see fit. + + +" s:ParsePath(sPath) +"   changing '\' to '/' or vice versa depending on OS (MS Windows or not) also calls simplify() +function! s:ParsePath(sPath) +   if (has('win32') || has('win64')) +      let l:sPath = substitute(a:sPath, '/', '\', 'g') +   else +      let l:sPath = substitute(a:sPath, '\', '/', 'g') +   endif +   let l:sPath = simplify(l:sPath) + +   " removing last "/" or "\" +   let l:sLastSymb = strpart(l:sPath, (strlen(l:sPath) - 1), 1) +   if (l:sLastSymb == '/' || l:sLastSymb == '\') +      let l:sPath = strpart(l:sPath, 0, (strlen(l:sPath) - 1)) +   endif +   return l:sPath +endfunction + +" s:Trim(sString) +" trims spaces from begin and end of string +function! s:Trim(sString) +   return substitute(substitute(a:sString, '^\s\+', '', ''), '\s\+$', '', '') +endfunction + +" s:IsAbsolutePath(path) <<< +"   this function from project.vim is written by Aric Blumer. +"   Returns true if filename has an absolute path. +function! s:IsAbsolutePath(path) +   if a:path =~ '^ftp:' || a:path =~ '^rcp:' || a:path =~ '^scp:' || a:path =~ '^http:' +      return 2 +   endif +   let path=expand(a:path) " Expand any environment variables that might be in the path +   if path[0] == '/' || path[0] == '~' || path[0] == '\\' || path[1] == ':' +      return 1 +   endif +   return 0 +endfunction " >>> + + + +function! s:GetDirsAndFilesFromIndexerList(aLines, projectName, dExistsResult) +   let l:aLines = a:aLines +   let l:dResult = a:dExistsResult +   let l:boolInNeededProject = (a:projectName == '' ? 1 : 0) +   let l:boolInProjectsParentSection = 0 +   let l:sProjectsParentFilter = '' + +   let l:sCurProjName = '' + +   for l:sLine in l:aLines + +      " if line is not empty +      if l:sLine !~ '^\s*$' && l:sLine !~ '^\s*\#.*$' + +         " look for project name [PrjName] +         let myMatch = matchlist(l:sLine, '^\s*\[\([^\]]\+\)\]') + +         if (len(myMatch) > 0) + +            " check for PROJECTS_PARENT section + +            if (strpart(myMatch[1], 0, 15) == 'PROJECTS_PARENT') +               " this is projects parent section +               let l:sProjectsParentFilter = '' +               let filterMatch = matchlist(myMatch[1], 'filter="\([^"]\+\)"') +               if (len(filterMatch) > 0) +                  let l:sProjectsParentFilter = filterMatch[1] +               endif +               let l:boolInProjectsParentSection = 1 +            else +               let l:boolInProjectsParentSection = 0 + + +               if (a:projectName != '') +                  if (myMatch[1] == a:projectName) +                     let l:boolInNeededProject = 1 +                  else +                     let l:boolInNeededProject = 0 +                  endif +               endif + +               if l:boolInNeededProject +                  let l:sCurProjName = myMatch[1] +                  let l:dResult[l:sCurProjName] = { 'files': [], 'paths': [], 'not_exist': [] } +               endif +            endif +         else + +            if l:boolInProjectsParentSection +               " parsing one project parent + +               let l:lFilter = split(l:sProjectsParentFilter, ' ') +               if (len(l:lFilter) == 0) +                  let l:lFilter = ['*'] +               endif +               " removing \/* from end of path +               let l:projectsParent = substitute(<SID>Trim(l:sLine), '[\\/*]\+$', '', '') + +               " creating list of projects +               let l:lProjects = split(expand(l:projectsParent.'/*'), '\n') +               let l:lIndexerFilesList = [] +               for l:sPrj in l:lProjects +                  if (isdirectory(l:sPrj)) +                     call add(l:lIndexerFilesList, '['.substitute(l:sPrj, '^.*[\\/]\([^\\/]\+\)$', '\1', '').']') +                     for l:sCurFilter in l:lFilter +                        call add(l:lIndexerFilesList, l:sPrj.'/**/'.l:sCurFilter) +                     endfor +                     call add(l:lIndexerFilesList, '') +                  endif +               endfor +               " parsing this list +               let l:dResult = <SID>GetDirsAndFilesFromIndexerList(l:lIndexerFilesList, a:projectName, l:dResult) +                +            elseif l:boolInNeededProject +               " looks like there's path +               if l:sCurProjName == '' +                  let l:sCurProjName = 'noname' +                  let l:dResult[l:sCurProjName] = { 'files': [], 'paths': [], 'not_exist': [] } +               endif +               if (!g:indexer_ctagsDontSpecifyFilesIfPossible && s:indexer_projectName != '') +                  " adding every file. +                  let l:dResult[l:sCurProjName].files = <SID>ConcatLists(l:dResult[l:sCurProjName].files, split(expand(substitute(<SID>Trim(l:sLine), '\\\*\*', '**', 'g')), '\n')) +               else +                  " adding just paths. (much more faster) +                  let l:dResult[l:sCurProjName].paths = <SID>ConcatLists(l:dResult[l:sCurProjName].paths, [<SID>ParsePath(expand(substitute(substitute(substitute(l:sLine, '^\(.*\)[\\/][^\\/]\+$', '\1', 'g'), '^\([^*]\+\).*$', '\1', ''), '[\\/]$', '', '')))]) +               endif +            endif + +         endif +      endif + +   endfor + +   " build paths +   if (!g:indexer_ctagsDontSpecifyFilesIfPossible && s:indexer_projectName != '') +      for l:sKey in keys(l:dResult) +         let l:lPaths = [] +         for l:sFile in l:dResult[l:sKey].files +            let l:sPath = substitute(l:sFile, '^\(.*\)[\\/][^\\/]\+$', '\1', 'g') +            call add(l:lPaths, l:sPath) +         endfor + +         let l:dResult[l:sKey].paths = <SID>ConcatLists(l:dResult[l:sKey].paths, l:lPaths) + +      endfor +   endif + +   return l:dResult +endfunction + +" getting dictionary with files, paths and non-existing files from indexer +" project file +function! s:GetDirsAndFilesFromIndexerFile(indexerFile, projectName) +   let l:aLines = readfile(a:indexerFile) +   let l:dResult = {} +   let l:dResult = <SID>GetDirsAndFilesFromIndexerList(l:aLines, a:projectName, l:dResult) +   return l:dResult +endfunction + +" getting dictionary with files, paths and non-existing files from +" project.vim's project file +function! s:GetDirsAndFilesFromProjectFile(projectFile, projectName) +   let l:aLines = readfile(a:projectFile) +   " if projectName is empty, then we should add files from whole projectFile +   let l:boolInNeededProject = (a:projectName == '' ? 1 : 0) + +   let l:iOpenedBraces = 0 " current count of opened { } +   let l:iOpenedBracesAtProjectStart = 0 +   let l:aPaths = [] " paths stack +   let l:sLastFoundPath = '' + +   let l:dResult = {} +   let l:sCurProjName = '' + +   for l:sLine in l:aLines +      " ignoring comments +      if l:sLine =~ '^#' | continue | endif + +      let l:sLine = substitute(l:sLine, '#.\+$', '' ,'') +      " searching for closing brace { } +      let sTmpLine = l:sLine +      while (sTmpLine =~ '}') +         let l:iOpenedBraces = l:iOpenedBraces - 1 + +         " if projectName is defined and there was last brace closed, then we +         " are finished parsing needed project +         if (l:iOpenedBraces <= l:iOpenedBracesAtProjectStart) && a:projectName != '' +            let l:boolInNeededProject = 0 +            " TODO: total break +         endif +         call remove(l:aPaths, len(l:aPaths) - 1) + +         let sTmpLine = substitute(sTmpLine, '}', '', '') +      endwhile + +      " searching for blabla=qweqwe +      let myMatch = matchlist(l:sLine, '\s*\(.\{-}\)=\(.\{-}\)\\\@<!\(\s\|$\)') +      if (len(myMatch) > 0) +         " now we found start of project folder or subfolder +         " +         if !l:boolInNeededProject +            if (a:projectName != '' && myMatch[1] == a:projectName) +               let l:iOpenedBracesAtProjectStart = l:iOpenedBraces +               let l:boolInNeededProject = 1 +            endif +         endif + +         if l:boolInNeededProject && (l:iOpenedBraces == l:iOpenedBracesAtProjectStart) +            let l:sCurProjName = myMatch[1] +            let l:dResult[myMatch[1]] = { 'files': [], 'paths': [], 'not_exist': [] } +         endif + +         let l:sLastFoundPath = myMatch[2] +         " ADDED! Jkooij +         " Strip the path of surrounding " characters, if there are any +         let l:sLastFoundPath = substitute(l:sLastFoundPath, "\"\\(.*\\)\"", "\\1", "g") +         let l:sLastFoundPath = expand(l:sLastFoundPath) " Expand any environment variables that might be in the path +         let l:sLastFoundPath = s:ParsePath(l:sLastFoundPath) + +      endif + +      " searching for opening brace { } +      let sTmpLine = l:sLine +      while (sTmpLine =~ '{') + +         if (s:IsAbsolutePath(l:sLastFoundPath) || len(l:aPaths) == 0) +            call add(l:aPaths, s:ParsePath(l:sLastFoundPath)) +         else +            call add(l:aPaths, s:ParsePath(l:aPaths[len(l:aPaths) - 1].'/'.l:sLastFoundPath)) +         endif + +         let l:iOpenedBraces = l:iOpenedBraces + 1 + +         if (l:boolInNeededProject && l:iOpenedBraces > l:iOpenedBracesAtProjectStart && isdirectory(l:aPaths[len(l:aPaths) - 1])) +            call add(l:dResult[l:sCurProjName].paths, l:aPaths[len(l:aPaths) - 1]) +         endif + +         let sTmpLine = substitute(sTmpLine, '{', '', '') +      endwhile + +      " searching for filename +      if (l:sLine =~ '^[^={}]*$' && l:sLine !~ '^\s*$') +         " here we found something like filename +         " +         if (l:boolInNeededProject && (!g:indexer_enableWhenProjectDirFound || s:indexer_projectName != '') && l:iOpenedBraces > l:iOpenedBracesAtProjectStart) +            " we are in needed project +            "let l:sCurFilename = expand(s:ParsePath(l:aPaths[len(l:aPaths) - 1].'/'.s:Trim(l:sLine))) +            " CHANGED! Jkooij +            " expand() will change slashes based on 'shellslash' flag, +            " so call s:ParsePath() on expand() result for consistent slashes +            let l:sCurFilename = s:ParsePath(expand(l:aPaths[len(l:aPaths) - 1].'/'.s:Trim(l:sLine))) +            if (filereadable(l:sCurFilename)) +               " file readable! adding it +               call add(l:dResult[l:sCurProjName].files, l:sCurFilename) +            elseif (!isdirectory(l:sCurFilename)) +               call add(l:dResult[l:sCurProjName].not_exist, l:sCurFilename) +            endif +         endif + +      endif + +   endfor + +   return l:dResult +endfunction + +" returns whether or not file exists in list +function! s:IsFileExistsInList(aList, sFilename) +   let l:sFilename = s:ParsePath(a:sFilename) +   if (index(a:aList, l:sFilename, 0, 1)) >= 0 +      return 1 +   endif +   return 0 +endfunction + +" updating tags using ctags. +" if boolAppend then just appends existing tags file with new tags from +" current file (%) +function! s:UpdateTags(boolAppend) + +   " one tags file +    +   let l:sTagsFileWOPath = substitute(join(g:indexer_indexedProjects, '_'), '\s', '_', 'g') +   let l:sTagsFile = s:tagsDirname.'/'.l:sTagsFileWOPath +   if !isdirectory(s:tagsDirname) +      call mkdir(s:tagsDirname, "p") +   endif + +   let l:sSavedFile = <SID>ParsePath(expand('%:p')) +   if (<SID>IsFileExistsInList(s:lNotExistFiles, l:sSavedFile)) +      " moving file from non-existing list to existing list +      call remove(s:lNotExistFiles, index(s:lNotExistFiles, l:sSavedFile)) +      call add(s:lFileList, l:sSavedFile) +   endif + +   let l:sRecurseCode = '' + +   if (a:boolAppend && filereadable(l:sTagsFile)) +      let l:sAppendCode = '-a' +      if (<SID>IsFileExistsInList(s:lFileList, l:sSavedFile)) +         " saved file are in file list +         let l:sFiles = l:sSavedFile +      else +         let l:sFiles = '' +      endif + +   else +      let l:sAppendCode = '' +      let l:sFiles = '' +      let l:sFile = '' +      if (g:indexer_ctagsDontSpecifyFilesIfPossible && s:sMode == 'IndexerFile') +         let l:sRecurseCode = '-R' +         for l:sPath in s:lPathList +            let l:sFiles = l:sFiles.' "'.l:sPath.'"' +         endfor +      else +         for l:sFile in s:lFileList +            let l:sFiles = l:sFiles.' "'.l:sFile.'"' +         endfor +      endif +   endif + +   if l:sFiles != '' +      "if (has('win32') || has('win64')) +         let l:sTagsFile = '"'.l:sTagsFile.'"' +      "endif + +      if (has('win32') || has('win64')) +         let l:cmd = 'ctags -f '.l:sTagsFile.' '.l:sRecurseCode.' '.l:sAppendCode.' '.g:indexer_ctagsCommandLineOptions.' '.l:sFiles +      else +         let l:cmd = 'ctags -f '.l:sTagsFile.' '.l:sRecurseCode.' '.l:sAppendCode.' '.g:indexer_ctagsCommandLineOptions.' '.l:sFiles.' &' +      endif + +      let l:resp = system(l:cmd) +      exec 'set tags='.substitute(s:tagsDirname.'/'.l:sTagsFileWOPath, ' ', '\\\\\\ ', 'g') +   endif + +   "multiple files, calls from bat file +   "exec 'set tags=' +   "let l:lLines = [] +   "for l:sFile in s:lFileList +      "let l:sTagFile = s:tagsDirname.'/'.substitute(l:sFile, '[\\/:]', '_', 'g') +      "call add(l:lLines, 'ctags -f '.l:sTagFile.' '.g:indexer_ctagsCommandLineOptions.' '.l:sFile) +      "exec 'set tags+='.l:sTagFile +   "endfor +   "call writefile(l:lLines, s:tagsDirname.'/maketags.bat') + +   "let l:cmd = s:tagsDirname.'/maketags.bat' +   "let l:resp = system(l:cmd) +endfunction + +function! s:ApplyProjectSettings(dParse) +   " paths for Vim +   set path=. +   for l:sPath in a:dParse.paths +      if isdirectory(l:sPath) +         exec 'set path+='.substitute(l:sPath, ' ', '\\ ', 'g') +      endif +   endfor + +   let s:lFileList = a:dParse.files +   let s:lPathList = a:dParse.paths +   let s:lNotExistFiles = a:dParse.not_exist + +   augroup Indexer_SavSrcFile +      autocmd! Indexer_SavSrcFile BufWritePost +   augroup END +   " collect extensions of files in project to make autocmd on save these +   " files +   let l:sExtsList = '' +   let l:lFullList = s:lFileList + s:lNotExistFiles +   for l:lFile in l:lFullList +      let l:sExt = substitute(l:lFile, '^.*\([.\\/][^.\\/]\+\)$', '\1', '') +      if strpart(l:sExt, 0, 1) != '.' +         let l:sExt = strpart(l:sExt, 1) +      endif +      if (stridx(l:sExtsList, l:sExt) == -1) +         if (l:sExtsList != '') +            let l:sExtsList = l:sExtsList.',' +         endif +         let l:sExtsList = l:sExtsList.'*'.l:sExt +      endif +   endfor + +   " defining autocmd at source files save +   exec 'autocmd Indexer_SavSrcFile BufWritePost '.l:sExtsList.' call <SID>UpdateTags('.(g:indexer_ctagsJustAppendTagsAtFileSave ? '1' : '0').')' + +   " start full tags update +   call <SID>UpdateTags(0) +endfunction + +" concatenates two lists preventing duplicates +function! s:ConcatLists(lExistingList, lAddingList) +   let l:lResList = a:lExistingList +   for l:sItem in a:lAddingList +      if (index(l:lResList, l:sItem) == -1) +         call add(l:lResList, l:sItem) +      endif +   endfor +   return l:lResList +endfunction + +function! s:GetDirsAndFilesFromAvailableFile() +   if (filereadable(g:indexer_indexerListFilename)) +      " read all projects from proj file +      let s:sMode = 'IndexerFile' +      let s:dParseAll = s:GetDirsAndFilesFromIndexerFile(g:indexer_indexerListFilename, s:indexer_projectName) +   elseif (filereadable(g:indexer_projectsSettingsFilename)) +      let s:sMode = 'ProjectFile' +      let s:dParseAll = s:GetDirsAndFilesFromProjectFile(g:indexer_projectsSettingsFilename, s:indexer_projectName) +   else +      let s:sMode = '' +      let s:dParseAll = {} +   endif +endfunction + +function! s:ParseProjectSettingsFile() +   call <SID>GetDirsAndFilesFromAvailableFile() + +   " let's found what files we should to index. +   " now we will search for project directory up by dir tree +   let l:i = 0 +   let l:sCurPath = '' +   while (g:indexer_enableWhenProjectDirFound && s:indexer_projectName == '' && l:i < 10) +      for l:sKey in keys(s:dParseAll) +         if (<SID>IsFileExistsInList(s:dParseAll[l:sKey].paths, expand('%:p:h').l:sCurPath)) +            let s:indexer_projectName = l:sKey +            if !(s:sMode == 'IndexerFile' && g:indexer_ctagsDontSpecifyFilesIfPossible) +               call <SID>GetDirsAndFilesFromAvailableFile() +            else +               call add(g:indexer_indexedProjects, l:sKey) +            endif +            break +         endif +      endfor +      let l:sCurPath = l:sCurPath.'/..' +      let l:i = l:i + 1 +   endwhile + +   if !(s:sMode == 'IndexerFile' && g:indexer_ctagsDontSpecifyFilesIfPossible) +      let s:iTotalFilesAvailableCnt = 0 +      if (!s:boolIndexingModeOn) +         for l:sKey in keys(s:dParseAll) +            let s:iTotalFilesAvailableCnt = s:iTotalFilesAvailableCnt + len(s:dParseAll[l:sKey].files) + +            if ((g:indexer_enableWhenProjectDirFound && <SID>IsFileExistsInList(s:dParseAll[l:sKey].paths, expand('%:p:h'))) || (<SID>IsFileExistsInList(s:dParseAll[l:sKey].files, expand('%:p')))) +               " user just opened file from project l:sKey. We should add it to +               " result lists + +               " adding name of this project to g:indexer_indexedProjects +               call add(g:indexer_indexedProjects, l:sKey) + +            endif +         endfor +      endif +   endif + +   " build final list of files, paths and non-existing files +   let l:dParse = { 'files':[], 'paths':[], 'not_exist':[] } +   for l:sKey in g:indexer_indexedProjects +      let l:dParse.files = <SID>ConcatLists(l:dParse.files, s:dParseAll[l:sKey].files) +      let l:dParse.paths = <SID>ConcatLists(l:dParse.paths, s:dParseAll[l:sKey].paths) +      let l:dParse.not_exist = <SID>ConcatLists(l:dParse.not_exist, s:dParseAll[l:sKey].not_exist) +   endfor + +   if (s:boolIndexingModeOn) +      call <SID>ApplyProjectSettings(l:dParse) +   else +      if (len(l:dParse.files) > 0 || len(l:dParse.paths) > 0) + +         let s:boolIndexingModeOn = 1 + +         " creating auto-refresh index at project file save +         augroup Indexer_SavPrjFile +            autocmd! Indexer_SavPrjFile BufWritePost +         augroup END + +         if (filereadable(g:indexer_indexerListFilename)) +            let l:sIdxFile = substitute(g:indexer_indexerListFilename, '^.*[\\/]\([^\\/]\+\)$', '\1', '') +            exec 'autocmd Indexer_SavPrjFile BufWritePost '.l:sIdxFile.' call <SID>ParseProjectSettingsFile()' +         elseif (filereadable(g:indexer_projectsSettingsFilename)) +            let l:sPrjFile = substitute(g:indexer_projectsSettingsFilename, '^.*[\\/]\([^\\/]\+\)$', '\1', '') +            exec 'autocmd Indexer_SavPrjFile BufWritePost '.l:sPrjFile.' call <SID>ParseProjectSettingsFile()' +         endif + +         call <SID>ApplyProjectSettings(l:dParse) + +         let l:iNonExistingCnt = len(s:lNotExistFiles) +         if (l:iNonExistingCnt > 0) +            if l:iNonExistingCnt < 100 +               echo "Indexer Warning: project loaded, but there's ".l:iNonExistingCnt." non-existing files: \n\n".join(s:lNotExistFiles, "\n") +            else +               echo "Indexer Warning: project loaded, but there's ".l:iNonExistingCnt." non-existing files. Type :IndexerInfo for details." +            endif +         endif +      else +         " there's no project started. +         " we should define autocmd to detect if file from project will be opened later +         augroup Indexer_LoadFile +            autocmd! Indexer_LoadFile BufReadPost +            autocmd Indexer_LoadFile BufReadPost * call <SID>IndexerInit() +         augroup END +      endif +   endif +endfunction + +function! s:IndexerInfo() +   if (s:sMode == '') +      echo '* Filelist: not found' +   elseif (s:sMode == 'IndexerFile') +      echo '* Filelist: indexer file: '.g:indexer_indexerListFilename +   elseif (s:sMode == 'ProjectFile') +      echo '* Filelist: project file: '.g:indexer_projectsSettingsFilename +   else +      echo '* Filelist: Unknown' +   endif +   echo '* Projects indexed: '.join(g:indexer_indexedProjects, ', ') +   if !(s:sMode == 'IndexerFile' && g:indexer_ctagsDontSpecifyFilesIfPossible) +      echo "* Files indexed: there's ".len(s:lFileList).' files. Type :IndexerFiles to list' +      echo "* Files not found: there's ".len(s:lNotExistFiles).' non-existing files. '.join(s:lNotExistFiles, ', ') +   endif + +   echo '* Paths: '.&path +   echo '* Tags file: '.&tags +   echo '* Project root: '.($INDEXER_PROJECT_ROOT != '' ? $INDEXER_PROJECT_ROOT : 'not found').'  (Project root is a directory which contains "'.g:indexer_dirNameForSearch.'" directory)' +endfunction + +function! s:IndexerFilesList() +   echo "* Files indexed: ".join(s:lFileList, ', ') +endfunction + +function! s:IndexerInit() + +   augroup Indexer_LoadFile +      autocmd! Indexer_LoadFile BufReadPost +   augroup END + +   " actual tags dirname. If .vimprj directory will be found then this tags +   " dirname will be /path/to/dir/.vimprj/tags +   let s:tagsDirname = g:indexer_tagsDirname +   let g:indexer_indexedProjects = [] +   let s:sMode = '' +   let s:lFileList = [] +   let s:lNotExistFiles = [] + +   let s:boolIndexingModeOn = 0 + +   if g:indexer_lookForProjectDir +      " need to look for .vimprj directory + +      let l:i = 0 +      let l:sCurPath = '' +      let $INDEXER_PROJECT_ROOT = '' +      while (l:i < g:indexer_recurseUpCount) +         if (isdirectory(expand('%:p:h').l:sCurPath.'/'.g:indexer_dirNameForSearch)) +            let $INDEXER_PROJECT_ROOT = simplify(expand('%:p:h').l:sCurPath) +            exec 'cd '.substitute($INDEXER_PROJECT_ROOT, ' ', '\\ ', 'g') +            break +         endif +         let l:sCurPath = l:sCurPath.'/..' +         let l:i = l:i + 1 +      endwhile + +      if $INDEXER_PROJECT_ROOT != '' +         " project root was found. +         " +         " set directory for tags in .vimprj dir +         let s:tagsDirname = $INDEXER_PROJECT_ROOT.'/'.g:indexer_dirNameForSearch.'/tags' + +         " sourcing all *vim files in .vimprj dir +         let l:lSourceFilesList = split(glob($INDEXER_PROJECT_ROOT.'/'.g:indexer_dirNameForSearch.'/*vim'), '\n') +         let l:sThisFile = expand('%:p') +         for l:sFile in l:lSourceFilesList +            if (l:sFile != l:sThisFile) +               exec 'source '.l:sFile +            endif +         endfor +      endif + +   endif + +   call s:ParseProjectSettingsFile() + +endfunction + + + + + + +" --------- init variables -------- +if !exists('g:indexer_lookForProjectDir') +   let g:indexer_lookForProjectDir = 1 +endif + +if !exists('g:indexer_dirNameForSearch') +   let g:indexer_dirNameForSearch = '.vimprj' +endif + +if !exists('g:indexer_recurseUpCount') +   let g:indexer_recurseUpCount = 10 +endif + +if !exists('g:indexer_indexerListFilename') +   let g:indexer_indexerListFilename = $HOME.'/.indexer_files' +endif + +if !exists('g:indexer_projectsSettingsFilename') +   let g:indexer_projectsSettingsFilename = $HOME.'/.vimprojects' +endif + +if !exists('g:indexer_projectName') +   let g:indexer_projectName = '' +endif + +if !exists('g:indexer_enableWhenProjectDirFound') +   let g:indexer_enableWhenProjectDirFound = '1' +endif + +if !exists('g:indexer_tagsDirname') +   let g:indexer_tagsDirname = $HOME.'/.vimtags' +endif + +if !exists('g:indexer_ctagsCommandLineOptions') +   let g:indexer_ctagsCommandLineOptions = '--c++-kinds=+p+l --fields=+iaS --extra=+q' +endif + +if !exists('g:indexer_ctagsJustAppendTagsAtFileSave') +   let g:indexer_ctagsJustAppendTagsAtFileSave = 1 +endif + +if !exists('g:indexer_ctagsDontSpecifyFilesIfPossible') +   let g:indexer_ctagsDontSpecifyFilesIfPossible = '0' +endif + +let s:indexer_projectName = g:indexer_projectName + + +" -------- init commands --------- + +if exists(':IndexerInfo') != 2 +   command -nargs=? -complete=file IndexerInfo call <SID>IndexerInfo() +endif +if exists(':IndexerFiles') != 2 +   command -nargs=? -complete=file IndexerFiles call <SID>IndexerFilesList() +endif +if exists(':IndexerRebuild') != 2 +   command -nargs=? -complete=file IndexerRebuild call <SID>UpdateTags(0) +endif + + + + + + +augroup Indexer_LoadFile +   autocmd! Indexer_LoadFile BufReadPost +   autocmd Indexer_LoadFile BufReadPost * call <SID>IndexerInit() +augroup END + +call <SID>IndexerInit() + diff --git a/modules/vim/vim.dot.link/plugin/project.vim b/modules/vim/vim.dot.link/plugin/project.vim new file mode 100644 index 0000000..47bd379 --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/project.vim @@ -0,0 +1,1293 @@ +"============================================================================= +" File:        project.vim +" Author:      Aric Blumer (Aric.Blumer at aricvim@charter.net) +" Last Change: Fri 13 Oct 2006 09:47:08 AM EDT +" Version:     1.4.1 +"============================================================================= +" See documentation in accompanying help file +" You may use this code in whatever way you see fit. + +if exists('loaded_project') || &cp +  finish +endif +let loaded_project=1 + +function! s:Project(filename) " <<< +    " Initialization <<< +    if exists("g:proj_running") +        if strlen(a:filename) != 0 +            call confirm('Project already loaded; ignoring filename "'.a:filename."\".\n".'See ":help project-invoking" for information about changing project files.', "&OK", 1) +        endif +        let filename=bufname(g:proj_running) +    else +        if strlen(a:filename) == 0 +            let filename ='~/.vimprojects'      " Default project filename +        else +            let filename = a:filename +        endif +    endif +    if !exists('g:proj_window_width') +        let g:proj_window_width=24              " Default project window width +    endif +    if !exists('g:proj_window_increment') +        let g:proj_window_increment=100         " Project Window width increment +    endif +    if !exists('g:proj_flags') +        if has("win32") || has("mac") +            let g:proj_flags='imst'             " Project default flags for windows/mac +        else +            let g:proj_flags='imstb'            " Project default flags for everything else +        endif +    endif +    if !exists("g:proj_running") || (bufwinnr(g:proj_running) == -1) " Open the Project Window +        exec 'silent vertical new '.filename +        if match(g:proj_flags, '\CF') == -1      " We're floating +            silent! wincmd H +            exec 'vertical resize '.g:proj_window_width +        endif +        setlocal nomodeline +    else +        silent! 99wincmd h +        if bufwinnr(g:proj_running) == -1 +            vertical split +            let v:errmsg="nothing" +            silent! bnext +            if 'nothing' != v:errmsg +                enew +            endif +        endif +        return +    endif +    " Process the flags +    let b:proj_cd_cmd='cd' +    if match(g:proj_flags, '\Cl') != -1 +        let b:proj_cd_cmd = 'lcd' +    endif + +    let b:proj_locate_command='silent! wincmd H' +    let b:proj_resize_command='exec ''vertical resize ''.g:proj_window_width' +    if match(g:proj_flags, '\CF') != -1         " Set the resize commands to nothing +        let b:proj_locate_command='' +        let b:proj_resize_command='' +    endif + +    let g:proj_last_buffer = -1 +    ">>> +    " ProjFoldText() <<< +    "   The foldtext function for displaying just the description. +    function! ProjFoldText() +        let line=substitute(getline(v:foldstart),'^[ \t#]*\([^=]*\).*', '\1', '') +        let line=strpart('                                     ', 0, (v:foldlevel - 1)).substitute(line,'\s*{\+\s*', '', '') +        return line +    endfunction ">>> +    " s:DoSetup() <<< +    "   Ensure everything is set up +    function! s:DoSetup() +        setlocal foldenable foldmethod=marker foldmarker={,} commentstring=%s foldcolumn=0 nonumber noswapfile shiftwidth=1 +        setlocal foldtext=ProjFoldText() nobuflisted nowrap +        setlocal winwidth=1 +        if match(g:proj_flags, '\Cn') != -1 +            setlocal number +        endif +    endfunction ">>> +    call s:DoSetup() +    " Syntax Stuff <<< +    if match(g:proj_flags, '\Cs')!=-1 && has('syntax') && exists('g:syntax_on') && !has('syntax_items') +        syntax match projectDescriptionDir '^\s*.\{-}=\s*\(\\ \|\f\|:\|"\)\+' contains=projectDescription,projectWhiteError +        syntax match projectDescription    '\<.\{-}='he=e-1,me=e-1         contained nextgroup=projectDirectory contains=projectWhiteError +        syntax match projectDescription    '{\|}' +        syntax match projectDirectory      '=\(\\ \|\f\|:\)\+'             contained +        syntax match projectDirectory      '=".\{-}"'                      contained +        syntax match projectScriptinout    '\<in\s*=\s*\(\\ \|\f\|:\|"\)\+' contains=projectDescription,projectWhiteError +        syntax match projectScriptinout    '\<out\s*=\s*\(\\ \|\f\|:\|"\)\+' contains=projectDescription,projectWhiteError +        syntax match projectComment        '#.*' +        syntax match projectCD             '\<CD\s*=\s*\(\\ \|\f\|:\|"\)\+' contains=projectDescription,projectWhiteError +        syntax match projectFilterEntry    '\<filter\s*=.*"'               contains=projectWhiteError,projectFilterError,projectFilter,projectFilterRegexp +        syntax match projectFilter         '\<filter='he=e-1,me=e-1        contained nextgroup=projectFilterRegexp,projectFilterError,projectWhiteError +        syntax match projectFlagsEntry     '\<flags\s*=\( \|[^ ]*\)'       contains=projectFlags,projectWhiteError +        syntax match projectFlags          '\<flags'                       contained nextgroup=projectFlagsValues,projectWhiteError +        syntax match projectFlagsValues    '=[^ ]* 'hs=s+1,me=e-1          contained contains=projectFlagsError +        syntax match projectFlagsError     '[^rtTsSwl= ]\+'                contained +        syntax match projectWhiteError     '=\s\+'hs=s+1                   contained +        syntax match projectWhiteError     '\s\+='he=e-1                   contained +        syntax match projectFilterError    '=[^"]'hs=s+1                   contained +        syntax match projectFilterRegexp   '=".*"'hs=s+1                   contained +        syntax match projectFoldText       '^[^=]\+{' + +        highlight def link projectDescription  Identifier +        highlight def link projectScriptinout  Identifier +        highlight def link projectFoldText     Identifier +        highlight def link projectComment      Comment +        highlight def link projectFilter       Identifier +        highlight def link projectFlags        Identifier +        highlight def link projectDirectory    Constant +        highlight def link projectFilterRegexp String +        highlight def link projectFlagsValues  String +        highlight def link projectWhiteError   Error +        highlight def link projectFlagsError   Error +        highlight def link projectFilterError  Error +    endif ">>> +    " s:SortR(start, end) <<< +    " Sort lines.  SortR() is called recursively. +    "  from ":help eval-examples" by Robert Webb, slightly modified +    function! s:SortR(start, end) +        if (a:start >= a:end) +            return +        endif +        let partition = a:start - 1 +        let middle = partition +        let partStr = getline((a:start + a:end) / 2) +        let i = a:start +        while (i <= a:end) +            let str = getline(i) +            if str < partStr +                let result = -1 +            elseif str > partStr +                let result = 1 +            else +                let result = 0 +            endif +            if (result <= 0) +                let partition = partition + 1 +                if (result == 0) +                    let middle = partition +                endif +                if (i != partition) +                    let str2 = getline(partition) +                    call setline(i, str2) +                    call setline(partition, str) +                endif +            endif +            let i = i + 1 +        endwhile +        if (middle != partition) +            let str = getline(middle) +            let str2 = getline(partition) +            call setline(middle, str2) +            call setline(partition, str) +        endif +        call s:SortR(a:start, partition - 1) +        call s:SortR(partition + 1, a:end) +    endfunc ">>> +    " s:IsAbsolutePath(path) <<< +    "   Returns true if filename has an absolute path. +    function! s:IsAbsolutePath(path) +        if a:path =~ '^ftp:' || a:path =~ '^rcp:' || a:path =~ '^scp:' || a:path =~ '^http:' +            return 2 +        endif +        if a:path =~ '\$' +            let path=expand(a:path) " Expand any environment variables that might be in the path +        else +            let path=a:path +        endif +        if path[0] == '/' || path[0] == '~' || path[0] == '\\' || path[1] == ':' +            return 1 +        endif +        return 0 +    endfunction " >>> +    " s:DoSetupAndSplit() <<< +    "   Call DoSetup to ensure the settings are correct.  Split to the next +    "   file. +    function! s:DoSetupAndSplit() +        call s:DoSetup()                " Ensure that all the settings are right +        let n = winnr()                 " Determine if there is a CTRL_W-p window +        silent! wincmd p +        if n == winnr() +            silent! wincmd l +        endif +        if n == winnr() +            " If n == winnr(), then there is no CTRL_W-p window +            " So we have to create a new one +            if bufnr('%') == g:proj_running +                exec 'silent vertical new' +            else +                exec 'silent vertical split | silent! bnext' +            endif +            wincmd p " Go back to the Project Window and ensure it is the right width +            exec b:proj_locate_command +            exec b:proj_resize_command +            wincmd p +        endif +    endfunction ">>> +    " s:DoSetupAndSplit_au() <<< +    "   Same as above but ensure that the Project window is the current +    "   window.  Only called from an autocommand +    function! s:DoSetupAndSplit_au() +        if winbufnr(0) != g:proj_running +            return +        endif +        call s:DoSetup()                " Ensure that all the settings are right +        if winbufnr(2) == -1            " We're the only window right now. +            exec 'silent vertical split | bnext' +            if bufnr('%') == g:proj_running +                enew +            endif +            if bufnr('%') == g:proj_last_buffer | bnext | bprev | bnext | endif +            wincmd p " Go back to the Project Window and ensure it is the right width +            exec b:proj_locate_command +            exec b:proj_resize_command +        elseif(winnr() != 1) +            exec b:proj_locate_command +            exec b:proj_resize_command +        endif +    endfunction +    function! s:RecordPrevBuffer_au() +        let g:proj_last_buffer = bufnr('%') +    endfunction ">>> +    " s:RecursivelyConstructDirectives(lineno) <<< +    "   Construct the inherited directives +    function! s:RecursivelyConstructDirectives(lineno) +        let lineno=s:FindFoldTop(a:lineno) +        let foldlineno = lineno +        let foldlev=foldlevel(lineno) +        let parent_infoline = '' +        if foldlev > 1 +            while foldlevel(lineno) >= foldlev " Go to parent fold +                if lineno < 1 +                    echoerr 'Some kind of fold error.  Check your syntax.' +                    return +                endif +                let lineno = lineno - 1 +            endwhile +            let parent_infoline = s:RecursivelyConstructDirectives(lineno) +        endif +        let parent_home = s:GetHome(parent_infoline, '') +        let parent_c_d = s:GetCd(parent_infoline, parent_home) +        let parent_scriptin = s:GetScriptin(parent_infoline, parent_home) +        let parent_scriptout = s:GetScriptout(parent_infoline, parent_home) +        let parent_filter = s:GetFilter(parent_infoline, '*') +        let infoline = getline(foldlineno) +        " Extract the home directory of this fold +        let home=s:GetHome(infoline, parent_home) +        if home != '' +            if (foldlevel(foldlineno) == 1) && !s:IsAbsolutePath(home) +                call confirm('Outermost Project Fold must have absolute path!  Or perhaps the path does not exist.', "&OK", 1) +                let home = '~'  " Some 'reasonable' value +            endif +        endif +        " Extract any CD information +        let c_d = s:GetCd(infoline, home) +        if c_d != '' +            if (foldlevel(foldlineno) == 1) && !s:IsAbsolutePath(c_d) +                call confirm('Outermost Project Fold must have absolute CD path!  Or perhaps the path does not exist.', "&OK", 1) +                let c_d = '.'  " Some 'reasonable' value +            endif +        else +            let c_d=parent_c_d +        endif +        " Extract scriptin +        let scriptin = s:GetScriptin(infoline, home) +        if scriptin == '' +            let scriptin = parent_scriptin +        endif +        " Extract scriptout +        let scriptout = s:GetScriptout(infoline, home) +        if scriptout == '' +            let scriptout = parent_scriptout +        endif +        " Extract filter +        let filter = s:GetFilter(infoline, parent_filter) +        if filter == '' | let filter = parent_filter | endif +        return s:ConstructInfo(home, c_d, scriptin, scriptout, '', filter) +    endfunction ">>> +    " s:ConstructInfo(home, c_d, scriptin, scriptout, flags, filter) <<< +    function! s:ConstructInfo(home, c_d, scriptin, scriptout, flags, filter) +        let retval='Directory='.a:home +        if a:c_d[0] != '' +            let retval=retval.' CD='.a:c_d +        endif +        if a:scriptin[0] != '' +            let retval=retval.' in='.a:scriptin +        endif +        if a:scriptout[0] != '' +            let retval=retval.' out='.a:scriptout +        endif +        if a:filter[0] != '' +            let retval=retval.' filter="'.a:filter.'"' +        endif +        return retval +    endfunction ">>> +    " s:OpenEntry(line, precmd, editcmd) <<< +    "   Get the filename under the cursor, and open a window with it. +    function! s:OpenEntry(line, precmd, editcmd, dir) +        silent exec a:precmd +        if (a:editcmd[0] != '') +            if a:dir +                let fname='.' +            else +                if (foldlevel(a:line) == 0) && (a:editcmd[0] != '') +                    return 0                    " If we're outside a fold, do nothing +                endif +                let fname=substitute(getline(a:line), '\s*#.*', '', '') " Get rid of comments and whitespace before comment +                let fname=substitute(fname, '^\s*\(.*\)', '\1', '') " Get rid of leading whitespace +                if strlen(fname) == 0 +                    return 0                    " The line is blank. Do nothing. +                endif +            endif +        else +            let fname='.' +        endif +        let infoline = s:RecursivelyConstructDirectives(a:line) +        let retval=s:OpenEntry2(a:line, infoline, fname, a:editcmd) +        call s:DisplayInfo() +        return retval +    endfunction +    ">>> +    " s:OpenEntry2(line, infoline, precmd, editcmd) <<< +    "   Get the filename under the cursor, and open a window with it. +    function! s:OpenEntry2(line, infoline, fname, editcmd) +        let fname=escape(a:fname, ' %#')        " Thanks to Thomas Link for cluing me in on % and # +        let home=s:GetHome(a:infoline, '').'/' +        if home=='/' +            echoerr 'Project structure error. Check your syntax.' +            return +        endif +        "Save the cd command +        let cd_cmd = b:proj_cd_cmd +        if a:editcmd[0] != '' " If editcmd is '', then just set up the environment in the Project Window +            call s:DoSetupAndSplit() +            " If it is an absolute path, don't prepend home +            if !s:IsAbsolutePath(fname) +                let fname=home.fname +            endif +            if s:IsAbsolutePath(fname) == 2 +                exec a:editcmd.' '.fname +            else +                silent exec 'silent '.a:editcmd.' '.fname +            endif +        else " only happens in the Project File +            exec 'au! BufEnter,BufLeave '.expand('%:p') +        endif +        " Extract any CD information +        let c_d = s:GetCd(a:infoline, home) +        if c_d != '' && (s:IsAbsolutePath(home) != 2) +            if match(g:proj_flags, '\CL') != -1 +                call s:SetupAutoCommand(c_d) +            endif +            if !isdirectory(glob(c_d)) +                call confirm("From this fold's entry,\nCD=".'"'.c_d.'" is not a valid directory.', "&OK", 1) +            else +                silent exec cd_cmd.' '.c_d +            endif +        endif +        " Extract any scriptin information +        let scriptin = s:GetScriptin(a:infoline, home) +        if scriptin != '' +            if !filereadable(glob(scriptin)) +                call confirm('"'.scriptin.'" not found. Ignoring.', "&OK", 1) +            else +                call s:SetupScriptAutoCommand('BufEnter', scriptin) +                exec 'source '.scriptin +            endif +        endif +        let scriptout = s:GetScriptout(a:infoline, home) +        if scriptout != '' +            if !filereadable(glob(scriptout)) +                call confirm('"'.scriptout.'" not found. Ignoring.', "&OK", 1) +            else +                call s:SetupScriptAutoCommand('BufLeave', scriptout) +            endif +        endif +        return 1 +    endfunction +    ">>> +    " s:DoFoldOrOpenEntry(cmd0, cmd1) <<< +    "   Used for double clicking. If the mouse is on a fold, open/close it. If +    "   not, try to open the file. +    function! s:DoFoldOrOpenEntry(cmd0, cmd1) +        if getline('.')=~'{\|}' || foldclosed('.') != -1 +            normal! za +        else +            call s:DoEnsurePlacementSize_au() +            call s:OpenEntry(line('.'), a:cmd0, a:cmd1, 0) +            if (match(g:proj_flags, '\Cc') != -1) +                let g:proj_mywinnumber = winbufnr(0) +                Project +                hide +                if(g:proj_mywinnumber != winbufnr(0)) +                    wincmd p +                endif +                wincmd = +            endif +        endif +    endfunction ">>> +    " s:VimDirListing(filter, padding, separator, filevariable, filecount, dirvariable, dircount) <<< +    function! s:VimDirListing(filter, padding, separator, filevariable, filecount, dirvariable, dircount) +        let end = 0 +        let files='' +        let filter = a:filter +        " Chop up the filter +        "   Apparently glob() cannot take something like this: glob('*.c *.h') +        let while_var = 1 +        while while_var +            let end = stridx(filter, ' ') +            if end == -1 +                let end = strlen(filter) +                let while_var = 0 +            endif +            let single=glob(strpart(filter, 0, end)) +            if strlen(single) != 0 +                let files = files.single."\010" +            endif +            let filter = strpart(filter, end + 1) +        endwhile +        " files now contains a list of everything in the directory. We need to +        " weed out the directories. +        let fnames=files +        let {a:filevariable}='' +        let {a:dirvariable}='' +        let {a:filecount}=0 +        let {a:dircount}=0 +        while strlen(fnames) > 0 +            let fname = substitute(fnames,  '\(\(\f\|[ :\[\]]\)*\).*', '\1', '') +            let fnames = substitute(fnames, '\(\f\|[ :\[\]]\)*.\(.*\)', '\2', '') +            if isdirectory(glob(fname)) +                let {a:dirvariable}={a:dirvariable}.a:padding.fname.a:separator +                let {a:dircount}={a:dircount} + 1 +            else +                let {a:filevariable}={a:filevariable}.a:padding.fname.a:separator +                let {a:filecount}={a:filecount} + 1 +            endif +        endwhile +    endfunction ">>> +    " s:GenerateEntry(recursive, name, absolute_dir, dir, c_d, filter_directive, filter, foldlev, sort) <<< +    function! s:GenerateEntry(recursive, line, name, absolute_dir, dir, c_d, filter_directive, filter, foldlev, sort) +        let line=a:line +        if a:dir =~ '\\ ' +            let dir='"'.substitute(a:dir, '\\ ', ' ', 'g').'"' +        else +            let dir=a:dir +        endif +        let spaces=strpart('                                                             ', 0, a:foldlev) +        let c_d=(strlen(a:c_d) > 0) ? 'CD='.a:c_d.' ' : '' +        let c_d=(strlen(a:filter_directive) > 0) ? c_d.'filter="'.a:filter_directive.'" ': c_d +        call append(line, spaces.'}') +        call append(line, spaces.a:name.'='.dir.' '.c_d.'{') +        if a:recursive +            exec 'cd '.a:absolute_dir +            call s:VimDirListing("*", '', "\010", 'b:files', 'b:filecount', 'b:dirs', 'b:dircount') +            cd - +            let dirs=b:dirs +            let dcount=b:dircount +            unlet b:files b:filecount b:dirs b:dircount +            while dcount > 0 +                let dname = substitute(dirs,  '\(\( \|\f\|:\)*\).*', '\1', '') +                let edname = escape(dname, ' ') +                let dirs = substitute(dirs, '\( \|\f\|:\)*.\(.*\)', '\2', '') +                let line=s:GenerateEntry(1, line + 1, dname, a:absolute_dir.'/'.edname, edname, '', '', a:filter, a:foldlev+1, a:sort) +                let dcount=dcount-1 +            endwhile +        endif +        return line+1 +    endfunction " >>> +    " s:DoEntryFromDir(line, name, absolute_dir, dir, c_d, filter_directive, filter, foldlev, sort) <<< +    "   Generate the fold from the directory hierarchy (if recursive), then +    "   fill it in with RefreshEntriesFromDir() +    function! s:DoEntryFromDir(recursive, line, name, absolute_dir, dir, c_d, filter_directive, filter, foldlev, sort) +        call s:GenerateEntry(a:recursive, a:line, a:name, escape(a:absolute_dir, ' '), escape(a:dir, ' '), escape(a:c_d, ' '), a:filter_directive, a:filter, a:foldlev, a:sort) +        normal! j +        call s:RefreshEntriesFromDir(1) +    endfunction ">>> +    " s:CreateEntriesFromDir(recursive) <<< +    "   Prompts user for information and then calls s:DoEntryFromDir() +    function! s:CreateEntriesFromDir(recursive) +        " Save a mark for the current cursor position +        normal! mk +        let line=line('.') +        let name = inputdialog('Enter the Name of the Entry: ') +        if strlen(name) == 0 +            return +        endif +        let foldlev=foldlevel(line) +        if (foldclosed(line) != -1) || (getline(line) =~ '}') +            let foldlev=foldlev - 1 +        endif +        let absolute = (foldlev <= 0)?'Absolute ': '' +        let home='' +        let filter='*' +        if (match(g:proj_flags, '\Cb') != -1) && has('browse') +            " Note that browse() is inconsistent: On Win32 you can't select a +            " directory, and it gives you a relative path. +            let dir = browse(0, 'Enter the '.absolute.'Directory to Load: ', '', '') +            let dir = fnamemodify(dir, ':p') +        else +            let dir = inputdialog('Enter the '.absolute.'Directory to Load: ', '') +        endif +        if (dir[strlen(dir)-1] == '/') || (dir[strlen(dir)-1] == '\\') +            let dir=strpart(dir, 0, strlen(dir)-1) " Remove trailing / or \ +        endif +        let dir = substitute(dir, '^\~', $HOME, 'g') +        if (foldlev > 0) +            let parent_directive=s:RecursivelyConstructDirectives(line) +            let filter = s:GetFilter(parent_directive, '*') +            let home=s:GetHome(parent_directive, '') +            if home[strlen(home)-1] != '/' && home[strlen(home)-1] != '\\' +                let home=home.'/' +            endif +            unlet parent_directive +            if s:IsAbsolutePath(dir) +                " It is not a relative path  Try to make it relative +                let hend=matchend(dir, '\C'.glob(home)) +                if hend != -1 +                    let dir=strpart(dir, hend)          " The directory can be a relative path +                else +                    let home="" +                endif +            endif +        endif +        if strlen(home.dir) == 0 +            return +        endif +        if !isdirectory(home.dir) +            if has("unix") +                silent exec '!mkdir '.home.dir.' > /dev/null' +            else +                call confirm('"'.home.dir.'" is not a valid directory.', "&OK", 1) +                return +            endif +        endif +        let c_d = inputdialog('Enter the CD parameter: ', '') +        let filter_directive = inputdialog('Enter the File Filter: ', '') +        if strlen(filter_directive) != 0 +            let filter = filter_directive +        endif +        " If I'm on a closed fold, go to the bottom of it +        if foldclosedend(line) != -1 +            let line = foldclosedend(line) +        endif +        let foldlev = foldlevel(line) +        " If we're at the end of a fold . . . +        if getline(line) =~ '}' +            let foldlev = foldlev - 1           " . . . decrease the indentation by 1. +        endif +        " Do the work +        call s:DoEntryFromDir(a:recursive, line, name, home.dir, dir, c_d, filter_directive, filter, foldlev, 0) +        " Restore the cursor position +        normal! `k +    endfunction ">>> +    " s:RefreshEntriesFromDir(recursive) <<< +    "   Finds metadata at the top of the fold, and then replaces all files +    "   with the contents of the directory.  Works recursively if recursive is 1. +    function! s:RefreshEntriesFromDir(recursive) +        if foldlevel('.') == 0 +            echo 'Nothing to refresh.' +            return +        endif +        " Open the fold. +        if getline('.') =~ '}' +            normal! zo[z +        else +            normal! zo]z[z +        endif +        let just_a_fold=0 +        let infoline = s:RecursivelyConstructDirectives(line('.')) +        let immediate_infoline = getline('.') +        if strlen(substitute(immediate_infoline, '[^=]*=\(\(\f\|:\|\\ \)*\).*', '\1', '')) == strlen(immediate_infoline) +            let just_a_fold = 1 +        endif +        " Extract the home directory of the fold +        let home = s:GetHome(infoline, '') +        if home == '' +            " No Match.  This means that this is just a label with no +            " directory entry. +            if a:recursive == 0 +                return          " We're done--nothing to do +            endif +            " Mark that it is just a fold, so later we don't delete filenames +            " that aren't there. +            let just_a_fold = 1 +        endif +        if just_a_fold == 0 +            " Extract the filter between quotes (we don't care what CD is). +            let filter = s:GetFilter(infoline, '*') +            " Extract the description (name) of the fold +            let name = substitute(infoline, '^[#\t ]*\([^=]*\)=.*', '\1', '') +            if strlen(name) == strlen(infoline) +                return                  " If there's no name, we're done. +            endif +            if (home == '') || (name == '') +                return +            endif +            " Extract the flags +            let flags = s:GetFlags(immediate_infoline) +            let sort = (match(g:proj_flags, '\CS') != -1) +            if flags != '' +                if match(flags, '\Cr') != -1 +                    " If the flags do not contain r (refresh), then treat it just +                    " like a fold +                    let just_a_fold = 1 +                endif +                if match(flags, '\CS') != -1 +                    let sort = 1 +                endif +                if match(flags, '\Cs') != -1 +                    let sort = 0 +                endif +            else +                let flags='' +            endif +        endif +        " Move to the first non-fold boundary line +        normal! j +        " Delete filenames until we reach the end of the fold +        while getline('.') !~ '}' +            if line('.') == line('$') +                break +            endif +            if getline('.') !~ '{' +                " We haven't reached a sub-fold, so delete what's there. +                if (just_a_fold == 0) && (getline('.') !~ '^\s*#') && (getline('.') !~ '#.*pragma keep') +                    d _ +                else +                    " Skip lines only in a fold and comment lines +                    normal! j +                endif +            else +                " We have reached a sub-fold. If we're doing recursive, then +                " call this function again. If not, find the end of the fold. +                if a:recursive == 1 +                    call s:RefreshEntriesFromDir(1) +                    normal! ]zj +                else +                    if foldclosed('.') == -1 +                        normal! zc +                    endif +                    normal! j +                endif +            endif +        endwhile +        if just_a_fold == 0 +            " We're not just in a fold, and we have deleted all the filenames. +            " Now it is time to regenerate what is in the directory. +            if !isdirectory(glob(home)) +                call confirm('"'.home.'" is not a valid directory.', "&OK", 1) +            else +                let foldlev=foldlevel('.') +                " T flag.  Thanks Tomas Z. +                if (match(flags, '\Ct') != -1) || ((match(g:proj_flags, '\CT') == -1) && (match(flags, '\CT') == -1)) +                    " Go to the top of the fold (force other folds to the +                    " bottom) +                    normal! [z +                    normal! j +                    " Skip any comments +                    while getline('.') =~ '^\s*#' +                        normal! j +                    endwhile +                endif +                normal! k +                let cwd=getcwd() +                let spaces=strpart('                                               ', 0, foldlev) +                exec 'cd '.home +                if match(g:proj_flags, '\Ci') != -1 +                    echon home."\r" +                endif +                call s:VimDirListing(filter, spaces, "\n", 'b:files', 'b:filecount', 'b:dirs', 'b:dircount') +                if b:filecount > 0 +                    normal! mk +                    silent! put =b:files +                    normal! `kj +                    if sort +                        call s:SortR(line('.'), line('.') + b:filecount - 1) +                    endif +                else +                    normal! j +                endif +                unlet b:files b:filecount b:dirs b:dircount +                exec 'cd '.cwd +            endif +        endif +        " Go to the top of the refreshed fold. +        normal! [z +    endfunction ">>> +    " s:MoveUp() <<< +    "   Moves the entity under the cursor up a line. +    function! s:MoveUp() +        let lineno=line('.') +        if lineno == 1 +            return +        endif +        let fc=foldclosed('.') +        let a_reg=@a +        if lineno == line('$') +            normal! "add"aP +        else +            normal! "addk"aP +        endif +        let @a=a_reg +        if fc != -1 +            normal! zc +        endif +    endfunction ">>> +    " s:MoveDown() <<< +    "   Moves the entity under the cursor down a line. +    function! s:MoveDown() +        let fc=foldclosed('.') +        let a_reg=@a +        normal! "add"ap +        let @a=a_reg +        if (fc != -1) && (foldclosed('.') == -1) +            normal! zc +        endif +    endfunction " >>> +    " s:DisplayInfo() <<< +    "   Displays filename and current working directory when i (info) is in +    "   the flags. +    function! s:DisplayInfo() +        if match(g:proj_flags, '\Ci') != -1 +            echo 'file: '.expand('%').', cwd: '.getcwd().', lines: '.line('$') +        endif +    endfunction ">>> +    " s:SetupAutoCommand(cwd) <<< +    "   Sets up an autocommand to ensure that the cwd is set to the one +    "   desired for the fold regardless.  :lcd only does this on a per-window +    "   basis, not a per-buffer basis. +    function! s:SetupAutoCommand(cwd) +        if !exists("b:proj_has_autocommand") +            let b:proj_cwd_save = escape(getcwd(), ' ') +            let b:proj_has_autocommand = 1 +            let bufname=escape(substitute(expand('%:p', 0), '\\', '/', 'g'), ' ') +            exec 'au BufEnter '.bufname." let b:proj_cwd_save=escape(getcwd(), ' ') | cd ".a:cwd +            exec 'au BufLeave '.bufname.' exec "cd ".b:proj_cwd_save' +            exec 'au BufWipeout '.bufname.' au! * '.bufname +        endif +    endfunction ">>> +    " s:SetupScriptAutoCommand(bufcmd, script) <<< +    "   Sets up an autocommand to run the scriptin script. +    function! s:SetupScriptAutoCommand(bufcmd, script) +        if !exists("b:proj_has_".a:bufcmd) +            let b:proj_has_{a:bufcmd} = 1 +            exec 'au '.a:bufcmd.' '.escape(substitute(expand('%:p', 0), '\\', '/', 'g'), ' ').' source '.a:script +        endif +    endfunction " >>> +    " s:DoEnsurePlacementSize_au() <<< +    "   Ensure that the Project window is on the left of the window and has +    "   the correct size. Only called from an autocommand +    function! s:DoEnsurePlacementSize_au() +        if (winbufnr(0) != g:proj_running) || (winnr() != 1) +            if exists("g:proj_doinghelp") +                if g:proj_doinghelp > 0 +                    let g:proj_doinghelp = g:proj_doinghelp - 1 +                    return +                endif +                unlet g:proj_doinghelp +                return +            endif +            exec b:proj_locate_command +        endif +        exec b:proj_resize_command +    endfunction ">>> +    " s:Spawn(number) <<< +    "   Spawn an external command on the file +    function! s:Spawn(number) +        echo | if exists("g:proj_run".a:number) +            let fname=getline('.') +            if fname!~'{\|}' +                let fname=substitute(fname, '\s*#.*', '', '') +                let fname=substitute(fname, '^\s*\(.*\)\s*', '\1', '') +                if fname == '' | return | endif +                let parent_infoline = s:RecursivelyConstructDirectives(line('.')) +                let home=expand(s:GetHome(parent_infoline, '')) +                let c_d=expand(s:GetCd(parent_infoline, '')) +                let command=substitute(g:proj_run{a:number}, '%%', "\010", 'g') +                let command=substitute(command, '%f', escape(home.'/'.fname, '\'), 'g') +                let command=substitute(command, '%F', substitute(escape(home.'/'.fname, '\'), ' ', '\\\\ ', 'g'), 'g') +                let command=substitute(command, '%s', escape(home.'/'.fname, '\'), 'g') +                let command=substitute(command, '%n', escape(fname, '\'), 'g') +                let command=substitute(command, '%N', substitute(fname, ' ', '\\\\ ', 'g'), 'g') +                let command=substitute(command, '%h', escape(home, '\'), 'g') +                let command=substitute(command, '%H', substitute(escape(home, '\'), ' ', '\\\\ ', 'g'), 'g') +                if c_d != '' +                    if c_d == home +                        let percent_r='.' +                    else +                        let percent_r=substitute(home, escape(c_d.'/', '\'), '', 'g') +                    endif +                else +                    let percent_r=home +                endif +                let command=substitute(command, '%r', percent_r, 'g') +                let command=substitute(command, '%R', substitute(percent_r, ' ', '\\\\ ', 'g'), 'g') +                let command=substitute(command, '%d', escape(c_d, '\'), 'g') +                let command=substitute(command, '%D', substitute(escape(c_d, '\'), ' ', '\\\\ ', 'g'), 'g') +                let command=substitute(command, "\010", '%', 'g') +                exec command +            endif +        endif +    endfunction ">>> +    " s:ListSpawn(varnamesegment) <<< +    "   List external commands +    function! s:ListSpawn(varnamesegment) +        let number = 1 +        while number < 10 +            if exists("g:proj_run".a:varnamesegment.number) +                echohl LineNr | echo number.':' | echohl None | echon ' '.substitute(escape(g:proj_run{a:varnamesegment}{number}, '\'), "\n", '\\n', 'g') +            else +                echohl LineNr | echo number.':' | echohl None +            endif +            let number=number + 1 +        endwhile +    endfunction ">>> +    " s:FindFoldTop(line) <<< +    "   Return the line number of the directive line +    function! s:FindFoldTop(line) +        let lineno=a:line +        if getline(lineno) =~ '}' +            let lineno = lineno - 1 +        endif +        while getline(lineno) !~ '{' && lineno > 1 +            if getline(lineno) =~ '}' +                let lineno=s:FindFoldTop(lineno) +            endif +            let lineno = lineno - 1 +        endwhile +        return lineno +    endfunction ">>> +    " s:FindFoldBottom(line) <<< +    "   Return the line number of the directive line +    function! s:FindFoldBottom(line) +        let lineno=a:line +        if getline(lineno) =~ '{' +            let lineno=lineno + 1 +        endif +        while getline(lineno) !~ '}' && lineno < line('$') +            if getline(lineno) =~ '{' +                let lineno=s:FindFoldBottom(lineno) +            endif +            let lineno = lineno + 1 +        endwhile +        return lineno +    endfunction ">>> +    " s:LoadAll(recurse, line) <<< +    "   Load all files in a project +    function! s:LoadAll(recurse, line) +        let b:loadcount=0 +        function! s:SpawnExec(infoline, fname, lineno, data) +            if s:OpenEntry2(a:lineno, a:infoline, a:fname, 'e') +                wincmd p +                let b:loadcount=b:loadcount+1 +                echon b:loadcount."\r" +                if getchar(0) != 0 +                    let b:stop_everything=1 +                endif +            endif +        endfunction +        call Project_ForEach(a:recurse, line('.'), "*<SID>SpawnExec", 0, '^\(.*l\)\@!') +        delfunction s:SpawnExec +        echon b:loadcount." Files Loaded\r" +        unlet b:loadcount +        if exists("b:stop_everything") | unlet b:stop_everything | endif +    endfunction ">>> +    " s:WipeAll(recurse, line) <<< +    "   Wipe all files in a project +    function! s:WipeAll(recurse, line) +        let b:wipecount=0 +        let b:totalcount=0 +        function! s:SpawnExec(home, c_d, fname, lineno, data) +            let fname=escape(a:fname, ' ') +            if s:IsAbsolutePath(fname) +                let fname=fnamemodify(fname, ':n')  " :n is coming, won't break anything now +            else +                let fname=fnamemodify(a:home.'/'.fname, ':n')  " :n is coming, won't break anything now +            endif +            let b:totalcount=b:totalcount+1 +            let fname=substitute(fname, '^\~', $HOME, 'g') +            if bufloaded(substitute(fname, '\\ ', ' ', 'g')) +                if getbufvar(fname.'\>', '&modified') == 1 +                    exec 'sb '.fname +                    wincmd L +                    w +                    wincmd p +                endif +                let b:wipecount=b:wipecount+1 +                exec 'bwipe! '.fname +            endif +            if b:totalcount % 5 == 0 +                echon b:wipecount.' of '.b:totalcount."\r" +                redraw +            endif +            if getchar(0) != 0 +                let b:stop_everything=1 +            endif +        endfunction +        call Project_ForEach(a:recurse, line('.'), "<SID>SpawnExec", 0, '^\(.*w\)\@!') +        delfunction s:SpawnExec +        echon b:wipecount.' of '.b:totalcount." Files Wiped\r" +        unlet b:wipecount b:totalcount +        if exists("b:stop_everything") | unlet b:stop_everything | endif +    endfunction ">>> +    " s:LoadAllSplit(recurse, line) <<< +    "   Load all files in a project using split windows. +    "   Contributed by A. Harrison +    function! s:LoadAllSplit(recurse, line) +        let b:loadcount=0 +        function! s:SpawnExec(infoline, fname, lineno, data) +            let winNr = winnr() "get ProjectWindow number +            if s:OpenEntry2(a:lineno, a:infoline, a:fname, 'sp') +                exec winNr."wincmd w" +                let b:loadcount=b:loadcount+1 +                echon b:loadcount."\r" +                if getchar(0) != 0 +                    let b:stop_everything=1 +                endif +            endif +        endfunction +        call Project_ForEach(a:recurse, line('.'), "*<SID>SpawnExec", 0, '^\(.*l\)\@!') +        delfunction s:SpawnExec +        echon b:loadcount." Files Loaded\r" +        unlet b:loadcount +        if exists("b:stop_everything") | unlet b:stop_everything | endif +    endfunction ">>> +    " s:GrepAll(recurse, lineno, pattern) <<< +    "   Grep all files in a project, optionally recursively +    function! s:GrepAll(recurse, lineno, pattern) +        cunmap <buffer> help +        let pattern=(a:pattern[0] == '')?input("GREP options and pattern: "):a:pattern +        cnoremap <buffer> help let g:proj_doinghelp = 1<CR>:help +        if pattern[0] == '' +            return +        endif +        let b:escape_spaces=1 +        let fnames=Project_GetAllFnames(a:recurse, a:lineno, ' ') +        unlet b:escape_spaces +        cclose " Make sure grep window is closed +        call s:DoSetupAndSplit() +        if match(g:proj_flags, '\Cv') == -1 +            silent! exec 'silent! grep '.pattern.' '.fnames +            if v:shell_error != 0 +                echo 'GREP error. Perhaps there are too many filenames.' +            else +                copen +            endif +        else +            silent! exec 'silent! vimgrep '.pattern.' '.fnames +            copen +        endif +    endfunction ">>> +    " GetXXX Functions <<< +    function! s:GetHome(info, parent_home) +        " Thanks to Adam Montague for pointing out the need for @ in urls. +        let home=substitute(a:info, '^[^=]*=\(\(\\ \|\f\|:\|@\)\+\).*', '\1', '') +        if strlen(home) == strlen(a:info) +            let home=substitute(a:info, '.\{-}"\(.\{-}\)".*', '\1', '') +            if strlen(home) != strlen(a:info) | let home=escape(home, ' ') | endif +        endif +        if strlen(home) == strlen(a:info) +            let home=a:parent_home +        elseif home=='.' +            let home=a:parent_home +        elseif !s:IsAbsolutePath(home) +            let home=a:parent_home.'/'.home +        endif +        return home +    endfunction +    function! s:GetFilter(info, parent_filter) +        let filter = substitute(a:info, '.*\<filter="\([^"]*\).*', '\1', '') +        if strlen(filter) == strlen(a:info) | let filter = a:parent_filter | endif +        return filter +    endfunction +    function! s:GetCd(info, home) +        let c_d=substitute(a:info, '.*\<CD=\(\(\\ \|\f\|:\)\+\).*', '\1', '') +        if strlen(c_d) == strlen(a:info) +            let c_d=substitute(a:info, '.*\<CD="\(.\{-}\)".*', '\1', '') +            if strlen(c_d) != strlen(a:info) | let c_d=escape(c_d, ' ') | endif +        endif +        if strlen(c_d) == strlen(a:info) +            let c_d='' +        elseif c_d == '.' +            let c_d = a:home +        elseif !s:IsAbsolutePath(c_d) +            let c_d = a:home.'/'.c_d +        endif +        return c_d +    endfunction +    function! s:GetScriptin(info, home) +        let scriptin = substitute(a:info, '.*\<in=\(\(\\ \|\f\|:\)\+\).*', '\1', '') +        if strlen(scriptin) == strlen(a:info) +            let scriptin=substitute(a:info, '.*\<in="\(.\{-}\)".*', '\1', '') +            if strlen(scriptin) != strlen(a:info) | let scriptin=escape(scriptin, ' ') | endif +        endif +        if strlen(scriptin) == strlen(a:info) | let scriptin='' | else +        if !s:IsAbsolutePath(scriptin) | let scriptin=a:home.'/'.scriptin | endif | endif +        return scriptin +    endfunction +    function! s:GetScriptout(info, home) +        let scriptout = substitute(a:info, '.*\<out=\(\(\\ \|\f\|:\)\+\).*', '\1', '') +        if strlen(scriptout) == strlen(a:info) +            let scriptout=substitute(a:info, '.*\<out="\(.\{-}\)".*', '\1', '') +            if strlen(scriptout) != strlen(a:info) | let scriptout=escape(scriptout, ' ') | endif +        endif +        if strlen(scriptout) == strlen(a:info) | let scriptout='' | else +        if !s:IsAbsolutePath(scriptout) | let scriptout=a:home.'/'.scriptout | endif | endif +        return scriptout +    endfunction +    function! s:GetFlags(info) +        let flags=substitute(a:info, '.*\<flags=\([^ {]*\).*', '\1', '') +        if (strlen(flags) == strlen(a:info)) +            let flags='' +        endif +        return flags +    endfunction ">>> +    " Project_GetAllFnames(recurse, lineno, separator) <<< +    "   Grep all files in a project, optionally recursively +    function! Project_GetAllFnames(recurse, lineno, separator) +        let b:fnamelist='' +        function! s:SpawnExec(home, c_d, fname, lineno, data) +            if exists('b:escape_spaces') +                let fname=escape(a:fname, ' ') +            else +                let fname=a:fname +            endif +            if !s:IsAbsolutePath(a:fname) +                let fname=a:home.'/'.fname +            endif +            let b:fnamelist=b:fnamelist.a:data.fname +        endfunction +        call Project_ForEach(a:recurse, line('.'), "<SID>SpawnExec", a:separator, '') +        delfunction s:SpawnExec +        let retval=b:fnamelist +        unlet b:fnamelist +        return retval +    endfunction ">>> +    " Project_GetAllFnames(recurse, lineno, separator) <<< +    "   Grep all files in a project, optionally recursively +    function! Project_GetFname(line) +        if (foldlevel(a:line) == 0) +            return '' +        endif +        let fname=substitute(getline(a:line), '\s*#.*', '', '') " Get rid of comments and whitespace before comment +        let fname=substitute(fname, '^\s*\(.*\)', '\1', '') " Get rid of leading whitespace +        if strlen(fname) == 0 +            return ''                    " The line is blank. Do nothing. +        endif +        if s:IsAbsolutePath(fname) +            return fname +        endif +        let infoline = s:RecursivelyConstructDirectives(a:line) +        return s:GetHome(infoline, '').'/'.fname +    endfunction ">>> +    " Project_ForEach(recurse, lineno, cmd, data, match) <<< +    "   Grep all files in a project, optionally recursively +    function! Project_ForEach(recurse, lineno, cmd, data, match) +        let info=s:RecursivelyConstructDirectives(a:lineno) +        let lineno=s:FindFoldTop(a:lineno) + 1 +        let flags=s:GetFlags(getline(lineno - 1)) +        if (flags == '') || (a:match=='') || (match(flags, a:match) != -1) +            call s:Project_ForEachR(a:recurse, lineno, info, a:cmd, a:data, a:match) +        endif +    endfunction +    function! s:Project_ForEachR(recurse, lineno, info, cmd, data, match) +        let home=s:GetHome(a:info, '') +        let c_d=s:GetCd(a:info, home) +        let scriptin = s:GetScriptin(a:info, home) +        let scriptout = s:GetScriptout(a:info, home) +        let filter = s:GetFilter(a:info, '') +        let lineno = a:lineno +        let curline=getline(lineno) +        while (curline !~ '}') && (curline < line('$')) +            if exists("b:stop_everything") && b:stop_everything | return 0 | endif +            if curline =~ '{' +                if a:recurse +                    let flags=s:GetFlags(curline) +                    if (flags == '') || (a:match=='') || (match(flags, a:match) != -1) +                        let this_home=s:GetHome(curline, home) +                        let this_cd=s:GetCd(curline, this_home) +                        if this_cd=='' | let this_cd=c_d | endif +                        let this_scriptin=s:GetScriptin(curline, this_home) +                        if this_scriptin == '' | let this_scriptin=scriptin | endif +                        let this_scriptout=s:GetScriptin(curline, this_home) +                        if this_scriptout == '' | let this_scriptout=scriptout | endif +                        let this_filter=s:GetFilter(curline, filter) +                        let lineno=s:Project_ForEachR(1, lineno+1, +                            \s:ConstructInfo(this_home, this_cd, this_scriptin, this_scriptout, flags, this_filter), a:cmd, a:data, a:match) +                    else +                        let lineno=s:FindFoldBottom(lineno) +                    endif +                else +                    let lineno=s:FindFoldBottom(lineno) +                endif +            else +                let fname=substitute(curline, '\s*#.*', '', '') +                let fname=substitute(fname, '^\s*\(.*\)', '\1', '') +                if (strlen(fname) != strlen(curline)) && (fname[0] != '') +                    if a:cmd[0] == '*' +                        call {strpart(a:cmd, 1)}(a:info, fname, lineno, a:data) +                    else +                        call {a:cmd}(home, c_d, fname, lineno, a:data) +                    endif +                endif +            endif +            let lineno=lineno + 1 +            let curline=getline(lineno) +        endwhile +        return lineno +    endfunction ">>> +    " s:SpawnAll(recurse, number) <<< +    "   Spawn an external command on the files of a project +    function! s:SpawnAll(recurse, number) +        echo | if exists("g:proj_run_fold".a:number) +            if g:proj_run_fold{a:number}[0] == '*' +                function! s:SpawnExec(home, c_d, fname, lineno, data) +                    let command=substitute(strpart(g:proj_run_fold{a:data}, 1), '%s', escape(a:fname, ' \'), 'g') +                    let command=substitute(command, '%f', escape(a:fname, '\'), 'g') +                    let command=substitute(command, '%h', escape(a:home, '\'), 'g') +                    let command=substitute(command, '%d', escape(a:c_d, '\'), 'g') +                    let command=substitute(command, '%F', substitute(escape(a:fname, '\'), ' ', '\\\\ ', 'g'), 'g') +                    exec command +                endfunction +                call Project_ForEach(a:recurse, line('.'), "<SID>SpawnExec", a:number, '.') +                delfunction s:SpawnExec +            else +                let info=s:RecursivelyConstructDirectives(line('.')) +                let home=s:GetHome(info, '') +                let c_d=s:GetCd(info, '') +                let b:escape_spaces=1 +                let fnames=Project_GetAllFnames(a:recurse, line('.'), ' ') +                unlet b:escape_spaces +                let command=substitute(g:proj_run_fold{a:number}, '%f', substitute(escape(fnames, '\'), '\\ ', ' ', 'g'), 'g') +                let command=substitute(command, '%s', escape(fnames, '\'), 'g') +                let command=substitute(command, '%h', escape(home, '\'), 'g') +                let command=substitute(command, '%d', escape(c_d, '\'), 'g') +                let command=substitute(command, '%F', escape(fnames, '\'), 'g') +                exec command +                if v:shell_error != 0 +                    echo 'Shell error. Perhaps there are too many filenames.' +                endif +            endif +        endif +    endfunction ">>> +    if !exists("g:proj_running") +        " s:DoProjectOnly(void) <<< +        "   Make the file window the only one. +        function! s:DoProjectOnly() +            if winbufnr(0) != g:proj_running +                let lzsave=&lz +                set lz +                only +                Project +                silent! wincmd p +                let &lz=lzsave +                unlet lzsave +            endif +        endfunction +        " >>> + +        " Mappings <<< +        nnoremap <buffer> <silent> <Return>   \|:call <SID>DoFoldOrOpenEntry('', 'e')<CR> +        nnoremap <buffer> <silent> <S-Return> \|:call <SID>DoFoldOrOpenEntry('', 'sp')<CR> +        nnoremap <buffer> <silent> <C-Return> \|:call <SID>DoFoldOrOpenEntry('silent! only', 'e')<CR> +        nnoremap <buffer> <silent> <LocalLeader>T \|:call <SID>DoFoldOrOpenEntry('', 'tabe')<CR> +        nmap     <buffer> <silent> <LocalLeader>s <S-Return> +        nnoremap <buffer> <silent> <LocalLeader>S \|:call <SID>LoadAllSplit(0, line('.'))<CR> +        nmap     <buffer> <silent> <LocalLeader>o <C-Return> +        nnoremap <buffer> <silent> <LocalLeader>i :echo <SID>RecursivelyConstructDirectives(line('.'))<CR> +        nnoremap <buffer> <silent> <LocalLeader>I :echo Project_GetFname(line('.'))<CR> +        nmap     <buffer> <silent> <M-CR> <Return><C-W>p +        nmap     <buffer> <silent> <LocalLeader>v <M-CR> +        nnoremap <buffer> <silent> <LocalLeader>l \|:call <SID>LoadAll(0, line('.'))<CR> +        nnoremap <buffer> <silent> <LocalLeader>L \|:call <SID>LoadAll(1, line('.'))<CR> +        nnoremap <buffer> <silent> <LocalLeader>w \|:call <SID>WipeAll(0, line('.'))<CR> +        nnoremap <buffer> <silent> <LocalLeader>W \|:call <SID>WipeAll(1, line('.'))<CR> +        nnoremap <buffer> <silent> <LocalLeader>W \|:call <SID>WipeAll(1, line('.'))<CR> +        nnoremap <buffer> <silent> <LocalLeader>g \|:call <SID>GrepAll(0, line('.'), "")<CR> +        nnoremap <buffer> <silent> <LocalLeader>G \|:call <SID>GrepAll(1, line('.'), "")<CR> +        nnoremap <buffer> <silent> <2-LeftMouse>   \|:call <SID>DoFoldOrOpenEntry('', 'e')<CR> +        nnoremap <buffer> <silent> <S-2-LeftMouse> \|:call <SID>DoFoldOrOpenEntry('', 'sp')<CR> +        nnoremap <buffer> <silent> <M-2-LeftMouse> <M-CR> +        nnoremap <buffer> <silent> <S-LeftMouse>   <LeftMouse> +        nmap     <buffer> <silent> <C-2-LeftMouse> <C-Return> +        nnoremap <buffer> <silent> <C-LeftMouse>   <LeftMouse> +        nnoremap <buffer> <silent> <3-LeftMouse>  <Nop> +        nmap     <buffer> <silent> <RightMouse>   <space> +        nmap     <buffer> <silent> <2-RightMouse> <space> +        nmap     <buffer> <silent> <3-RightMouse> <space> +        nmap     <buffer> <silent> <4-RightMouse> <space> +        nnoremap <buffer> <silent> <space>  \|:silent exec 'vertical resize '.(match(g:proj_flags, '\Ct')!=-1 && winwidth('.') > g:proj_window_width?(g:proj_window_width):(winwidth('.') + g:proj_window_increment))<CR> +        nnoremap <buffer> <silent> <C-Up>   \|:silent call <SID>MoveUp()<CR> +        nnoremap <buffer> <silent> <C-Down> \|:silent call <SID>MoveDown()<CR> +        nmap     <buffer> <silent> <LocalLeader><Up> <C-Up> +        nmap     <buffer> <silent> <LocalLeader><Down> <C-Down> +        let k=1 +        while k < 10 +            exec 'nnoremap <buffer> <LocalLeader>'.k.'  \|:call <SID>Spawn('.k.')<CR>' +            exec 'nnoremap <buffer> <LocalLeader>f'.k.' \|:call <SID>SpawnAll(0, '.k.')<CR>' +            exec 'nnoremap <buffer> <LocalLeader>F'.k.' \|:call <SID>SpawnAll(1, '.k.')<CR>' +            let k=k+1 +        endwhile +        nnoremap <buffer>          <LocalLeader>0 \|:call <SID>ListSpawn("")<CR> +        nnoremap <buffer>          <LocalLeader>f0 \|:call <SID>ListSpawn("_fold")<CR> +        nnoremap <buffer>          <LocalLeader>F0 \|:call <SID>ListSpawn("_fold")<CR> +        nnoremap <buffer> <silent> <LocalLeader>c :call <SID>CreateEntriesFromDir(0)<CR> +        nnoremap <buffer> <silent> <LocalLeader>C :call <SID>CreateEntriesFromDir(1)<CR> +        nnoremap <buffer> <silent> <LocalLeader>r :call <SID>RefreshEntriesFromDir(0)<CR> +        nnoremap <buffer> <silent> <LocalLeader>R :call <SID>RefreshEntriesFromDir(1)<CR> +        " For Windows users: same as \R +        nnoremap <buffer> <silent>           <F5> :call <SID>RefreshEntriesFromDir(1)<CR> +        nnoremap <buffer> <silent> <LocalLeader>e :call <SID>OpenEntry(line('.'), '', '', 0)<CR> +        nnoremap <buffer> <silent> <LocalLeader>E :call <SID>OpenEntry(line('.'), '', 'e', 1)<CR> +        " The :help command stomps on the Project Window.  Try to avoid that. +        " This is not perfect, but it is alot better than without the mappings. +        cnoremap <buffer> help let g:proj_doinghelp = 1<CR>:help +        nnoremap <buffer> <F1> :let g:proj_doinghelp = 1<CR><F1> +        " This is to avoid changing the buffer, but it is not fool-proof. +        nnoremap <buffer> <silent> <C-^> <Nop> +        "nnoremap <script> <Plug>ProjectOnly :let lzsave=&lz<CR>:set lz<CR><C-W>o:Project<CR>:silent! wincmd p<CR>:let &lz=lzsave<CR>:unlet lzsave<CR> +        nnoremap <script> <Plug>ProjectOnly :call <SID>DoProjectOnly()<CR> +        if match(g:proj_flags, '\Cm') != -1 +            if !hasmapto('<Plug>ProjectOnly') +                nmap <silent> <unique> <C-W>o <Plug>ProjectOnly +                nmap <silent> <unique> <C-W><C-O> <C-W>o +            endif +        endif " >>> +        if filereadable(glob('~/.vimproject_mappings')) | source ~/.vimproject_mappings | endif +        " Autocommands <<< +        " Autocommands to clean up if we do a buffer wipe +        " These don't work unless we substitute \ for / for Windows +        let bufname=escape(substitute(expand('%:p', 0), '\\', '/', 'g'), ' ') +        exec 'au BufWipeout '.bufname.' au! * '.bufname +        exec 'au BufWipeout '.bufname.' unlet g:proj_running' +        exec 'au BufWipeout '.bufname.' nunmap <C-W>o' +        exec 'au BufWipeout '.bufname.' nunmap <C-W><C-O>' +        " Autocommands to keep the window the specified size +        exec 'au WinLeave '.bufname.' call s:DoEnsurePlacementSize_au()' +        exec 'au BufEnter '.bufname.' call s:DoSetupAndSplit_au()' +        au WinLeave * call s:RecordPrevBuffer_au() +        " >>> +        setlocal buflisted +        let g:proj_running = bufnr(bufname.'\>') +        if g:proj_running == -1 +            call confirm('Project/Vim error. Please Enter :Project again and report this bug.', "&OK", 1) +            unlet g:proj_running +        endif +        setlocal nobuflisted +    endif +endfunction " >>> + +if exists(':Project') != 2 +    command -nargs=? -complete=file Project call <SID>Project('<args>') +endif +" Toggle Mapping +if !exists("*<SID>DoToggleProject()") "<<< +    function! s:DoToggleProject() +        if !exists('g:proj_running') || bufwinnr(g:proj_running) == -1 +            Project +        else +            let g:proj_mywindow = winnr() +            Project +            hide +            if(winnr() != g:proj_mywindow) +                wincmd p +            endif +            unlet g:proj_mywindow +        endif +    endfunction +endif ">>> +nnoremap <script> <Plug>ToggleProject :call <SID>DoToggleProject()<CR> +if exists('g:proj_flags') && (match(g:proj_flags, '\Cg') != -1) +    if !hasmapto('<Plug>ToggleProject') +        nmap <silent> <F12> <Plug>ToggleProject +    endif +endif + +finish + +" vim600: set foldmethod=marker foldmarker=<<<,>>> foldlevel=1: diff --git a/modules/vim/vim.dot.link/plugin/snipMate.vim b/modules/vim/vim.dot.link/plugin/snipMate.vim new file mode 100644 index 0000000..3efee2a --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/snipMate.vim @@ -0,0 +1,247 @@ +" File:          snipMate.vim +" Author:        Michael Sanders +" Last Updated:  July 13, 2009 +" Version:       0.83 +" Description:   snipMate.vim implements some of TextMate's snippets features in +"                Vim. A snippet is a piece of often-typed text that you can +"                insert into your document using a trigger word followed by a "<tab>". +" +"                For more help see snipMate.txt; you can do this by using: +"                :helptags ~/.vim/doc +"                :h snipMate.txt + +if exists('loaded_snips') || &cp || version < 700 +	finish +endif +let loaded_snips = 1 +if !exists('snips_author') | let snips_author = 'Me' | endif + +au BufRead,BufNewFile *.snippets\= set ft=snippet +au FileType snippet setl noet fdm=indent + +let s:snippets = {} | let s:multi_snips = {} + +if !exists('snippets_dir') +	let snippets_dir = substitute(globpath(&rtp, 'snippets/'), "\n", ',', 'g') +endif + +fun! MakeSnip(scope, trigger, content, ...) +	let multisnip = a:0 && a:1 != '' +	let var = multisnip ? 's:multi_snips' : 's:snippets' +	if !has_key({var}, a:scope) | let {var}[a:scope] = {} | endif +	if !has_key({var}[a:scope], a:trigger) +		let {var}[a:scope][a:trigger] = multisnip ? [[a:1, a:content]] : a:content +	elseif multisnip | let {var}[a:scope][a:trigger] += [[a:1, a:content]] +	else +		echom 'Warning in snipMate.vim: Snippet '.a:trigger.' is already defined.' +				\ .' See :h multi_snip for help on snippets with multiple matches.' +	endif +endf + +fun! ExtractSnips(dir, ft) +	for path in split(globpath(a:dir, '*'), "\n") +		if isdirectory(path) +			let pathname = fnamemodify(path, ':t') +			for snipFile in split(globpath(path, '*.snippet'), "\n") +				call s:ProcessFile(snipFile, a:ft, pathname) +			endfor +		elseif fnamemodify(path, ':e') == 'snippet' +			call s:ProcessFile(path, a:ft) +		endif +	endfor +endf + +" Processes a single-snippet file; optionally add the name of the parent +" directory for a snippet with multiple matches. +fun s:ProcessFile(file, ft, ...) +	let keyword = fnamemodify(a:file, ':t:r') +	if keyword  == '' | return | endif +	try +		let text = join(readfile(a:file), "\n") +	catch /E484/ +		echom "Error in snipMate.vim: couldn't read file: ".a:file +	endtry +	return a:0 ? MakeSnip(a:ft, a:1, text, keyword) +			\  : MakeSnip(a:ft, keyword, text) +endf + +fun! ExtractSnipsFile(file, ft) +	if !filereadable(a:file) | return | endif +	let text = readfile(a:file) +	let inSnip = 0 +	for line in text + ["\n"] +		if inSnip && (line[0] == "\t" || line == '') +			let content .= strpart(line, 1)."\n" +			continue +		elseif inSnip +			call MakeSnip(a:ft, trigger, content[:-2], name) +			let inSnip = 0 +		endif + +		if line[:6] == 'snippet' +			let inSnip = 1 +			let trigger = strpart(line, 8) +			let name = '' +			let space = stridx(trigger, ' ') + 1 +			if space " Process multi snip +				let name = strpart(trigger, space) +				let trigger = strpart(trigger, 0, space - 1) +			endif +			let content = '' +		endif +	endfor +endf + +fun! ResetSnippets() +	let s:snippets = {} | let s:multi_snips = {} | let g:did_ft = {} +endf + +let g:did_ft = {} +fun! GetSnippets(dir, filetypes) +	for ft in split(a:filetypes, '\.') +		if has_key(g:did_ft, ft) | continue | endif +		call s:DefineSnips(a:dir, ft, ft) +		if ft == 'objc' || ft == 'cpp' || ft == 'cs' +			call s:DefineSnips(a:dir, 'c', ft) +		elseif ft == 'xhtml' +			call s:DefineSnips(a:dir, 'html', 'xhtml') +		endif +		let g:did_ft[ft] = 1 +	endfor +endf + +" Define "aliasft" snippets for the filetype "realft". +fun s:DefineSnips(dir, aliasft, realft) +	for path in split(globpath(a:dir, a:aliasft.'/')."\n". +					\ globpath(a:dir, a:aliasft.'-*/'), "\n") +		call ExtractSnips(path, a:realft) +	endfor +	for path in split(globpath(a:dir, a:aliasft.'.snippets')."\n". +					\ globpath(a:dir, a:aliasft.'-*.snippets'), "\n") +		call ExtractSnipsFile(path, a:realft) +	endfor +endf + +fun! TriggerSnippet() +	if exists('g:SuperTabMappingForward') +		if g:SuperTabMappingForward == "<tab>" +			let SuperTabKey = "\<c-n>" +		elseif g:SuperTabMappingBackward == "<tab>" +			let SuperTabKey = "\<c-p>" +		endif +	endif + +	if pumvisible() " Update snippet if completion is used, or deal with supertab +		if exists('SuperTabKey') +			call feedkeys(SuperTabKey) | return '' +		endif +		call feedkeys("\<esc>a", 'n') " Close completion menu +		call feedkeys("\<tab>") | return '' +	endif + +	if exists('g:snipPos') | return snipMate#jumpTabStop(0) | endif + +	let word = matchstr(getline('.'), '\S\+\%'.col('.').'c') +	for scope in [bufnr('%')] + split(&ft, '\.') + ['_'] +		let [trigger, snippet] = s:GetSnippet(word, scope) +		" If word is a trigger for a snippet, delete the trigger & expand +		" the snippet. +		if snippet != '' +			let col = col('.') - len(trigger) +			sil exe 's/\V'.escape(trigger, '/.').'\%#//' +			return snipMate#expandSnip(snippet, col) +		endif +	endfor + +	if exists('SuperTabKey') +		call feedkeys(SuperTabKey) +		return '' +	endif +	return "\<tab>" +endf + +fun! BackwardsSnippet() +	if exists('g:snipPos') | return snipMate#jumpTabStop(1) | endif + +	if exists('g:SuperTabMappingForward') +		if g:SuperTabMappingBackward == "<s-tab>" +			let SuperTabKey = "\<c-p>" +		elseif g:SuperTabMappingForward == "<s-tab>" +			let SuperTabKey = "\<c-n>" +		endif +	endif +	if exists('SuperTabKey') +		call feedkeys(SuperTabKey) +		return '' +	endif +	return "\<s-tab>" +endf + +" Check if word under cursor is snippet trigger; if it isn't, try checking if +" the text after non-word characters is (e.g. check for "foo" in "bar.foo") +fun s:GetSnippet(word, scope) +	let word = a:word | let snippet = '' +	while snippet == '' +		if exists('s:snippets["'.a:scope.'"]["'.escape(word, '\"').'"]') +			let snippet = s:snippets[a:scope][word] +		elseif exists('s:multi_snips["'.a:scope.'"]["'.escape(word, '\"').'"]') +			let snippet = s:ChooseSnippet(a:scope, word) +			if snippet == '' | break | endif +		else +			if match(word, '\W') == -1 | break | endif +			let word = substitute(word, '.\{-}\W', '', '') +		endif +	endw +	if word == '' && a:word != '.' && stridx(a:word, '.') != -1 +		let [word, snippet] = s:GetSnippet('.', a:scope) +	endif +	return [word, snippet] +endf + +fun s:ChooseSnippet(scope, trigger) +	let snippet = [] +	let i = 1 +	for snip in s:multi_snips[a:scope][a:trigger] +		let snippet += [i.'. '.snip[0]] +		let i += 1 +	endfor +	if i == 2 | return s:multi_snips[a:scope][a:trigger][0][1] | endif +	let num = inputlist(snippet) - 1 +	return num == -1 ? '' : s:multi_snips[a:scope][a:trigger][num][1] +endf + +fun! ShowAvailableSnips() +	let line  = getline('.') +	let col   = col('.') +	let word  = matchstr(getline('.'), '\S\+\%'.col.'c') +	let words = [word] +	if stridx(word, '.') +		let words += split(word, '\.', 1) +	endif +	let matchlen = 0 +	let matches = [] +	for scope in [bufnr('%')] + split(&ft, '\.') + ['_'] +		let triggers = has_key(s:snippets, scope) ? keys(s:snippets[scope]) : [] +		if has_key(s:multi_snips, scope) +			let triggers += keys(s:multi_snips[scope]) +		endif +		for trigger in triggers +			for word in words +				if word == '' +					let matches += [trigger] " Show all matches if word is empty +				elseif trigger =~ '^'.word +					let matches += [trigger] +					let len = len(word) +					if len > matchlen | let matchlen = len | endif +				endif +			endfor +		endfor +	endfor + +	" This is to avoid a bug with Vim when using complete(col - matchlen, matches) +	" (Issue#46 on the Google Code snipMate issue tracker). +	call setline(line('.'), substitute(line, repeat('.', matchlen).'\%'.col.'c', '', '')) +	call complete(col, matches) +	return '' +endf +" vim:noet:sw=4:ts=4:ft=vim diff --git a/modules/vim/vim.dot.link/plugin/startshell_mapping.vim.disabled b/modules/vim/vim.dot.link/plugin/startshell_mapping.vim.disabled new file mode 100644 index 0000000..e9704f4 --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/startshell_mapping.vim.disabled @@ -0,0 +1,36 @@ +"plugin from http://got-ravings.blogspot.com/2010/07/vim-pr0n-sample-nerd-tree-plugins.html +"guard against sourcing the script twice +if exists("g:loaded_nerdtree_start_shell_mapping") +    finish +endif +let g:loaded_nerdtree_start_shell_mapping = 1 + +"bind 'S' to NERDTreeStartShell() +call NERDTreeAddKeyMap({ +    \ 'key': 'S', +    \ 'callback': 'NERDTreeStartShell', +    \ 'quickhelpText': 'start a :shell in this dir' }) + +"change to the dir of the current node and start a :shell +function! NERDTreeStartShell() + +    "grab the currently selected dir node (returns  +    "the parent dir if a file is selected) +    let n = g:NERDTreeDirNode.GetSelected() + +    "save the cwd so we can restore it after the :shell exits +    let oldCWD = getcwd() + +    try + +        ":lcd to to the selected dir and :shell out +        exec 'lcd ' . n.path.str({'format': 'Cd'}) +        redraw! +        shell + +    "make sure we restore the cwd to its original state +    finally +        exec 'lcd ' . oldCWD +    endtry + +endfunction diff --git a/modules/vim/vim.dot.link/plugin/taglist.vim b/modules/vim/vim.dot.link/plugin/taglist.vim new file mode 100644 index 0000000..59901f6 --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/taglist.vim @@ -0,0 +1,4546 @@ +" File: taglist.vim +" Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com) +" Version: 4.5 +" Last Modified: September 21, 2007 +" Copyright: Copyright (C) 2002-2007 Yegappan Lakshmanan +"            Permission is hereby granted to use and distribute this code, +"            with or without modifications, provided that this copyright +"            notice is copied with it. Like anything else that's free, +"            taglist.vim is provided *as is* and comes with no warranty of any +"            kind, either expressed or implied. In no event will the copyright +"            holder be liable for any damamges resulting from the use of this +"            software. +" +" The "Tag List" plugin is a source code browser plugin for Vim and provides +" an overview of the structure of the programming language files and allows +" you to efficiently browse through source code files for different +" programming languages.  You can visit the taglist plugin home page for more +" information: +" +"       http://vim-taglist.sourceforge.net +" +" You can subscribe to the taglist mailing list to post your questions +" or suggestions for improvement or to report bugs. Visit the following +" page for subscribing to the mailing list: +" +"       http://groups.yahoo.com/group/taglist/ +" +" For more information about using this plugin, after installing the +" taglist plugin, use the ":help taglist" command. +" +" Installation +" ------------ +" 1. Download the taglist.zip file and unzip the files to the $HOME/.vim +"    or the $HOME/vimfiles or the $VIM/vimfiles directory. This should +"    unzip the following two files (the directory structure should be +"    preserved): +" +"       plugin/taglist.vim - main taglist plugin file +"       doc/taglist.txt    - documentation (help) file +" +"    Refer to the 'add-plugin', 'add-global-plugin' and 'runtimepath' +"    Vim help pages for more details about installing Vim plugins. +" 2. Change to the $HOME/.vim/doc or $HOME/vimfiles/doc or +"    $VIM/vimfiles/doc directory, start Vim and run the ":helptags ." +"    command to process the taglist help file. +" 3. If the exuberant ctags utility is not present in your PATH, then set the +"    Tlist_Ctags_Cmd variable to point to the location of the exuberant ctags +"    utility (not to the directory) in the .vimrc file. +" 4. If you are running a terminal/console version of Vim and the +"    terminal doesn't support changing the window width then set the +"    'Tlist_Inc_Winwidth' variable to 0 in the .vimrc file. +" 5. Restart Vim. +" 6. You can now use the ":TlistToggle" command to open/close the taglist +"    window. You can use the ":help taglist" command to get more +"    information about using the taglist plugin. +" +" ****************** Do not modify after this line ************************ + +" Line continuation used here +let s:cpo_save = &cpo +set cpo&vim + +if !exists('loaded_taglist') +    " First time loading the taglist plugin +    " +    " To speed up the loading of Vim, the taglist plugin uses autoload +    " mechanism to load the taglist functions. +    " Only define the configuration variables, user commands and some +    " auto-commands and finish sourcing the file + +    " The taglist plugin requires the built-in Vim system() function. If this +    " function is not available, then don't load the plugin. +    if !exists('*system') +        echomsg 'Taglist: Vim system() built-in function is not available. ' . +                    \ 'Plugin is not loaded.' +        let loaded_taglist = 'no' +        let &cpo = s:cpo_save +        finish +    endif + +    " Location of the exuberant ctags tool +    if !exists('Tlist_Ctags_Cmd') +        if executable('exuberant-ctags') +            " On Debian Linux, exuberant ctags is installed +            " as exuberant-ctags +            let Tlist_Ctags_Cmd = 'exuberant-ctags' +        elseif executable('exctags') +            " On Free-BSD, exuberant ctags is installed as exctags +            let Tlist_Ctags_Cmd = 'exctags' +        elseif executable('ctags') +            let Tlist_Ctags_Cmd = 'ctags' +        elseif executable('ctags.exe') +            let Tlist_Ctags_Cmd = 'ctags.exe' +        elseif executable('tags') +            let Tlist_Ctags_Cmd = 'tags' +        else +            echomsg 'Taglist: Exuberant ctags (http://ctags.sf.net) ' . +                        \ 'not found in PATH. Plugin is not loaded.' +            " Skip loading the plugin +            let loaded_taglist = 'no' +            let &cpo = s:cpo_save +            finish +        endif +    endif + + +    " Automatically open the taglist window on Vim startup +    if !exists('Tlist_Auto_Open') +        let Tlist_Auto_Open = 0 +    endif + +    " When the taglist window is toggle opened, move the cursor to the +    " taglist window +    if !exists('Tlist_GainFocus_On_ToggleOpen') +        let Tlist_GainFocus_On_ToggleOpen = 0 +    endif + +    " Process files even when the taglist window is not open +    if !exists('Tlist_Process_File_Always') +        let Tlist_Process_File_Always = 0 +    endif + +    if !exists('Tlist_Show_Menu') +        let Tlist_Show_Menu = 0 +    endif + +    " Tag listing sort type - 'name' or 'order' +    if !exists('Tlist_Sort_Type') +        let Tlist_Sort_Type = 'order' +    endif + +    " Tag listing window split (horizontal/vertical) control +    if !exists('Tlist_Use_Horiz_Window') +        let Tlist_Use_Horiz_Window = 0 +    endif + +    " Open the vertically split taglist window on the left or on the right +    " side.  This setting is relevant only if Tlist_Use_Horiz_Window is set to +    " zero (i.e.  only for vertically split windows) +    if !exists('Tlist_Use_Right_Window') +        let Tlist_Use_Right_Window = 0 +    endif + +    " Increase Vim window width to display vertically split taglist window. +    " For MS-Windows version of Vim running in a MS-DOS window, this must be +    " set to 0 otherwise the system may hang due to a Vim limitation. +    if !exists('Tlist_Inc_Winwidth') +        if (has('win16') || has('win95')) && !has('gui_running') +            let Tlist_Inc_Winwidth = 0 +        else +            let Tlist_Inc_Winwidth = 1 +        endif +    endif + +    " Vertically split taglist window width setting +    if !exists('Tlist_WinWidth') +        let Tlist_WinWidth = 30 +    endif + +    " Horizontally split taglist window height setting +    if !exists('Tlist_WinHeight') +        let Tlist_WinHeight = 10 +    endif + +    " Display tag prototypes or tag names in the taglist window +    if !exists('Tlist_Display_Prototype') +        let Tlist_Display_Prototype = 0 +    endif + +    " Display tag scopes in the taglist window +    if !exists('Tlist_Display_Tag_Scope') +        let Tlist_Display_Tag_Scope = 1 +    endif + +    " Use single left mouse click to jump to a tag. By default this is disabled. +    " Only double click using the mouse will be processed. +    if !exists('Tlist_Use_SingleClick') +        let Tlist_Use_SingleClick = 0 +    endif + +    " Control whether additional help is displayed as part of the taglist or +    " not.  Also, controls whether empty lines are used to separate the tag +    " tree. +    if !exists('Tlist_Compact_Format') +        let Tlist_Compact_Format = 0 +    endif + +    " Exit Vim if only the taglist window is currently open. By default, this is +    " set to zero. +    if !exists('Tlist_Exit_OnlyWindow') +        let Tlist_Exit_OnlyWindow = 0 +    endif + +    " Automatically close the folds for the non-active files in the taglist +    " window +    if !exists('Tlist_File_Fold_Auto_Close') +        let Tlist_File_Fold_Auto_Close = 0 +    endif + +    " Close the taglist window when a tag is selected +    if !exists('Tlist_Close_On_Select') +        let Tlist_Close_On_Select = 0 +    endif + +    " Automatically update the taglist window to display tags for newly +    " edited files +    if !exists('Tlist_Auto_Update') +        let Tlist_Auto_Update = 1 +    endif + +    " Automatically highlight the current tag +    if !exists('Tlist_Auto_Highlight_Tag') +        let Tlist_Auto_Highlight_Tag = 1 +    endif +     +    " Automatically highlight the current tag on entering a buffer +    if !exists('Tlist_Highlight_Tag_On_BufEnter') +        let Tlist_Highlight_Tag_On_BufEnter = 1 +    endif + +    " Enable fold column to display the folding for the tag tree +    if !exists('Tlist_Enable_Fold_Column') +        let Tlist_Enable_Fold_Column = 1 +    endif + +    " Display the tags for only one file in the taglist window +    if !exists('Tlist_Show_One_File') +        let Tlist_Show_One_File = 0 +    endif + +    if !exists('Tlist_Max_Submenu_Items') +        let Tlist_Max_Submenu_Items = 20 +    endif + +    if !exists('Tlist_Max_Tag_Length') +        let Tlist_Max_Tag_Length = 10 +    endif + +    " Do not change the name of the taglist title variable. The winmanager +    " plugin relies on this name to determine the title for the taglist +    " plugin. +    let TagList_title = "__Tag_List__" + +    " Taglist debug messages +    let s:tlist_msg = '' + +    " Define the taglist autocommand to automatically open the taglist window +    " on Vim startup +    if g:Tlist_Auto_Open +        autocmd VimEnter * nested call s:Tlist_Window_Check_Auto_Open() +    endif + +    " Refresh the taglist +    if g:Tlist_Process_File_Always +        autocmd BufEnter * call s:Tlist_Refresh() +    endif + +    if g:Tlist_Show_Menu +        autocmd GUIEnter * call s:Tlist_Menu_Init() +    endif + +    " When the taglist buffer is created when loading a Vim session file, +    " the taglist buffer needs to be initialized. The BufFilePost event +    " is used to handle this case. +    autocmd BufFilePost __Tag_List__ call s:Tlist_Vim_Session_Load() + +    " Define the user commands to manage the taglist window +    command! -nargs=0 -bar TlistToggle call s:Tlist_Window_Toggle() +    command! -nargs=0 -bar TlistOpen call s:Tlist_Window_Open() +    " For backwards compatiblity define the Tlist command +    command! -nargs=0 -bar Tlist TlistToggle +    command! -nargs=+ -complete=file TlistAddFiles +                \  call s:Tlist_Add_Files(<f-args>) +    command! -nargs=+ -complete=dir TlistAddFilesRecursive +                \ call s:Tlist_Add_Files_Recursive(<f-args>) +    command! -nargs=0 -bar TlistClose call s:Tlist_Window_Close() +    command! -nargs=0 -bar TlistUpdate call s:Tlist_Update_Current_File() +    command! -nargs=0 -bar TlistHighlightTag call s:Tlist_Window_Highlight_Tag( +                        \ fnamemodify(bufname('%'), ':p'), line('.'), 2, 1) +    " For backwards compatiblity define the TlistSync command +    command! -nargs=0 -bar TlistSync TlistHighlightTag +    command! -nargs=* -complete=buffer TlistShowPrototype +                \ echo Tlist_Get_Tag_Prototype_By_Line(<f-args>) +    command! -nargs=* -complete=buffer TlistShowTag +                \ echo Tlist_Get_Tagname_By_Line(<f-args>) +    command! -nargs=* -complete=file TlistSessionLoad +                \ call s:Tlist_Session_Load(<q-args>) +    command! -nargs=* -complete=file TlistSessionSave +                \ call s:Tlist_Session_Save(<q-args>) +    command! -bar TlistLock let Tlist_Auto_Update=0 +    command! -bar TlistUnlock let Tlist_Auto_Update=1 + +    " Commands for enabling/disabling debug and to display debug messages +    command! -nargs=? -complete=file -bar TlistDebug +                \ call s:Tlist_Debug_Enable(<q-args>) +    command! -nargs=0 -bar TlistUndebug  call s:Tlist_Debug_Disable() +    command! -nargs=0 -bar TlistMessages call s:Tlist_Debug_Show() + +    " Define autocommands to autoload the taglist plugin when needed. + +    " Trick to get the current script ID +    map <SID>xx <SID>xx +    let s:tlist_sid = substitute(maparg('<SID>xx'), '<SNR>\(\d\+_\)xx$', +                                \ '\1', '') +    unmap <SID>xx + +    exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_* source ' . +                \ escape(expand('<sfile>'), ' ') +    exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Window_* source ' . +                \ escape(expand('<sfile>'), ' ') +    exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Menu_* source ' . +                \ escape(expand('<sfile>'), ' ') +    exe 'autocmd FuncUndefined Tlist_* source ' . +                \ escape(expand('<sfile>'), ' ') +    exe 'autocmd FuncUndefined TagList_* source ' . +                \ escape(expand('<sfile>'), ' ') + +    let loaded_taglist = 'fast_load_done' + +    if g:Tlist_Show_Menu && has('gui_running') +        call s:Tlist_Menu_Init() +    endif + +    " restore 'cpo' +    let &cpo = s:cpo_save +    finish +endif + +if !exists('s:tlist_sid') +    " Two or more versions of taglist plugin are installed. Don't +    " load this version of the plugin. +    finish +endif + +unlet! s:tlist_sid + +if loaded_taglist != 'fast_load_done' +    " restore 'cpo' +    let &cpo = s:cpo_save +    finish +endif + +" Taglist plugin functionality is available +let loaded_taglist = 'available' + +"------------------- end of user configurable options -------------------- + +" Default language specific settings for supported file types and tag types +" +" Variable name format: +" +"       s:tlist_def_{vim_ftype}_settings +"  +" vim_ftype - Filetype detected by Vim +" +" Value format: +" +"       <ctags_ftype>;<flag>:<name>;<flag>:<name>;... +" +" ctags_ftype - File type supported by exuberant ctags +" flag        - Flag supported by exuberant ctags to generate a tag type +" name        - Name of the tag type used in the taglist window to display the +"               tags of this type +" + +" assembly language +let s:tlist_def_asm_settings = 'asm;d:define;l:label;m:macro;t:type' + +" aspperl language +let s:tlist_def_aspperl_settings = 'asp;f:function;s:sub;v:variable' + +" aspvbs language +let s:tlist_def_aspvbs_settings = 'asp;f:function;s:sub;v:variable' + +" awk language +let s:tlist_def_awk_settings = 'awk;f:function' + +" beta language +let s:tlist_def_beta_settings = 'beta;f:fragment;s:slot;v:pattern' + +" c language +let s:tlist_def_c_settings = 'c;d:macro;g:enum;s:struct;u:union;t:typedef;' . +                           \ 'v:variable;f:function' + +" c++ language +let s:tlist_def_cpp_settings = 'c++;n:namespace;v:variable;d:macro;t:typedef;' . +                             \ 'c:class;g:enum;s:struct;u:union;f:function' + +" c# language +let s:tlist_def_cs_settings = 'c#;d:macro;t:typedef;n:namespace;c:class;' . +                             \ 'E:event;g:enum;s:struct;i:interface;' . +                             \ 'p:properties;m:method' + +" cobol language +let s:tlist_def_cobol_settings = 'cobol;d:data;f:file;g:group;p:paragraph;' . +                               \ 'P:program;s:section' + +" eiffel language +let s:tlist_def_eiffel_settings = 'eiffel;c:class;f:feature' + +" erlang language +let s:tlist_def_erlang_settings = 'erlang;d:macro;r:record;m:module;f:function' + +" expect (same as tcl) language +let s:tlist_def_expect_settings = 'tcl;c:class;f:method;p:procedure' + +" fortran language +let s:tlist_def_fortran_settings = 'fortran;p:program;b:block data;' . +                    \ 'c:common;e:entry;i:interface;k:type;l:label;m:module;' . +                    \ 'n:namelist;t:derived;v:variable;f:function;s:subroutine' + +" HTML language +let s:tlist_def_html_settings = 'html;a:anchor;f:javascript function' + +" java language +let s:tlist_def_java_settings = 'java;p:package;c:class;i:interface;' . +                              \ 'f:field;m:method' + +" javascript language +let s:tlist_def_javascript_settings = 'javascript;f:function' + +" lisp language +let s:tlist_def_lisp_settings = 'lisp;f:function' + +" lua language +let s:tlist_def_lua_settings = 'lua;f:function' + +" makefiles +let s:tlist_def_make_settings = 'make;m:macro' + +" pascal language +let s:tlist_def_pascal_settings = 'pascal;f:function;p:procedure' + +" perl language +let s:tlist_def_perl_settings = 'perl;c:constant;l:label;p:package;s:subroutine' + +" php language +let s:tlist_def_php_settings = 'php;c:class;d:constant;v:variable;f:function' + +" python language +let s:tlist_def_python_settings = 'python;c:class;m:member;f:function' + +" rexx language +let s:tlist_def_rexx_settings = 'rexx;s:subroutine' + +" ruby language +let s:tlist_def_ruby_settings = 'ruby;c:class;f:method;F:function;' . +                              \ 'm:singleton method' + +" scheme language +let s:tlist_def_scheme_settings = 'scheme;s:set;f:function' + +" shell language +let s:tlist_def_sh_settings = 'sh;f:function' + +" C shell language +let s:tlist_def_csh_settings = 'sh;f:function' + +" Z shell language +let s:tlist_def_zsh_settings = 'sh;f:function' + +" slang language +let s:tlist_def_slang_settings = 'slang;n:namespace;f:function' + +" sml language +let s:tlist_def_sml_settings = 'sml;e:exception;c:functor;s:signature;' . +                             \ 'r:structure;t:type;v:value;f:function' + +" sql language +let s:tlist_def_sql_settings = 'sql;c:cursor;F:field;P:package;r:record;' . +            \ 's:subtype;t:table;T:trigger;v:variable;f:function;p:procedure' + +" tcl language +let s:tlist_def_tcl_settings = 'tcl;c:class;f:method;m:method;p:procedure' + +" vera language +let s:tlist_def_vera_settings = 'vera;c:class;d:macro;e:enumerator;' . +                                \ 'f:function;g:enum;m:member;p:program;' . +                                \ 'P:prototype;t:task;T:typedef;v:variable;' . +                                \ 'x:externvar' + +"verilog language +let s:tlist_def_verilog_settings = 'verilog;m:module;c:constant;P:parameter;' . +            \ 'e:event;r:register;t:task;w:write;p:port;v:variable;f:function' + +" vim language +let s:tlist_def_vim_settings = 'vim;a:autocmds;v:variable;f:function' + +" yacc language +let s:tlist_def_yacc_settings = 'yacc;l:label' + +"------------------- end of language specific options -------------------- + +" Vim window size is changed by the taglist plugin or not +let s:tlist_winsize_chgd = -1 +" Taglist window is maximized or not +let s:tlist_win_maximized = 0 +" Name of files in the taglist +let s:tlist_file_names='' +" Number of files in the taglist +let s:tlist_file_count = 0 +" Number of filetypes supported by taglist +let s:tlist_ftype_count = 0 +" Is taglist part of other plugins like winmanager or cream? +let s:tlist_app_name = "none" +" Are we displaying brief help text +let s:tlist_brief_help = 1 +" List of files removed on user request +let s:tlist_removed_flist = "" +" Index of current file displayed in the taglist window +let s:tlist_cur_file_idx = -1 +" Taglist menu is empty or not +let s:tlist_menu_empty = 1 + +" An autocommand is used to refresh the taglist window when entering any +" buffer. We don't want to refresh the taglist window if we are entering the +" file window from one of the taglist functions. The 'Tlist_Skip_Refresh' +" variable is used to skip the refresh of the taglist window and is set +" and cleared appropriately. +let s:Tlist_Skip_Refresh = 0 + +" Tlist_Window_Display_Help() +function! s:Tlist_Window_Display_Help() +    if s:tlist_app_name == "winmanager" +        " To handle a bug in the winmanager plugin, add a space at the +        " last line +        call setline('$', ' ') +    endif + +    if s:tlist_brief_help +        " Add the brief help +        call append(0, '" Press <F1> to display help text') +    else +        " Add the extensive help +        call append(0, '" <enter> : Jump to tag definition') +        call append(1, '" o : Jump to tag definition in new window') +        call append(2, '" p : Preview the tag definition') +        call append(3, '" <space> : Display tag prototype') +        call append(4, '" u : Update tag list') +        call append(5, '" s : Select sort field') +        call append(6, '" d : Remove file from taglist') +        call append(7, '" x : Zoom-out/Zoom-in taglist window') +        call append(8, '" + : Open a fold') +        call append(9, '" - : Close a fold') +        call append(10, '" * : Open all folds') +        call append(11, '" = : Close all folds') +        call append(12, '" [[ : Move to the start of previous file') +        call append(13, '" ]] : Move to the start of next file') +        call append(14, '" q : Close the taglist window') +        call append(15, '" <F1> : Remove help text') +    endif +endfunction + +" Tlist_Window_Toggle_Help_Text() +" Toggle taglist plugin help text between the full version and the brief +" version +function! s:Tlist_Window_Toggle_Help_Text() +    if g:Tlist_Compact_Format +        " In compact display mode, do not display help +        return +    endif + +    " Include the empty line displayed after the help text +    let brief_help_size = 1 +    let full_help_size = 16 + +    setlocal modifiable + +    " Set report option to a huge value to prevent informational messages +    " while deleting the lines +    let old_report = &report +    set report=99999 + +    " Remove the currently highlighted tag. Otherwise, the help text +    " might be highlighted by mistake +    match none + +    " Toggle between brief and full help text +    if s:tlist_brief_help +        let s:tlist_brief_help = 0 + +        " Remove the previous help +        exe '1,' . brief_help_size . ' delete _' + +        " Adjust the start/end line numbers for the files +        call s:Tlist_Window_Update_Line_Offsets(0, 1, full_help_size - brief_help_size) +    else +        let s:tlist_brief_help = 1 + +        " Remove the previous help +        exe '1,' . full_help_size . ' delete _' + +        " Adjust the start/end line numbers for the files +        call s:Tlist_Window_Update_Line_Offsets(0, 0, full_help_size - brief_help_size) +    endif + +    call s:Tlist_Window_Display_Help() + +    " Restore the report option +    let &report = old_report + +    setlocal nomodifiable +endfunction + +" Taglist debug support +let s:tlist_debug = 0 + +" File for storing the debug messages +let s:tlist_debug_file = '' + +" Tlist_Debug_Enable +" Enable logging of taglist debug messages. +function! s:Tlist_Debug_Enable(...) +    let s:tlist_debug = 1 + +    " Check whether a valid file name is supplied. +    if a:1 != '' +        let s:tlist_debug_file = fnamemodify(a:1, ':p') + +        " Empty the log file +        exe 'redir! > ' . s:tlist_debug_file +        redir END + +        " Check whether the log file is present/created +        if !filewritable(s:tlist_debug_file) +            call s:Tlist_Warning_Msg('Taglist: Unable to create log file ' +                        \ . s:tlist_debug_file) +            let s:tlist_debug_file = '' +        endif +    endif +endfunction + +" Tlist_Debug_Disable +" Disable logging of taglist debug messages. +function! s:Tlist_Debug_Disable(...) +    let s:tlist_debug = 0 +    let s:tlist_debug_file = '' +endfunction + +" Tlist_Debug_Show +" Display the taglist debug messages in a new window +function! s:Tlist_Debug_Show() +    if s:tlist_msg == '' +        call s:Tlist_Warning_Msg('Taglist: No debug messages') +        return +    endif + +    " Open a new window to display the taglist debug messages +    new taglist_debug.txt +    " Delete all the lines (if the buffer already exists) +    silent! %delete _ +    " Add the messages +    silent! put =s:tlist_msg +    " Move the cursor to the first line +    normal! gg +endfunction + +" Tlist_Log_Msg +" Log the supplied debug message along with the time +function! s:Tlist_Log_Msg(msg) +    if s:tlist_debug +        if s:tlist_debug_file != '' +            exe 'redir >> ' . s:tlist_debug_file +            silent echon strftime('%H:%M:%S') . ': ' . a:msg . "\n" +            redir END +        else +            " Log the message into a variable +            " Retain only the last 3000 characters +            let len = strlen(s:tlist_msg) +            if len > 3000 +                let s:tlist_msg = strpart(s:tlist_msg, len - 3000) +            endif +            let s:tlist_msg = s:tlist_msg . strftime('%H:%M:%S') . ': ' .  +                        \ a:msg . "\n" +        endif +    endif +endfunction + +" Tlist_Warning_Msg() +" Display a message using WarningMsg highlight group +function! s:Tlist_Warning_Msg(msg) +    echohl WarningMsg +    echomsg a:msg +    echohl None +endfunction + +" Last returned file index for file name lookup. +" Used to speed up file lookup +let s:tlist_file_name_idx_cache = -1 + +" Tlist_Get_File_Index() +" Return the index of the specified filename +function! s:Tlist_Get_File_Index(fname) +    if s:tlist_file_count == 0 || a:fname == '' +        return -1 +    endif + +    " If the new filename is same as the last accessed filename, then +    " return that index +    if s:tlist_file_name_idx_cache != -1 && +                \ s:tlist_file_name_idx_cache < s:tlist_file_count +        if s:tlist_{s:tlist_file_name_idx_cache}_filename == a:fname +            " Same as the last accessed file +            return s:tlist_file_name_idx_cache +        endif +    endif + +    " First, check whether the filename is present +    let s_fname = a:fname . "\n" +    let i = stridx(s:tlist_file_names, s_fname) +    if i == -1 +        let s:tlist_file_name_idx_cache = -1 +        return -1 +    endif + +    " Second, compute the file name index +    let nl_txt = substitute(strpart(s:tlist_file_names, 0, i), "[^\n]", '', 'g') +    let s:tlist_file_name_idx_cache = strlen(nl_txt) +    return s:tlist_file_name_idx_cache +endfunction + +" Last returned file index for line number lookup. +" Used to speed up file lookup +let s:tlist_file_lnum_idx_cache = -1 + +" Tlist_Window_Get_File_Index_By_Linenum() +" Return the index of the filename present in the specified line number +" Line number refers to the line number in the taglist window +function! s:Tlist_Window_Get_File_Index_By_Linenum(lnum) +    call s:Tlist_Log_Msg('Tlist_Window_Get_File_Index_By_Linenum (' . a:lnum . ')') + +    " First try to see whether the new line number is within the range +    " of the last returned file +    if s:tlist_file_lnum_idx_cache != -1 && +                \ s:tlist_file_lnum_idx_cache < s:tlist_file_count +        if a:lnum >= s:tlist_{s:tlist_file_lnum_idx_cache}_start && +                    \ a:lnum <= s:tlist_{s:tlist_file_lnum_idx_cache}_end +            return s:tlist_file_lnum_idx_cache +        endif +    endif + +    let fidx = -1 + +    if g:Tlist_Show_One_File +        " Displaying only one file in the taglist window. Check whether +        " the line is within the tags displayed for that file +        if s:tlist_cur_file_idx != -1 +            if a:lnum >= s:tlist_{s:tlist_cur_file_idx}_start +                        \ && a:lnum <= s:tlist_{s:tlist_cur_file_idx}_end +                let fidx = s:tlist_cur_file_idx +            endif + +        endif +    else +        " Do a binary search in the taglist +        let left = 0 +        let right = s:tlist_file_count - 1 + +        while left < right +            let mid = (left + right) / 2 + +            if a:lnum >= s:tlist_{mid}_start && a:lnum <= s:tlist_{mid}_end +                let s:tlist_file_lnum_idx_cache = mid +                return mid +            endif + +            if a:lnum < s:tlist_{mid}_start +                let right = mid - 1 +            else +                let left = mid + 1 +            endif +        endwhile + +        if left >= 0 && left < s:tlist_file_count +                    \ && a:lnum >= s:tlist_{left}_start +                    \ && a:lnum <= s:tlist_{left}_end +            let fidx = left +        endif +    endif + +    let s:tlist_file_lnum_idx_cache = fidx + +    return fidx +endfunction + +" Tlist_Exe_Cmd_No_Acmds +" Execute the specified Ex command after disabling autocommands +function! s:Tlist_Exe_Cmd_No_Acmds(cmd) +    let old_eventignore = &eventignore +    set eventignore=all +    exe a:cmd +    let &eventignore = old_eventignore +endfunction + +" Tlist_Skip_File() +" Check whether tag listing is supported for the specified file +function! s:Tlist_Skip_File(filename, ftype) +    " Skip buffers with no names and buffers with filetype not set +    if a:filename == '' || a:ftype == '' +        return 1 +    endif + +    " Skip files which are not supported by exuberant ctags +    " First check whether default settings for this filetype are available. +    " If it is not available, then check whether user specified settings are +    " available. If both are not available, then don't list the tags for this +    " filetype +    let var = 's:tlist_def_' . a:ftype . '_settings' +    if !exists(var) +        let var = 'g:tlist_' . a:ftype . '_settings' +        if !exists(var) +            return 1 +        endif +    endif + +    " Skip files which are not readable or files which are not yet stored +    " to the disk +    if !filereadable(a:filename) +        return 1 +    endif + +    return 0 +endfunction + +" Tlist_User_Removed_File +" Returns 1 if a file is removed by a user from the taglist +function! s:Tlist_User_Removed_File(filename) +    return stridx(s:tlist_removed_flist, a:filename . "\n") != -1 +endfunction + +" Tlist_Update_Remove_List +" Update the list of user removed files from the taglist +" add == 1, add the file to the removed list +" add == 0, delete the file from the removed list +function! s:Tlist_Update_Remove_List(filename, add) +    if a:add +        let s:tlist_removed_flist = s:tlist_removed_flist . a:filename . "\n" +    else +        let idx = stridx(s:tlist_removed_flist, a:filename . "\n") +        let text_before = strpart(s:tlist_removed_flist, 0, idx) +        let rem_text = strpart(s:tlist_removed_flist, idx) +        let next_idx = stridx(rem_text, "\n") +        let text_after = strpart(rem_text, next_idx + 1) + +        let s:tlist_removed_flist = text_before . text_after +    endif +endfunction + +" Tlist_FileType_Init +" Initialize the ctags arguments and tag variable for the specified +" file type +function! s:Tlist_FileType_Init(ftype) +    call s:Tlist_Log_Msg('Tlist_FileType_Init (' . a:ftype . ')') +    " If the user didn't specify any settings, then use the default +    " ctags args. Otherwise, use the settings specified by the user +    let var = 'g:tlist_' . a:ftype . '_settings' +    if exists(var) +        " User specified ctags arguments +        let settings = {var} . ';' +    else +        " Default ctags arguments +        let var = 's:tlist_def_' . a:ftype . '_settings' +        if !exists(var) +            " No default settings for this file type. This filetype is +            " not supported +            return 0 +        endif +        let settings = s:tlist_def_{a:ftype}_settings . ';' +    endif + +    let msg = 'Taglist: Invalid ctags option setting - ' . settings + +    " Format of the option that specifies the filetype and ctags arugments: +    " +    "       <language_name>;flag1:name1;flag2:name2;flag3:name3 +    " + +    " Extract the file type to pass to ctags. This may be different from the +    " file type detected by Vim +    let pos = stridx(settings, ';') +    if pos == -1 +        call s:Tlist_Warning_Msg(msg) +        return 0 +    endif +    let ctags_ftype = strpart(settings, 0, pos) +    if ctags_ftype == '' +        call s:Tlist_Warning_Msg(msg) +        return 0 +    endif +    " Make sure a valid filetype is supplied. If the user didn't specify a +    " valid filetype, then the ctags option settings may be treated as the +    " filetype +    if ctags_ftype =~ ':' +        call s:Tlist_Warning_Msg(msg) +        return 0 +    endif + +    " Remove the file type from settings +    let settings = strpart(settings, pos + 1) +    if settings == '' +        call s:Tlist_Warning_Msg(msg) +        return 0 +    endif + +    " Process all the specified ctags flags. The format is +    " flag1:name1;flag2:name2;flag3:name3 +    let ctags_flags = '' +    let cnt = 0 +    while settings != '' +        " Extract the flag +        let pos = stridx(settings, ':') +        if pos == -1 +            call s:Tlist_Warning_Msg(msg) +            return 0 +        endif +        let flag = strpart(settings, 0, pos) +        if flag == '' +            call s:Tlist_Warning_Msg(msg) +            return 0 +        endif +        " Remove the flag from settings +        let settings = strpart(settings, pos + 1) + +        " Extract the tag type name +        let pos = stridx(settings, ';') +        if pos == -1 +            call s:Tlist_Warning_Msg(msg) +            return 0 +        endif +        let name = strpart(settings, 0, pos) +        if name == '' +            call s:Tlist_Warning_Msg(msg) +            return 0 +        endif +        let settings = strpart(settings, pos + 1) + +        let cnt = cnt + 1 + +        let s:tlist_{a:ftype}_{cnt}_name = flag +        let s:tlist_{a:ftype}_{cnt}_fullname = name +        let ctags_flags = ctags_flags . flag +    endwhile + +    let s:tlist_{a:ftype}_ctags_args = '--language-force=' . ctags_ftype . +                            \ ' --' . ctags_ftype . '-types=' . ctags_flags +    let s:tlist_{a:ftype}_count = cnt +    let s:tlist_{a:ftype}_ctags_flags = ctags_flags + +    " Save the filetype name +    let s:tlist_ftype_{s:tlist_ftype_count}_name = a:ftype +    let s:tlist_ftype_count = s:tlist_ftype_count + 1 + +    return 1 +endfunction + +" Tlist_Detect_Filetype +" Determine the filetype for the specified file using the filetypedetect +" autocmd. +function! s:Tlist_Detect_Filetype(fname) +    " Ignore the filetype autocommands +    let old_eventignore = &eventignore +    set eventignore=FileType + +    " Save the 'filetype', as this will be changed temporarily +    let old_filetype = &filetype + +    " Run the filetypedetect group of autocommands to determine +    " the filetype +    exe 'doautocmd filetypedetect BufRead ' . a:fname + +    " Save the detected filetype +    let ftype = &filetype + +    " Restore the previous state +    let &filetype = old_filetype +    let &eventignore = old_eventignore + +    return ftype +endfunction + +" Tlist_Get_Buffer_Filetype +" Get the filetype for the specified buffer +function! s:Tlist_Get_Buffer_Filetype(bnum) +    let buf_ft = getbufvar(a:bnum, '&filetype') + +    if bufloaded(a:bnum) +        " For loaded buffers, the 'filetype' is already determined +        return buf_ft +    endif + +    " For unloaded buffers, if the 'filetype' option is set, return it +    if buf_ft != '' +        return buf_ft +    endif + +    " Skip non-existent buffers +    if !bufexists(a:bnum) +        return '' +    endif + +    " For buffers whose filetype is not yet determined, try to determine +    " the filetype +    let bname = bufname(a:bnum) + +    return s:Tlist_Detect_Filetype(bname) +endfunction + +" Tlist_Discard_TagInfo +" Discard the stored tag information for a file +function! s:Tlist_Discard_TagInfo(fidx) +    call s:Tlist_Log_Msg('Tlist_Discard_TagInfo (' . +                \ s:tlist_{a:fidx}_filename . ')') +    let ftype = s:tlist_{a:fidx}_filetype + +    " Discard information about the tags defined in the file +    let i = 1 +    while i <= s:tlist_{a:fidx}_tag_count +        let fidx_i = 's:tlist_' . a:fidx . '_' . i +        unlet! {fidx_i}_tag +        unlet! {fidx_i}_tag_name +        unlet! {fidx_i}_tag_type +        unlet! {fidx_i}_ttype_idx +        unlet! {fidx_i}_tag_proto +        unlet! {fidx_i}_tag_searchpat +        unlet! {fidx_i}_tag_linenum +        let i = i + 1 +    endwhile + +    let s:tlist_{a:fidx}_tag_count = 0 + +    " Discard information about tag type groups +    let i = 1 +    while i <= s:tlist_{ftype}_count +        let ttype = s:tlist_{ftype}_{i}_name +        if s:tlist_{a:fidx}_{ttype} != '' +            let fidx_ttype = 's:tlist_' . a:fidx . '_' . ttype +            let {fidx_ttype} = '' +            let {fidx_ttype}_offset = 0 +            let cnt = {fidx_ttype}_count +            let {fidx_ttype}_count = 0 +            let j = 1 +            while j <= cnt +                unlet! {fidx_ttype}_{j} +                let j = j + 1 +            endwhile +        endif +        let i = i + 1 +    endwhile + +    " Discard the stored menu command also +    let s:tlist_{a:fidx}_menu_cmd = '' +endfunction + +" Tlist_Window_Update_Line_Offsets +" Update the line offsets for tags for files starting from start_idx +" and displayed in the taglist window by the specified offset +function! s:Tlist_Window_Update_Line_Offsets(start_idx, increment, offset) +    let i = a:start_idx + +    while i < s:tlist_file_count +        if s:tlist_{i}_visible +            " Update the start/end line number only if the file is visible +            if a:increment +                let s:tlist_{i}_start = s:tlist_{i}_start + a:offset +                let s:tlist_{i}_end = s:tlist_{i}_end + a:offset +            else +                let s:tlist_{i}_start = s:tlist_{i}_start - a:offset +                let s:tlist_{i}_end = s:tlist_{i}_end - a:offset +            endif +        endif +        let i = i + 1 +    endwhile +endfunction + +" Tlist_Discard_FileInfo +" Discard the stored information for a file +function! s:Tlist_Discard_FileInfo(fidx) +    call s:Tlist_Log_Msg('Tlist_Discard_FileInfo (' . +                \ s:tlist_{a:fidx}_filename . ')') +    call s:Tlist_Discard_TagInfo(a:fidx) + +    let ftype = s:tlist_{a:fidx}_filetype + +    let i = 1 +    while i <= s:tlist_{ftype}_count +        let ttype = s:tlist_{ftype}_{i}_name +        unlet! s:tlist_{a:fidx}_{ttype} +        unlet! s:tlist_{a:fidx}_{ttype}_offset +        unlet! s:tlist_{a:fidx}_{ttype}_count +        let i = i + 1 +    endwhile + +    unlet! s:tlist_{a:fidx}_filename +    unlet! s:tlist_{a:fidx}_sort_type +    unlet! s:tlist_{a:fidx}_filetype +    unlet! s:tlist_{a:fidx}_mtime +    unlet! s:tlist_{a:fidx}_start +    unlet! s:tlist_{a:fidx}_end +    unlet! s:tlist_{a:fidx}_valid +    unlet! s:tlist_{a:fidx}_visible +    unlet! s:tlist_{a:fidx}_tag_count +    unlet! s:tlist_{a:fidx}_menu_cmd +endfunction + +" Tlist_Window_Remove_File_From_Display +" Remove the specified file from display +function! s:Tlist_Window_Remove_File_From_Display(fidx) +    call s:Tlist_Log_Msg('Tlist_Window_Remove_File_From_Display (' . +                \ s:tlist_{a:fidx}_filename . ')') +    " If the file is not visible then no need to remove it +    if !s:tlist_{a:fidx}_visible +        return +    endif + +    " Remove the tags displayed for the specified file from the window +    let start = s:tlist_{a:fidx}_start +    " Include the empty line after the last line also +    if g:Tlist_Compact_Format +        let end = s:tlist_{a:fidx}_end +    else +        let end = s:tlist_{a:fidx}_end + 1 +    endif + +    setlocal modifiable +    exe 'silent! ' . start . ',' . end . 'delete _' +    setlocal nomodifiable + +    " Correct the start and end line offsets for all the files following +    " this file, as the tags for this file are removed +    call s:Tlist_Window_Update_Line_Offsets(a:fidx + 1, 0, end - start + 1) +endfunction + +" Tlist_Remove_File +" Remove the file under the cursor or the specified file index +" user_request - User requested to remove the file from taglist +function! s:Tlist_Remove_File(file_idx, user_request) +    let fidx = a:file_idx + +    if fidx == -1 +        let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.')) +        if fidx == -1 +            return +        endif +    endif +    call s:Tlist_Log_Msg('Tlist_Remove_File (' . +                \ s:tlist_{fidx}_filename . ', ' . a:user_request . ')') + +    let save_winnr = winnr() +    let winnum = bufwinnr(g:TagList_title) +    if winnum != -1 +        " Taglist window is open, remove the file from display + +        if save_winnr != winnum +            let old_eventignore = &eventignore +            set eventignore=all +            exe winnum . 'wincmd w' +        endif + +        call s:Tlist_Window_Remove_File_From_Display(fidx) + +        if save_winnr != winnum +            exe save_winnr . 'wincmd w' +            let &eventignore = old_eventignore +        endif +    endif + +    let fname = s:tlist_{fidx}_filename + +    if a:user_request +        " As the user requested to remove the file from taglist, +        " add it to the removed list +        call s:Tlist_Update_Remove_List(fname, 1) +    endif + +    " Remove the file name from the taglist list of filenames +    let idx = stridx(s:tlist_file_names, fname . "\n") +    let text_before = strpart(s:tlist_file_names, 0, idx) +    let rem_text = strpart(s:tlist_file_names, idx) +    let next_idx = stridx(rem_text, "\n") +    let text_after = strpart(rem_text, next_idx + 1) +    let s:tlist_file_names = text_before . text_after + +    call s:Tlist_Discard_FileInfo(fidx) + +    " Shift all the file variables by one index +    let i = fidx + 1 + +    while i < s:tlist_file_count +        let j = i - 1 + +        let s:tlist_{j}_filename = s:tlist_{i}_filename +        let s:tlist_{j}_sort_type = s:tlist_{i}_sort_type +        let s:tlist_{j}_filetype = s:tlist_{i}_filetype +        let s:tlist_{j}_mtime = s:tlist_{i}_mtime +        let s:tlist_{j}_start = s:tlist_{i}_start +        let s:tlist_{j}_end = s:tlist_{i}_end +        let s:tlist_{j}_valid = s:tlist_{i}_valid +        let s:tlist_{j}_visible = s:tlist_{i}_visible +        let s:tlist_{j}_tag_count = s:tlist_{i}_tag_count +        let s:tlist_{j}_menu_cmd = s:tlist_{i}_menu_cmd + +        let k = 1 +        while k <= s:tlist_{j}_tag_count +            let s:tlist_{j}_{k}_tag = s:tlist_{i}_{k}_tag +            let s:tlist_{j}_{k}_tag_name = s:tlist_{i}_{k}_tag_name +            let s:tlist_{j}_{k}_tag_type = s:Tlist_Get_Tag_Type_By_Tag(i, k) +            let s:tlist_{j}_{k}_ttype_idx = s:tlist_{i}_{k}_ttype_idx +            let s:tlist_{j}_{k}_tag_proto = s:Tlist_Get_Tag_Prototype(i, k) +            let s:tlist_{j}_{k}_tag_searchpat = s:Tlist_Get_Tag_SearchPat(i, k) +            let s:tlist_{j}_{k}_tag_linenum = s:Tlist_Get_Tag_Linenum(i, k) +            let k = k + 1 +        endwhile + +        let ftype = s:tlist_{i}_filetype + +        let k = 1 +        while k <= s:tlist_{ftype}_count +            let ttype = s:tlist_{ftype}_{k}_name +            let s:tlist_{j}_{ttype} = s:tlist_{i}_{ttype} +            let s:tlist_{j}_{ttype}_offset = s:tlist_{i}_{ttype}_offset +            let s:tlist_{j}_{ttype}_count = s:tlist_{i}_{ttype}_count +            if s:tlist_{j}_{ttype} != '' +                let l = 1 +                while l <= s:tlist_{j}_{ttype}_count +                    let s:tlist_{j}_{ttype}_{l} = s:tlist_{i}_{ttype}_{l} +                    let l = l + 1 +                endwhile +            endif +            let k = k + 1 +        endwhile + +        " As the file and tag information is copied to the new index, +        " discard the previous information +        call s:Tlist_Discard_FileInfo(i) + +        let i = i + 1 +    endwhile + +    " Reduce the number of files displayed +    let s:tlist_file_count = s:tlist_file_count - 1 + +    if g:Tlist_Show_One_File +        " If the tags for only one file is displayed and if we just +        " now removed that file, then invalidate the current file idx +        if s:tlist_cur_file_idx == fidx +            let s:tlist_cur_file_idx = -1 +        endif +    endif +endfunction + +" Tlist_Window_Goto_Window +" Goto the taglist window +function! s:Tlist_Window_Goto_Window() +    let winnum = bufwinnr(g:TagList_title) +    if winnum != -1 +        if winnr() != winnum +            call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w') +        endif +    endif +endfunction + +" Tlist_Window_Create +" Create a new taglist window. If it is already open, jump to it +function! s:Tlist_Window_Create() +    call s:Tlist_Log_Msg('Tlist_Window_Create()') +    " If the window is open, jump to it +    let winnum = bufwinnr(g:TagList_title) +    if winnum != -1 +        " Jump to the existing window +        if winnr() != winnum +            exe winnum . 'wincmd w' +        endif +        return +    endif + +    " If used with winmanager don't open windows. Winmanager will handle +    " the window/buffer management +    if s:tlist_app_name == "winmanager" +        return +    endif + +    " Create a new window. If user prefers a horizontal window, then open +    " a horizontally split window. Otherwise open a vertically split +    " window +    if g:Tlist_Use_Horiz_Window +        " Open a horizontally split window +        let win_dir = 'botright' +        " Horizontal window height +        let win_size = g:Tlist_WinHeight +    else +        if s:tlist_winsize_chgd == -1 +            " Open a vertically split window. Increase the window size, if +            " needed, to accomodate the new window +            if g:Tlist_Inc_Winwidth && +                        \ &columns < (80 + g:Tlist_WinWidth) +                " Save the original window position +                let s:tlist_pre_winx = getwinposx() +                let s:tlist_pre_winy = getwinposy() + +                " one extra column is needed to include the vertical split +                let &columns= &columns + g:Tlist_WinWidth + 1 + +                let s:tlist_winsize_chgd = 1 +            else +                let s:tlist_winsize_chgd = 0 +            endif +        endif + +        if g:Tlist_Use_Right_Window +            " Open the window at the rightmost place +            let win_dir = 'botright vertical' +        else +            " Open the window at the leftmost place +            let win_dir = 'topleft vertical' +        endif +        let win_size = g:Tlist_WinWidth +    endif + +    " If the tag listing temporary buffer already exists, then reuse it. +    " Otherwise create a new buffer +    let bufnum = bufnr(g:TagList_title) +    if bufnum == -1 +        " Create a new buffer +        let wcmd = g:TagList_title +    else +        " Edit the existing buffer +        let wcmd = '+buffer' . bufnum +    endif + +    " Create the taglist window +    exe 'silent! ' . win_dir . ' ' . win_size . 'split ' . wcmd + +    " Save the new window position +    let s:tlist_winx = getwinposx() +    let s:tlist_winy = getwinposy() + +    " Initialize the taglist window +    call s:Tlist_Window_Init() +endfunction + +" Tlist_Window_Zoom +" Zoom (maximize/minimize) the taglist window +function! s:Tlist_Window_Zoom() +    if s:tlist_win_maximized +        " Restore the window back to the previous size +        if g:Tlist_Use_Horiz_Window +            exe 'resize ' . g:Tlist_WinHeight +        else +            exe 'vert resize ' . g:Tlist_WinWidth +        endif +        let s:tlist_win_maximized = 0 +    else +        " Set the window size to the maximum possible without closing other +        " windows +        if g:Tlist_Use_Horiz_Window +            resize +        else +            vert resize +        endif +        let s:tlist_win_maximized = 1 +    endif +endfunction + +" Tlist_Ballon_Expr +" When the mouse cursor is over a tag in the taglist window, display the +" tag prototype (balloon) +function! Tlist_Ballon_Expr() +    " Get the file index +    let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(v:beval_lnum) +    if fidx == -1 +        return '' +    endif + +    " Get the tag output line for the current tag +    let tidx = s:Tlist_Window_Get_Tag_Index(fidx, v:beval_lnum) +    if tidx == 0 +        return '' +    endif + +    " Get the tag search pattern and display it +    return s:Tlist_Get_Tag_Prototype(fidx, tidx) +endfunction + +" Tlist_Window_Check_Width +" Check the width of the taglist window. For horizontally split windows, the +" 'winfixheight' option is used to fix the height of the window. For +" vertically split windows, Vim doesn't support the 'winfixwidth' option. So +" need to handle window width changes from this function. +function! s:Tlist_Window_Check_Width() +    let tlist_winnr = bufwinnr(g:TagList_title) +    if tlist_winnr == -1 +        return +    endif + +    let width = winwidth(tlist_winnr) +    if width != g:Tlist_WinWidth +        call s:Tlist_Log_Msg("Tlist_Window_Check_Width: Changing window " . +                    \ "width from " . width . " to " . g:Tlist_WinWidth) +        let save_winnr = winnr() +        if save_winnr != tlist_winnr +            call s:Tlist_Exe_Cmd_No_Acmds(tlist_winnr . 'wincmd w') +        endif +        exe 'vert resize ' . g:Tlist_WinWidth +        if save_winnr != tlist_winnr +            call s:Tlist_Exe_Cmd_No_Acmds('wincmd p') +        endif +    endif +endfunction + +" Tlist_Window_Exit_Only_Window +" If the 'Tlist_Exit_OnlyWindow' option is set, then exit Vim if only the +" taglist window is present. +function! s:Tlist_Window_Exit_Only_Window() +    " Before quitting Vim, delete the taglist buffer so that +    " the '0 mark is correctly set to the previous buffer. +    if v:version < 700 +	if winbufnr(2) == -1 +	    bdelete +	    quit +	endif +    else +	if winbufnr(2) == -1 +	    if tabpagenr('$') == 1 +		" Only one tag page is present +		bdelete +		quit +	    else +		" More than one tab page is present. Close only the current +		" tab page +		close +	    endif +	endif +    endif +endfunction + +" Tlist_Window_Init +" Set the default options for the taglist window +function! s:Tlist_Window_Init() +    call s:Tlist_Log_Msg('Tlist_Window_Init()') + +    " The 'readonly' option should not be set for the taglist buffer. +    " If Vim is started as "view/gview" or if the ":view" command is +    " used, then the 'readonly' option is set for all the buffers. +    " Unset it for the taglist buffer +    setlocal noreadonly + +    " Set the taglist buffer filetype to taglist +    setlocal filetype=taglist + +    " Define taglist window element highlighting +    syntax match TagListComment '^" .*' +    syntax match TagListFileName '^[^" ].*$' +    syntax match TagListTitle '^  \S.*$' +    syntax match TagListTagScope  '\s\[.\{-\}\]$' + +    " Define the highlighting only if colors are supported +    if has('gui_running') || &t_Co > 2 +        " Colors to highlight various taglist window elements +        " If user defined highlighting group exists, then use them. +        " Otherwise, use default highlight groups. +        if hlexists('MyTagListTagName') +            highlight link TagListTagName MyTagListTagName +        else +            highlight default link TagListTagName Search +        endif +        " Colors to highlight comments and titles +        if hlexists('MyTagListComment') +            highlight link TagListComment MyTagListComment +        else +            highlight clear TagListComment +            highlight default link TagListComment Comment +        endif +        if hlexists('MyTagListTitle') +            highlight link TagListTitle MyTagListTitle +        else +            highlight clear TagListTitle +            highlight default link TagListTitle Title +        endif +        if hlexists('MyTagListFileName') +            highlight link TagListFileName MyTagListFileName +        else +            highlight clear TagListFileName +            highlight default TagListFileName guibg=Grey ctermbg=darkgray +                        \ guifg=white ctermfg=white +        endif +        if hlexists('MyTagListTagScope') +            highlight link TagListTagScope MyTagListTagScope +        else +            highlight clear TagListTagScope +            highlight default link TagListTagScope Identifier +        endif +    else +        highlight default TagListTagName term=reverse cterm=reverse +    endif + +    " Folding related settings +    setlocal foldenable +    setlocal foldminlines=0 +    setlocal foldmethod=manual +    setlocal foldlevel=9999 +    if g:Tlist_Enable_Fold_Column +        setlocal foldcolumn=3 +    else +        setlocal foldcolumn=0 +    endif +    setlocal foldtext=v:folddashes.getline(v:foldstart) + +    if s:tlist_app_name != "winmanager" +        " Mark buffer as scratch +        silent! setlocal buftype=nofile +        if s:tlist_app_name == "none" +            silent! setlocal bufhidden=delete +        endif +        silent! setlocal noswapfile +        " Due to a bug in Vim 6.0, the winbufnr() function fails for unlisted +        " buffers. So if the taglist buffer is unlisted, multiple taglist +        " windows will be opened. This bug is fixed in Vim 6.1 and above +        if v:version >= 601 +            silent! setlocal nobuflisted +        endif +    endif + +    silent! setlocal nowrap + +    " If the 'number' option is set in the source window, it will affect the +    " taglist window. So forcefully disable 'number' option for the taglist +    " window +    silent! setlocal nonumber + +    " Use fixed height when horizontally split window is used +    if g:Tlist_Use_Horiz_Window +        if v:version >= 602 +            set winfixheight +        endif +    endif +    if !g:Tlist_Use_Horiz_Window && v:version >= 700 +        set winfixwidth +    endif + +    " Setup balloon evaluation to display tag prototype +    if v:version >= 700 && has('balloon_eval') +        setlocal balloonexpr=Tlist_Ballon_Expr() +        set ballooneval +    endif + +    " Setup the cpoptions properly for the maps to work +    let old_cpoptions = &cpoptions +    set cpoptions&vim + +    " Create buffer local mappings for jumping to the tags and sorting the list +    nnoremap <buffer> <silent> <CR> +                \ :call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR> +    nnoremap <buffer> <silent> o +                \ :call <SID>Tlist_Window_Jump_To_Tag('newwin')<CR> +    nnoremap <buffer> <silent> p +                \ :call <SID>Tlist_Window_Jump_To_Tag('preview')<CR> +    nnoremap <buffer> <silent> P +                \ :call <SID>Tlist_Window_Jump_To_Tag('prevwin')<CR> +    if v:version >= 700 +    nnoremap <buffer> <silent> t +                \ :call <SID>Tlist_Window_Jump_To_Tag('checktab')<CR> +    nnoremap <buffer> <silent> <C-t> +                \ :call <SID>Tlist_Window_Jump_To_Tag('newtab')<CR> +    endif +    nnoremap <buffer> <silent> <2-LeftMouse> +                \ :call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR> +    nnoremap <buffer> <silent> s +                \ :call <SID>Tlist_Change_Sort('cmd', 'toggle', '')<CR> +    nnoremap <buffer> <silent> + :silent! foldopen<CR> +    nnoremap <buffer> <silent> - :silent! foldclose<CR> +    nnoremap <buffer> <silent> * :silent! %foldopen!<CR> +    nnoremap <buffer> <silent> = :silent! %foldclose<CR> +    nnoremap <buffer> <silent> <kPlus> :silent! foldopen<CR> +    nnoremap <buffer> <silent> <kMinus> :silent! foldclose<CR> +    nnoremap <buffer> <silent> <kMultiply> :silent! %foldopen!<CR> +    nnoremap <buffer> <silent> <Space> :call <SID>Tlist_Window_Show_Info()<CR> +    nnoremap <buffer> <silent> u :call <SID>Tlist_Window_Update_File()<CR> +    nnoremap <buffer> <silent> d :call <SID>Tlist_Remove_File(-1, 1)<CR> +    nnoremap <buffer> <silent> x :call <SID>Tlist_Window_Zoom()<CR> +    nnoremap <buffer> <silent> [[ :call <SID>Tlist_Window_Move_To_File(-1)<CR> +    nnoremap <buffer> <silent> <BS> :call <SID>Tlist_Window_Move_To_File(-1)<CR> +    nnoremap <buffer> <silent> ]] :call <SID>Tlist_Window_Move_To_File(1)<CR> +    nnoremap <buffer> <silent> <Tab> :call <SID>Tlist_Window_Move_To_File(1)<CR> +    nnoremap <buffer> <silent> <F1> :call <SID>Tlist_Window_Toggle_Help_Text()<CR> +    nnoremap <buffer> <silent> q :close<CR> + +    " Insert mode mappings +    inoremap <buffer> <silent> <CR> +                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR> +    " Windows needs return +    inoremap <buffer> <silent> <Return> +                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR> +    inoremap <buffer> <silent> o +                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('newwin')<CR> +    inoremap <buffer> <silent> p +                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('preview')<CR> +    inoremap <buffer> <silent> P +                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('prevwin')<CR> +    if v:version >= 700 +    inoremap <buffer> <silent> t +                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('checktab')<CR> +    inoremap <buffer> <silent> <C-t> +                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('newtab')<CR> +    endif +    inoremap <buffer> <silent> <2-LeftMouse> +                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR> +    inoremap <buffer> <silent> s +                \ <C-o>:call <SID>Tlist_Change_Sort('cmd', 'toggle', '')<CR> +    inoremap <buffer> <silent> +             <C-o>:silent! foldopen<CR> +    inoremap <buffer> <silent> -             <C-o>:silent! foldclose<CR> +    inoremap <buffer> <silent> *             <C-o>:silent! %foldopen!<CR> +    inoremap <buffer> <silent> =             <C-o>:silent! %foldclose<CR> +    inoremap <buffer> <silent> <kPlus>       <C-o>:silent! foldopen<CR> +    inoremap <buffer> <silent> <kMinus>      <C-o>:silent! foldclose<CR> +    inoremap <buffer> <silent> <kMultiply>   <C-o>:silent! %foldopen!<CR> +    inoremap <buffer> <silent> <Space>       <C-o>:call +                                    \ <SID>Tlist_Window_Show_Info()<CR> +    inoremap <buffer> <silent> u +                            \ <C-o>:call <SID>Tlist_Window_Update_File()<CR> +    inoremap <buffer> <silent> d    <C-o>:call <SID>Tlist_Remove_File(-1, 1)<CR> +    inoremap <buffer> <silent> x    <C-o>:call <SID>Tlist_Window_Zoom()<CR> +    inoremap <buffer> <silent> [[   <C-o>:call <SID>Tlist_Window_Move_To_File(-1)<CR> +    inoremap <buffer> <silent> <BS> <C-o>:call <SID>Tlist_Window_Move_To_File(-1)<CR> +    inoremap <buffer> <silent> ]]   <C-o>:call <SID>Tlist_Window_Move_To_File(1)<CR> +    inoremap <buffer> <silent> <Tab> <C-o>:call <SID>Tlist_Window_Move_To_File(1)<CR> +    inoremap <buffer> <silent> <F1>  <C-o>:call <SID>Tlist_Window_Toggle_Help_Text()<CR> +    inoremap <buffer> <silent> q    <C-o>:close<CR> + +    " Map single left mouse click if the user wants this functionality +    if g:Tlist_Use_SingleClick == 1 +        " Contributed by Bindu Wavell +        " attempt to perform single click mapping, it would be much +        " nicer if we could nnoremap <buffer> ... however vim does +        " not fire the <buffer> <leftmouse> when you use the mouse +        " to enter a buffer. +        let clickmap = ':if bufname("%") =~ "__Tag_List__" <bar> ' . +                    \ 'call <SID>Tlist_Window_Jump_To_Tag("useopen") ' . +                    \ '<bar> endif <CR>' +        if maparg('<leftmouse>', 'n') == '' +            " no mapping for leftmouse +            exe ':nnoremap <silent> <leftmouse> <leftmouse>' . clickmap +        else +            " we have a mapping +            let mapcmd = ':nnoremap <silent> <leftmouse> <leftmouse>' +            let mapcmd = mapcmd . substitute(substitute( +                        \ maparg('<leftmouse>', 'n'), '|', '<bar>', 'g'), +                        \ '\c^<leftmouse>', '', '') +            let mapcmd = mapcmd . clickmap +            exe mapcmd +        endif +    endif + +    " Define the taglist autocommands +    augroup TagListAutoCmds +        autocmd! +        " Display the tag prototype for the tag under the cursor. +        autocmd CursorHold __Tag_List__ call s:Tlist_Window_Show_Info() +        " Highlight the current tag periodically +        autocmd CursorHold * silent call s:Tlist_Window_Highlight_Tag( +                            \ fnamemodify(bufname('%'), ':p'), line('.'), 1, 0) + +        " Adjust the Vim window width when taglist window is closed +        autocmd BufUnload __Tag_List__ call s:Tlist_Post_Close_Cleanup() +        " Close the fold for this buffer when leaving the buffer +        if g:Tlist_File_Fold_Auto_Close +            autocmd BufEnter * silent +                \ call s:Tlist_Window_Open_File_Fold(expand('<abuf>')) +        endif +        " Exit Vim itself if only the taglist window is present (optional) +        if g:Tlist_Exit_OnlyWindow +	    autocmd BufEnter __Tag_List__ nested +			\ call s:Tlist_Window_Exit_Only_Window() +        endif +        if s:tlist_app_name != "winmanager" && +                    \ !g:Tlist_Process_File_Always && +                    \ (!has('gui_running') || !g:Tlist_Show_Menu) +            " Auto refresh the taglist window +            autocmd BufEnter * call s:Tlist_Refresh() +        endif + +        if !g:Tlist_Use_Horiz_Window +            if v:version < 700 +                autocmd WinEnter * call s:Tlist_Window_Check_Width() +            endif +        endif +        if v:version >= 700 +            autocmd TabEnter * silent call s:Tlist_Refresh_Folds() +        endif +    augroup end + +    " Restore the previous cpoptions settings +    let &cpoptions = old_cpoptions +endfunction + +" Tlist_Window_Refresh +" Display the tags for all the files in the taglist window +function! s:Tlist_Window_Refresh() +    call s:Tlist_Log_Msg('Tlist_Window_Refresh()') +    " Set report option to a huge value to prevent informational messages +    " while deleting the lines +    let old_report = &report +    set report=99999 + +    " Mark the buffer as modifiable +    setlocal modifiable + +    " Delete the contents of the buffer to the black-hole register +    silent! %delete _ + +    " As we have cleared the taglist window, mark all the files +    " as not visible +    let i = 0 +    while i < s:tlist_file_count +        let s:tlist_{i}_visible = 0 +        let i = i + 1 +    endwhile + +    if g:Tlist_Compact_Format == 0 +        " Display help in non-compact mode +        call s:Tlist_Window_Display_Help() +    endif + +    " Mark the buffer as not modifiable +    setlocal nomodifiable + +    " Restore the report option +    let &report = old_report + +    " If the tags for only one file should be displayed in the taglist +    " window, then no need to add the tags here. The bufenter autocommand +    " will add the tags for that file. +    if g:Tlist_Show_One_File +        return +    endif + +    " List all the tags for the previously processed files +    " Do this only if taglist is configured to display tags for more than +    " one file. Otherwise, when Tlist_Show_One_File is configured, +    " tags for the wrong file will be displayed. +    let i = 0 +    while i < s:tlist_file_count +        call s:Tlist_Window_Refresh_File(s:tlist_{i}_filename, +                    \ s:tlist_{i}_filetype) +        let i = i + 1 +    endwhile + +    if g:Tlist_Auto_Update +        " Add and list the tags for all buffers in the Vim buffer list +        let i = 1 +        let last_bufnum = bufnr('$') +        while i <= last_bufnum +            if buflisted(i) +                let fname = fnamemodify(bufname(i), ':p') +                let ftype = s:Tlist_Get_Buffer_Filetype(i) +                " If the file doesn't support tag listing, skip it +                if !s:Tlist_Skip_File(fname, ftype) +                    call s:Tlist_Window_Refresh_File(fname, ftype) +                endif +            endif +            let i = i + 1 +        endwhile +    endif + +    " If Tlist_File_Fold_Auto_Close option is set, then close all the folds +    if g:Tlist_File_Fold_Auto_Close +        " Close all the folds +        silent! %foldclose +    endif + +    " Move the cursor to the top of the taglist window +    normal! gg +endfunction + +" Tlist_Post_Close_Cleanup() +" Close the taglist window and adjust the Vim window width +function! s:Tlist_Post_Close_Cleanup() +    call s:Tlist_Log_Msg('Tlist_Post_Close_Cleanup()') +    " Mark all the files as not visible +    let i = 0 +    while i < s:tlist_file_count +        let s:tlist_{i}_visible = 0 +        let i = i + 1 +    endwhile + +    " Remove the taglist autocommands +    silent! autocmd! TagListAutoCmds + +    " Clear all the highlights +    match none + +    silent! syntax clear TagListTitle +    silent! syntax clear TagListComment +    silent! syntax clear TagListTagScope + +    " Remove the left mouse click mapping if it was setup initially +    if g:Tlist_Use_SingleClick +        if hasmapto('<LeftMouse>') +            nunmap <LeftMouse> +        endif +    endif + +    if s:tlist_app_name != "winmanager" +    if g:Tlist_Use_Horiz_Window || g:Tlist_Inc_Winwidth == 0 || +                \ s:tlist_winsize_chgd != 1 || +                \ &columns < (80 + g:Tlist_WinWidth) +        " No need to adjust window width if using horizontally split taglist +        " window or if columns is less than 101 or if the user chose not to +        " adjust the window width +    else +        " If the user didn't manually move the window, then restore the window +        " position to the pre-taglist position +        if s:tlist_pre_winx != -1 && s:tlist_pre_winy != -1 && +                    \ getwinposx() == s:tlist_winx && +                    \ getwinposy() == s:tlist_winy +            exe 'winpos ' . s:tlist_pre_winx . ' ' . s:tlist_pre_winy +        endif + +        " Adjust the Vim window width +        let &columns= &columns - (g:Tlist_WinWidth + 1) +    endif +    endif + +    let s:tlist_winsize_chgd = -1 + +    " Reset taglist state variables +    if s:tlist_app_name == "winmanager" +        let s:tlist_app_name = "none" +    endif +    let s:tlist_window_initialized = 0 +endfunction + +" Tlist_Window_Refresh_File() +" List the tags defined in the specified file in a Vim window +function! s:Tlist_Window_Refresh_File(filename, ftype) +    call s:Tlist_Log_Msg('Tlist_Window_Refresh_File (' . a:filename . ')') +    " First check whether the file already exists +    let fidx = s:Tlist_Get_File_Index(a:filename) +    if fidx != -1 +        let file_listed = 1 +    else +        let file_listed = 0 +    endif + +    if !file_listed +        " Check whether this file is removed based on user request +        " If it is, then don't display the tags for this file +        if s:Tlist_User_Removed_File(a:filename) +            return +        endif +    endif + +    if file_listed && s:tlist_{fidx}_visible +        " Check whether the file tags are currently valid +        if s:tlist_{fidx}_valid +            " Goto the first line in the file +            exe s:tlist_{fidx}_start + +            " If the line is inside a fold, open the fold +            if foldclosed('.') != -1 +                exe "silent! " . s:tlist_{fidx}_start . "," . +                            \ s:tlist_{fidx}_end . "foldopen!" +            endif +            return +        endif + +        " Discard and remove the tags for this file from display +        call s:Tlist_Discard_TagInfo(fidx) +        call s:Tlist_Window_Remove_File_From_Display(fidx) +    endif + +    " Process and generate a list of tags defined in the file +    if !file_listed || !s:tlist_{fidx}_valid +        let ret_fidx = s:Tlist_Process_File(a:filename, a:ftype) +        if ret_fidx == -1 +            return +        endif +        let fidx = ret_fidx +    endif + +    " Set report option to a huge value to prevent informational messages +    " while adding lines to the taglist window +    let old_report = &report +    set report=99999 + +    if g:Tlist_Show_One_File +        " Remove the previous file +        if s:tlist_cur_file_idx != -1 +            call s:Tlist_Window_Remove_File_From_Display(s:tlist_cur_file_idx) +            let s:tlist_{s:tlist_cur_file_idx}_visible = 0 +            let s:tlist_{s:tlist_cur_file_idx}_start = 0 +            let s:tlist_{s:tlist_cur_file_idx}_end = 0 +        endif +        let s:tlist_cur_file_idx = fidx +    endif + +    " Mark the buffer as modifiable +    setlocal modifiable + +    " Add new files to the end of the window. For existing files, add them at +    " the same line where they were previously present. If the file is not +    " visible, then add it at the end +    if s:tlist_{fidx}_start == 0 || !s:tlist_{fidx}_visible +        if g:Tlist_Compact_Format +            let s:tlist_{fidx}_start = line('$') +        else +            let s:tlist_{fidx}_start = line('$') + 1 +        endif +    endif + +    let s:tlist_{fidx}_visible = 1 + +    " Goto the line where this file should be placed +    if g:Tlist_Compact_Format +        exe s:tlist_{fidx}_start +    else +        exe s:tlist_{fidx}_start - 1 +    endif + +    let txt = fnamemodify(s:tlist_{fidx}_filename, ':t') . ' (' . +                \ fnamemodify(s:tlist_{fidx}_filename, ':p:h') . ')' +    if g:Tlist_Compact_Format == 0 +        silent! put =txt +    else +        silent! put! =txt +        " Move to the next line +        exe line('.') + 1 +    endif +    let file_start = s:tlist_{fidx}_start + +    " Add the tag names grouped by tag type to the buffer with a title +    let i = 1 +    let ttype_cnt = s:tlist_{a:ftype}_count +    while i <= ttype_cnt +        let ttype = s:tlist_{a:ftype}_{i}_name +        " Add the tag type only if there are tags for that type +        let fidx_ttype = 's:tlist_' . fidx . '_' . ttype +        let ttype_txt = {fidx_ttype} +        if ttype_txt != '' +            let txt = '  ' . s:tlist_{a:ftype}_{i}_fullname +            if g:Tlist_Compact_Format == 0 +                let ttype_start_lnum = line('.') + 1 +                silent! put =txt +            else +                let ttype_start_lnum = line('.') +                silent! put! =txt +            endif +            silent! put =ttype_txt + +            let {fidx_ttype}_offset = ttype_start_lnum - file_start + +            " create a fold for this tag type +            let fold_start = ttype_start_lnum +            let fold_end = fold_start + {fidx_ttype}_count +            exe fold_start . ',' . fold_end  . 'fold' + +            " Adjust the cursor position +            if g:Tlist_Compact_Format == 0 +                exe ttype_start_lnum + {fidx_ttype}_count +            else +                exe ttype_start_lnum + {fidx_ttype}_count + 1 +            endif + +            if g:Tlist_Compact_Format == 0 +                " Separate the tag types by a empty line +                silent! put ='' +            endif +        endif +        let i = i + 1 +    endwhile + +    if s:tlist_{fidx}_tag_count == 0 +        if g:Tlist_Compact_Format == 0 +            silent! put ='' +        endif +    endif + +    let s:tlist_{fidx}_end = line('.') - 1 + +    " Create a fold for the entire file +    exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold' +    exe 'silent! ' . s:tlist_{fidx}_start . ',' . +                \ s:tlist_{fidx}_end . 'foldopen!' + +    " Goto the starting line for this file, +    exe s:tlist_{fidx}_start + +    if s:tlist_app_name == "winmanager" +        " To handle a bug in the winmanager plugin, add a space at the +        " last line +        call setline('$', ' ') +    endif + +    " Mark the buffer as not modifiable +    setlocal nomodifiable + +    " Restore the report option +    let &report = old_report + +    " Update the start and end line numbers for all the files following this +    " file +    let start = s:tlist_{fidx}_start +    " include the empty line after the last line +    if g:Tlist_Compact_Format +        let end = s:tlist_{fidx}_end +    else +        let end = s:tlist_{fidx}_end + 1 +    endif +    call s:Tlist_Window_Update_Line_Offsets(fidx + 1, 1, end - start + 1) + +    " Now that we have updated the taglist window, update the tags +    " menu (if present) +    if g:Tlist_Show_Menu +        call s:Tlist_Menu_Update_File(1) +    endif +endfunction + +" Tlist_Init_File +" Initialize the variables for a new file +function! s:Tlist_Init_File(filename, ftype) +    call s:Tlist_Log_Msg('Tlist_Init_File (' . a:filename . ')') +    " Add new files at the end of the list +    let fidx = s:tlist_file_count +    let s:tlist_file_count = s:tlist_file_count + 1 +    " Add the new file name to the taglist list of file names +    let s:tlist_file_names = s:tlist_file_names . a:filename . "\n" + +    " Initialize the file variables +    let s:tlist_{fidx}_filename = a:filename +    let s:tlist_{fidx}_sort_type = g:Tlist_Sort_Type +    let s:tlist_{fidx}_filetype = a:ftype +    let s:tlist_{fidx}_mtime = -1 +    let s:tlist_{fidx}_start = 0 +    let s:tlist_{fidx}_end = 0 +    let s:tlist_{fidx}_valid = 0 +    let s:tlist_{fidx}_visible = 0 +    let s:tlist_{fidx}_tag_count = 0 +    let s:tlist_{fidx}_menu_cmd = '' + +    " Initialize the tag type variables +    let i = 1 +    while i <= s:tlist_{a:ftype}_count +        let ttype = s:tlist_{a:ftype}_{i}_name +        let s:tlist_{fidx}_{ttype} = '' +        let s:tlist_{fidx}_{ttype}_offset = 0 +        let s:tlist_{fidx}_{ttype}_count = 0 +        let i = i + 1 +    endwhile + +    return fidx +endfunction + +" Tlist_Get_Tag_Type_By_Tag +" Return the tag type for the specified tag index +function! s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx) +    let ttype_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_type' + +    " Already parsed and have the tag name +    if exists(ttype_var) +        return {ttype_var} +    endif + +    let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag +    let {ttype_var} = s:Tlist_Extract_Tagtype(tag_line) + +    return {ttype_var} +endfunction + +" Tlist_Get_Tag_Prototype +function! s:Tlist_Get_Tag_Prototype(fidx, tidx) +    let tproto_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_proto' + +    " Already parsed and have the tag prototype +    if exists(tproto_var) +        return {tproto_var} +    endif + +    " Parse and extract the tag prototype +    let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag +    let start = stridx(tag_line, '/^') + 2 +    let end = stridx(tag_line, '/;"' . "\t") +    if tag_line[end - 1] == '$' +        let end = end -1 +    endif +    let tag_proto = strpart(tag_line, start, end - start) +    let {tproto_var} = substitute(tag_proto, '\s*', '', '') + +    return {tproto_var} +endfunction + +" Tlist_Get_Tag_SearchPat +function! s:Tlist_Get_Tag_SearchPat(fidx, tidx) +    let tpat_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_searchpat' + +    " Already parsed and have the tag search pattern +    if exists(tpat_var) +        return {tpat_var} +    endif + +    " Parse and extract the tag search pattern +    let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag +    let start = stridx(tag_line, '/^') + 2 +    let end = stridx(tag_line, '/;"' . "\t") +    if tag_line[end - 1] == '$' +        let end = end -1 +    endif +    let {tpat_var} = '\V\^' . strpart(tag_line, start, end - start) . +                        \ (tag_line[end] == '$' ? '\$' : '') + +    return {tpat_var} +endfunction + +" Tlist_Get_Tag_Linenum +" Return the tag line number, given the tag index +function! s:Tlist_Get_Tag_Linenum(fidx, tidx) +    let tline_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_linenum' + +    " Already parsed and have the tag line number +    if exists(tline_var) +        return {tline_var} +    endif + +    " Parse and extract the tag line number +    let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag +    let start = strridx(tag_line, 'line:') + 5 +    let end = strridx(tag_line, "\t") +    if end < start +        let {tline_var} = strpart(tag_line, start) + 0 +    else +        let {tline_var} = strpart(tag_line, start, end - start) + 0 +    endif + +    return {tline_var} +endfunction + +" Tlist_Parse_Tagline +" Parse a tag line from the ctags output. Separate the tag output based on the +" tag type and store it in the tag type variable. +" The format of each line in the ctags output is: +" +"     tag_name<TAB>file_name<TAB>ex_cmd;"<TAB>extension_fields +" +function! s:Tlist_Parse_Tagline(tag_line) +    if a:tag_line == '' +        " Skip empty lines +        return +    endif + +    " Extract the tag type +    let ttype = s:Tlist_Extract_Tagtype(a:tag_line) + +    " Make sure the tag type is a valid and supported one +    if ttype == '' || stridx(s:ctags_flags, ttype) == -1 +        " Line is not in proper tags format or Tag type is not supported +        return +    endif + +    " Update the total tag count +    let s:tidx = s:tidx + 1 + +    " The following variables are used to optimize this code.  Vim is slow in +    " using curly brace names. To reduce the amount of processing needed, the +    " curly brace variables are pre-processed here +    let fidx_tidx = 's:tlist_' . s:fidx . '_' . s:tidx +    let fidx_ttype = 's:tlist_' . s:fidx . '_' . ttype + +    " Update the count of this tag type +    let ttype_idx = {fidx_ttype}_count + 1 +    let {fidx_ttype}_count = ttype_idx + +    " Store the ctags output for this tag +    let {fidx_tidx}_tag = a:tag_line + +    " Store the tag index and the tag type index (back pointers) +    let {fidx_ttype}_{ttype_idx} = s:tidx +    let {fidx_tidx}_ttype_idx = ttype_idx + +    " Extract the tag name +    let tag_name = strpart(a:tag_line, 0, stridx(a:tag_line, "\t")) + +    " Extract the tag scope/prototype +    if g:Tlist_Display_Prototype +        let ttxt = '    ' . s:Tlist_Get_Tag_Prototype(s:fidx, s:tidx) +    else +        let ttxt = '    ' . tag_name + +        " Add the tag scope, if it is available and is configured. Tag +        " scope is the last field after the 'line:<num>\t' field +        if g:Tlist_Display_Tag_Scope +            let tag_scope = s:Tlist_Extract_Tag_Scope(a:tag_line) +            if tag_scope != '' +                let ttxt = ttxt . ' [' . tag_scope . ']' +            endif +        endif +    endif + +    " Add this tag to the tag type variable +    let {fidx_ttype} = {fidx_ttype} . ttxt . "\n" + +    " Save the tag name +    let {fidx_tidx}_tag_name = tag_name +endfunction + +" Tlist_Process_File +" Get the list of tags defined in the specified file and store them +" in Vim variables. Returns the file index where the tags are stored. +function! s:Tlist_Process_File(filename, ftype) +    call s:Tlist_Log_Msg('Tlist_Process_File (' . a:filename . ', ' . +                \ a:ftype . ')') +    " Check whether this file is supported +    if s:Tlist_Skip_File(a:filename, a:ftype) +        return -1 +    endif + +    " If the tag types for this filetype are not yet created, then create +    " them now +    let var = 's:tlist_' . a:ftype . '_count' +    if !exists(var) +        if s:Tlist_FileType_Init(a:ftype) == 0 +            return -1 +        endif +    endif + +    " If this file is already processed, then use the cached values +    let fidx = s:Tlist_Get_File_Index(a:filename) +    if fidx == -1 +        " First time, this file is loaded +        let fidx = s:Tlist_Init_File(a:filename, a:ftype) +    else +        " File was previously processed. Discard the tag information +        call s:Tlist_Discard_TagInfo(fidx) +    endif + +    let s:tlist_{fidx}_valid = 1 + +    " Exuberant ctags arguments to generate a tag list +    let ctags_args = ' -f - --format=2 --excmd=pattern --fields=nks ' + +    " Form the ctags argument depending on the sort type +    if s:tlist_{fidx}_sort_type == 'name' +        let ctags_args = ctags_args . '--sort=yes' +    else +        let ctags_args = ctags_args . '--sort=no' +    endif + +    " Add the filetype specific arguments +    let ctags_args = ctags_args . ' ' . s:tlist_{a:ftype}_ctags_args + +    " Ctags command to produce output with regexp for locating the tags +    let ctags_cmd = g:Tlist_Ctags_Cmd . ctags_args +    let ctags_cmd = ctags_cmd . ' "' . a:filename . '"' + +    if &shellxquote == '"' +        " Double-quotes within double-quotes will not work in the +        " command-line.If the 'shellxquote' option is set to double-quotes, +        " then escape the double-quotes in the ctags command-line. +        let ctags_cmd = escape(ctags_cmd, '"') +    endif + +    " In Windows 95, if not using cygwin, disable the 'shellslash' +    " option. Otherwise, this will cause problems when running the +    " ctags command. +    if has('win95') && !has('win32unix') +        let old_shellslash = &shellslash +        set noshellslash +    endif + +    if has('win32') && !has('win32unix') && !has('win95') +                \ && (&shell =~ 'cmd.exe') +        " Windows does not correctly deal with commands that have more than 1 +        " set of double quotes.  It will strip them all resulting in: +        " 'C:\Program' is not recognized as an internal or external command +        " operable program or batch file.  To work around this, place the +        " command inside a batch file and call the batch file. +        " Do this only on Win2K, WinXP and above. +        " Contributed by: David Fishburn. +        let s:taglist_tempfile = fnamemodify(tempname(), ':h') . +                    \ '\taglist.cmd' +        exe 'redir! > ' . s:taglist_tempfile +        silent echo ctags_cmd +        redir END + +        call s:Tlist_Log_Msg('Cmd inside batch file: ' . ctags_cmd) +        let ctags_cmd = '"' . s:taglist_tempfile . '"' +    endif + +    call s:Tlist_Log_Msg('Cmd: ' . ctags_cmd) + +    " Run ctags and get the tag list +    let cmd_output = system(ctags_cmd) + +    " Restore the value of the 'shellslash' option. +    if has('win95') && !has('win32unix') +        let &shellslash = old_shellslash +    endif + +    if exists('s:taglist_tempfile') +        " Delete the temporary cmd file created on MS-Windows +        call delete(s:taglist_tempfile) +    endif + +    " Handle errors +    if v:shell_error +        let msg = "Taglist: Failed to generate tags for " . a:filename +        call s:Tlist_Warning_Msg(msg) +        if cmd_output != '' +            call s:Tlist_Warning_Msg(cmd_output) +        endif +        return fidx +    endif + +    " Store the modification time for the file +    let s:tlist_{fidx}_mtime = getftime(a:filename) + +    " No tags for current file +    if cmd_output == '' +        call s:Tlist_Log_Msg('No tags defined in ' . a:filename) +        return fidx +    endif + +    call s:Tlist_Log_Msg('Generated tags information for ' . a:filename) + +    if v:version > 601 +        " The following script local variables are used by the +        " Tlist_Parse_Tagline() function. +        let s:ctags_flags = s:tlist_{a:ftype}_ctags_flags +        let s:fidx = fidx +        let s:tidx = 0 + +        " Process the ctags output one line at a time.  The substitute() +        " command is used to parse the tag lines instead of using the +        " matchstr()/stridx()/strpart() functions for performance reason +        call substitute(cmd_output, "\\([^\n]\\+\\)\n", +                    \ '\=s:Tlist_Parse_Tagline(submatch(1))', 'g') + +        " Save the number of tags for this file +        let s:tlist_{fidx}_tag_count = s:tidx + +        " The following script local variables are no longer needed +        unlet! s:ctags_flags +        unlet! s:tidx +        unlet! s:fidx +    else +        " Due to a bug in Vim earlier than version 6.1, +        " we cannot use substitute() to parse the ctags output. +        " Instead the slow str*() functions are used +        let ctags_flags = s:tlist_{a:ftype}_ctags_flags +        let tidx = 0 + +        while cmd_output != '' +            " Extract one line at a time +            let idx = stridx(cmd_output, "\n") +            let one_line = strpart(cmd_output, 0, idx) +            " Remove the line from the tags output +            let cmd_output = strpart(cmd_output, idx + 1) + +            if one_line == '' +                " Line is not in proper tags format +                continue +            endif + +            " Extract the tag type +            let ttype = s:Tlist_Extract_Tagtype(one_line) + +            " Make sure the tag type is a valid and supported one +            if ttype == '' || stridx(ctags_flags, ttype) == -1 +                " Line is not in proper tags format or Tag type is not +                " supported +                continue +            endif + +            " Update the total tag count +            let tidx = tidx + 1 + +            " The following variables are used to optimize this code.  Vim is +            " slow in using curly brace names. To reduce the amount of +            " processing needed, the curly brace variables are pre-processed +            " here +            let fidx_tidx = 's:tlist_' . fidx . '_' . tidx +            let fidx_ttype = 's:tlist_' . fidx . '_' . ttype + +            " Update the count of this tag type +            let ttype_idx = {fidx_ttype}_count + 1 +            let {fidx_ttype}_count = ttype_idx + +            " Store the ctags output for this tag +            let {fidx_tidx}_tag = one_line + +            " Store the tag index and the tag type index (back pointers) +            let {fidx_ttype}_{ttype_idx} = tidx +            let {fidx_tidx}_ttype_idx = ttype_idx + +            " Extract the tag name +            let tag_name = strpart(one_line, 0, stridx(one_line, "\t")) + +            " Extract the tag scope/prototype +            if g:Tlist_Display_Prototype +                let ttxt = '    ' . s:Tlist_Get_Tag_Prototype(fidx, tidx) +            else +                let ttxt = '    ' . tag_name + +                " Add the tag scope, if it is available and is configured. Tag +                " scope is the last field after the 'line:<num>\t' field +                if g:Tlist_Display_Tag_Scope +                    let tag_scope = s:Tlist_Extract_Tag_Scope(one_line) +                    if tag_scope != '' +                        let ttxt = ttxt . ' [' . tag_scope . ']' +                    endif +                endif +            endif + +            " Add this tag to the tag type variable +            let {fidx_ttype} = {fidx_ttype} . ttxt . "\n" + +            " Save the tag name +            let {fidx_tidx}_tag_name = tag_name +        endwhile + +        " Save the number of tags for this file +        let s:tlist_{fidx}_tag_count = tidx +    endif + +    call s:Tlist_Log_Msg('Processed ' . s:tlist_{fidx}_tag_count .  +                \ ' tags in ' . a:filename) + +    return fidx +endfunction + +" Tlist_Update_File +" Update the tags for a file (if needed) +function! Tlist_Update_File(filename, ftype) +    call s:Tlist_Log_Msg('Tlist_Update_File (' . a:filename . ')') +    " If the file doesn't support tag listing, skip it +    if s:Tlist_Skip_File(a:filename, a:ftype) +        return +    endif + +    " Convert the file name to a full path +    let fname = fnamemodify(a:filename, ':p') + +    " First check whether the file already exists +    let fidx = s:Tlist_Get_File_Index(fname) + +    if fidx != -1 && s:tlist_{fidx}_valid +        " File exists and the tags are valid +        " Check whether the file was modified after the last tags update +        " If it is modified, then update the tags +        if s:tlist_{fidx}_mtime == getftime(fname) +            return +        endif +    else +        " If the tags were removed previously based on a user request, +        " as we are going to update the tags (based on the user request), +        " remove the filename from the deleted list +        call s:Tlist_Update_Remove_List(fname, 0) +    endif + +    " If the taglist window is opened, update it +    let winnum = bufwinnr(g:TagList_title) +    if winnum == -1 +        " Taglist window is not present. Just update the taglist +        " and return +        call s:Tlist_Process_File(fname, a:ftype) +    else +        if g:Tlist_Show_One_File && s:tlist_cur_file_idx != -1 +            " If tags for only one file are displayed and we are not +            " updating the tags for that file, then no need to +            " refresh the taglist window. Otherwise, the taglist +            " window should be updated. +            if s:tlist_{s:tlist_cur_file_idx}_filename != fname +                call s:Tlist_Process_File(fname, a:ftype) +                return +            endif +        endif + +        " Save the current window number +        let save_winnr = winnr() + +        " Goto the taglist window +        call s:Tlist_Window_Goto_Window() + +        " Save the cursor position +        let save_line = line('.') +        let save_col = col('.') + +        " Update the taglist window +        call s:Tlist_Window_Refresh_File(fname, a:ftype) + +        " Restore the cursor position +        if v:version >= 601 +            call cursor(save_line, save_col) +        else +            exe save_line +            exe 'normal! ' . save_col . '|' +        endif + +        if winnr() != save_winnr +            " Go back to the original window +            call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w') +        endif +    endif + +    " Update the taglist menu +    if g:Tlist_Show_Menu +        call s:Tlist_Menu_Update_File(1) +    endif +endfunction + +" Tlist_Window_Close +" Close the taglist window +function! s:Tlist_Window_Close() +    call s:Tlist_Log_Msg('Tlist_Window_Close()') +    " Make sure the taglist window exists +    let winnum = bufwinnr(g:TagList_title) +    if winnum == -1 +        call s:Tlist_Warning_Msg('Error: Taglist window is not open') +        return +    endif + +    if winnr() == winnum +        " Already in the taglist window. Close it and return +        if winbufnr(2) != -1 +            " If a window other than the taglist window is open, +            " then only close the taglist window. +            close +        endif +    else +        " Goto the taglist window, close it and then come back to the +        " original window +        let curbufnr = bufnr('%') +        exe winnum . 'wincmd w' +        close +        " Need to jump back to the original window only if we are not +        " already in that window +        let winnum = bufwinnr(curbufnr) +        if winnr() != winnum +            exe winnum . 'wincmd w' +        endif +    endif +endfunction + +" Tlist_Window_Mark_File_Window +" Mark the current window as the file window to use when jumping to a tag. +" Only if the current window is a non-plugin, non-preview and non-taglist +" window +function! s:Tlist_Window_Mark_File_Window() +    if getbufvar('%', '&buftype') == '' && !&previewwindow +        let w:tlist_file_window = "yes" +    endif +endfunction + +" Tlist_Window_Open +" Open and refresh the taglist window +function! s:Tlist_Window_Open() +    call s:Tlist_Log_Msg('Tlist_Window_Open()') +    " If the window is open, jump to it +    let winnum = bufwinnr(g:TagList_title) +    if winnum != -1 +        " Jump to the existing window +        if winnr() != winnum +            exe winnum . 'wincmd w' +        endif +        return +    endif + +    if s:tlist_app_name == "winmanager" +        " Taglist plugin is no longer part of the winmanager app +        let s:tlist_app_name = "none" +    endif + +    " Get the filename and filetype for the specified buffer +    let curbuf_name = fnamemodify(bufname('%'), ':p') +    let curbuf_ftype = s:Tlist_Get_Buffer_Filetype('%') +    let cur_lnum = line('.') + +    " Mark the current window as the desired window to open a file when a tag +    " is selected. +    call s:Tlist_Window_Mark_File_Window() + +    " Open the taglist window +    call s:Tlist_Window_Create() + +    call s:Tlist_Window_Refresh() + +    if g:Tlist_Show_One_File +        " Add only the current buffer and file +        " +        " If the file doesn't support tag listing, skip it +        if !s:Tlist_Skip_File(curbuf_name, curbuf_ftype) +            call s:Tlist_Window_Refresh_File(curbuf_name, curbuf_ftype) +        endif +    endif + +    if g:Tlist_File_Fold_Auto_Close +        " Open the fold for the current file, as all the folds in +        " the taglist window are closed +        let fidx = s:Tlist_Get_File_Index(curbuf_name) +        if fidx != -1 +            exe "silent! " . s:tlist_{fidx}_start . "," . +                        \ s:tlist_{fidx}_end . "foldopen!" +        endif +    endif + +    " Highlight the current tag +    call s:Tlist_Window_Highlight_Tag(curbuf_name, cur_lnum, 1, 1) +endfunction + +" Tlist_Window_Toggle() +" Open or close a taglist window +function! s:Tlist_Window_Toggle() +    call s:Tlist_Log_Msg('Tlist_Window_Toggle()') +    " If taglist window is open then close it. +    let winnum = bufwinnr(g:TagList_title) +    if winnum != -1 +        call s:Tlist_Window_Close() +        return +    endif + +    call s:Tlist_Window_Open() + +    " Go back to the original window, if Tlist_GainFocus_On_ToggleOpen is not +    " set +    if !g:Tlist_GainFocus_On_ToggleOpen +        call s:Tlist_Exe_Cmd_No_Acmds('wincmd p') +    endif + +    " Update the taglist menu +    if g:Tlist_Show_Menu +        call s:Tlist_Menu_Update_File(0) +    endif +endfunction + +" Tlist_Process_Filelist +" Process multiple files. Each filename is separated by "\n" +" Returns the number of processed files +function! s:Tlist_Process_Filelist(file_names) +    let flist = a:file_names + +    " Enable lazy screen updates +    let old_lazyredraw = &lazyredraw +    set lazyredraw + +    " Keep track of the number of processed files +    let fcnt = 0 + +    " Process one file at a time +    while flist != '' +        let nl_idx = stridx(flist, "\n") +        let one_file = strpart(flist, 0, nl_idx) + +        " Remove the filename from the list +        let flist = strpart(flist, nl_idx + 1) + +        if one_file == '' +            continue +        endif + +        " Skip directories +        if isdirectory(one_file) +            continue +        endif + +        let ftype = s:Tlist_Detect_Filetype(one_file) + +        echon "\r                                                              " +        echon "\rProcessing tags for " . fnamemodify(one_file, ':p:t') + +        let fcnt = fcnt + 1 + +        call Tlist_Update_File(one_file, ftype) +    endwhile + +    " Clear the displayed informational messages +    echon "\r                                                            " + +    " Restore the previous state +    let &lazyredraw = old_lazyredraw + +    return fcnt +endfunction + +" Tlist_Process_Dir +" Process the files in a directory matching the specified pattern +function! s:Tlist_Process_Dir(dir_name, pat) +    let flist = glob(a:dir_name . '/' . a:pat) . "\n" + +    let fcnt = s:Tlist_Process_Filelist(flist) + +    let len = strlen(a:dir_name) +    if a:dir_name[len - 1] == '\' || a:dir_name[len - 1] == '/' +        let glob_expr = a:dir_name . '*' +    else +        let glob_expr = a:dir_name . '/*' +    endif +    let all_files = glob(glob_expr) . "\n" + +    while all_files != '' +        let nl_idx = stridx(all_files, "\n") +        let one_file = strpart(all_files, 0, nl_idx) + +        let all_files = strpart(all_files, nl_idx + 1) +        if one_file == '' +            continue +        endif + +        " Skip non-directory names +        if !isdirectory(one_file) +            continue +        endif + +        echon "\r                                                              " +        echon "\rProcessing files in directory " . fnamemodify(one_file, ':t') +        let fcnt = fcnt + s:Tlist_Process_Dir(one_file, a:pat) +    endwhile + +    return fcnt +endfunction + +" Tlist_Add_Files_Recursive +" Add files recursively from a directory +function! s:Tlist_Add_Files_Recursive(dir, ...) +    let dir_name = fnamemodify(a:dir, ':p') +    if !isdirectory(dir_name) +        call s:Tlist_Warning_Msg('Error: ' . dir_name . ' is not a directory') +        return +    endif + +    if a:0 == 1 +        " User specified file pattern +        let pat = a:1 +    else +        " Default file pattern +        let pat = '*' +    endif + +    echon "\r                                                              " +    echon "\rProcessing files in directory " . fnamemodify(dir_name, ':t') +    let fcnt = s:Tlist_Process_Dir(dir_name, pat) + +    echon "\rAdded " . fcnt . " files to the taglist" +endfunction + +" Tlist_Add_Files +" Add the specified list of files to the taglist +function! s:Tlist_Add_Files(...) +    let flist = '' +    let i = 1 + +    " Get all the files matching the file patterns supplied as argument +    while i <= a:0 +        let flist = flist . glob(a:{i}) . "\n" +        let i = i + 1 +    endwhile + +    if flist == '' +        call s:Tlist_Warning_Msg('Error: No matching files are found') +        return +    endif + +    let fcnt = s:Tlist_Process_Filelist(flist) +    echon "\rAdded " . fcnt . " files to the taglist" +endfunction + +" Tlist_Extract_Tagtype +" Extract the tag type from the tag text +function! s:Tlist_Extract_Tagtype(tag_line) +    " The tag type is after the tag prototype field. The prototype field +    " ends with the /;"\t string. We add 4 at the end to skip the characters +    " in this special string.. +    let start = strridx(a:tag_line, '/;"' . "\t") + 4 +    let end = strridx(a:tag_line, 'line:') - 1 +    let ttype = strpart(a:tag_line, start, end - start) + +    return ttype +endfunction + +" Tlist_Extract_Tag_Scope +" Extract the tag scope from the tag text +function! s:Tlist_Extract_Tag_Scope(tag_line) +    let start = strridx(a:tag_line, 'line:') +    let end = strridx(a:tag_line, "\t") +    if end <= start +        return '' +    endif + +    let tag_scope = strpart(a:tag_line, end + 1) +    let tag_scope = strpart(tag_scope, stridx(tag_scope, ':') + 1) + +    return tag_scope +endfunction + +" Tlist_Refresh() +" Refresh the taglist +function! s:Tlist_Refresh() +    call s:Tlist_Log_Msg('Tlist_Refresh (Skip_Refresh = ' . +                \ s:Tlist_Skip_Refresh . ', ' . bufname('%') . ')') +    " If we are entering the buffer from one of the taglist functions, then +    " no need to refresh the taglist window again. +    if s:Tlist_Skip_Refresh +        " We still need to update the taglist menu +        if g:Tlist_Show_Menu +            call s:Tlist_Menu_Update_File(0) +        endif +        return +    endif + +    " If part of the winmanager plugin and not configured to process +    " tags always and not configured to display the tags menu, then return +    if (s:tlist_app_name == 'winmanager') && !g:Tlist_Process_File_Always +                \ && !g:Tlist_Show_Menu +        return +    endif + +    " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help +    if &buftype != '' +        return +    endif + +    let filename = fnamemodify(bufname('%'), ':p') +    let ftype = s:Tlist_Get_Buffer_Filetype('%') + +    " If the file doesn't support tag listing, skip it +    if s:Tlist_Skip_File(filename, ftype) +        return +    endif + +    let tlist_win = bufwinnr(g:TagList_title) + +    " If the taglist window is not opened and not configured to process +    " tags always and not displaying the tags menu, then return +    if tlist_win == -1 && !g:Tlist_Process_File_Always && !g:Tlist_Show_Menu +        return +    endif + +    let fidx = s:Tlist_Get_File_Index(filename) +    if fidx == -1 +        " Check whether this file is removed based on user request +        " If it is, then don't display the tags for this file +        if s:Tlist_User_Removed_File(filename) +            return +        endif + +        " If the taglist should not be auto updated, then return +        if !g:Tlist_Auto_Update +            return +        endif +    endif + +    let cur_lnum = line('.') + +    if fidx == -1 +        " Update the tags for the file +        let fidx = s:Tlist_Process_File(filename, ftype) +    else +        let mtime = getftime(filename) +        if s:tlist_{fidx}_mtime != mtime +            " Invalidate the tags listed for this file +            let s:tlist_{fidx}_valid = 0 + +            " Update the taglist and the window +            call Tlist_Update_File(filename, ftype) + +            " Store the new file modification time +            let s:tlist_{fidx}_mtime = mtime +        endif +    endif + +    " Update the taglist window +    if tlist_win != -1 +        " Disable screen updates +        let old_lazyredraw = &lazyredraw +        set nolazyredraw + +        " Save the current window number +        let save_winnr = winnr() + +        " Goto the taglist window +        call s:Tlist_Window_Goto_Window() + +        if !g:Tlist_Auto_Highlight_Tag || !g:Tlist_Highlight_Tag_On_BufEnter +            " Save the cursor position +            let save_line = line('.') +            let save_col = col('.') +        endif + +        " Update the taglist window +        call s:Tlist_Window_Refresh_File(filename, ftype) + +        " Open the fold for the file +        exe "silent! " . s:tlist_{fidx}_start . "," . +                    \ s:tlist_{fidx}_end . "foldopen!" + +        if g:Tlist_Highlight_Tag_On_BufEnter && g:Tlist_Auto_Highlight_Tag +            if g:Tlist_Show_One_File && s:tlist_cur_file_idx != fidx +                " If displaying tags for only one file in the taglist +                " window and about to display the tags for a new file, +                " then center the current tag line for the new file +                let center_tag_line = 1 +            else +                let center_tag_line = 0 +            endif + +            " Highlight the current tag +            call s:Tlist_Window_Highlight_Tag(filename, cur_lnum, 1, center_tag_line) +        else +            " Restore the cursor position +            if v:version >= 601 +                call cursor(save_line, save_col) +            else +                exe save_line +                exe 'normal! ' . save_col . '|' +            endif +        endif + +        " Jump back to the original window +        if save_winnr != winnr() +            call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w') +        endif + +        " Restore screen updates +        let &lazyredraw = old_lazyredraw +    endif + +    " Update the taglist menu +    if g:Tlist_Show_Menu +        call s:Tlist_Menu_Update_File(0) +    endif +endfunction + +" Tlist_Change_Sort() +" Change the sort order of the tag listing +" caller == 'cmd', command used in the taglist window +" caller == 'menu', taglist menu +" action == 'toggle', toggle sort from name to order and vice versa +" action == 'set', set the sort order to sort_type +function! s:Tlist_Change_Sort(caller, action, sort_type) +    call s:Tlist_Log_Msg('Tlist_Change_Sort (caller = ' . a:caller . +            \ ', action = ' . a:action . ', sort_type = ' . a:sort_type . ')') +    if a:caller == 'cmd' +        let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.')) +        if fidx == -1 +            return +        endif + +        " Remove the previous highlighting +        match none +    elseif a:caller == 'menu' +        let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p')) +        if fidx == -1 +            return +        endif +    endif + +    if a:action == 'toggle' +        let sort_type = s:tlist_{fidx}_sort_type + +        " Toggle the sort order from 'name' to 'order' and vice versa +        if sort_type == 'name' +            let s:tlist_{fidx}_sort_type = 'order' +        else +            let s:tlist_{fidx}_sort_type = 'name' +        endif +    else +        let s:tlist_{fidx}_sort_type = a:sort_type +    endif + +    " Invalidate the tags listed for this file +    let s:tlist_{fidx}_valid = 0 + +    if a:caller  == 'cmd' +        " Save the current line for later restoration +        let curline = '\V\^' . getline('.') . '\$' + +        call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename, +                    \   s:tlist_{fidx}_filetype) + +        exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!' + +        " Go back to the cursor line before the tag list is sorted +        call search(curline, 'w') + +        call s:Tlist_Menu_Update_File(1) +    else +        call s:Tlist_Menu_Remove_File() + +        call s:Tlist_Refresh() +    endif +endfunction + +" Tlist_Update_Current_File() +" Update taglist for the current buffer by regenerating the tag list +" Contributed by WEN Guopeng. +function! s:Tlist_Update_Current_File() +    call s:Tlist_Log_Msg('Tlist_Update_Current_File()') +    if winnr() == bufwinnr(g:TagList_title) +        " In the taglist window. Update the current file +        call s:Tlist_Window_Update_File() +    else +        " Not in the taglist window. Update the current buffer +        let filename = fnamemodify(bufname('%'), ':p') +        let fidx = s:Tlist_Get_File_Index(filename) +        if fidx != -1 +            let s:tlist_{fidx}_valid = 0 +        endif +        let ft = s:Tlist_Get_Buffer_Filetype('%') +        call Tlist_Update_File(filename, ft) +    endif +endfunction + +" Tlist_Window_Update_File() +" Update the tags displayed in the taglist window +function! s:Tlist_Window_Update_File() +    call s:Tlist_Log_Msg('Tlist_Window_Update_File()') +    let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.')) +    if fidx == -1 +        return +    endif + +    " Remove the previous highlighting +    match none + +    " Save the current line for later restoration +    let curline = '\V\^' . getline('.') . '\$' + +    let s:tlist_{fidx}_valid = 0 + +    " Update the taglist window +    call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename, +                \ s:tlist_{fidx}_filetype) + +    exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!' + +    " Go back to the tag line before the list is updated +    call search(curline, 'w') +endfunction + +" Tlist_Window_Get_Tag_Type_By_Linenum() +" Return the tag type index for the specified line in the taglist window +function! s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum) +    let ftype = s:tlist_{a:fidx}_filetype + +    " Determine to which tag type the current line number belongs to using the +    " tag type start line number and the number of tags in a tag type +    let i = 1 +    while i <= s:tlist_{ftype}_count +        let ttype = s:tlist_{ftype}_{i}_name +        let start_lnum = +                    \ s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_offset +        let end =  start_lnum + s:tlist_{a:fidx}_{ttype}_count +        if a:lnum >= start_lnum && a:lnum <= end +            break +        endif +        let i = i + 1 +    endwhile + +    " Current line doesn't belong to any of the displayed tag types +    if i > s:tlist_{ftype}_count +        return '' +    endif + +    return ttype +endfunction + +" Tlist_Window_Get_Tag_Index() +" Return the tag index for the specified line in the taglist window +function! s:Tlist_Window_Get_Tag_Index(fidx, lnum) +    let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(a:fidx, a:lnum) + +    " Current line doesn't belong to any of the displayed tag types +    if ttype == '' +        return 0 +    endif + +    " Compute the index into the displayed tags for the tag type +    let ttype_lnum = s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_offset +    let tidx = a:lnum - ttype_lnum +    if tidx == 0 +        return 0 +    endif + +    " Get the corresponding tag line and return it +    return s:tlist_{a:fidx}_{ttype}_{tidx} +endfunction + +" Tlist_Window_Highlight_Line +" Highlight the current line +function! s:Tlist_Window_Highlight_Line() +    " Clear previously selected name +    match none + +    " Highlight the current line +    if g:Tlist_Display_Prototype == 0 +        let pat = '/\%' . line('.') . 'l\s\+\zs.*/' +    else +        let pat = '/\%' . line('.') . 'l.*/' +    endif + +    exe 'match TagListTagName ' . pat +endfunction + +" Tlist_Window_Open_File +" Open the specified file in either a new window or an existing window +" and place the cursor at the specified tag pattern +function! s:Tlist_Window_Open_File(win_ctrl, filename, tagpat) +    call s:Tlist_Log_Msg('Tlist_Window_Open_File (' . a:filename . ',' . +                \ a:win_ctrl . ')') +    let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh +    let s:Tlist_Skip_Refresh = 1 + +    if s:tlist_app_name == "winmanager" +        " Let the winmanager edit the file +        call WinManagerFileEdit(a:filename, a:win_ctrl == 'newwin') +    else + +    if a:win_ctrl == 'newtab' +        " Create a new tab +        exe 'tabnew ' . escape(a:filename, ' ') +        " Open the taglist window in the new tab +        call s:Tlist_Window_Open() +    endif + +    if a:win_ctrl == 'checktab' +        " Check whether the file is present in any of the tabs. +        " If the file is present in the current tab, then use the +        " current tab. +        if bufwinnr(a:filename) != -1 +            let file_present_in_tab = 1 +            let i = tabpagenr() +        else +            let i = 1 +            let bnum = bufnr(a:filename) +            let file_present_in_tab = 0 +            while i <= tabpagenr('$') +                if index(tabpagebuflist(i), bnum) != -1 +                    let file_present_in_tab = 1 +                    break +                endif +                let i += 1 +            endwhile +        endif + +        if file_present_in_tab +            " Goto the tab containing the file +            exe 'tabnext ' . i +        else +            " Open a new tab +            exe 'tabnew ' . escape(a:filename, ' ') + +            " Open the taglist window +            call s:Tlist_Window_Open() +        endif +    endif + +    let winnum = -1 +    if a:win_ctrl == 'prevwin' +        " Open the file in the previous window, if it is usable +        let cur_win = winnr() +        wincmd p +        if &buftype == '' && !&previewwindow +            exe "edit " . escape(a:filename, ' ') +            let winnum = winnr() +        else +            " Previous window is not usable +            exe cur_win . 'wincmd w' +        endif +    endif + +    " Goto the window containing the file.  If the window is not there, open a +    " new window +    if winnum == -1 +        let winnum = bufwinnr(a:filename) +    endif + +    if winnum == -1 +        " Locate the previously used window for opening a file +        let fwin_num = 0 +        let first_usable_win = 0 + +        let i = 1 +        let bnum = winbufnr(i) +        while bnum != -1 +            if getwinvar(i, 'tlist_file_window') == 'yes' +                let fwin_num = i +                break +            endif +            if first_usable_win == 0 && +                        \ getbufvar(bnum, '&buftype') == '' && +                        \ !getwinvar(i, '&previewwindow') +                " First non-taglist, non-plugin and non-preview window +                let first_usable_win = i +            endif +            let i = i + 1 +            let bnum = winbufnr(i) +        endwhile + +        " If a previously used window is not found, then use the first +        " non-taglist window +        if fwin_num == 0 +            let fwin_num = first_usable_win +        endif + +        if fwin_num != 0 +            " Jump to the file window +            exe fwin_num . "wincmd w" + +            " If the user asked to jump to the tag in a new window, then split +            " the existing window into two. +            if a:win_ctrl == 'newwin' +                split +            endif +            exe "edit " . escape(a:filename, ' ') +        else +            " Open a new window +            if g:Tlist_Use_Horiz_Window +                exe 'leftabove split ' . escape(a:filename, ' ') +            else +                if winbufnr(2) == -1 +                    " Only the taglist window is present +                    if g:Tlist_Use_Right_Window +                        exe 'leftabove vertical split ' . +                                    \ escape(a:filename, ' ') +                    else +                        exe 'rightbelow vertical split ' . +                                    \ escape(a:filename, ' ') +                    endif + +                    " Go to the taglist window to change the window size to +                    " the user configured value +                    call s:Tlist_Exe_Cmd_No_Acmds('wincmd p') +                    if g:Tlist_Use_Horiz_Window +                        exe 'resize ' . g:Tlist_WinHeight +                    else +                        exe 'vertical resize ' . g:Tlist_WinWidth +                    endif +                    " Go back to the file window +                    call s:Tlist_Exe_Cmd_No_Acmds('wincmd p') +                else +                    " A plugin or help window is also present +                    wincmd w +                    exe 'leftabove split ' . escape(a:filename, ' ') +                endif +            endif +        endif +        " Mark the window, so that it can be reused. +        call s:Tlist_Window_Mark_File_Window() +    else +        if v:version >= 700 +            " If the file is opened in more than one window, then check +            " whether the last accessed window has the selected file. +            " If it does, then use that window. +            let lastwin_bufnum = winbufnr(winnr('#')) +            if bufnr(a:filename) == lastwin_bufnum +                let winnum = winnr('#') +            endif +        endif +        exe winnum . 'wincmd w' + +        " If the user asked to jump to the tag in a new window, then split the +        " existing window into two. +        if a:win_ctrl == 'newwin' +            split +        endif +    endif +    endif + +    " Jump to the tag +    if a:tagpat != '' +        " Add the current cursor position to the jump list, so that user can +        " jump back using the ' and ` marks. +        mark ' +        silent call search(a:tagpat, 'w') + +        " Bring the line to the middle of the window +        normal! z. + +        " If the line is inside a fold, open the fold +        if foldclosed('.') != -1 +            .foldopen +        endif +    endif + +    " If the user selects to preview the tag then jump back to the +    " taglist window +    if a:win_ctrl == 'preview' +        " Go back to the taglist window +        let winnum = bufwinnr(g:TagList_title) +        exe winnum . 'wincmd w' +    else +        " If the user has selected to close the taglist window, when a +        " tag is selected, close the taglist  window +        if g:Tlist_Close_On_Select +            call s:Tlist_Window_Goto_Window() +            close + +            " Go back to the window displaying the selected file +            let wnum = bufwinnr(a:filename) +            if wnum != -1 && wnum != winnr() +                call s:Tlist_Exe_Cmd_No_Acmds(wnum . 'wincmd w') +            endif +        endif +    endif + +    let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh +endfunction + +" Tlist_Window_Jump_To_Tag() +" Jump to the location of the current tag +" win_ctrl == useopen - Reuse the existing file window +" win_ctrl == newwin - Open a new window +" win_ctrl == preview - Preview the tag +" win_ctrl == prevwin - Open in previous window +" win_ctrl == newtab - Open in new tab +function! s:Tlist_Window_Jump_To_Tag(win_ctrl) +    call s:Tlist_Log_Msg('Tlist_Window_Jump_To_Tag(' . a:win_ctrl . ')') +    " Do not process comment lines and empty lines +    let curline = getline('.') +    if curline =~ '^\s*$' || curline[0] == '"' +        return +    endif + +    " If inside a closed fold, then use the first line of the fold +    " and jump to the file. +    let lnum = foldclosed('.') +    if lnum == -1 +        " Jump to the selected tag or file +        let lnum = line('.') +    else +        " Open the closed fold +        .foldopen! +    endif + +    let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum) +    if fidx == -1 +        return +    endif + +    " Get the tag output for the current tag +    let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum) +    if tidx != 0 +        let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, tidx) + +        " Highlight the tagline +        call s:Tlist_Window_Highlight_Line() +    else +        " Selected a line which is not a tag name. Just edit the file +        let tagpat = '' +    endif + +    call s:Tlist_Window_Open_File(a:win_ctrl, s:tlist_{fidx}_filename, tagpat) +endfunction + +" Tlist_Window_Show_Info() +" Display information about the entry under the cursor +function! s:Tlist_Window_Show_Info() +    call s:Tlist_Log_Msg('Tlist_Window_Show_Info()') + +    " Clear the previously displayed line +    echo + +    " Do not process comment lines and empty lines +    let curline = getline('.') +    if curline =~ '^\s*$' || curline[0] == '"' +        return +    endif + +    " If inside a fold, then don't display the prototype +    if foldclosed('.') != -1 +        return +    endif + +    let lnum = line('.') + +    " Get the file index +    let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum) +    if fidx == -1 +        return +    endif + +    if lnum == s:tlist_{fidx}_start +        " Cursor is on a file name +        let fname = s:tlist_{fidx}_filename +        if strlen(fname) > 50 +            let fname = fnamemodify(fname, ':t') +        endif +        echo fname . ', Filetype=' . s:tlist_{fidx}_filetype . +                    \  ', Tag count=' . s:tlist_{fidx}_tag_count +        return +    endif + +    " Get the tag output line for the current tag +    let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum) +    if tidx == 0 +        " Cursor is on a tag type +        let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum) +        if ttype == '' +            return +        endif + +        let ttype_name = '' + +        let ftype = s:tlist_{fidx}_filetype +        let i = 1 +        while i <= s:tlist_{ftype}_count +            if ttype == s:tlist_{ftype}_{i}_name +                let ttype_name = s:tlist_{ftype}_{i}_fullname +                break +            endif +            let i = i + 1 +        endwhile + +        echo 'Tag type=' . ttype_name . +                    \ ', Tag count=' . s:tlist_{fidx}_{ttype}_count +        return +    endif + +    " Get the tag search pattern and display it +    echo s:Tlist_Get_Tag_Prototype(fidx, tidx) +endfunction + +" Tlist_Find_Nearest_Tag_Idx +" Find the tag idx nearest to the supplied line number +" Returns -1, if a tag couldn't be found for the specified line number +function! s:Tlist_Find_Nearest_Tag_Idx(fidx, linenum) +    let sort_type = s:tlist_{a:fidx}_sort_type + +    let left = 1 +    let right = s:tlist_{a:fidx}_tag_count + +    if sort_type == 'order' +        " Tags sorted by order, use a binary search. +        " The idea behind this function is taken from the ctags.vim script (by +        " Alexey Marinichev) available at the Vim online website. + +        " If the current line is the less than the first tag, then no need to +        " search +        let first_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, 1) + +        if a:linenum < first_lnum +            return -1 +        endif + +        while left < right +            let middle = (right + left + 1) / 2 +            let middle_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, middle) + +            if middle_lnum == a:linenum +                let left = middle +                break +            endif + +            if middle_lnum > a:linenum +                let right = middle - 1 +            else +                let left = middle +            endif +        endwhile +    else +        " Tags sorted by name, use a linear search. (contributed by Dave +        " Eggum). +        " Look for a tag with a line number less than or equal to the supplied +        " line number. If multiple tags are found, then use the tag with the +        " line number closest to the supplied line number. IOW, use the tag +        " with the highest line number. +        let closest_lnum = 0 +        let final_left = 0 +        while left <= right +            let lnum = s:Tlist_Get_Tag_Linenum(a:fidx, left) + +            if lnum < a:linenum && lnum > closest_lnum +                let closest_lnum = lnum +                let final_left = left +            elseif lnum == a:linenum +                let closest_lnum = lnum +                let final_left = left +                break +            else +                let left = left + 1 +            endif +        endwhile +        if closest_lnum == 0 +            return -1 +        endif +        if left >= right +            let left = final_left +        endif +    endif + +    return left +endfunction + +" Tlist_Window_Highlight_Tag() +" Highlight the current tag +" cntx == 1, Called by the taglist plugin itself +" cntx == 2, Forced by the user through the TlistHighlightTag command +" center = 1, move the tag line to the center of the taglist window +function! s:Tlist_Window_Highlight_Tag(filename, cur_lnum, cntx, center) +    " Highlight the current tag only if the user configured the +    " taglist plugin to do so or if the user explictly invoked the +    " command to highlight the current tag. +    if !g:Tlist_Auto_Highlight_Tag && a:cntx == 1 +        return +    endif + +    if a:filename == '' +        return +    endif + +    " Make sure the taglist window is present +    let winnum = bufwinnr(g:TagList_title) +    if winnum == -1 +        call s:Tlist_Warning_Msg('Error: Taglist window is not open') +        return +    endif + +    let fidx = s:Tlist_Get_File_Index(a:filename) +    if fidx == -1 +        return +    endif + +    " If the file is currently not displayed in the taglist window, then retrn +    if !s:tlist_{fidx}_visible +        return +    endif + +    " If there are no tags for this file, then no need to proceed further +    if s:tlist_{fidx}_tag_count == 0 +        return +    endif + +    " Ignore all autocommands +    let old_ei = &eventignore +    set eventignore=all + +    " Save the original window number +    let org_winnr = winnr() + +    if org_winnr == winnum +        let in_taglist_window = 1 +    else +        let in_taglist_window = 0 +    endif + +    " Go to the taglist window +    if !in_taglist_window +        exe winnum . 'wincmd w' +    endif + +    " Clear previously selected name +    match none + +    let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, a:cur_lnum) +    if tidx == -1 +        " Make sure the current tag line is visible in the taglist window. +        " Calling the winline() function makes the line visible.  Don't know +        " of a better way to achieve this. +        let lnum = line('.') + +        if lnum < s:tlist_{fidx}_start || lnum > s:tlist_{fidx}_end +            " Move the cursor to the beginning of the file +            exe s:tlist_{fidx}_start +        endif + +        if foldclosed('.') != -1 +            .foldopen +        endif + +        call winline() + +        if !in_taglist_window +            exe org_winnr . 'wincmd w' +        endif + +        " Restore the autocommands +        let &eventignore = old_ei +        return +    endif + +    " Extract the tag type +    let ttype = s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx) + +    " Compute the line number +    " Start of file + Start of tag type + offset +    let lnum = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_offset + +                \ s:tlist_{fidx}_{tidx}_ttype_idx + +    " Goto the line containing the tag +    exe lnum + +    " Open the fold +    if foldclosed('.') != -1 +        .foldopen +    endif + +    if a:center +        " Move the tag line to the center of the taglist window +        normal! z. +    else +        " Make sure the current tag line is visible in the taglist window. +        " Calling the winline() function makes the line visible.  Don't know +        " of a better way to achieve this. +        call winline() +    endif + +    " Highlight the tag name +    call s:Tlist_Window_Highlight_Line() + +    " Go back to the original window +    if !in_taglist_window +        exe org_winnr . 'wincmd w' +    endif + +    " Restore the autocommands +    let &eventignore = old_ei +    return +endfunction + +" Tlist_Get_Tag_Prototype_By_Line +" Get the prototype for the tag on or before the specified line number in the +" current buffer +function! Tlist_Get_Tag_Prototype_By_Line(...) +    if a:0 == 0 +        " Arguments are not supplied. Use the current buffer name +        " and line number +        let filename = bufname('%') +        let linenr = line('.') +    elseif a:0 == 2 +        " Filename and line number are specified +        let filename = a:1 +        let linenr = a:2 +        if linenr !~ '\d\+' +            " Invalid line number +            return "" +        endif +    else +        " Sufficient arguments are not supplied +        let msg =  'Usage: Tlist_Get_Tag_Prototype_By_Line <filename> ' . +                                \ '<line_number>' +        call s:Tlist_Warning_Msg(msg) +        return "" +    endif + +    " Expand the file to a fully qualified name +    let filename = fnamemodify(filename, ':p') +    if filename == '' +        return "" +    endif + +    let fidx = s:Tlist_Get_File_Index(filename) +    if fidx == -1 +        return "" +    endif + +    " If there are no tags for this file, then no need to proceed further +    if s:tlist_{fidx}_tag_count == 0 +        return "" +    endif + +    " Get the tag text using the line number +    let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr) +    if tidx == -1 +        return "" +    endif + +    return s:Tlist_Get_Tag_Prototype(fidx, tidx) +endfunction + +" Tlist_Get_Tagname_By_Line +" Get the tag name on or before the specified line number in the +" current buffer +function! Tlist_Get_Tagname_By_Line(...) +    if a:0 == 0 +        " Arguments are not supplied. Use the current buffer name +        " and line number +        let filename = bufname('%') +        let linenr = line('.') +    elseif a:0 == 2 +        " Filename and line number are specified +        let filename = a:1 +        let linenr = a:2 +        if linenr !~ '\d\+' +            " Invalid line number +            return "" +        endif +    else +        " Sufficient arguments are not supplied +        let msg =  'Usage: Tlist_Get_Tagname_By_Line <filename> <line_number>' +        call s:Tlist_Warning_Msg(msg) +        return "" +    endif + +    " Make sure the current file has a name +    let filename = fnamemodify(filename, ':p') +    if filename == '' +        return "" +    endif + +    let fidx = s:Tlist_Get_File_Index(filename) +    if fidx == -1 +        return "" +    endif + +    " If there are no tags for this file, then no need to proceed further +    if s:tlist_{fidx}_tag_count == 0 +        return "" +    endif + +    " Get the tag name using the line number +    let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr) +    if tidx == -1 +        return "" +    endif + +    return s:tlist_{fidx}_{tidx}_tag_name +endfunction + +" Tlist_Window_Move_To_File +" Move the cursor to the beginning of the current file or the next file +" or the previous file in the taglist window +" dir == -1, move to start of current or previous function +" dir == 1, move to start of next function +function! s:Tlist_Window_Move_To_File(dir) +    if foldlevel('.') == 0 +        " Cursor is on a non-folded line (it is not in any of the files) +        " Move it to a folded line +        if a:dir == -1 +            normal! zk +        else +            " While moving down to the start of the next fold, +            " no need to do go to the start of the next file. +            normal! zj +            return +        endif +    endif + +    let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.')) +    if fidx == -1 +        return +    endif + +    let cur_lnum = line('.') + +    if a:dir == -1 +        if cur_lnum > s:tlist_{fidx}_start +            " Move to the beginning of the current file +            exe s:tlist_{fidx}_start +            return +        endif + +        if fidx != 0 +            " Move to the beginning of the previous file +            let fidx = fidx - 1 +        else +            " Cursor is at the first file, wrap around to the last file +            let fidx = s:tlist_file_count - 1 +        endif + +        exe s:tlist_{fidx}_start +        return +    else +        " Move to the beginning of the next file +        let fidx = fidx + 1 + +        if fidx >= s:tlist_file_count +            " Cursor is at the last file, wrap around to the first file +            let fidx = 0 +        endif + +        if s:tlist_{fidx}_start != 0 +            exe s:tlist_{fidx}_start +        endif +        return +    endif +endfunction + +" Tlist_Session_Load +" Load a taglist session (information about all the displayed files +" and the tags) from the specified file +function! s:Tlist_Session_Load(...) +    if a:0 == 0 || a:1 == '' +        call s:Tlist_Warning_Msg('Usage: TlistSessionLoad <filename>') +        return +    endif + +    let sessionfile = a:1 + +    if !filereadable(sessionfile) +        let msg = 'Taglist: Error - Unable to open file ' . sessionfile +        call s:Tlist_Warning_Msg(msg) +        return +    endif + +    " Mark the current window as the file window +    call s:Tlist_Window_Mark_File_Window() + +    " Source the session file +    exe 'source ' . sessionfile + +    let new_file_count = g:tlist_file_count +    unlet! g:tlist_file_count + +    let i = 0 +    while i < new_file_count +        let ftype = g:tlist_{i}_filetype +        unlet! g:tlist_{i}_filetype + +        if !exists('s:tlist_' . ftype . '_count') +            if s:Tlist_FileType_Init(ftype) == 0 +                let i = i + 1 +                continue +            endif +        endif + +        let fname = g:tlist_{i}_filename +        unlet! g:tlist_{i}_filename + +        let fidx = s:Tlist_Get_File_Index(fname) +        if fidx != -1 +            let s:tlist_{fidx}_visible = 0 +            let i = i + 1 +            continue +        else +            " As we are loading the tags from the session file, if this +            " file was previously deleted by the user, now we need to +            " add it back. So remove the file from the deleted list. +            call s:Tlist_Update_Remove_List(fname, 0) +        endif + +        let fidx = s:Tlist_Init_File(fname, ftype) + +        let s:tlist_{fidx}_filename = fname + +        let s:tlist_{fidx}_sort_type = g:tlist_{i}_sort_type +        unlet! g:tlist_{i}_sort_type + +        let s:tlist_{fidx}_filetype = ftype +        let s:tlist_{fidx}_mtime = getftime(fname) + +        let s:tlist_{fidx}_start = 0 +        let s:tlist_{fidx}_end = 0 + +        let s:tlist_{fidx}_valid = 1 + +        let s:tlist_{fidx}_tag_count = g:tlist_{i}_tag_count +        unlet! g:tlist_{i}_tag_count + +        let j = 1 +        while j <= s:tlist_{fidx}_tag_count +            let s:tlist_{fidx}_{j}_tag = g:tlist_{i}_{j}_tag +            let s:tlist_{fidx}_{j}_tag_name = g:tlist_{i}_{j}_tag_name +            let s:tlist_{fidx}_{j}_ttype_idx = g:tlist_{i}_{j}_ttype_idx +            unlet! g:tlist_{i}_{j}_tag +            unlet! g:tlist_{i}_{j}_tag_name +            unlet! g:tlist_{i}_{j}_ttype_idx +            let j = j + 1 +        endwhile + +        let j = 1 +        while j <= s:tlist_{ftype}_count +            let ttype = s:tlist_{ftype}_{j}_name + +            if exists('g:tlist_' . i . '_' . ttype) +                let s:tlist_{fidx}_{ttype} = g:tlist_{i}_{ttype} +                unlet! g:tlist_{i}_{ttype} +                let s:tlist_{fidx}_{ttype}_offset = 0 +                let s:tlist_{fidx}_{ttype}_count = g:tlist_{i}_{ttype}_count +                unlet! g:tlist_{i}_{ttype}_count + +                let k = 1 +                while k <= s:tlist_{fidx}_{ttype}_count +                    let s:tlist_{fidx}_{ttype}_{k} = g:tlist_{i}_{ttype}_{k} +                    unlet! g:tlist_{i}_{ttype}_{k} +                    let k = k + 1 +                endwhile +            else +                let s:tlist_{fidx}_{ttype} = '' +                let s:tlist_{fidx}_{ttype}_offset = 0 +                let s:tlist_{fidx}_{ttype}_count = 0 +            endif + +            let j = j + 1 +        endwhile + +        let i = i + 1 +    endwhile + +    " If the taglist window is open, then update it +    let winnum = bufwinnr(g:TagList_title) +    if winnum != -1 +        let save_winnr = winnr() + +        " Goto the taglist window +        call s:Tlist_Window_Goto_Window() + +        " Refresh the taglist window +        call s:Tlist_Window_Refresh() + +        " Go back to the original window +        if save_winnr != winnr() +            call s:Tlist_Exe_Cmd_No_Acmds('wincmd p') +        endif +    endif +endfunction + +" Tlist_Session_Save +" Save a taglist session (information about all the displayed files +" and the tags) into the specified file +function! s:Tlist_Session_Save(...) +    if a:0 == 0 || a:1 == '' +        call s:Tlist_Warning_Msg('Usage: TlistSessionSave <filename>') +        return +    endif + +    let sessionfile = a:1 + +    if s:tlist_file_count == 0 +        " There is nothing to save +        call s:Tlist_Warning_Msg('Warning: Taglist is empty. Nothing to save.') +        return +    endif + +    if filereadable(sessionfile) +        let ans = input('Do you want to overwrite ' . sessionfile . ' (Y/N)?') +        if ans !=? 'y' +            return +        endif + +        echo "\n" +    endif + +    let old_verbose = &verbose +    set verbose&vim + +    exe 'redir! > ' . sessionfile + +    silent! echo '" Taglist session file. This file is auto-generated.' +    silent! echo '" File information' +    silent! echo 'let tlist_file_count = ' . s:tlist_file_count + +    let i = 0 + +    while i < s:tlist_file_count +        " Store information about the file +        silent! echo 'let tlist_' . i . "_filename = '" . +                                            \ s:tlist_{i}_filename . "'" +        silent! echo 'let tlist_' . i . '_sort_type = "' . +                                                \ s:tlist_{i}_sort_type . '"' +        silent! echo 'let tlist_' . i . '_filetype = "' . +                                            \ s:tlist_{i}_filetype . '"' +        silent! echo 'let tlist_' . i . '_tag_count = ' . +                                                        \ s:tlist_{i}_tag_count +        " Store information about all the tags +        let j = 1 +        while j <= s:tlist_{i}_tag_count +            let txt = escape(s:tlist_{i}_{j}_tag, '"\\') +            silent! echo 'let tlist_' . i . '_' . j . '_tag = "' . txt . '"' +            silent! echo 'let tlist_' . i . '_' . j . '_tag_name = "' . +                        \ s:tlist_{i}_{j}_tag_name . '"' +            silent! echo 'let tlist_' . i . '_' . j . '_ttype_idx' . ' = ' . +                        \ s:tlist_{i}_{j}_ttype_idx +            let j = j + 1 +        endwhile + +        " Store information about all the tags grouped by their type +        let ftype = s:tlist_{i}_filetype +        let j = 1 +        while j <= s:tlist_{ftype}_count +            let ttype = s:tlist_{ftype}_{j}_name +            if s:tlist_{i}_{ttype}_count != 0 +                let txt = escape(s:tlist_{i}_{ttype}, '"\') +                let txt = substitute(txt, "\n", "\\\\n", 'g') +                silent! echo 'let tlist_' . i . '_' . ttype . ' = "' . +                                                \ txt . '"' +                silent! echo 'let tlist_' . i . '_' . ttype . '_count = ' . +                                                     \ s:tlist_{i}_{ttype}_count +                let k = 1 +                while k <= s:tlist_{i}_{ttype}_count +                    silent! echo 'let tlist_' . i . '_' . ttype . '_' . k . +                                \ ' = ' . s:tlist_{i}_{ttype}_{k} +                    let k = k + 1 +                endwhile +            endif +            let j = j + 1 +        endwhile + +        silent! echo + +        let i = i + 1 +    endwhile + +    redir END + +    let &verbose = old_verbose +endfunction + +" Tlist_Buffer_Removed +" A buffer is removed from the Vim buffer list. Remove the tags defined +" for that file +function! s:Tlist_Buffer_Removed(filename) +    call s:Tlist_Log_Msg('Tlist_Buffer_Removed (' . a:filename .  ')') + +    " Make sure a valid filename is supplied +    if a:filename == '' +        return +    endif + +    " Get tag list index of the specified file +    let fidx = s:Tlist_Get_File_Index(a:filename) +    if fidx == -1 +        " File not present in the taglist +        return +    endif + +    " Remove the file from the list +    call s:Tlist_Remove_File(fidx, 0) +endfunction + +" When a buffer is deleted, remove the file from the taglist +autocmd BufDelete * silent call s:Tlist_Buffer_Removed(expand('<afile>:p')) + +" Tlist_Window_Open_File_Fold +" Open the fold for the specified file and close the fold for all the +" other files +function! s:Tlist_Window_Open_File_Fold(acmd_bufnr) +    call s:Tlist_Log_Msg('Tlist_Window_Open_File_Fold (' . a:acmd_bufnr . ')') + +    " Make sure the taglist window is present +    let winnum = bufwinnr(g:TagList_title) +    if winnum == -1 +        call s:Tlist_Warning_Msg('Taglist: Error - Taglist window is not open') +        return +    endif + +    " Save the original window number +    let org_winnr = winnr() +    if org_winnr == winnum +        let in_taglist_window = 1 +    else +        let in_taglist_window = 0 +    endif + +    if in_taglist_window +        " When entering the taglist window, no need to update the folds +        return +    endif + +    " Go to the taglist window +    if !in_taglist_window +        call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w') +    endif + +    " Close all the folds +    silent! %foldclose + +    " Get tag list index of the specified file +    let fname = fnamemodify(bufname(a:acmd_bufnr + 0), ':p') +    if filereadable(fname) +        let fidx = s:Tlist_Get_File_Index(fname) +        if fidx != -1 +            " Open the fold for the file +            exe "silent! " . s:tlist_{fidx}_start . "," . +                        \ s:tlist_{fidx}_end . "foldopen" +        endif +    endif + +    " Go back to the original window +    if !in_taglist_window +        call s:Tlist_Exe_Cmd_No_Acmds(org_winnr . 'wincmd w') +    endif +endfunction + +" Tlist_Window_Check_Auto_Open +" Open the taglist window automatically on Vim startup. +" Open the window only when files present in any of the Vim windows support +" tags. +function! s:Tlist_Window_Check_Auto_Open() +    let open_window = 0 + +    let i = 1 +    let buf_num = winbufnr(i) +    while buf_num != -1 +        let filename = fnamemodify(bufname(buf_num), ':p') +        let ft = s:Tlist_Get_Buffer_Filetype(buf_num) +        if !s:Tlist_Skip_File(filename, ft) +            let open_window = 1 +            break +        endif +        let i = i + 1 +        let buf_num = winbufnr(i) +    endwhile + +    if open_window +        call s:Tlist_Window_Toggle() +    endif +endfunction + +" Tlist_Refresh_Folds +" Remove and create the folds for all the files displayed in the taglist +" window. Used after entering a tab. If this is not done, then the folds +" are not properly created for taglist windows displayed in multiple tabs. +function! s:Tlist_Refresh_Folds() +    let winnum = bufwinnr(g:TagList_title) +    if winnum == -1 +        return +    endif + +    let save_wnum = winnr() +    exe winnum . 'wincmd w' + +    " First remove all the existing folds +    normal! zE + +    " Create the folds for each in the tag list +    let fidx = 0 +    while fidx < s:tlist_file_count +        let ftype = s:tlist_{fidx}_filetype + +        " Create the folds for each tag type in a file +        let j = 1 +        while j <= s:tlist_{ftype}_count +            let ttype = s:tlist_{ftype}_{j}_name +            if s:tlist_{fidx}_{ttype}_count +                let s = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_offset +                let e = s + s:tlist_{fidx}_{ttype}_count +                exe s . ',' . e . 'fold' +            endif +            let j = j + 1 +        endwhile + +        exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold' +        exe 'silent! ' . s:tlist_{fidx}_start . ',' . +                    \ s:tlist_{fidx}_end . 'foldopen!' +        let fidx = fidx + 1 +    endwhile + +    exe save_wnum . 'wincmd w' +endfunction + +function! s:Tlist_Menu_Add_Base_Menu() +    call s:Tlist_Log_Msg('Adding the base menu') + +    " Add the menu +    anoremenu <silent> T&ags.Refresh\ menu :call <SID>Tlist_Menu_Refresh()<CR> +    anoremenu <silent> T&ags.Sort\ menu\ by.Name +                    \ :call <SID>Tlist_Change_Sort('menu', 'set', 'name')<CR> +    anoremenu <silent> T&ags.Sort\ menu\ by.Order +                    \ :call <SID>Tlist_Change_Sort('menu', 'set', 'order')<CR> +    anoremenu T&ags.-SEP1-           : + +    if &mousemodel =~ 'popup' +        anoremenu <silent> PopUp.T&ags.Refresh\ menu +                    \ :call <SID>Tlist_Menu_Refresh()<CR> +        anoremenu <silent> PopUp.T&ags.Sort\ menu\ by.Name +                  \ :call <SID>Tlist_Change_Sort('menu', 'set', 'name')<CR> +        anoremenu <silent> PopUp.T&ags.Sort\ menu\ by.Order +                  \ :call <SID>Tlist_Change_Sort('menu', 'set', 'order')<CR> +        anoremenu PopUp.T&ags.-SEP1-           : +    endif +endfunction + +let s:menu_char_prefix = +            \ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + +" Tlist_Menu_Get_Tag_Type_Cmd +" Get the menu command for the specified tag type +" fidx - File type index +" ftype - File Type +" add_ttype_name - To add or not to add the tag type name to the menu entries +" ttype_idx - Tag type index +function! s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, ttype_idx) +    " Curly brace variable name optimization +    let ftype_ttype_idx = a:ftype . '_' . a:ttype_idx + +    let ttype = s:tlist_{ftype_ttype_idx}_name +    if a:add_ttype_name +        " If the tag type name contains space characters, escape it. This +        " will be used to create the menu entries. +        let ttype_fullname = escape(s:tlist_{ftype_ttype_idx}_fullname, ' ') +    endif + +    " Curly brace variable name optimization +    let fidx_ttype = a:fidx . '_' . ttype + +    " Number of tag entries for this tag type +    let tcnt = s:tlist_{fidx_ttype}_count +    if tcnt == 0 " No entries for this tag type +        return '' +    endif + +    let mcmd = '' + +    " Create the menu items for the tags. +    " Depending on the number of tags of this type, split the menu into +    " multiple sub-menus, if needed. +    if tcnt > g:Tlist_Max_Submenu_Items +        let j = 1 +        while j <= tcnt +            let final_index = j + g:Tlist_Max_Submenu_Items - 1 +            if final_index > tcnt +                let final_index = tcnt +            endif + +            " Extract the first and last tag name and form the +            " sub-menu name +            let tidx = s:tlist_{fidx_ttype}_{j} +            let first_tag = s:tlist_{a:fidx}_{tidx}_tag_name + +            let tidx = s:tlist_{fidx_ttype}_{final_index} +            let last_tag = s:tlist_{a:fidx}_{tidx}_tag_name + +            " Truncate the names, if they are greater than the +            " max length +            let first_tag = strpart(first_tag, 0, g:Tlist_Max_Tag_Length) +            let last_tag = strpart(last_tag, 0, g:Tlist_Max_Tag_Length) + +            " Form the menu command prefix +            let m_prefix = 'anoremenu <silent> T\&ags.' +            if a:add_ttype_name +                let m_prefix = m_prefix . ttype_fullname . '.' +            endif +            let m_prefix = m_prefix . first_tag . '\.\.\.' . last_tag . '.' + +            " Character prefix used to number the menu items (hotkey) +            let m_prefix_idx = 0 + +            while j <= final_index +                let tidx = s:tlist_{fidx_ttype}_{j} + +                let tname = s:tlist_{a:fidx}_{tidx}_tag_name + +                let mcmd = mcmd . m_prefix . '\&' . +                            \ s:menu_char_prefix[m_prefix_idx] . '\.' . +                            \ tname . ' :call <SID>Tlist_Menu_Jump_To_Tag(' . +                            \ tidx . ')<CR>|' + +                let m_prefix_idx = m_prefix_idx + 1 +                let j = j + 1 +            endwhile +        endwhile +    else +        " Character prefix used to number the menu items (hotkey) +        let m_prefix_idx = 0 + +        let m_prefix = 'anoremenu <silent> T\&ags.' +        if a:add_ttype_name +            let m_prefix = m_prefix . ttype_fullname . '.' +        endif +        let j = 1 +        while j <= tcnt +            let tidx = s:tlist_{fidx_ttype}_{j} + +            let tname = s:tlist_{a:fidx}_{tidx}_tag_name + +            let mcmd = mcmd . m_prefix . '\&' . +                        \ s:menu_char_prefix[m_prefix_idx] . '\.' . +                        \ tname . ' :call <SID>Tlist_Menu_Jump_To_Tag(' . tidx +                        \ . ')<CR>|' + +            let m_prefix_idx = m_prefix_idx + 1 +            let j = j + 1 +        endwhile +    endif + +    return mcmd +endfunction + +" Update the taglist menu with the tags for the specified file +function! s:Tlist_Menu_File_Refresh(fidx) +    call s:Tlist_Log_Msg('Refreshing the tag menu for ' . s:tlist_{a:fidx}_filename) +    " The 'B' flag is needed in the 'cpoptions' option +    let old_cpoptions = &cpoptions +    set cpoptions&vim + +    exe s:tlist_{a:fidx}_menu_cmd + +    " Update the popup menu (if enabled) +    if &mousemodel =~ 'popup' +        let cmd = substitute(s:tlist_{a:fidx}_menu_cmd, ' T\\&ags\.', +                                        \ ' PopUp.T\\\&ags.', "g") +        exe cmd +    endif + +    " The taglist menu is not empty now +    let s:tlist_menu_empty = 0 + +    " Restore the 'cpoptions' settings +    let &cpoptions = old_cpoptions +endfunction + +" Tlist_Menu_Update_File +" Add the taglist menu +function! s:Tlist_Menu_Update_File(clear_menu) +    if !has('gui_running') +        " Not running in GUI mode +        return +    endif + +    call s:Tlist_Log_Msg('Updating the tag menu, clear_menu = ' . a:clear_menu) + +    " Remove the tags menu +    if a:clear_menu +        call s:Tlist_Menu_Remove_File() + +    endif + +    " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help +    if &buftype != '' +        return +    endif + +    let filename = fnamemodify(bufname('%'), ':p') +    let ftype = s:Tlist_Get_Buffer_Filetype('%') + +    " If the file doesn't support tag listing, skip it +    if s:Tlist_Skip_File(filename, ftype) +        return +    endif + +    let fidx = s:Tlist_Get_File_Index(filename) +    if fidx == -1 || !s:tlist_{fidx}_valid +        " Check whether this file is removed based on user request +        " If it is, then don't display the tags for this file +        if s:Tlist_User_Removed_File(filename) +            return +        endif + +        " Process the tags for the file +        let fidx = s:Tlist_Process_File(filename, ftype) +        if fidx == -1 +            return +        endif +    endif + +    let fname = escape(fnamemodify(bufname('%'), ':t'), '.') +    if fname != '' +        exe 'anoremenu T&ags.' .  fname . ' <Nop>' +        anoremenu T&ags.-SEP2-           : +    endif + +    if !s:tlist_{fidx}_tag_count +        return +    endif + +    if s:tlist_{fidx}_menu_cmd != '' +        " Update the menu with the cached command +        call s:Tlist_Menu_File_Refresh(fidx) + +        return +    endif + +    " We are going to add entries to the tags menu, so the menu won't be +    " empty +    let s:tlist_menu_empty = 0 + +    let cmd = '' + +    " Determine whether the tag type name needs to be added to the menu +    " If more than one tag type is present in the taglisting for a file, +    " then the tag type name needs to be present +    let add_ttype_name = -1 +    let i = 1 +    while i <= s:tlist_{ftype}_count && add_ttype_name < 1 +        let ttype = s:tlist_{ftype}_{i}_name +        if s:tlist_{fidx}_{ttype}_count +            let add_ttype_name = add_ttype_name + 1 +        endif +        let i = i + 1 +    endwhile + +    " Process the tags by the tag type and get the menu command +    let i = 1 +    while i <= s:tlist_{ftype}_count +        let mcmd = s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, i) +        if mcmd != '' +            let cmd = cmd . mcmd +        endif + +        let i = i + 1 +    endwhile + +    " Cache the menu command for reuse +    let s:tlist_{fidx}_menu_cmd = cmd + +    " Update the menu +    call s:Tlist_Menu_File_Refresh(fidx) +endfunction + +" Tlist_Menu_Remove_File +" Remove the tags displayed in the tags menu +function! s:Tlist_Menu_Remove_File() +    if !has('gui_running') || s:tlist_menu_empty +        return +    endif + +    call s:Tlist_Log_Msg('Removing the tags menu for a file') + +    " Cleanup the Tags menu +    silent! unmenu T&ags +    if &mousemodel =~ 'popup' +        silent! unmenu PopUp.T&ags +    endif + +    " Add a dummy menu item to retain teared off menu +    noremenu T&ags.Dummy l + +    silent! unmenu! T&ags +    if &mousemodel =~ 'popup' +        silent! unmenu! PopUp.T&ags +    endif + +    call s:Tlist_Menu_Add_Base_Menu() + +    " Remove the dummy menu item +    unmenu T&ags.Dummy + +    let s:tlist_menu_empty = 1 +endfunction + +" Tlist_Menu_Refresh +" Refresh the taglist menu +function! s:Tlist_Menu_Refresh() +    call s:Tlist_Log_Msg('Refreshing the tags menu') +    let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p')) +    if fidx != -1 +        " Invalidate the cached menu command +        let s:tlist_{fidx}_menu_cmd = '' +    endif + +    " Update the taglist, menu and window +    call s:Tlist_Update_Current_File() +endfunction + +" Tlist_Menu_Jump_To_Tag +" Jump to the selected tag +function! s:Tlist_Menu_Jump_To_Tag(tidx) +    let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p')) +    if fidx == -1 +        return +    endif + +    let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, a:tidx) +    if tagpat == '' +        return +    endif + +    " Add the current cursor position to the jump list, so that user can +    " jump back using the ' and ` marks. +    mark ' + +    silent call search(tagpat, 'w') + +    " Bring the line to the middle of the window +    normal! z. + +    " If the line is inside a fold, open the fold +    if foldclosed('.') != -1 +        .foldopen +    endif +endfunction + +" Tlist_Menu_Init +" Initialize the taglist menu +function! s:Tlist_Menu_Init() +    call s:Tlist_Menu_Add_Base_Menu() + +    " Automatically add the tags defined in the current file to the menu +    augroup TagListMenuCmds +        autocmd! + +        if !g:Tlist_Process_File_Always +            autocmd BufEnter * call s:Tlist_Refresh() +        endif +        autocmd BufLeave * call s:Tlist_Menu_Remove_File() +    augroup end + +    call s:Tlist_Menu_Update_File(0) +endfunction + +" Tlist_Vim_Session_Load +" Initialize the taglist window/buffer, which is created when loading +" a Vim session file. +function! s:Tlist_Vim_Session_Load() +    call s:Tlist_Log_Msg('Tlist_Vim_Session_Load') + +    " Initialize the taglist window +    call s:Tlist_Window_Init() + +    " Refresh the taglist window +    call s:Tlist_Window_Refresh() +endfunction + +" Tlist_Set_App +" Set the name of the external plugin/application to which taglist +" belongs. +" Taglist plugin is part of another plugin like cream or winmanager. +function! Tlist_Set_App(name) +    if a:name == "" +        return +    endif + +    let s:tlist_app_name = a:name +endfunction + +" Winmanager integration + +" Initialization required for integration with winmanager +function! TagList_Start() +    " If current buffer is not taglist buffer, then don't proceed +    if bufname('%') != '__Tag_List__' +        return +    endif + +    call Tlist_Set_App('winmanager') + +    " Get the current filename from the winmanager plugin +    let bufnum = WinManagerGetLastEditedFile() +    if bufnum != -1 +        let filename = fnamemodify(bufname(bufnum), ':p') +        let ftype = s:Tlist_Get_Buffer_Filetype(bufnum) +    endif + +    " Initialize the taglist window, if it is not already initialized +    if !exists('s:tlist_window_initialized') || !s:tlist_window_initialized +        call s:Tlist_Window_Init() +        call s:Tlist_Window_Refresh() +        let s:tlist_window_initialized = 1 +    endif + +    " Update the taglist window +    if bufnum != -1 +        if !s:Tlist_Skip_File(filename, ftype) && g:Tlist_Auto_Update +            call s:Tlist_Window_Refresh_File(filename, ftype) +        endif +    endif +endfunction + +function! TagList_IsValid() +    return 0 +endfunction + +function! TagList_WrapUp() +    return 0 +endfunction + +" restore 'cpo' +let &cpo = s:cpo_save +unlet s:cpo_save + diff --git a/modules/vim/vim.dot.link/plugin/vcsbzr.vim b/modules/vim/vim.dot.link/plugin/vcsbzr.vim new file mode 100644 index 0000000..b8665b8 --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/vcsbzr.vim @@ -0,0 +1,262 @@ +" vim600: set foldmethod=marker: +" +" BZR extension for VCSCommand. +" +" Maintainer:    Bob Hiestand <bob.hiestand@gmail.com> +" License: +" Copyright (c) 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 +" +" VCSCommandBZRExec +"   This variable specifies the BZR executable.  If not set, it defaults to +"   'bzr' executed from the user's executable path. + +" Section: Plugin header {{{1 + +if exists('VCSCommandDisableAll') +	finish +endif + +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('VCSCommandBZRExec', 'bzr')) +  " BZR is not installed +  finish +endif + +let s:save_cpo=&cpo +set cpo&vim + +" Section: Variable initialization {{{1 + +let s:bzrFunctions = {} + +" Section: Utility functions {{{1 + +" Function: s:Executable() {{{2 +" Returns the executable used to invoke bzr suitable for use in a shell +" command. +function! s:Executable() +	return shellescape(VCSCommandGetOption('VCSCommandBZRExec', 'bzr')) +endfunction + +" Function: s:DoCommand(cmd, cmdName, statusText) {{{2 +" Wrapper to VCSCommandDoCommand to add the name of the BZR executable to the +" command argument. +function! s:DoCommand(cmd, cmdName, statusText, options) +  if VCSCommandGetVCSType(expand('%')) == 'BZR' +    let fullCmd = s:Executable() . ' ' . a:cmd +    return VCSCommandDoCommand(fullCmd, a:cmdName, a:statusText, a:options) +  else +    throw 'BZR VCSCommand plugin called on non-BZR item.' +  endif +endfunction + +" Section: VCS function implementations {{{1 + +" Function: s:bzrFunctions.Identify(buffer) {{{2 +function! s:bzrFunctions.Identify(buffer) +  let fileName = resolve(bufname(a:buffer)) +  let l:save_bzr_log=$BZR_LOG +  try +    let $BZR_LOG=has("win32") || has("win95") || has("win64") || has("win16") ? "nul" : "/dev/null" +    let statusText = s:VCSCommandUtility.system(s:Executable() . ' info -- "' . fileName . '"') +  finally +    let $BZR_LOG=l:save_bzr_log +  endtry +  if(v:shell_error) +    return 0 +  else +    return 1 +  endif +endfunction + +" Function: s:bzrFunctions.Add() {{{2 +function! s:bzrFunctions.Add(argList) +  return s:DoCommand(join(['add'] + a:argList, ' '), 'add', join(a:argList, ' '), {}) +endfunction + +" Function: s:bzrFunctions.Annotate(argList) {{{2 +function! s:bzrFunctions.Annotate(argList) +  if len(a:argList) == 0 +    if &filetype == 'BZRannotate' +      " 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 +  endif +  return resultBuffer +endfunction + +" Function: s:bzrFunctions.Commit(argList) {{{2 +function! s:bzrFunctions.Commit(argList) +  let resultBuffer = s:DoCommand('commit -F "' . a:argList[0] . '"', 'commit', '', {}) +  if resultBuffer == 0 +    echomsg 'No commit needed.' +  endif +endfunction + +" Function: s:bzrFunctions.Delete() {{{2 +function! s:bzrFunctions.Delete(argList) +  return s:DoCommand(join(['rm'] + a:argList, ' '), 'rm', join(a:argList, ' '), {}) +endfunction + +" Function: s:bzrFunctions.Diff(argList) {{{2 +function! s:bzrFunctions.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 + +  return s:DoCommand(join(['diff'] + revOptions), 'diff', caption, {'allowNonZeroExit': 1}) +endfunction + +" Function: s:bzrFunctions.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:bzrFunctions.GetBufferInfo() +  let originalBuffer = VCSCommandGetOriginalBuffer(bufnr('%')) +  let fileName = resolve(bufname(originalBuffer)) +  let statusText = s:VCSCommandUtility.system(s:Executable() . ' status -S -- "' . fileName . '"') +  let revision = s:VCSCommandUtility.system(s:Executable() . ' revno -- "' . fileName . '"') +  if(v:shell_error) +    return [] +  endif + +  " File not under BZR control. +  if statusText =~ '^?' +    return ['Unknown'] +  endif + +  let [flags, repository] = matchlist(statusText, '^\(.\{3}\)\s\+\(\S\+\)')[1:2] +  if revision == '' +    " Error +    return ['Unknown'] +  elseif flags =~ '^A' +    return ['New', 'New'] +  else +    return [revision, repository] +  endif +endfunction + +" Function: s:bzrFunctions.Info(argList) {{{2 +function! s:bzrFunctions.Info(argList) +  return s:DoCommand(join(['version-info'] + a:argList, ' '), 'version-info', join(a:argList, ' '), {}) +endfunction + +" Function: s:bzrFunctions.Lock(argList) {{{2 +function! s:bzrFunctions.Lock(argList) +  echomsg 'bzr lock is not necessary' +endfunction + +" Function: s:bzrFunctions.Log() {{{2 +function! s:bzrFunctions.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:bzrFunctions.Revert(argList) {{{2 +function! s:bzrFunctions.Revert(argList) +  return s:DoCommand('revert', 'revert', '', {}) +endfunction + +" Function: s:bzrFunctions.Review(argList) {{{2 +function! s:bzrFunctions.Review(argList) +  if len(a:argList) == 0 +    let versiontag = '(current)' +    let versionOption = '' +  else +    let versiontag = a:argList[0] +    let versionOption = ' -r ' . versiontag . ' ' +  endif + +  return s:DoCommand('cat' . versionOption, 'review', versiontag, {}) +endfunction + +" Function: s:bzrFunctions.Status(argList) {{{2 +function! s:bzrFunctions.Status(argList) +  let options = ['-S'] +  if len(a:argList) != 0 +    let options = a:argList +  endif +  return s:DoCommand(join(['status'] + options, ' '), 'status', join(options, ' '), {}) +endfunction + +" Function: s:bzrFunctions.Unlock(argList) {{{2 +function! s:bzrFunctions.Unlock(argList) +  echomsg 'bzr unlock is not necessary' +endfunction +" Function: s:bzrFunctions.Update(argList) {{{2 +function! s:bzrFunctions.Update(argList) +  return s:DoCommand('update', 'update', '', {}) +endfunction + +" Annotate setting {{{2 +let s:bzrFunctions.AnnotateSplitRegex = '^[^|]\+ | ' + +" Section: Plugin Registration {{{1 +let s:VCSCommandUtility = VCSCommandRegisterModule('BZR', expand('<sfile>'), s:bzrFunctions, []) + +let &cpo = s:save_cpo diff --git a/modules/vim/vim.dot.link/plugin/vcscommand.vim b/modules/vim/vim.dot.link/plugin/vcscommand.vim new file mode 100644 index 0000000..98214f2 --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/vcscommand.vim @@ -0,0 +1,1427 @@ +" vim600: set foldmethod=marker: +" +" Vim plugin to assist in working with files under control of various Version +" Control Systems, such as CVS, SVN, SVK, and git. +" +" Maintainer:    Bob Hiestand <bob.hiestand@gmail.com> +" License: +" Copyright (c) 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.  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. +" +"                  If '!' is used, the view of the annotated buffer is split +"                  so that the annotation is in a separate window from the +"                  content, and each is highlighted separately. +" +" 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>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. +" +" VCSCommandDisableAll +"   This variable, if set, prevents the plugin or any extensions from loading +"   at all.  This is useful when a single runtime distribution is used on +"   multiple systems with varying versions. +" +" 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. +" +" VCSCommandDisableMenu +"   This variable, if set to a non-zero value, prevents the default command +"   menu from being set. +" +" 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. +" +" VCSCommandMappings +"   This variable, if set, overrides the default mappings used for shortcuts. +"   It should be a List of 2-element Lists, each containing a shortcut and +"   function name pair. +" +" VCSCommandMapPrefix +"   This variable, if set, overrides the default mapping prefix ('<Leader>c'). +"   This allows customization of the mapping space used by the vcscommand +"   shortcuts. +" +" VCSCommandMenuPriority +"   This variable, if set, overrides the default menu priority '' (empty) +" +" VCSCommandMenuRoot +"   This variable, if set, overrides the default menu root 'Plugin.VCS' +" +" 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. +" +" VCSCommandVCSTypeOverride +"   This variable allows the VCS type detection to be overridden on a +"   path-by-path basis.  The value of this variable is expected to be a List +"   of Lists.  Each high-level List item is a List containing two elements. +"   The first element is a regular expression that will be matched against the +"   full file name of a given buffer.  If it matches, the second element will +"   be used as the VCS type. +" +" 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('VCSCommandDisableAll') +	finish +endif + +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 + +" Hidden functions for use by extensions +let s:VCSCommandUtility = {} + +" 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 + +" 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:VCSCommandUtility.system(...) {{{2 +" Replacement for system() function.  This version protects the quoting in the +" command line on Windows systems. + +function! s:VCSCommandUtility.system(...) +	if (has("win32") || has("win64")) && &sxq !~ '"' +		let save_sxq = &sxq +		set sxq=\" +	endif +	try +		return call('system', a:000) +	finally +		if exists("save_sxq") +			let &sxq = save_sxq +		endif +	endtry +endfunction + +" Function: s:VCSCommandUtility.addMenuItem(shortcut, command) {{{2 +" Adds the given menu item. + +function! s:VCSCommandUtility.addMenuItem(shortcut, command) +	if s:menuEnabled +	    exe 'amenu <silent> '.s:menuPriority.' '.s:menuRoot.'.'.a:shortcut.' '.a:command +	endif +endfunction + +" Function: s:ClearMenu() {{{2 +" Removes all VCSCommand menu items +function! s:ClearMenu() +	if s:menuEnabled +		execute 'aunmenu' s:menuRoot +	endif +endfunction + +" Function: s:CreateMapping(shortcut, expansion, display) {{{2 +" Creates the given mapping by prepending the contents of +" 'VCSCommandMapPrefix' (by default '<Leader>c') to the given shortcut and +" mapping it to the given plugin function.  If a mapping exists for the +" specified shortcut + prefix, emit an error but continue.  If a mapping +" exists for the specified function, do nothing. + +function! s:CreateMapping(shortcut, expansion, display) +	let lhs = VCSCommandGetOption('VCSCommandMapPrefix', '<Leader>c') . a:shortcut +	if !hasmapto(a:expansion) +		try +			execute 'nmap <silent> <unique>' lhs a:expansion +		catch /^Vim(.*):E227:/ +			if(&verbose != 0) +				echohl WarningMsg|echomsg 'VCSCommand:  mapping ''' . lhs . ''' already exists, refusing to overwrite.  The mapping for ' . a:display . ' will not be available.'|echohl None +			endif +		endtry +	endif +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 bufexists(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 bufexists(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') + +	" 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 + +		call s:SetupScratchBuffer(a:command, vcsType, a:originalBuffer, a:statusText) + +	finally +		let s:isEditFileRunning -= 1 +	endtry +endfunction + +" Function: s:SetupScratchBuffer(command, vcsType, originalBuffer, statusText) {{{2 +" Creates convenience buffer variables and the name of a vcscommand result +" buffer. + +function! s:SetupScratchBuffer(command, vcsType, originalBuffer, statusText) +	let nameExtension = VCSCommandGetOption('VCSCommandResultBufferNameExtension', '') +	if nameExtension == '' +		let nameFunction = VCSCommandGetOption('VCSCommandResultBufferNameFunction', 's:GenerateResultBufferName') +	else +		let nameFunction = VCSCommandGetOption('VCSCommandResultBufferNameFunction', 's:GenerateResultBufferNameWithExtension') +	endif + +	let name = call(nameFunction, [a:command, a:originalBuffer, a:vcsType, a:statusText]) + +	let b:VCSCommandCommand = a:command +	let b:VCSCommandOriginalBuffer = a:originalBuffer +	let b:VCSCommandSourceFile = bufname(a:originalBuffer) +	let b:VCSCommandVCSType = a:vcsType +	if a:statusText != '' +		let b:VCSCommandStatusText = a:statusText +	endif + +	setlocal buftype=nofile +	setlocal noswapfile +	let &filetype = tolower(a:vcsType . a:command) + +	if VCSCommandGetOption('VCSCommandDeleteOnHide', 0) +		setlocal bufhidden=delete +	endif +	silent noautocmd file `=name` +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('t:vcsCommandVimDiffSourceBuffer') +			if a:vimDiffBuff == t:vcsCommandVimDiffSourceBuffer +				" Original file is being removed. +				unlet! t:vcsCommandVimDiffSourceBuffer +				unlet! t:vcsCommandVimDiffRestoreCmd +				unlet! t:vcsCommandVimDiffScratchList +			else +				let index = index(t:vcsCommandVimDiffScratchList, a:vimDiffBuff) +				if index >= 0 +					call remove(t:vcsCommandVimDiffScratchList, index) +					if len(t:vcsCommandVimDiffScratchList) == 0 +						if exists('t:vcsCommandVimDiffRestoreCmd') +							" All scratch buffers are gone, reset the original. +							" Only restore if the source buffer is still in Diff mode + +							let sourceWinNR = bufwinnr(t:vcsCommandVimDiffSourceBuffer) +							if sourceWinNR != -1 +								" The buffer is visible in at least one window +								let currentWinNR = winnr() +								while winbufnr(sourceWinNR) != -1 +									if winbufnr(sourceWinNR) == t:vcsCommandVimDiffSourceBuffer +										execute sourceWinNR . 'wincmd w' +										if getwinvar(0, '&diff') +											execute t:vcsCommandVimDiffRestoreCmd +										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' t:vcsCommandVimDiffSourceBuffer +								if getwinvar(0, '&diff') +									execute t:vcsCommandVimDiffRestoreCmd +								endif +								execute 'hide buffer' currentBufNR +							endif + +							unlet t:vcsCommandVimDiffRestoreCmd +						endif +						" All buffers are gone. +						unlet t:vcsCommandVimDiffSourceBuffer +						unlet t:vcsCommandVimDiffScratchList +					endif +				endif +			endif +		endif +	finally +		let s:isEditFileRunning -= 1 +	endtry +endfunction + +" Section: Generic VCS command functions {{{1 + +" Function: s:VCSAnnotate(...) {{{2 +function! s:VCSAnnotate(bang, ...) +	try +		let line = line('.') +		let currentBuffer = bufnr('%') +		let originalBuffer = VCSCommandGetOriginalBuffer(currentBuffer) + +		let annotateBuffer = s:ExecuteVCSCommand('Annotate', a:000) +		if annotateBuffer == -1 +			return -1 +		endif +		if a:bang == '!' && VCSCommandGetOption('VCSCommandDisableSplitAnnotate', 0) == 0 +			let vcsType = VCSCommandGetVCSType(annotateBuffer) +			let functionMap = s:plugins[vcsType][1] +			let splitRegex = '' +			if has_key(s:plugins[vcsType][1], 'AnnotateSplitRegex') +				let splitRegex = s:plugins[vcsType][1]['AnnotateSplitRegex'] +			endif +			let splitRegex = VCSCommandGetOption('VCSCommand' . vcsType . 'AnnotateSplitRegex', splitRegex) +			if splitRegex == '' +				return annotateBuffer +			endif +			let originalFileType = getbufvar(originalBuffer, '&ft') +			let annotateFileType = getbufvar(annotateBuffer, '&ft') +			execute "normal 0zR\<c-v>G/" . splitRegex . "/e\<cr>d" +			call setbufvar('%', '&filetype', getbufvar(originalBuffer, '&filetype')) +			set scrollbind +			leftabove vert new +			normal 0P +			execute "normal" . col('$') . "\<c-w>|" +			call s:SetupScratchBuffer('annotate', vcsType, originalBuffer, 'header') +			wincmd l +		endif + +		if currentBuffer == originalBuffer +			" Starting from the original source buffer, so the +			" current line is relevant. +			if a:0 == 0 +				" No argument list means that we're annotating +				" the current version, so jumping to the same +				" line is the expected action. +				execute "normal" line . 'G' +				if has('folding') +					" The execution of the buffer created autocommand +					" re-folds the buffer.  Display the current line +					" unfolded. +					normal zv +				endif +			endif +		endif + +		return annotateBuffer +	catch +		call s:ReportError(v:exception) +		return -1 +	endtry +endfunction + +" 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 +		silent do VCSCommand User VCSBufferCreated +	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 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 +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:VCSDiff(...)  "{{{2 +	let resultBuffer = s:ExecuteVCSCommand('Diff', a:000) +	if resultBuffer > 0 +		let &filetype = 'diff' +	elseif resultBuffer == 0 +		echomsg 'No differences found' +	endif +	return resultBuffer +endfunction + +function! s:VCSReview(...)  "{{{2 +	let resultBuffer = s:ExecuteVCSCommand('Review', a:000) +	if resultBuffer > 0 +		let &filetype = getbufvar(b:VCSCommandOriginalBuffer, '&filetype') +	endif +	return resultBuffer +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('t:vcsCommandVimDiffSourceBuffer') && t:vcsCommandVimDiffSourceBuffer != originalBuffer +				" Clear the existing vimdiff setup by removing the result buffers. +				call s:WipeoutCommandBuffers(t:vcsCommandVimDiffSourceBuffer, 'vimdiff') +			endif + +			let orientation = &diffopt =~ 'horizontal' ? 'horizontal' : 'vertical' +			let orientation = VCSCommandGetOption('VCSCommandSplit', orientation) +			let orientation = VCSCommandGetOption('VCSCommandDiffSplit', orientation) + +			" Split and diff +			if(a:0 == 2) +				" Reset the vimdiff system, as 2 explicit versions were provided. +				if exists('t:vcsCommandVimDiffSourceBuffer') +					call s:WipeoutCommandBuffers(t:vcsCommandVimDiffSourceBuffer, 'vimdiff') +				endif +				let resultBuffer = s:VCSReview(a:1) +				if resultBuffer < 0 +					echomsg 'Can''t open revision ' . a:1 +					return resultBuffer +				endif +				let b:VCSCommandCommand = 'vimdiff' +				diffthis +				let t:vcsCommandVimDiffScratchList = [resultBuffer] +				" If no split method is defined, cheat, and set it to vertical. +				try +					call s:OverrideOption('VCSCommandSplit', orientation) +					let resultBuffer = s:VCSReview(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 t:vcsCommandVimDiffScratchList += [resultBuffer] +			else +				" Add new buffer +				call s:OverrideOption('VCSCommandEdit', 'split') +				try +					" Force splitting behavior, otherwise why use vimdiff? +					call s:OverrideOption('VCSCommandSplit', orientation) +					try +						if(a:0 == 0) +							let resultBuffer = s:VCSReview() +						else +							let resultBuffer = s:VCSReview(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('t:vcsCommandVimDiffSourceBuffer') +					" New instance of vimdiff. +					let t:vcsCommandVimDiffScratchList = [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 t:vcsCommandVimDiffRestoreCmd = +								\    '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 t:vcsCommandVimDiffScratchList += [resultBuffer] +				endif +			endif + +			let t:vcsCommandVimDiffSourceBuffer = 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 +	if exists("g:VCSCommandVCSTypeOverride") +		let fullpath = fnamemodify(bufname(a:buffer), ':p') +		for [path, vcsType] in g:VCSCommandVCSTypeOverride +			if match(fullpath, path) > -1 +				call setbufvar(a:buffer, 'VCSCommandVCSType', vcsType) +				return vcsType +			endif +		endfor +	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 shortcut in keys(a:mappingMap) +			let expansion = ":call <SID>ExecuteExtensionMapping('" . shortcut . "')<CR>" +			call s:CreateMapping(shortcut, expansion, a:name . " extension mapping " . shortcut) +		endfor +	endif +	return s:VCSCommandUtility +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 = s:VCSCommandUtility.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=* -bang VCSAnnotate call s:VCSAnnotate(<q-bang>, <f-args>) +com! -nargs=* -bang VCSBlame call s:VCSAnnotate(<q-bang>, <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:VCSDiff(<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:VCSReview(<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 = {}|call s:ClearMenu()|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>VCSSplitAnnotate :VCSAnnotate!<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 + +let s:defaultMappings = [ +			\['a', 'VCSAdd'], +			\['c', 'VCSCommit'], +			\['D', 'VCSDelete'], +			\['d', 'VCSDiff'], +			\['G', 'VCSClearAndGotoOriginal'], +			\['g', 'VCSGotoOriginal'], +			\['i', 'VCSInfo'], +			\['L', 'VCSLock'], +			\['l', 'VCSLog'], +			\['N', 'VCSSplitAnnotate'], +			\['n', 'VCSAnnotate'], +			\['q', 'VCSRevert'], +			\['r', 'VCSReview'], +			\['s', 'VCSStatus'], +			\['U', 'VCSUnlock'], +			\['u', 'VCSUpdate'], +			\['v', 'VCSVimDiff'], +			\] + +if !VCSCommandGetOption('VCSCommandDisableMappings', 0) +	for [s:shortcut, s:vcsFunction] in VCSCommandGetOption('VCSCommandMappings', s:defaultMappings) +		call s:CreateMapping(s:shortcut, '<Plug>' . s:vcsFunction, '''' . s:vcsFunction . '''') +	endfor +	unlet s:shortcut s:vcsFunction +endif +unlet s:defaultMappings + +" Section: Menu items {{{1 + +let s:menuEnabled = !VCSCommandGetOption('VCSCommandDisableMenu', 0) +let s:menuRoot = VCSCommandGetOption('VCSCommandMenuRoot', '&Plugin.VCS') +let s:menuPriority = VCSCommandGetOption('VCSCommandMenuPriority', '') + +for [s:shortcut, s:command] in [ +			\['&Add', '<Plug>VCSAdd'], +			\['A&nnotate', '<Plug>VCSAnnotate'], +			\['&Commit', '<Plug>VCSCommit'], +			\['Delete', '<Plug>VCSDelete'], +			\['&Diff', '<Plug>VCSDiff'], +			\['&Info', '<Plug>VCSInfo'], +			\['&Log', '<Plug>VCSLog'], +			\['Revert', '<Plug>VCSRevert'], +			\['&Review', '<Plug>VCSReview'], +			\['&Status', '<Plug>VCSStatus'], +			\['&Update', '<Plug>VCSUpdate'], +			\['&VimDiff', '<Plug>VCSVimDiff'] +			\] +	call s:VCSCommandUtility.addMenuItem(s:shortcut, s:command) +endfor +unlet s:shortcut s:command + +" 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 diff --git a/modules/vim/vim.dot.link/plugin/vcscvs.vim b/modules/vim/vim.dot.link/plugin/vcscvs.vim new file mode 100644 index 0000000..73d6a7f --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/vcscvs.vim @@ -0,0 +1,449 @@ +" vim600: set foldmethod=marker: +" +" CVS extension for VCSCommand. +" +" Maintainer:    Bob Hiestand <bob.hiestand@gmail.com> +" License: +" Copyright (c) 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 exists('VCSCommandDisableAll') +	finish +endif + +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:Executable() {{{2 +" Returns the executable used to invoke cvs suitable for use in a shell +" command. +function! s:Executable() +	return shellescape(VCSCommandGetOption('VCSCommandCVSExec', 'cvs')) +endfunction + +" 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 = s:Executable() . ' ' . a:cmd +		let ret = VCSCommandDoCommand(fullCmd, a:cmdName, a:statusText, a:options) + +		if ret > 0 +			if getline(line('$')) =~ '^cvs \w\+: closing down connection' +				$d +				1 +			endif + +		endif + +		return ret +	else +		throw 'CVS VCSCommand plugin called on non-CVS item.' +	endif +endfunction + +" Function: s:GetRevision() {{{2 +" Function for retrieving the current buffer's revision number. +" Returns: Revision number or an empty string if an error occurs. + +function! s: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' .  s: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 +		" 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 + +	return s:DoCommand(join(['diff'] + diffOptions + revOptions), 'diff', caption, {'allowNonZeroExit': 1}) +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=s:VCSCommandUtility.system(s:Executable() . ' 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 + +	return s:DoCommand(join(['log'] + options), 'log', caption, {}) +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 + +	return s:DoCommand('-q update -p' . versionOption, 'review', versiontag, {}) +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 + +" Annotate setting {{{2 +let s:cvsFunctions.AnnotateSplitRegex = '): ' + +" 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', 'e'], +			\['CVSEditors', 'CVSEditors', 'E'], +			\['CVSUnedit', 'CVSUnedit', 't'], +			\['CVSWatchers', 'CVSWatchers', 'wv'], +			\['CVSWatchAdd', 'CVSWatch add', 'wa'], +			\['CVSWatchOff', 'CVSWatch off', 'wf'], +			\['CVSWatchOn', 'CVSWatch on', 'wn'], +			\['CVSWatchRemove', 'CVSWatch remove', 'wr'] +			\] + +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: Plugin Registration {{{1 +let s:VCSCommandUtility = VCSCommandRegisterModule('CVS', expand('<sfile>'), s:cvsFunctions, s:cvsExtensionMappings) + +" Section: Menu items {{{1 +for [s:shortcut, s:command] in [ +			\['CVS.&Edit', '<Plug>CVSEdit'], +			\['CVS.Ed&itors', '<Plug>CVSEditors'], +			\['CVS.Unedi&t', '<Plug>CVSUnedit'], +			\['CVS.&Watchers', '<Plug>CVSWatchers'], +			\['CVS.WatchAdd', '<Plug>CVSWatchAdd'], +			\['CVS.WatchOn', '<Plug>CVSWatchOn'], +			\['CVS.WatchOff', '<Plug>CVSWatchOff'], +			\['CVS.WatchRemove', '<Plug>CVSWatchRemove'] +			\] +	call s:VCSCommandUtility.addMenuItem(s:shortcut, s:command) +endfor +unlet s:shortcut s:command + +let &cpo = s:save_cpo diff --git a/modules/vim/vim.dot.link/plugin/vcsgit.vim b/modules/vim/vim.dot.link/plugin/vcsgit.vim new file mode 100644 index 0000000..4e299d9 --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/vcsgit.vim @@ -0,0 +1,247 @@ +" vim600: set foldmethod=marker: +" +" git extension for VCSCommand. +" +" Maintainer:    Bob Hiestand <bob.hiestand@gmail.com> +" License: +" Copyright (c) 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 exists('VCSCommandDisableAll') +	finish +endif + +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:Executable() {{{2 +" Returns the executable used to invoke git suitable for use in a shell +" command. +function! s:Executable() +	return shellescape(VCSCommandGetOption('VCSCommandGitExec', 'git')) +endfunction + +" 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 = s:Executable() . ' ' . 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 s:VCSCommandUtility.system(s:Executable() . ' 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 + +	return s:DoCommand('blame ' . options, 'annotate', options, {}) +endfunction + +" Function: s:gitFunctions.Commit(argList) {{{2 +function! s:gitFunctions.Commit(argList) +	try +		return s:DoCommand('commit -F "' . a:argList[0] . '"', 'commit', '', {}) +	catch /\m^Version control command failed.*nothing\%( added\)\? to commit/ +		echomsg 'No commit needed.' +	endtry +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 + +	return s:DoCommand(join(['diff'] + diffOptions + a:argList), 'diff', join(a:argList), {}) +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(s:VCSCommandUtility.system(s:Executable() . ' 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(s:VCSCommandUtility.system(s:Executable() . ' 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) +	return s:DoCommand(join(['log'] + a:argList), 'log', join(a:argList, ' '), {}) +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 = s:VCSCommandUtility.system(s:Executable() . ' rev-parse --show-prefix') +	finally +		call VCSCommandChdir(oldCwd) +	endtry + +	let prefix = substitute(prefix, '\n$', '', '') +	let blob = '"' . revision . ':' . prefix . '<VCSCOMMANDFILE>"' +	return s:DoCommand('show ' . blob, 'review', revision, {}) +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 + +" Annotate setting {{{2 +let s:gitFunctions.AnnotateSplitRegex = ') ' + +" Section: Plugin Registration {{{1 +let s:VCSCommandUtility = VCSCommandRegisterModule('git', expand('<sfile>'), s:gitFunctions, []) + +let &cpo = s:save_cpo diff --git a/modules/vim/vim.dot.link/plugin/vcshg.vim b/modules/vim/vim.dot.link/plugin/vcshg.vim new file mode 100644 index 0000000..2c616c0 --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/vcshg.vim @@ -0,0 +1,273 @@ +" vim600: set foldmethod=marker: +" +" Mercurial extension for VCSCommand. +" +" Maintainer:    Bob Hiestand <bob.hiestand@gmail.com> +" License: +" Copyright (c) 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 +" +" VCSCommandHGExec +"   This variable specifies the mercurial executable.  If not set, it defaults +"   to 'hg' executed from the user's executable path. +" +" VCSCommandHGDiffExt +"   This variable, if set, sets the external diff program used by Subversion. +" +" VCSCommandHGDiffOpt +"   This variable, if set, determines the options passed to the hg diff +"   command (such as 'u', 'w', or 'b'). + +" Section: Plugin header {{{1 + +if exists('VCSCommandDisableAll') +	finish +endif + +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('VCSCommandHGExec', 'hg')) +	" HG is not installed +	finish +endif + +let s:save_cpo=&cpo +set cpo&vim + +" Section: Variable initialization {{{1 + +let s:hgFunctions = {} + +" Section: Utility functions {{{1 + +" Function: s:Executable() {{{2 +" Returns the executable used to invoke hg suitable for use in a shell +" command. +function! s:Executable() +	return shellescape(VCSCommandGetOption('VCSCommandHGExec', 'hg')) +endfunction + +" Function: s:DoCommand(cmd, cmdName, statusText, options) {{{2 +" Wrapper to VCSCommandDoCommand to add the name of the HG executable to the +" command argument. +function! s:DoCommand(cmd, cmdName, statusText, options) +	if VCSCommandGetVCSType(expand('%')) == 'HG' +		let fullCmd = s:Executable() . ' ' . a:cmd +		return VCSCommandDoCommand(fullCmd, a:cmdName, a:statusText, a:options) +	else +		throw 'HG VCSCommand plugin called on non-HG item.' +	endif +endfunction + +" Section: VCS function implementations {{{1 + +" Function: s:hgFunctions.Identify(buffer) {{{2 +function! s:hgFunctions.Identify(buffer) +	let oldCwd = VCSCommandChangeToCurrentFileDir(resolve(bufname(a:buffer))) +	try +		call s:VCSCommandUtility.system(s:Executable() . ' root') +		if(v:shell_error) +			return 0 +		else +			return g:VCSCOMMAND_IDENTIFY_INEXACT +		endif +	finally +		call VCSCommandChdir(oldCwd) +	endtry +endfunction + +" Function: s:hgFunctions.Add() {{{2 +function! s:hgFunctions.Add(argList) +	return s:DoCommand(join(['add -v'] + a:argList, ' '), 'add', join(a:argList, ' '), {}) +endfunction + +" Function: s:hgFunctions.Annotate(argList) {{{2 +function! s:hgFunctions.Annotate(argList) +	if len(a:argList) == 0 +		if &filetype == 'HGannotate' +			" 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 = ' -un' +		endif +	elseif len(a:argList) == 1 && a:argList[0] !~ '^-' +		let caption = a:argList[0] +		let options = ' -un -r' . caption +	else +		let caption = join(a:argList, ' ') +		let options = ' ' . caption +	endif + +	return s:DoCommand('blame' . options, 'annotate', caption, {}) +endfunction + +" Function: s:hgFunctions.Commit(argList) {{{2 +function! s:hgFunctions.Commit(argList) +	try +		return s:DoCommand('commit -v -l "' . a:argList[0] . '"', 'commit', '', {}) +	catch /Version control command failed.*nothing changed/ +		echomsg 'No commit needed.' +	endtry +endfunction + +" Function: s:hgFunctions.Delete() {{{2 +function! s:hgFunctions.Delete(argList) +	return s:DoCommand(join(['remove'] + a:argList, ' '), 'remove', join(a:argList, ' '), {}) +endfunction + +" Function: s:hgFunctions.Diff(argList) {{{2 +function! s:hgFunctions.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 hgDiffExt = VCSCommandGetOption('VCSCommandHGDiffExt', '') +	if hgDiffExt == '' +		let diffExt = [] +	else +		let diffExt = ['--diff-cmd ' . hgDiffExt] +	endif + +	let hgDiffOpt = VCSCommandGetOption('VCSCommandHGDiffOpt', '') +	if hgDiffOpt == '' +		let diffOptions = [] +	else +		let diffOptions = ['-x -' . hgDiffOpt] +	endif + +	return s:DoCommand(join(['diff'] + diffExt + diffOptions + revOptions), 'diff', caption, {}) +endfunction + +" Function: s:hgFunctions.Info(argList) {{{2 +function! s:hgFunctions.Info(argList) +	return s:DoCommand(join(['log --limit 1'] + a:argList, ' '), 'log', join(a:argList, ' '), {}) +endfunction + +" Function: s:hgFunctions.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:hgFunctions.GetBufferInfo() +	let originalBuffer = VCSCommandGetOriginalBuffer(bufnr('%')) +	let fileName = bufname(originalBuffer) +	let statusText = s:VCSCommandUtility.system(s:Executable() . ' status -- "' . fileName . '"') +	if(v:shell_error) +		return [] +	endif + +	" File not under HG control. +	if statusText =~ '^?' +		return ['Unknown'] +	endif + +	let parentsText = s:VCSCommandUtility.system(s:Executable() . ' parents -- "' . fileName . '"') +	let revision = matchlist(parentsText, '^changeset:\s\+\(\S\+\)\n')[1] + +	let logText = s:VCSCommandUtility.system(s:Executable() . ' log -- "' . fileName . '"') +	let repository = matchlist(logText, '^changeset:\s\+\(\S\+\)\n')[1] + +	if revision == '' +		" Error +		return ['Unknown'] +	elseif statusText =~ '^A' +		return ['New', 'New'] +	else +		return [revision, repository] +	endif +endfunction + +" Function: s:hgFunctions.Log(argList) {{{2 +function! s:hgFunctions.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:hgFunctions.Revert(argList) {{{2 +function! s:hgFunctions.Revert(argList) +	return s:DoCommand('revert', 'revert', '', {}) +endfunction + +" Function: s:hgFunctions.Review(argList) {{{2 +function! s:hgFunctions.Review(argList) +	if len(a:argList) == 0 +		let versiontag = '(current)' +		let versionOption = '' +	else +		let versiontag = a:argList[0] +		let versionOption = ' -r ' . versiontag . ' ' +	endif + +	return s:DoCommand('cat' . versionOption, 'review', versiontag, {}) +endfunction + +" Function: s:hgFunctions.Status(argList) {{{2 +function! s:hgFunctions.Status(argList) +	let options = ['-A', '-v'] +	if len(a:argList) != 0 +		let options = a:argList +	endif +	return s:DoCommand(join(['status'] + options, ' '), 'status', join(options, ' '), {}) +endfunction + +" Function: s:hgFunctions.Update(argList) {{{2 +function! s:hgFunctions.Update(argList) +	return s:DoCommand('update', 'update', '', {}) +endfunction + +" Annotate setting {{{2 +let s:hgFunctions.AnnotateSplitRegex = '\d\+: ' + +" Section: Plugin Registration {{{1 +let s:VCSCommandUtility = VCSCommandRegisterModule('HG', expand('<sfile>'), s:hgFunctions, []) + +let &cpo = s:save_cpo diff --git a/modules/vim/vim.dot.link/plugin/vcssvk.vim b/modules/vim/vim.dot.link/plugin/vcssvk.vim new file mode 100644 index 0000000..b7cc6c9 --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/vcssvk.vim @@ -0,0 +1,257 @@ +" vim600: set foldmethod=marker: +" +" SVK extension for VCSCommand. +" +" Maintainer:    Bob Hiestand <bob.hiestand@gmail.com> +" License: +" Copyright (c) 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 exists('VCSCommandDisableAll') +	finish +endif + +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:Executable() {{{2 +" Returns the executable used to invoke SVK suitable for use in a shell +" command. +function! s:Executable() +	return shellescape(VCSCommandGetOption('VCSCommandSVKExec', 'svk')) +endfunction + +" 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 = s:Executable() . ' ' . 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 = s:VCSCommandUtility.system(s:Executable() . ' info -- "' . directoryName . '"', "no") +	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 +	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 + +	return s:DoCommand(join(['diff'] + revOptions), 'diff', caption, {}) +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 = s:VCSCommandUtility.system(s:Executable() . ' 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 + +	return s:DoCommand('cat' . versionOption, 'review', versiontag, {}) +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 +let s:VCSCommandUtility = VCSCommandRegisterModule('SVK', expand('<sfile>'), s:svkFunctions, []) + +let &cpo = s:save_cpo diff --git a/modules/vim/vim.dot.link/plugin/vcssvn.vim b/modules/vim/vim.dot.link/plugin/vcssvn.vim new file mode 100644 index 0000000..758f819 --- /dev/null +++ b/modules/vim/vim.dot.link/plugin/vcssvn.vim @@ -0,0 +1,284 @@ +" vim600: set foldmethod=marker: +" +" SVN extension for VCSCommand. +" +" Maintainer:    Bob Hiestand <bob.hiestand@gmail.com> +" License: +" Copyright (c) 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 exists('VCSCommandDisableAll') +	finish +endif + +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:Executable() {{{2 +" Returns the executable used to invoke git suitable for use in a shell +" command. +function! s:Executable() +	return shellescape(VCSCommandGetOption('VCSCommandSVNExec', 'svn')) +endfunction + +" 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 = s:Executable() . ' ' . 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 + +	return s:DoCommand('blame --non-interactive' . options, 'annotate', caption, {}) +endfunction + +" Function: s:svnFunctions.Commit(argList) {{{2 +function! s:svnFunctions.Commit(argList) +	let resultBuffer = s:DoCommand('commit --non-interactive -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 --non-interactive'] + 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 + +	return s:DoCommand(join(['diff --non-interactive'] + diffExt + diffOptions + revOptions), 'diff', caption, {}) +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 = s:VCSCommandUtility.system(s:Executable() . ' status --non-interactive -vu -- "' . fileName . '"') +	if(v:shell_error) +		return [] +	endif + +	" File not under SVN control. +	if statusText =~ '^?' +		return ['Unknown'] +	endif + +	let [flags, revision, repository] = matchlist(statusText, '^\(.\{9}\)\s*\(\d\+\)\s\+\(\d\+\)')[1:3] +	if revision == '' +		" Error +		return ['Unknown'] +	elseif flags =~ '^A' +		return ['New', 'New'] +	elseif flags =~ '*' +		return [revision, repository, '*'] +	else +		return [revision, repository] +	endif +endfunction + +" Function: s:svnFunctions.Info(argList) {{{2 +function! s:svnFunctions.Info(argList) +	return s:DoCommand(join(['info --non-interactive'] + a:argList, ' '), 'info', join(a:argList, ' '), {}) +endfunction + +" Function: s:svnFunctions.Lock(argList) {{{2 +function! s:svnFunctions.Lock(argList) +	return s:DoCommand(join(['lock --non-interactive'] + 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 --non-interactive', '-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 + +	return s:DoCommand('cat --non-interactive' . versionOption, 'review', versiontag, {}) +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 --non-interactive'] + options, ' '), 'status', join(options, ' '), {}) +endfunction + +" Function: s:svnFunctions.Unlock(argList) {{{2 +function! s:svnFunctions.Unlock(argList) +	return s:DoCommand(join(['unlock --non-interactive'] + a:argList, ' '), 'unlock', join(a:argList, ' '), {}) +endfunction + +" Function: s:svnFunctions.Update(argList) {{{2 +function! s:svnFunctions.Update(argList) +	return s:DoCommand('update --non-interactive', 'update', '', {}) +endfunction + +" Annotate setting {{{2 +let s:svnFunctions.AnnotateSplitRegex = '\s\+\S\+\s\+\S\+ ' + +" Section: Plugin Registration {{{1 +let s:VCSCommandUtility = VCSCommandRegisterModule('SVN', expand('<sfile>'), s:svnFunctions, []) + +let &cpo = s:save_cpo  | 
