aboutsummaryrefslogtreecommitdiff
path: root/vim/bundle/tlib_vim/autoload/tlib/vcs.vim
blob: 15d051faecfd73c44a5e6a9def4f962e404ab927 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
" @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: 2015-11-07.
" @Revision:    190

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'
            \ },
            \ '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


function! tlib#vcs#FindVCS(filename) "{{{3
    let type = ''
    let dir  = ''
    let dirname = fnamemodify(a:filename, isdirectory(a:filename) ? ':p' : ':p:h')
    let path = escape(dirname, ';') .';'
    " TLogVAR a:filename, dirname, path
    Tlibtrace 'tlib', a: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)
        return ['', '']
    else
        return [type, dir]
    endif
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, '\%(\\\@<!\\\(\d\d\d\)\)\+', '\=eval(''"''. submatch(0) .''"'')', 'g')
        " let filename = eval(a:filename)
        " TLogVAR a:filename, filename, &enc
        return filename
    else
        return a:filename
    endif
endf