diff --git a/autoload/gitgutter/diff_highlight.vim b/autoload/gitgutter/diff_highlight.vim index e097704..3031582 100644 --- a/autoload/gitgutter/diff_highlight.vim +++ b/autoload/gitgutter/diff_highlight.vim @@ -1,7 +1,12 @@ -" Calculates the changed portions of lines. Based closely on diff-highlight -" (included with git) - please note its caveats. +" Calculates the changed portions of lines. " -" https://github.com/git/git/blob/master/contrib/diff-highlight/DiffHighlight.pm +" Based on: +" +" - diff-highlight (included with git) +" https://github.com/git/git/blob/master/contrib/diff-highlight/DiffHighlight.pm +" +" - Diff Strategies, Neil Fraser +" https://neil.fraser.name/writing/diff/ " Returns a list of intra-line changed regions. @@ -40,10 +45,49 @@ function! gitgutter#diff_highlight#process(hunk_body) let prefix = s:common_prefix(rline, aline) let [rsuffix, asuffix] = s:common_suffix(rline, aline, prefix+1) + let rtext = rline[prefix+1:rsuffix-1] + let atext = aline[prefix+1:asuffix-1] + + " singular insertion + if empty(rtext) + if len(atext) != len(aline) " not whole line + call add(regions, [i+1+removed, '+', prefix+1+1, asuffix+1-1]) + endif + continue + endif + + " singular deletion + if empty(atext) + if len(rtext) != len(rline) " not whole line + call add(regions, [i+1, '-', prefix+1+1, rsuffix+1-1]) + endif + continue + endif + + " two insertions + let j = stridx(atext, rtext) + if j != -1 + call add(regions, [i+1+removed, '+', prefix+1+1, prefix+j+1]) + call add(regions, [i+1+removed, '+', prefix+1+1+j+len(rtext), asuffix+1-1]) + continue + endif + + " two deletions + let j = stridx(rtext, atext) + if j != -1 + call add(regions, [i+1, '-', prefix+1+1, prefix+j+1]) + call add(regions, [i+1, '-', prefix+1+1+j+len(atext), rsuffix+1-1]) + continue + endif + + " fall back to highlighting entire changed area + + " if a change (but not the whole line) if (prefix != 0 || rsuffix != len(rline)) && prefix+1 < rsuffix call add(regions, [i+1, '-', prefix+1+1, rsuffix+1-1]) endif + " if a change (but not the whole line) if (prefix != 0 || asuffix != len(aline)) && prefix+1 < asuffix call add(regions, [i+1+removed, '+', prefix+1+1, asuffix+1-1]) endif diff --git a/test/test_gitgutter.vim b/test/test_gitgutter.vim index 103a007..c3c1d02 100644 --- a/test/test_gitgutter.vim +++ b/test/test_gitgutter.vim @@ -953,18 +953,18 @@ function Test_diff_highlight() call assert_equal(expected, gitgutter#diff_highlight#process(hunk)) " change in middle - let hunk = ['-foo bar baz', '+foo (bar) baz'] - let expected = [[1, '-', 6, 8], [2, '+', 6, 10]] + let hunk = ['-foo bar baz', '+foo zip baz'] + let expected = [[1, '-', 6, 8], [2, '+', 6, 8]] call assert_equal(expected, gitgutter#diff_highlight#process(hunk)) " change at start - let hunk = ['-foo bar baz', '+(foo) bar baz'] - let expected = [[1, '-', 2, 4], [2, '+', 2, 6]] + let hunk = ['-foo bar baz', '+zip bar baz'] + let expected = [[1, '-', 2, 4], [2, '+', 2, 4]] call assert_equal(expected, gitgutter#diff_highlight#process(hunk)) " change at end - let hunk = ['-foo bar baz', '+foo bar (baz)'] - let expected = [[1, '-', 10, 12], [2, '+', 10, 14]] + let hunk = ['-foo bar baz', '+foo bar zip'] + let expected = [[1, '-', 10, 12], [2, '+', 10, 12]] call assert_equal(expected, gitgutter#diff_highlight#process(hunk)) " removed in middle @@ -976,4 +976,39 @@ function Test_diff_highlight() let hunk = ['-foo baz', '+foo bar baz'] let expected = [[2, '+', 8, 11]] call assert_equal(expected, gitgutter#diff_highlight#process(hunk)) + + " two insertions at start + let hunk = ['-foo bar baz', '+(foo) bar baz'] + let expected = [[2, '+', 2, 2], [2, '+', 6, 6]] + call assert_equal(expected, gitgutter#diff_highlight#process(hunk)) + + " two insertions in middle + let hunk = ['-foo bar baz', '+foo (bar) baz'] + let expected = [[2, '+', 6, 6], [2, '+', 10, 10]] + call assert_equal(expected, gitgutter#diff_highlight#process(hunk)) + + " two insertions at end + let hunk = ['-foo bar baz', '+foo bar (baz)'] + let expected = [[2, '+', 10, 10], [2, '+', 14, 14]] + call assert_equal(expected, gitgutter#diff_highlight#process(hunk)) + + " singular insertion + let hunk = ['-The cat in the hat.', '+The furry cat in the hat.'] + call assert_equal([[2, '+', 6, 11]], gitgutter#diff_highlight#process(hunk)) + + " singular deletion + let hunk = ['-The cat in the hat.', '+The cat.'] + call assert_equal([[1, '-', 9, 19]], gitgutter#diff_highlight#process(hunk)) + + " two insertions + let hunk = ['-The cat in the hat.', '+The furry cat in the teal hat.'] + call assert_equal([[2, '+', 6, 11], [2, '+', 22, 26]], gitgutter#diff_highlight#process(hunk)) + + " two deletions + let hunk = ['-The furry cat in the teal hat.', '+The cat in the hat.'] + call assert_equal([[1, '-', 6, 11], [1, '-', 22, 26]], gitgutter#diff_highlight#process(hunk)) + + " two edits + let hunk = ['-The cat in the hat.', '+The ox in the box.'] + call assert_equal([[1, '-', 6, 8], [1, '-', 17, 19], [2, '+', 6, 7], [2, '+', 16, 18]], gitgutter#diff_highlight#process(hunk)) endfunction