diff --git a/autoload/fugitive.vim b/autoload/fugitive.vim index 758ee1f..7b2a9f9 100644 --- a/autoload/fugitive.vim +++ b/autoload/fugitive.vim @@ -1517,12 +1517,12 @@ function! fugitive#BufReadStatus() abort nunmap ~ nnoremap :execute StageNext(v:count1) nnoremap :execute StagePrevious(v:count1) - exe "nnoremap " nowait "- :silent execute StageToggle(line('.'),line('.')+v:count1-1)" - exe "xnoremap " nowait "- :silent execute StageToggle(line(\"'<\"),line(\"'>\"))" - exe "nnoremap " nowait "s :silent execute StageToggle(line('.'),line('.')+v:count1-1)" - exe "xnoremap " nowait "s :silent execute StageToggle(line(\"'<\"),line(\"'>\"))" - exe "nnoremap " nowait "u :silent execute StageToggle(line('.'),line('.')+v:count1-1)" - exe "xnoremap " nowait "u :silent execute StageToggle(line(\"'<\"),line(\"'>\"))" + exe "nnoremap " nowait "- :execute StageToggle(line('.'),v:count)" + exe "xnoremap " nowait "- :execute StageToggle(line(\"'<\"),line(\"'>\")-line(\"'<\")+1)" + exe "nnoremap " nowait "s :execute StageToggle(line('.'),v:count)" + exe "xnoremap " nowait "s :execute StageToggle(line(\"'<\"),line(\"'>\")-line(\"'<\")+1)" + exe "nnoremap " nowait "u :execute StageToggle(line('.'),v:count)" + exe "xnoremap " nowait "u :execute StageToggle(line(\"'<\"),line(\"'>\")-line(\"'<\")+1)" nnoremap C :Gcommit:echohl WarningMsgecho ':Gstatus C is deprecated in favor of cc'echohl NONE nnoremap ca :Gcommit --amend nnoremap cc :Gcommit @@ -2201,42 +2201,103 @@ function! s:StageDiffEdit() abort endif endfunction -function! s:StageToggle(lnum1,lnum2) abort - if a:lnum1 == 1 && a:lnum2 == 1 +function! s:StageApply(info, lnum1, count, reverse, extra) abort + let cmd = ['apply', '-p0'] + 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 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' + endif + while getline(end) =~# '^[-+ ]' + let end += 1 + if getline(end) =~# '^[' . (a:reverse ? '+' : '-') . ' ]' + call add(lines, ' ' . getline(end)[1:-1]) + endif + endwhile + while start > 0 && getline(start) !~# '^@' + let start -= 1 + if getline(start) =~# '^[' . (a:reverse ? '+' : '-') . ' ]' + call insert(lines, ' ' . getline(start)[1:-1]) + elseif getline(start) =~# '^@' + call insert(lines, getline(start)) + endif + endwhile + if start == 0 || getline(start) !~# '^@@ ' + return "fugitive: could not find hunk" + endif + let i = b:fugitive_expanded[info.section][info.filename][0] + let head = [] + while get(b:fugitive_diff[info.section], i, '@') !~# '^@' + call add(head, b:fugitive_diff[info.section][i]) + let i += 1 + endwhile + call extend(lines, head, 'keep') + let temp = tempname() + call writefile(lines, temp) + if a:reverse + call add(cmd, '--reverse') + endif + call extend(cmd, ['--', temp]) + let output = call('s:TreeChomp', cmd) + return v:shell_error ? output : '' +endfunction + +function! s:StageToggle(lnum1, count) abort + if a:lnum1 == 1 && a:count == 0 return 'Gedit .git/|call search("^index$", "wc")' endif try - let output = '' - for lnum in range(a:lnum1,a:lnum2) - let info = s:StageInfo(lnum) - 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 '' + 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) + if empty(filename) || info.offset >= 0 continue endif execute lnum @@ -2254,16 +2315,15 @@ function! s:StageToggle(lnum1,lnum2) abort if !exists('target') let target = [filename, info.section ==# 'Staged' ? '' : 'Staged'] endif - let output .= call('s:TreeChomp', cmd)."\n" + call call('s:TreeChomp', cmd) endfor if exists('target') - call s:StageReloadSeek(target, a:lnum1, a:lnum2) + exe s:ReloadStatus() endif - echo s:sub(s:gsub(output,'\n+','\n'),'\n$','') catch /^fugitive:/ return 'echoerr v:errmsg' endtry - return 'checktime' + return '' endfunction function! s:StagePatch(lnum1,lnum2) abort