mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-02-04 10:30:05 +08:00
339 lines
11 KiB
VimL
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,
|
|
\})
|