Allow staging part of an additions-only hunk.

See #279.
This commit is contained in:
Andy Stewart
2019-08-12 17:19:05 +01:00
parent fef14f1d49
commit bc1d28db46
6 changed files with 109 additions and 6 deletions

View File

@@ -187,6 +187,11 @@ You can stage or undo an individual hunk when your cursor is in it:
* stage the hunk with `<Leader>hs` or
* undo it with `<Leader>hu`.
You can stage part of an additions-only hunk by:
* either visually selecting the part you want and staging with your mapping, e.g. `<Leader>hs`;
* or using a range with the `GitGutterStageHunk` command, e.g. `:42,45GitGutterStageHunk`.
See the FAQ if you want to unstage staged changes.
The `.` command will work with both these if you install [repeat.vim](https://github.com/tpope/vim-repeat).

View File

@@ -126,6 +126,9 @@ function! gitgutter#setup_maps()
nmap <buffer> ]c <Plug>GitGutterNextHunk
endif
if !hasmapto('<Plug>GitGutterStageHunk') && maparg('<Leader>hs', 'x') ==# ''
xmap <buffer> <Leader>hs <Plug>GitGutterStageHunk
endif
if !hasmapto('<Plug>GitGutterStageHunk') && maparg('<Leader>hs', 'n') ==# ''
nmap <buffer> <Leader>hs <Plug>GitGutterStageHunk
endif

View File

