" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim]) " @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @Created: 2012-03-08. " @Last Change: 2017-04-10. " @Revision: 224 scriptencoding utf-8 " A dictionarie of supported VCS (currently: git, hg, svn, bzr). " :display: g:tlib#vcs#def {...} TLet g:tlib#vcs#def = { \ 'git': { \ 'dir': '.git', \ 'ls': 'git ls-files --full-name', \ 'ls.postprocess': '*tlib#vcs#GitLsPostprocess', \ 'diff': 'git diff --no-ext-diff -U0 %s', \ 'status': 'git status -s', \ 'status.filterrx': '^\C[ MADRCU!?]\{2}\s'}, \ 'hg': { \ 'dir': '.hg', \ 'diff': 'hg diff -U0 %s', \ 'ls': 'hg manifest'}, \ 'svn': { \ 'dir': '.svn', \ 'diff': 'svn diff --diff-cmd diff --extensions -U0 %s'}, \ 'bzr': { \ 'dir': '.bzr', \ 'diff': 'bzr diff --diff-options=-U0 %s'} \ } " A dictionary of custom executables for VCS commands. If the value is " empty, support for that VCS will be removed. If no key is present, it " is assumed that the VCS "type" is the name of the executable. " :display: g:tlib#vcs#executables {...} TLet g:tlib#vcs#executables = {} " If non-empty, use it as a format string to check whether a VCS is " installed on your computer. TLet g:tlib#vcs#check = has('win16') || has('win32') || has('win64') ? '%s.exe' : '%s' if !empty(g:tlib#vcs#check) for [s:cmd, s:def] in items(g:tlib#vcs#def) if !has_key(g:tlib#vcs#executables, s:cmd) let s:cmd1 = printf(g:tlib#vcs#check, s:cmd) let g:tlib#vcs#executables[s:cmd] = executable(s:cmd1) ? s:cmd1 : '' endif endfor unlet! s:cmd s:def s:cmd1 endif function! tlib#vcs#Executable(type) "{{{3 return get(g:tlib#vcs#executables, a:type, '') endf let s:vcs_cache = {} autocmd TLib FocusGained * let s:vcs_cache = {} function! tlib#vcs#FindVCS(filename) "{{{3 let type = '' let dir = '' let filename = fnamemodify(a:filename, ':p') let dirname = isdirectory(filename) ? filename : fnamemodify(filename, ':h') if !has_key(s:vcs_cache, dirname) let path = escape(dirname, ';') .';' " TLogVAR filename, dirname, path Tlibtrace 'tlib', filename, path let depth = -1 for vcs in keys(g:tlib#vcs#def) let subdir = g:tlib#vcs#def[vcs].dir let vcsdir = finddir(subdir, path) " TLogVAR vcs, subdir, vcsdir Tlibtrace 'tlib', vcs, subdir, vcsdir if !empty(vcsdir) let vcsdir_depth = len(split(fnamemodify(vcsdir, ':p'), '\/')) if vcsdir_depth > depth let depth = vcsdir_depth let type = vcs let dir = vcsdir " TLogVAR type, depth endif endif endfor Tlibtrace 'tlib', type, dir " TLogVAR type, dir if empty(type) let s:vcs_cache[dirname] = ['', ''] else let s:vcs_cache[dirname] = [type, dir] endif endif return s:vcs_cache[dirname] endf function! s:GetCmd(vcstype, cmd) let vcsdef = get(g:tlib#vcs#def, a:vcstype, {}) if has_key(vcsdef, a:cmd) let cmd = vcsdef[a:cmd] if cmd =~# '^\*' let cmd = substitute(cmd, '^\*', '', '') else let bin = get(g:tlib#vcs#executables, a:vcstype, '') if empty(bin) let cmd = '' elseif bin != a:vcstype " let bin = escape(shellescape(bin), '\') let bin = escape(bin, '\') let cmd = substitute(cmd, '^.\{-}\zs'. escape(a:vcstype, '\'), bin, '') endif endif return cmd else return '' endif endf " :display: tlib#vcs#Ls(?filename=bufname('%'), ?vcs=[type, dir]) " Return the files under VCS. function! tlib#vcs#Ls(...) "{{{3 if a:0 >= 2 let vcs = a:2 else let vcs = tlib#vcs#FindVCS(a:0 >= 1 ? a:1 : bufname('%')) endif Tlibtrace 'tlib', vcs, a:000 " TLogVAR vcs if !empty(vcs) let [vcstype, vcsdir] = vcs if has_key(g:tlib#vcs#def, vcstype) let ls = s:GetCmd(vcstype, 'ls') " TLogVAR ls if !empty(ls) let rootdir = fnamemodify(vcsdir, ':p:h:h') " TLogVAR vcsdir, rootdir if ls =~# '%s' let cmd = printf(ls, shellescape(rootdir)) else let cmd = ls endif " TLogVAR cmd, getcwd() Tlibtrace 'tlib', getcwd(), vcstype, vcsdir, rootdir, cmd let filess = tlib#sys#SystemInDir(rootdir, cmd) " TLogVAR filess let files = split(filess, '\n') let postprocess = s:GetCmd(vcstype, 'ls.postprocess') if !empty(postprocess) call map(files, 'call(postprocess, [v:val])') endif call map(files, 'join([rootdir, v:val], "/")') " TLogVAR files return files endif endif endif return [] endf " :display: tlib#vcs#Diff(filename, ?vcs=[type, dir]) " Return the diff for "filename" function! tlib#vcs#Diff(filename, ...) "{{{3 let vcs = a:0 >= 1 ? a:1 : tlib#vcs#FindVCS(a:filename) if !empty(vcs) let [vcstype, vcsdir] = vcs let diff = s:GetCmd(vcstype, 'diff') if !empty(diff) let cmd = printf(diff, shellescape(fnamemodify(a:filename, ':p'))) let patch = system(cmd) return patch endif endif return [] endf function! tlib#vcs#GitLsPostprocess(filename) abort "{{{3 if a:filename =~# '^".\{-}"$' let filename = matchstr(a:filename, '^"\zs.\{-}\ze"$') let filename = substitute(filename, '\%(\\\@= 1 ? a:1 : '%' let vcs = a:0 >= 2 ? a:2 : tlib#vcs#FindVCS(filename) if !empty(vcs) let [vcstype, vcsdir] = vcs let cstatus = s:GetCmd(vcstype, 'status') if !empty(cstatus) let status = exists('*systemlist') ? systemlist(cstatus) : split(system(cstatus), '\n') let sfilter = s:GetCmd(vcstype, 'status.filterrx') if !empty(sfilter) let status = filter(status, 'v:val =~# sfilter') endif return status endif endif endf function! tlib#vcs#IsDirty(...) abort "{{{3 let filename = a:0 >= 1 ? a:1 : '%' let vcs = a:0 >= 2 ? a:2 : tlib#vcs#FindVCS(filename) let status = tlib#vcs#Status(filename, vcs) return empty(status) ? '' : vcs[0] .'!' endf " function! tlib#vcs#EnableTStatus() abort "{{{3 " if has('vim_starting') " autocmd VimEnter * TStatusregister1 --event=FocusGained,BufRead,BufWritePost %s tlib#vcs#IsDirty() " else " TStatusregister1 --event=FocusGained,BufRead,BufWritePost %s tlib#vcs#IsDirty() " endif " endf