1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-02-04 10:30:05 +08:00
SpaceVim/bundle/gina.vim/autoload/gina/action/index.vim

339 lines
11 KiB
VimL

let s:File = vital#gina#import('System.File')
let s:Path = vital#gina#import('System.Filepath')
function! gina#action#index#define(binder) abort
call a:binder.define('index:add', function('s:on_add'), {
\ 'hidden': 1,
\ 'description': 'Add changes to an index',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': {},
\})
call a:binder.define('index:add:force', function('s:on_add'), {
\ 'hidden': 1,
\ 'description': 'Add changes to an index',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': { 'force': 1 },
\})
call a:binder.define('index:add:intent-to-add', function('s:on_add'), {
\ 'hidden': 1,
\ 'description': 'Intent to add changes to an index',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': { 'intent-to-add': 1 },
\})
call a:binder.define('index:rm', function('s:on_rm'), {
\ 'hidden': 1,
\ 'description': 'Remove files from a working tree and from an index',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': {},
\})
call a:binder.define('index:rm:force', function('s:on_rm'), {
\ 'hidden': 1,
\ 'description': 'Remove files from a working tree and from an index',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': { 'force': 1 },
\})
call a:binder.define('index:rm:cached', function('s:on_rm'), {
\ 'hidden': 1,
\ 'description': 'Remove files from an index but a working tree',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': { 'cached': 1 },
\})
call a:binder.define('index:reset', function('s:on_reset'), {
\ 'hidden': 1,
\ 'description': 'Reset changes on an index',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': {},
\})
call a:binder.define('index:stage', function('s:on_stage'), {
\ 'description': 'Stage changes to an index',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path', 'sign'],
\ 'options': {},
\})
call a:binder.define('index:stage:force', function('s:on_stage'), {
\ 'hidden': 1,
\ 'description': 'Stage changes to an index',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path', 'sign'],
\ 'options': { 'force': 1 },
\})
call a:binder.define('index:unstage', function('s:on_unstage'), {
\ 'description': 'Unstage changes from an index',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path', 'sign'],
\ 'options': {},
\})
call a:binder.define('index:toggle', function('s:on_toggle'), {
\ 'description': 'Toggle stage/unstage of changes in an index',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path', 'sign'],
\ 'options': {},
\})
call a:binder.define('index:checkout', function('s:on_checkout'), {
\ 'description': 'Checkout a content from an index',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': {},
\})
call a:binder.define('index:checkout:force', function('s:on_checkout'), {
\ 'hidden': 1,
\ 'description': 'Checkout a content from an index',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': { 'force': 1 },
\})
call a:binder.define('index:checkout:HEAD', function('s:on_checkout'), {
\ 'hidden': 1,
\ 'description': 'Checkout a content from a HEAD',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': { 'rev': 'HEAD' },
\})
call a:binder.define('index:checkout:HEAD:force', function('s:on_checkout'), {
\ 'hidden': 1,
\ 'description': 'Checkout a content from a HEAD',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': { 'rev': 'HEAD', 'force': 1 },
\})
call a:binder.define('index:checkout:origin', function('s:on_checkout'), {
\ 'hidden': 1,
\ 'description': 'Checkout a content from an origin/HEAD',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': { 'rev': 'origin/HEAD' },
\})
call a:binder.define('index:checkout:origin:force', function('s:on_checkout'), {
\ 'hidden': 1,
\ 'description': 'Checkout a content from an origin/HEAD',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': { 'rev': 'origin/HEAD', 'force': 1 },
\})
call a:binder.define('index:checkout:ours', function('s:on_checkout'), {
\ 'hidden': 1,
\ 'description': 'Checkout a content from local (ours) during merge',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': { 'ours': 1 },
\})
call a:binder.define('index:checkout:theirs', function('s:on_checkout'), {
\ 'hidden': 1,
\ 'description': 'Checkout a content from remote (theirs) during merge',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path'],
\ 'options': { 'theirs': 1 },
\})
call a:binder.define('index:discard', function('s:on_discard'), {
\ 'description': 'Discard changes on a working tree',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path', 'sign'],
\ 'options': {},
\})
call a:binder.define('index:discard:force', function('s:on_discard'), {
\ 'hidden': 1,
\ 'description': 'Discard changes on a working tree',
\ 'mapping_mode': 'nv',
\ 'requirements': ['path', 'sign'],
\ 'options': { 'force': 1 },
\})
endfunction
function! s:on_add(candidates, options) abort
if empty(a:candidates)
return
endif
let options = extend({
\ 'force': 0,
\ 'intent-to-add': 0,
\}, a:options)
let pathlist = map(copy(a:candidates), 'v:val.path')
execute printf(
\ '%s Gina add --ignore-errors %s %s -- %s',
\ options.mods,
\ options.force ? '--force' : '',
\ options['intent-to-add'] ? '--intent-to-add' : '',
\ gina#util#shellescape(pathlist),
\)
endfunction
function! s:on_rm(candidates, options) abort
if empty(a:candidates)
return
endif
let options = extend({
\ 'cached': 0,
\ 'force': 0,
\}, a:options)
let pathlist = map(copy(a:candidates), 'v:val.path')
execute printf(
\ '%s Gina rm --quiet --ignore-unmatch %s %s -- %s',
\ options.mods,
\ options.force ? '--force' : '',
\ options.cached ? '--cached' : '',
\ gina#util#shellescape(pathlist),
\)
endfunction
function! s:on_reset(candidates, options) abort
if empty(a:candidates)
return
endif
let options = extend({}, a:options)
let pathlist = map(copy(a:candidates), 'v:val.path')
execute printf(
\ '%s Gina reset --quiet -- %s',
\ options.mods,
\ gina#util#shellescape(pathlist),
\)
endfunction
function! s:on_stage(candidates, options) abort dict
if empty(a:candidates)
return
endif
let options = extend({
\ 'force': 0,
\}, a:options)
let rm_candidates = []
let add_candidates = []
for candidate in a:candidates
if candidate.sign =~# '^.D$'
call add(rm_candidates, candidate)
elseif candidate.sign !~# '^. $'
call add(add_candidates, candidate)
endif
endfor
if options.force
call self.call(options.mods . 'index:add:force', add_candidates)
if !empty(rm_candidates)
call gina#process#wait()
endif
call self.call(options.mods . 'index:rm:force', rm_candidates)
else
call self.call(options.mods . 'index:add', add_candidates)
if !empty(rm_candidates)
call gina#process#wait()
endif
call self.call(options.mods . 'index:rm', rm_candidates)
endif
endfunction
function! s:on_unstage(candidates, options) abort dict
let options = extend({}, a:options)
call self.call(options.mods . 'index:reset', a:candidates)
endfunction
function! s:on_toggle(candidates, options) abort dict
if empty(a:candidates)
return
endif
let options = extend({}, a:options)
let stage_candidates = []
let unstage_candidates = []
for candidate in a:candidates
if candidate.sign =~# '^\%(??\|!!\|.\w\)$'
call add(stage_candidates, candidate)
elseif candidate.sign =~# '^\w.$'
call add(unstage_candidates, candidate)
endif
endfor
call self.call(options.mods . 'index:stage', stage_candidates)
if !empty(unstage_candidates)
call gina#process#wait()
endif
call self.call(options.mods . 'index:unstage', unstage_candidates)
endfunction
function! s:on_checkout(candidates, options) abort
if empty(a:candidates)
return
endif
let options = extend({
\ 'force': 0,
\ 'ours': 0,
\ 'theirs': 0,
\ 'rev': '',
\}, a:options)
let pathlist = map(copy(a:candidates), 'v:val.path')
execute printf(
\ '%s Gina! checkout --quiet %s %s %s %s -- %s',
\ options.mods,
\ options.force ? '--force' : '',
\ options.ours ? '--ours' : '',
\ options.theirs ? '--theirs' : '',
\ gina#util#shellescape(options.rev),
\ gina#util#shellescape(pathlist),
\)
endfunction
function! s:on_discard(candidates, options) abort dict
if empty(a:candidates)
return
endif
let git = gina#core#get_or_fail()
let options = extend({
\ 'force': 0,
\}, a:options)
let delete_candidates = []
let checkout_candidates = []
for candidate in a:candidates
if candidate.sign =~# '^\%(??\|!!\)$'
call add(delete_candidates, candidate)
else
call add(checkout_candidates, candidate)
endif
endfor
if !options.force
call gina#core#console#warn(join([
\ 'A discard action will discard all local changes on the working ',
\ 'tree and the operation is irreversible, mean that you have no ',
\ 'chance to revert the operation.',
\], "\n"))
call gina#core#console#info(
\ 'This operation will be performed to the following candidates:'
\)
for candidate in extend(copy(delete_candidates), checkout_candidates)
call gina#core#console#echo('- ' . s:Path.realpath(candidate.path))
endfor
if !gina#core#console#confirm('Are you sure to discard the changes?', 'n')
return
endif
endif
" delete untracked files
for candidate in delete_candidates
let abspath = s:Path.realpath(gina#core#repo#abspath(git, candidate.path))
if isdirectory(abspath)
if g:gina#action#index#discard_directories
call s:File.rmdir(abspath, 'r')
else
call gina#core#console#info(printf(
\ '"%s" is directory. While g:gina#action#index#discard_directories is not set, it is not removed.',
\ candidate.path,
\))
endif
elseif filewritable(abspath)
call delete(abspath)
endif
endfor
call self.call(options.mods . 'index:checkout:HEAD:force', checkout_candidates)
if !empty(delete_candidates) && empty(checkout_candidates)
call gina#core#emitter#emit('modified:delay')
endif
endfunction
" Config ---------------------------------------------------------------------
call gina#config(expand('<sfile>'), {
\ 'discard_directories': 0,
\})