@@ -169,8 +169,12 @@ function! gitgutter#hunk#text_object(inner) abort
endfunction
function! gitgutter#hunk#stage() abort
call s:hunk_op(function('s:stage'))
function! gitgutter#hunk#stage(...) abort
if a:0 && (a:1 != 1 || a:2 != line('$'))
call s:hunk_op(function('s:stage'), a:1, a:2)
else
call s:hunk_op(function('s:stage'))
endif
silent! call repeat#set("\<Plug>GitGutterStageHunk", -1)
endfunction
@@ -185,7 +189,7 @@ function! gitgutter#hunk#preview() abort
endfunction
function! s:hunk_op(op)
function! s:hunk_op(op, ...)
let bufnr = bufnr('')
if gitgutter#utility#is_active(bufnr)
@@ -210,7 +214,14 @@ function! s:hunk_op(op)
call gitgutter#utility#warn('did not recognise your choice')
endif
else
call a:op(gitgutter#diff#hunk_diff(bufnr, diff))
let hunk_diff = gitgutter#diff#hunk_diff(bufnr, diff)
if a:0
let hunk_first_line = s:current_hunk()[2]
let hunk_diff = s:part_of_diff(hunk_diff, a:1-hunk_first_line, a:2-hunk_first_line)
endif
call a:op(hunk_diff)
endif
endif
endfunction
@@ -271,6 +282,18 @@ function! s:preview(hunk_diff)
endfunction
" Returns a new hunk diff using the specified lines from the given one.
" a:first, a:last - 0-based indexes into the body of the hunk.
function! s:part_of_diff(hunk_diff, first, last)
let diff_lines = split(a:hunk_diff, '\n', 1)
" adjust line count in header
let diff_lines[4] = substitute(diff_lines[4], '\(+\d\+\)\(,\d\+\)\?', '\=submatch(1).",".(a:last-a:first+1)', '')
return join(diff_lines[0:4] + diff_lines[5+a:first:5+a:last], "\n")."\n"
endfunction
function! s:adjust_header(bufnr, hunk_diff)
let filepath = gitgutter#utility#repo_path(a:bufnr, 0)
return s:adjust_hunk_summary(s:fix_file_references(filepath, a:hunk_diff))

View File

@@ -164,7 +164,9 @@ Commands for jumping between hunks:~
Commands for operating on a hunk:~
*gitgutter-:GitGutterStageHunk*
:GitGutterStageHunk Stage the hunk the cursor is in.
:GitGutterStageHunk Stage the hunk the cursor is in. Use a visual selection
to stage part of an (additions-only) hunk; or use a
range.
*gitgutter-:GitGutterUndoHunk*
:GitGutterUndoHunk Undo the hunk the cursor is in.

View File

@@ -136,7 +136,7 @@ command! -bar GitGutterSignsToggle call gitgutter#sign#toggle()
command! -bar -count=1 GitGutterNextHunk call gitgutter#hunk#next_hunk(<count>)
command! -bar -count=1 GitGutterPrevHunk call gitgutter#hunk#prev_hunk(<count>)
command! -bar GitGutterStageHunk call gitgutter#hunk#stage()
command! -bar -range=% GitGutterStageHunk call gitgutter#hunk#stage(<line1>,<line2>)
command! -bar GitGutterUndoHunk call gitgutter#hunk#undo()
command! -bar GitGutterPreviewHunk call gitgutter#hunk#preview()
@@ -191,6 +191,7 @@ command! -bar GitGutterDebug call gitgutter#debug#debug()
nnoremap <silent> <expr> <Plug>GitGutterNextHunk &diff ? ']c' : ":\<C-U>execute v:count1 . 'GitGutterNextHunk'\<CR>"
nnoremap <silent> <expr> <Plug>GitGutterPrevHunk &diff ? '[c' : ":\<C-U>execute v:count1 . 'GitGutterPrevHunk'\<CR>"
xnoremap <silent> <Plug>GitGutterStageHunk :GitGutterStageHunk<CR>
nnoremap <silent> <Plug>GitGutterStageHunk :GitGutterStageHunk<CR>
nnoremap <silent> <Plug>GitGutterUndoHunk :GitGutterUndoHunk<CR>
nnoremap <silent> <Plug>GitGutterPreviewHunk :GitGutterPreviewHunk<CR>

View File

@@ -417,6 +417,75 @@ function Test_hunk_stage_nearby_hunk()
endfunction
function Test_hunk_stage_partial_visual_added()
call append(5, ['A','B','C','D'])
execute "normal 7GVj:GitGutterStageHunk\<CR>"
let expected = [
\ 'line=6 id=3000 name=GitGutterLineAdded priority=10',
\ 'line=9 id=3001 name=GitGutterLineAdded priority=10',
\ ]
call assert_equal(expected, s:signs('fixture.txt'))
let expected = [
\ 'diff --git a/fixture.txt b/fixture.txt',
\ 'index 8a7026e..f5c6aff 100644',
\ '--- a/fixture.txt',
\ '+++ b/fixture.txt',
\ '@@ -6,2 +5,0 @@ e',
\ '-B',
\ '-C',
\ ]
call assert_equal(expected, s:git_diff())
let expected = [
\ 'diff --git a/fixture.txt b/fixture.txt',
\ 'index f5c6aff..8a7026e 100644',
\ '--- a/fixture.txt',
\ '+++ b/fixture.txt',
\ '@@ -5,0 +6,2 @@ e',
\ '+B',
\ '+C',
\ ]
call assert_equal(expected, s:git_diff_staged())
endfunction
function Test_hunk_stage_partial_cmd_added()
call append(5, ['A','B','C','D'])
normal 6G
7,8GitGutterStageHunk
let expected = [
\ 'line=6 id=3000 name=GitGutterLineAdded priority=10',
\ 'line=9 id=3001 name=GitGutterLineAdded priority=10',
\ ]
call assert_equal(expected, s:signs('fixture.txt'))
let expected = [
\ 'diff --git a/fixture.txt b/fixture.txt',
\ 'index 8a7026e..f5c6aff 100644',
\ '--- a/fixture.txt',
\ '+++ b/fixture.txt',
\ '@@ -6,2 +5,0 @@ e',
\ '-B',
\ '-C',
\ ]
call assert_equal(expected, s:git_diff())
let expected = [
\ 'diff --git a/fixture.txt b/fixture.txt',
\ 'index f5c6aff..8a7026e 100644',
\ '--- a/fixture.txt',
\ '+++ b/fixture.txt',
\ '@@ -5,0 +6,2 @@ e',
\ '+B',
\ '+C',
\ ]
call assert_equal(expected, s:git_diff_staged())
endfunction
function Test_hunk_undo()
let _shell = &shell
set shell=foo