Refactor status spaghetti into dispatch mechanism
This commit is contained in:
parent
15fb5f68ad
commit
26cf153e76
@ -1532,12 +1532,12 @@ function! fugitive#BufReadStatus() abort
|
||||
nunmap <buffer> ~
|
||||
nnoremap <buffer> <silent> <C-N> :<C-U>execute <SID>StageNext(v:count1)<CR>
|
||||
nnoremap <buffer> <silent> <C-P> :<C-U>execute <SID>StagePrevious(v:count1)<CR>
|
||||
exe "nnoremap <buffer> <silent>" nowait "- :<C-U>execute <SID>StageToggle(line('.'),v:count)<CR>"
|
||||
exe "xnoremap <buffer> <silent>" nowait "- :<C-U>execute <SID>StageToggle(line(\"'<\"),line(\"'>\")-line(\"'<\")+1)<CR>"
|
||||
exe "nnoremap <buffer> <silent>" nowait "s :<C-U>execute <SID>StageToggleOnly('Unstaged',line('.'),v:count)<CR>"
|
||||
exe "xnoremap <buffer> <silent>" nowait "s :<C-U>execute <SID>StageToggle(line(\"'<\"),line(\"'>\")-line(\"'<\")+1)<CR>"
|
||||
exe "nnoremap <buffer> <silent>" nowait "u :<C-U>execute <SID>StageToggleOnly('Staged',line('.'),v:count)<CR>"
|
||||
exe "xnoremap <buffer> <silent>" nowait "u :<C-U>execute <SID>StageToggle(line(\"'<\"),line(\"'>\")-line(\"'<\")+1)<CR>"
|
||||
exe "nnoremap <buffer> <silent>" nowait "- :<C-U>execute <SID>Do('Toggle',0)<CR>"
|
||||
exe "xnoremap <buffer> <silent>" nowait "- :<C-U>execute <SID>Do('Toggle',1)<CR>"
|
||||
exe "nnoremap <buffer> <silent>" nowait "s :<C-U>execute <SID>Do('Stage',0)<CR>"
|
||||
exe "xnoremap <buffer> <silent>" nowait "s :<C-U>execute <SID>Do('Stage',1)<CR>"
|
||||
exe "nnoremap <buffer> <silent>" nowait "u :<C-U>execute <SID>Do('Unstage',0)<CR>"
|
||||
exe "xnoremap <buffer> <silent>" nowait "u :<C-U>execute <SID>Do('Unstage',1)<CR>"
|
||||
nnoremap <buffer> <silent> C :<C-U>Gcommit<CR>:echohl WarningMsg<Bar>echo ':Gstatus C is deprecated in favor of cc'<Bar>echohl NONE<CR>
|
||||
nnoremap <buffer> <silent> a :<C-U>execute <SID>StageInline('toggle',line('.'),v:count)<CR>
|
||||
nnoremap <buffer> <silent> i :<C-U>execute <SID>StageInline('toggle',line('.'),v:count)<CR>
|
||||
@ -2067,6 +2067,151 @@ function! s:StageInfo(...) abort
|
||||
\ 'index': index}
|
||||
endfunction
|
||||
|
||||
function! s:Selection(arg1, ...) abort
|
||||
if a:arg1 ==# 'n'
|
||||
let arg1 = line('.')
|
||||
let arg2 = v:count
|
||||
elseif a:arg1 ==# 'v'
|
||||
let arg1 = line("'<")
|
||||
let arg2 = line("'>")
|
||||
else
|
||||
let arg1 = a:arg1
|
||||
let arg2 = a:0 ? a:1 : 0
|
||||
endif
|
||||
let first = arg1
|
||||
if arg2 < 0
|
||||
let last = first - arg2 + 1
|
||||
elseif arg2 > 0
|
||||
let last = arg2
|
||||
else
|
||||
let last = first
|
||||
endif
|
||||
while getline(first) =~# '^$\|^[A-Z][a-z]'
|
||||
let first += 1
|
||||
endwhile
|
||||
if first > last || &filetype !=# 'fugitive'
|
||||
return []
|
||||
endif
|
||||
let flnum = first
|
||||
while getline(flnum) =~# '^[ @\+-]'
|
||||
let flnum -= 1
|
||||
endwhile
|
||||
let slnum = flnum + 1
|
||||
let section = ''
|
||||
let index = 0
|
||||
while len(getline(slnum - 1)) && empty(section)
|
||||
let slnum -= 1
|
||||
let heading = matchstr(getline(slnum), '^\u\l\+.* (\d\+)$')
|
||||
if empty(heading) && getline(slnum) !~# '^[ @\+-]'
|
||||
let index += 1
|
||||
endif
|
||||
endwhile
|
||||
let results = []
|
||||
let template = {
|
||||
\ 'heading': heading,
|
||||
\ 'section': matchstr(heading, '^\u\l\+\ze.* (\d\+)$'),
|
||||
\ 'filename': '',
|
||||
\ 'paths': [],
|
||||
\ 'commit': '',
|
||||
\ 'status': '',
|
||||
\ 'patch': 0,
|
||||
\ 'index': index}
|
||||
let line = getline(flnum)
|
||||
let lnum = first - (arg1 == flnum ? 0 : 1)
|
||||
let root = s:Tree() . '/'
|
||||
while lnum <= last
|
||||
if line =~# '^\u\l\+\ze.* (\d\+)$'
|
||||
let template.heading = getline(lnum)
|
||||
let template.section = matchstr(template.heading, '^\u\l\+\ze.* (\d\+)$')
|
||||
let template.index = 0
|
||||
elseif line =~# '^[ @\+-]'
|
||||
let template.index -= 1
|
||||
if !results[-1].patch
|
||||
let results[-1].patch = lnum
|
||||
endif
|
||||
let results[-1].lnum = lnum
|
||||
elseif line =~# '^[A-Z?] '
|
||||
let filename = matchstr(line, '^[A-Z?] \zs.*')
|
||||
call add(results, extend(deepcopy(template), {
|
||||
\ 'lnum': lnum,
|
||||
\ 'filename': filename,
|
||||
\ 'paths': map(reverse(split(filename, ' -> ')), 'root . v:val'),
|
||||
\ 'status': matchstr(line, '^[A-Z?]'),
|
||||
\ }))
|
||||
elseif line =~# '^\x\x\x\+ '
|
||||
call add(results, extend({
|
||||
\ 'lnum': lnum,
|
||||
\ 'commit': matchstr(line, '^\x\x\x\+'),
|
||||
\ }, template, 'keep'))
|
||||
elseif line =~# '^\l\+ \x\x\x\+ '
|
||||
call add(results, extend({
|
||||
\ 'lnum': lnum,
|
||||
\ 'commit': matchstr(line, '^\l\+ \zs\x\x\x\+'),
|
||||
\ 'status': matchstr(line, '^\l\+'),
|
||||
\ }, template, 'keep'))
|
||||
endif
|
||||
let lnum += 1
|
||||
let template.index += 1
|
||||
let line = getline(lnum)
|
||||
endwhile
|
||||
if len(results) && results[0].patch && arg2 == 0
|
||||
while getline(results[0].patch) =~# '^[ \+-]'
|
||||
let results[0].patch -= 1
|
||||
endwhile
|
||||
while getline(results[0].lnum + 1) =~# '^[ \+-]'
|
||||
let results[0].lnum += 1
|
||||
endwhile
|
||||
endif
|
||||
return results
|
||||
endfunction
|
||||
|
||||
function! s:Do(action, visual) abort
|
||||
let line = getline('.')
|
||||
if !a:0 && !v:count && line =~# '^[A-Z][a-z]'
|
||||
let header = matchstr(line, '^\S\+\ze:')
|
||||
if len(header) && exists('*s:Do' . a:action . header . 'Header')
|
||||
call s:Do{a:action}{header}Header(matchstr(line, ': \zs.*'))
|
||||
endif
|
||||
let section = matchstr(line, '^\S\+')
|
||||
if exists('*s:Do' . a:action . section . 'Heading')
|
||||
call s:Do{a:action}{section}Heading(line)
|
||||
return s:ReloadStatus()
|
||||
endif
|
||||
endif
|
||||
let selection = s:Selection(a:visual ? 'v' : 'n')
|
||||
if empty(selection)
|
||||
return ''
|
||||
endif
|
||||
call filter(selection, 'v:val.section ==# selection[0].section')
|
||||
let reload = 0
|
||||
let status = 0
|
||||
let err = ''
|
||||
try
|
||||
for record in selection
|
||||
if exists('*s:Do' . a:action . record.section)
|
||||
let status = s:Do{a:action}{record.section}(record)
|
||||
else
|
||||
continue
|
||||
endif
|
||||
if !status
|
||||
return ''
|
||||
endif
|
||||
let reload = reload || (status > 0)
|
||||
endfor
|
||||
if status < 0
|
||||
execute record.lnum + 1
|
||||
endif
|
||||
call s:StageReveal()
|
||||
catch /^fugitive:/
|
||||
return 'echoerr v:errmsg'
|
||||
finally
|
||||
if reload
|
||||
execute s:ReloadStatus()
|
||||
endif
|
||||
endtry
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! s:StageReveal(...) abort
|
||||
let begin = a:0 ? a:1 : line('.')
|
||||
if getline(begin) =~# '^@'
|
||||
@ -2213,28 +2358,14 @@ function! s:StageDiffEdit() abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:StageApply(info, lnum1, count, reverse, extra) abort
|
||||
let cmd = ['apply', '-p0'] + a:extra
|
||||
function! s:StageApply(info, reverse, extra) abort
|
||||
let cmd = ['apply', '-p0', '--recount'] + a:extra
|
||||
let info = a:info
|
||||
let start = a:lnum1
|
||||
let end = start
|
||||
if !a:count
|
||||
while start > 0 && getline(start) !~# '^@@'
|
||||
let start -= 1
|
||||
endwhile
|
||||
while getline(end + 1) =~# '^[-+ ]'
|
||||
let end += 1
|
||||
endwhile
|
||||
else
|
||||
let end = a:lnum1 + a:count - 1
|
||||
call add(cmd, '--recount')
|
||||
endif
|
||||
let start = info.patch
|
||||
let end = info.lnum
|
||||
let lines = getline(start, end)
|
||||
if empty(filter(copy(lines), 'v:val =~# "^[+-]"'))
|
||||
return ''
|
||||
endif
|
||||
if len(filter(copy(lines), 'v:val !~# "^[ @\+-]"'))
|
||||
return 'fugitive: cannot apply hunks across multiple files'
|
||||
return -1
|
||||
endif
|
||||
while getline(end) =~# '^[-+ ]'
|
||||
let end += 1
|
||||
@ -2251,7 +2382,7 @@ function! s:StageApply(info, lnum1, count, reverse, extra) abort
|
||||
endif
|
||||
endwhile
|
||||
if start == 0 || getline(start) !~# '^@@ '
|
||||
return "fugitive: could not find hunk"
|
||||
call s:throw("could not find hunk")
|
||||
endif
|
||||
let i = b:fugitive_expanded[info.section][info.filename][0]
|
||||
let head = []
|
||||
@ -2267,30 +2398,34 @@ function! s:StageApply(info, lnum1, count, reverse, extra) abort
|
||||
endif
|
||||
call extend(cmd, ['--', temp])
|
||||
let output = call('s:TreeChomp', cmd)
|
||||
return v:shell_error ? output : ''
|
||||
if !v:shell_error
|
||||
return 1
|
||||
endif
|
||||
call s:throw(output)
|
||||
endfunction
|
||||
|
||||
function! s:StageDelete(lnum, count) abort
|
||||
let info = s:StageInfo(a:lnum)
|
||||
let info = get(s:Selection(a:lnum, -a:count), 0, {'filename': ''})
|
||||
if empty(info.filename)
|
||||
return ''
|
||||
endif
|
||||
let hash = s:TreeChomp('hash-object', '-w', './' . info.filename)
|
||||
let hash = s:TreeChomp('hash-object', '-w', '--', info.paths[0])
|
||||
if empty(hash)
|
||||
return ''
|
||||
elseif info.offset >= 0
|
||||
let output = s:StageApply(info, a:lnum, a:count, 1, info.section ==# 'Staged' ? ['--index'] : [])
|
||||
if len(output)
|
||||
return 'echoerr ' . string(output)
|
||||
endif
|
||||
elseif info.patch
|
||||
try
|
||||
call s:StageApply(info, 1, info.section ==# 'Staged' ? ['--index'] : [])
|
||||
catch /^fugitive:/
|
||||
return 'echoerr v:errmsg'
|
||||
endtry
|
||||
elseif info.status ==# 'U'
|
||||
call s:TreeChomp('rm', './' . info.filename)
|
||||
call s:TreeChomp('rm', '--', info.paths[0])
|
||||
elseif info.status ==# '?'
|
||||
call s:TreeChomp('clean', '-f', './' . info.filename)
|
||||
call s:TreeChomp('clean', '-f', '--', info.paths[0])
|
||||
elseif info.section ==# 'Unstaged'
|
||||
call s:TreeChomp('checkout', './' . info.filename)
|
||||
call s:TreeChomp('checkout', '--', info.paths[0])
|
||||
else
|
||||
call s:TreeChomp('checkout', 'HEAD^{}', './' . info.filename)
|
||||
call s:TreeChomp('checkout', 'HEAD^{}', '--', info.paths[0])
|
||||
endif
|
||||
exe s:ReloadStatus()
|
||||
let @@ = hash
|
||||
@ -2298,80 +2433,91 @@ function! s:StageDelete(lnum, count) abort
|
||||
\ string('To restore, :Git cat-file blob '.hash[0:6].' > '.info.filename)
|
||||
endfunction
|
||||
|
||||
function! s:StageToggle(lnum1, count) abort
|
||||
if a:lnum1 == 1 && a:count == 0
|
||||
return 'Gedit .git/|call search("^index$", "wc")'
|
||||
endif
|
||||
try
|
||||
let info = s:StageInfo(a:lnum1)
|
||||
if empty(info.filename)
|
||||
if info.section ==# 'Staged'
|
||||
call s:TreeChomp('reset','-q')
|
||||
silent! edit!
|
||||
1
|
||||
call search('^Unstaged','W')
|
||||
return ''
|
||||
elseif info.section ==# 'Unstaged'
|
||||
call s:TreeChomp('add','.')
|
||||
silent! edit!
|
||||
1
|
||||
call search('^Staged','W')
|
||||
return ''
|
||||
elseif info.section ==# 'Unpushed' && len(info.commit)
|
||||
let remote = matchstr(info.heading, 'to \zs[^/]\+\ze/')
|
||||
if empty(remote)
|
||||
let remote = '.'
|
||||
endif
|
||||
let branch = matchstr(info.heading, 'to \%([^/]\+/\)\=\zs\S\+')
|
||||
call feedkeys(':Gpush ' . remote . ' ' . info.commit . ':' . branch)
|
||||
return ''
|
||||
elseif info.section ==# 'Unpulled'
|
||||
call feedkeys(':Grebase ' . info.commit)
|
||||
return ''
|
||||
endif
|
||||
elseif info.offset >= 0
|
||||
let output = s:StageApply(info, a:lnum1, a:count, info.section ==# 'Staged', ['--cached'])
|
||||
return len(output) ? 'redraw|echoerr ' . string(output) : s:ReloadStatus()
|
||||
endif
|
||||
let lnum2 = a:count ? a:lnum1 + a:count - 1 : a:lnum1
|
||||
for lnum in range(a:lnum1, lnum2)
|
||||
let info = s:StageInfo(lnum)
|
||||
let filename = info.filename
|
||||
if empty(filename) || info.offset >= 0
|
||||
continue
|
||||
endif
|
||||
execute lnum
|
||||
if info.section ==# 'Staged'
|
||||
let files_to_unstage = split(filename, ' -> ')
|
||||
let filename = files_to_unstage[-1]
|
||||
let cmd = ['reset', '-q', '--'] + map(copy(files_to_unstage), 's:Tree() . "/" . v:val')
|
||||
elseif getline(lnum) =~# '^D'
|
||||
let cmd = ['rm', './' . filename]
|
||||
elseif getline(lnum) =~# '^M'
|
||||
let cmd = ['add', './' . filename]
|
||||
else
|
||||
let cmd = ['add','-A', './' . filename]
|
||||
endif
|
||||
if !exists('target')
|
||||
let target = [filename, info.section ==# 'Staged' ? '' : 'Staged']
|
||||
endif
|
||||
call call('s:TreeChomp', cmd)
|
||||
endfor
|
||||
if exists('target')
|
||||
exe s:ReloadStatus()
|
||||
endif
|
||||
catch /^fugitive:/
|
||||
return 'echoerr v:errmsg'
|
||||
endtry
|
||||
return ''
|
||||
function! s:DoToggleHeadHeader(value) abort
|
||||
exe 'edit' s:fnameescape(b:git_dir)
|
||||
call search('\C^index$', 'wc')
|
||||
endfunction
|
||||
|
||||
function! s:StageToggleOnly(section, lnum1, count) abort
|
||||
let info = s:StageInfo(a:lnum1)
|
||||
if info.section ==# a:section
|
||||
return s:StageToggle(a:lnum1, a:count)
|
||||
function! s:DoToggleUnpushedHeading(heading) abort
|
||||
let remote = matchstr(a:heading, 'to \zs[^/]\+\ze/')
|
||||
if empty(remote)
|
||||
let remote = '.'
|
||||
endif
|
||||
let branch = matchstr(a:heading, 'to \%([^/]\+/\)\=\zs\S\+')
|
||||
call feedkeys(':Gpush ' . remote . ' ' . 'HEAD:' . branch)
|
||||
endfunction
|
||||
|
||||
function! s:DoToggleUnpushed(record) abort
|
||||
let remote = matchstr(a:record.heading, 'to \zs[^/]\+\ze/')
|
||||
if empty(remote)
|
||||
let remote = '.'
|
||||
endif
|
||||
let branch = matchstr(a:record.heading, 'to \%([^/]\+/\)\=\zs\S\+')
|
||||
call feedkeys(':Gpush ' . remote . ' ' . a:record.commit . ':' . branch)
|
||||
endfunction
|
||||
|
||||
function! s:DoToggleUnpulledHeading(heading) abort
|
||||
call feedkeys(':Grebase')
|
||||
endfunction
|
||||
|
||||
function! s:DoToggleUnpulled(record) abort
|
||||
call feedkeys(':Grebase ' . a:record.commit)
|
||||
endfunction
|
||||
|
||||
function! s:DoToggleStagedHeading(...) abort
|
||||
call s:TreeChomp('reset', '-q')
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! s:DoUnstageStagedHeading(heading) abort
|
||||
return s:DoToggleStagedHeading(a:heading)
|
||||
endfunction
|
||||
|
||||
function! s:DoToggleUnstagedHeading(...) abort
|
||||
call s:TreeChomp('add', '-u')
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! s:DoStageUnstagedHeading(heading) abort
|
||||
return s:DoToggleUnstagedHeading(a:heading)
|
||||
endfunction
|
||||
|
||||
function! s:DoToggleStaged(record) abort
|
||||
if a:record.patch
|
||||
return s:StageApply(a:record, 1, ['--cached'])
|
||||
else
|
||||
return s:StageNext(a:count ? a:count : 1)
|
||||
call s:TreeChomp(['reset', '-q', '--'] + a:record.paths)
|
||||
return 1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:DoStageStaged(record) abort
|
||||
return -1
|
||||
endfunction
|
||||
|
||||
function! s:DoUnstageStaged(record) abort
|
||||
return s:DoToggleStaged(a:record)
|
||||
endfunction
|
||||
|
||||
function! s:DoToggleUnstaged(record) abort
|
||||
if a:record.patch
|
||||
return s:StageApply(a:record, 0, ['--cached'])
|
||||
else
|
||||
call s:TreeChomp(['add', '-A', '--'] + a:record.paths)
|
||||
return 1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:DoStageUnstaged(record) abort
|
||||
return s:DoToggleUnstaged(a:record)
|
||||
endfunction
|
||||
|
||||
function! s:DoUnstageUnstaged(record) abort
|
||||
if a:record.status ==# 'A'
|
||||
call s:TreeChomp(['reset', '-q', '--'] + a:record.paths)
|
||||
return 1
|
||||
else
|
||||
return -1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@ -4084,7 +4230,7 @@ function! fugitive#MapJumps(...) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:StatusCfile(...) abort
|
||||
function! s:DoCfile(...) abort
|
||||
let tree = FugitiveTreeForGitDir(b:git_dir)
|
||||
let lead = s:cpath(tree, getcwd()) ? './' : tree . '/'
|
||||
let info = s:StageInfo()
|
||||
@ -4109,7 +4255,7 @@ function! s:StatusCfile(...) abort
|
||||
endfunction
|
||||
|
||||
function! fugitive#StatusCfile() abort
|
||||
let file = s:Generate(s:StatusCfile()[0])
|
||||
let file = s:Generate(s:DoCfile()[0])
|
||||
return empty(file) ? fugitive#Cfile() : s:fnameescape(file)
|
||||
endfunction
|
||||
|
||||
@ -4296,7 +4442,7 @@ endfunction
|
||||
|
||||
function! s:GF(mode) abort
|
||||
try
|
||||
let results = &filetype ==# 'fugitive' ? s:StatusCfile() : &filetype ==# 'gitcommit' ? [s:MessageCfile()] : s:cfile()
|
||||
let results = &filetype ==# 'fugitive' ? s:DoCfile() : &filetype ==# 'gitcommit' ? [s:MessageCfile()] : s:cfile()
|
||||
catch /^fugitive:/
|
||||
return 'echoerr v:errmsg'
|
||||
endtry
|
||||
|
Loading…
x
Reference in New Issue
Block a user