1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-24 09:50:04 +08:00
SpaceVim/bundle/gina.vim/autoload/gina/core.vim

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