mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-24 09:50:04 +08:00
176 lines
4.7 KiB
VimL
Vendored
176 lines
4.7 KiB
VimL
Vendored
let s:Cache = vital#gina#import('System.Cache.Memory')
|
|
let s:Git = vital#gina#import('Git')
|
|
|
|
let s:registry = s:Cache.new()
|
|
let s:reference = s:Cache.new()
|
|
|
|
let s:CACHE_NEVER = 'never' " No cache. Search .git always.
|
|
let s:CACHE_TRUTH = 'truth' " Use a cache when a git repository is found.
|
|
let s:CACHE_ALWAYS = 'always' " Use a cache always.
|
|
|
|
|
|
function! gina#core#get_or_fail(...) abort
|
|
let options = extend({
|
|
\ 'expr': '%',
|
|
\ 'cache': s:CACHE_TRUTH,
|
|
\}, get(a:000, 0, {})
|
|
\)
|
|
let git = gina#core#get(options)
|
|
if !empty(git)
|
|
return git
|
|
endif
|
|
throw gina#core#revelator#warning(printf(
|
|
\ 'No git repository for a buffer "%s" is found.',
|
|
\ expand(options.expr)
|
|
\))
|
|
endfunction
|
|
|
|
function! gina#core#get(...) abort
|
|
let options = extend({
|
|
\ 'expr': '%',
|
|
\ 'cache': s:CACHE_ALWAYS,
|
|
\}, get(a:000, 0, {})
|
|
\)
|
|
if options.cache !=# s:CACHE_NEVER
|
|
let cached = s:get_cached_instance(options.expr)
|
|
if !empty(cached)
|
|
call gina#core#console#debug(printf(
|
|
\ 'A cached git instanse "%s" is used for "%s"',
|
|
\ get(cached, 'refname', ''),
|
|
\ expand(options.expr),
|
|
\))
|
|
return cached
|
|
elseif options.cache ==# s:CACHE_TRUTH && cached isnot# v:null
|
|
call gina#core#console#debug(printf(
|
|
\ 'An empty cached git instanse is used for "%s"',
|
|
\ expand(options.expr),
|
|
\))
|
|
return cached
|
|
endif
|
|
endif
|
|
|
|
let params = gina#core#buffer#parse(options.expr)
|
|
if empty(params)
|
|
let git = {}
|
|
let params.path = expand(options.expr)
|
|
else
|
|
let git = s:get_from_cache(params.repo)
|
|
endif
|
|
if empty(git)
|
|
if s:is_file_buffer(options.expr)
|
|
let git = s:get_from_bufname(params.path)
|
|
else
|
|
let git = s:get_from_cwd(bufnr(options.expr))
|
|
endif
|
|
endif
|
|
call s:set_cached_instance(options.expr, git)
|
|
return git
|
|
endfunction
|
|
|
|
function! gina#core#git_version() abort
|
|
if exists('s:git_version')
|
|
return s:git_version
|
|
endif
|
|
let r = gina#process#call(gina#core#get(), ['--version'])
|
|
let s:git_version = matchstr(join(r.stdout, "\n"), '\%(\d\+\.\)\+\d')
|
|
return s:git_version
|
|
endfunction
|
|
|
|
|
|
" Private --------------------------------------------------------------------
|
|
function! s:is_file_buffer(expr) abort
|
|
return getbufvar(a:expr, '&buftype', '') =~# '^\%(\|nowrite\|acwrite\)$'
|
|
endfunction
|
|
|
|
function! s:get_cached_instance(expr) abort
|
|
let refinfo = getbufvar(a:expr, 'gina', {})
|
|
if empty(refinfo)
|
|
return v:null
|
|
endif
|
|
" Check if the refinfo is fresh enough
|
|
if refinfo.bufname !=# simplify(bufname(a:expr))
|
|
return v:null
|
|
elseif refinfo.buftype !=# getbufvar(a:expr, '&buftype', '')
|
|
return v:null
|
|
elseif refinfo.cwd !=# simplify(getcwd())
|
|
return v:null
|
|
endif
|
|
" refinfo is fresh enough, use a cached git instance
|
|
return s:get_from_cache(refinfo.refname)
|
|
endfunction
|
|
|
|
function! s:set_cached_instance(expr, git) abort
|
|
if bufexists(bufnr(a:expr))
|
|
call setbufvar(a:expr, 'gina', {
|
|
\ 'refname': get(a:git, 'refname', ''),
|
|
\ 'bufname': simplify(bufname(a:expr)),
|
|
\ 'buftype': getbufvar(a:expr, '&buftype', ''),
|
|
\ 'cwd': simplify(getcwd()),
|
|
\})
|
|
endif
|
|
endfunction
|
|
|
|
function! s:get_available_refname(refname, git) abort
|
|
let refname = a:refname
|
|
let ref = s:reference.get(refname, '')
|
|
let index = 1
|
|
while !empty(ref) && ref !=# a:git.worktree
|
|
let refname = a:refname . '~' . index
|
|
let ref = s:reference.get(refname, '')
|
|
let index += 1
|
|
endwhile
|
|
return refname
|
|
endfunction
|
|
|
|
function! s:get_from_cache(reference) abort
|
|
if s:registry.has(a:reference)
|
|
return s:registry.get(a:reference)
|
|
elseif s:reference.has(a:reference)
|
|
return s:registry.get(s:reference.get(a:reference), {})
|
|
endif
|
|
return {}
|
|
endfunction
|
|
|
|
function! s:get_from_path(path) abort
|
|
let path = simplify(fnamemodify(a:path, ':p'))
|
|
let git = s:Git.new(path)
|
|
if empty(git)
|
|
return {}
|
|
endif
|
|
let git.refname = s:get_available_refname(
|
|
\ fnamemodify(git.worktree, ':t'),
|
|
\ git,
|
|
\)
|
|
call s:registry.set(git.worktree, git)
|
|
call s:reference.set(path, git.worktree)
|
|
call s:reference.set(git.refname, git.worktree)
|
|
return git
|
|
endfunction
|
|
|
|
function! s:get_from_bufname(path) abort
|
|
let git = s:get_from_path(a:path)
|
|
if !empty(git)
|
|
return git
|
|
endif
|
|
|
|
" Resolve symbol link
|
|
let sympath = simplify(resolve(a:path))
|
|
if sympath !=# a:path
|
|
let git = s:get_from_path(sympath)
|
|
if !empty(git)
|
|
return git
|
|
endif
|
|
endif
|
|
|
|
" Not found
|
|
return {}
|
|
endfunction
|
|
|
|
function! s:get_from_cwd(bufnr) abort
|
|
let winnr = bufwinnr(a:bufnr)
|
|
let cwdpath = winnr == -1
|
|
\ ? simplify(getcwd())
|
|
\ : simplify(getcwd(winnr))
|
|
return s:get_from_path(cwdpath)
|
|
endfunction
|