let s:Path = vital#gina#import('System.Filepath') let s:Git = vital#gina#import('Git') function! gina#core#treeish#parse(treeish) abort " Ref: https://git-scm.com/docs/gitrevisions if a:treeish =~# '^:/' || a:treeish =~# '^[^:]*^{/' || a:treeish !~# ':' return [a:treeish, v:null] endif let m = matchlist(a:treeish, '^\(:[0-3]\|[^:]*\)\%(:\(.*\)\)\?$') return [m[1], m[2]] endfunction function! gina#core#treeish#build(rev, path) abort let rev = a:rev is# v:null ? ':0' : a:rev if a:path is# v:null return rev endif return printf('%s:%s', rev, s:Path.unixpath(a:path)) endfunction function! gina#core#treeish#split(rev) abort if a:rev =~# '^.\{-}\.\.\..*$' let [lhs, rhs] = matchlist(a:rev, '^\(.\{-}\)\.\.\.\(.*\)$')[1 : 2] let lhs = empty(lhs) ? 'HEAD' : lhs let rhs = empty(rhs) ? 'HEAD' : rhs return [lhs . '...' . rhs, rhs] elseif a:rev =~# '^.\{-}\.\..*$' let [lhs, rhs] = matchlist(a:rev, '^\(.\{-}\)\.\.\(.*\)$')[1 : 2] let lhs = empty(lhs) ? 'HEAD' : lhs let rhs = empty(rhs) ? 'HEAD' : rhs return [lhs, rhs] else return [a:rev, ''] endif endfunction function! gina#core#treeish#sha1(git, rev) abort let ref = s:Git.ref(a:git, a:rev) if !empty(ref) return ref.hash endif " Fallback to rev-parse (e.g. HEAD@{2.days.ago}) let result = gina#process#call_or_fail(a:git, ['rev-parse', a:rev]) return get(result.stdout, 0, '') endfunction function! gina#core#treeish#resolve(git, rev, ...) abort let aggressive = a:0 ? a:1 : 0 if a:rev =~# '^.\{-}\.\.\..*$' let [lhs, rhs] = matchlist(a:rev, '^\(.\{-}\)\.\.\.\(.*\)$')[1 : 2] let lhs = empty(lhs) ? 'HEAD' : lhs let rhs = empty(rhs) ? 'HEAD' : rhs return s:find_common_ancestor(a:git, lhs, rhs) elseif a:rev =~# '^.\{-}\.\..*$' let [lhs, _] = matchlist(a:rev, '^\(.\{-}\)\.\.\(.*\)$')[1 : 2] let lhs = empty(lhs) ? 'HEAD' : lhs if aggressive let ref = s:Git.ref(a:git, lhs) return get(ref, 'name', lhs) else return lhs endif elseif aggressive let ref = s:Git.ref(a:git, a:rev) return get(ref, 'name', a:rev) else return a:rev endif endfunction function! gina#core#treeish#validate(git, rev, path, ...) abort let treeish = gina#core#treeish#build(a:rev, a:path) let result = gina#process#call(a:git, ['rev-parse', treeish]) if result.status throw gina#core#revelator#warning(a:0 ? a:1 : join(result.stderr, "\n")) endif endfunction " Private -------------------------------------------------------------------- function! s:find_common_ancestor(git, rev1, rev2) abort let lhs = empty(a:rev1) ? 'HEAD' : a:rev1 let rhs = empty(a:rev2) ? 'HEAD' : a:rev2 let result = gina#process#call_or_fail(a:git, [ \ 'merge-base', lhs, rhs \]) return get(result.stdout, 0, '') endfunction