mirror of
https://github.com/airblade/vim-gitgutter.git
synced 2025-11-08 11:33:48 -05:00
@@ -12,6 +12,7 @@ Features:
|
|||||||
* Never saves the buffer.
|
* Never saves the buffer.
|
||||||
* Quick jumping between blocks of changed lines ("hunks").
|
* Quick jumping between blocks of changed lines ("hunks").
|
||||||
* Stage/undo/preview individual hunks.
|
* Stage/undo/preview individual hunks.
|
||||||
|
* Previews highlight intra-line changes.
|
||||||
* Stage partial hunks.
|
* Stage partial hunks.
|
||||||
* Provides a hunk text object.
|
* Provides a hunk text object.
|
||||||
* Diffs against index (default) or any commit.
|
* Diffs against index (default) or any commit.
|
||||||
|
|||||||
100
autoload/gitgutter/diff_highlight.vim
Normal file
100
autoload/gitgutter/diff_highlight.vim
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
" Calculates the changed portions of lines. Based closely on diff-highlight
|
||||||
|
" (included with git) - please note its caveats.
|
||||||
|
"
|
||||||
|
" https://github.com/git/git/blob/master/contrib/diff-highlight/DiffHighlight.pm
|
||||||
|
|
||||||
|
|
||||||
|
" Returns a list of intra-line changed regions.
|
||||||
|
" Each element is a list:
|
||||||
|
"
|
||||||
|
" [
|
||||||
|
" line number (1-based),
|
||||||
|
" type ('+' or '-'),
|
||||||
|
" start column (1-based, inclusive),
|
||||||
|
" stop column (1-based, inclusive),
|
||||||
|
" ]
|
||||||
|
"
|
||||||
|
" Args:
|
||||||
|
" hunk_body - list of lines
|
||||||
|
function! gitgutter#diff_highlight#process(hunk_body)
|
||||||
|
" Check whether we have the same number of lines added as removed.
|
||||||
|
let [removed, added] = [0, 0]
|
||||||
|
for line in a:hunk_body
|
||||||
|
if line[0] == '-'
|
||||||
|
let removed += 1
|
||||||
|
elseif line[0] == '+'
|
||||||
|
let added += 1
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
if removed != added
|
||||||
|
return []
|
||||||
|
endif
|
||||||
|
|
||||||
|
let regions = []
|
||||||
|
|
||||||
|
for i in range(removed)
|
||||||
|
" pair lines by position
|
||||||
|
let rline = a:hunk_body[i]
|
||||||
|
let aline = a:hunk_body[i + removed]
|
||||||
|
|
||||||
|
let prefix = s:common_prefix(rline, aline)
|
||||||
|
let [rsuffix, asuffix] = s:common_suffix(rline, aline, prefix+1)
|
||||||
|
|
||||||
|
if (prefix != 0 || rsuffix != 0) && prefix+1 < rsuffix
|
||||||
|
call add(regions, [i+1, '-', prefix+1+1, rsuffix+1-1])
|
||||||
|
endif
|
||||||
|
|
||||||
|
if (prefix != 0 || asuffix != 0) && prefix+1 < asuffix
|
||||||
|
call add(regions, [i+1+removed, '+', prefix+1+1, asuffix+1-1])
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return regions
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
" Returns 0-based index of last character of common prefix
|
||||||
|
" Does not treat leading +/- as different.
|
||||||
|
"
|
||||||
|
" a, b - strings
|
||||||
|
"
|
||||||
|
function! s:common_prefix(a, b)
|
||||||
|
let len = min([len(a:a), len(a:b)])
|
||||||
|
" ignore initial +/-
|
||||||
|
for i in range(1, len - 1)
|
||||||
|
if a:a[i:i] != a:b[i:i]
|
||||||
|
return i - 1
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
return i
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
if $VIM_GITGUTTER_TEST
|
||||||
|
function! gitgutter#diff_highlight#common_prefix(a, b)
|
||||||
|
return s:common_prefix(a:a, a:b)
|
||||||
|
endfunction
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
" Returns 0-based indices of start of common suffix
|
||||||
|
"
|
||||||
|
" a, b - strings
|
||||||
|
" start - 0-based index to start from
|
||||||
|
function! s:common_suffix(a, b, start)
|
||||||
|
let [sa, sb] = [len(a:a), len(a:b)]
|
||||||
|
while sa >= a:start && sb >= a:start
|
||||||
|
if a:a[sa] ==# a:b[sb]
|
||||||
|
let sa -= 1
|
||||||
|
let sb -= 1
|
||||||
|
else
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endwhile
|
||||||
|
return [sa+1, sb+1]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
if $VIM_GITGUTTER_TEST
|
||||||
|
function! gitgutter#diff_highlight#common_suffix(a, b, start)
|
||||||
|
return s:common_suffix(a:a, a:b, a:start)
|
||||||
|
endfunction
|
||||||
|
endif
|
||||||
@@ -102,6 +102,10 @@ function! gitgutter#highlight#define_highlights() abort
|
|||||||
highlight default link GitGutterChangeLineNr CursorLineNr
|
highlight default link GitGutterChangeLineNr CursorLineNr
|
||||||
highlight default link GitGutterDeleteLineNr CursorLineNr
|
highlight default link GitGutterDeleteLineNr CursorLineNr
|
||||||
highlight default link GitGutterChangeDeleteLineNr CursorLineNr
|
highlight default link GitGutterChangeDeleteLineNr CursorLineNr
|
||||||
|
|
||||||
|
" Highlights used intra line.
|
||||||
|
highlight GitGutterAddIntraLine gui=reverse
|
||||||
|
highlight GitGutterDeleteIntraLine gui=reverse
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! gitgutter#highlight#define_signs() abort
|
function! gitgutter#highlight#define_signs() abort
|
||||||
|
|||||||
@@ -458,11 +458,20 @@ function! s:populate_hunk_preview_window(header, body)
|
|||||||
call nvim_buf_set_lines(winbufnr(s:winid), 0, -1, v:false, [])
|
call nvim_buf_set_lines(winbufnr(s:winid), 0, -1, v:false, [])
|
||||||
call nvim_buf_set_lines(winbufnr(s:winid), 0, -1, v:false, a:body)
|
call nvim_buf_set_lines(winbufnr(s:winid), 0, -1, v:false, a:body)
|
||||||
call nvim_buf_set_option(winbufnr(s:winid), 'modified', v:false)
|
call nvim_buf_set_option(winbufnr(s:winid), 'modified', v:false)
|
||||||
|
|
||||||
|
let ns_id = nvim_create_namespace('GitGutter')
|
||||||
|
call nvim_buf_clear_namespace(winbufnr(s:winid), ns_id, 0, -1)
|
||||||
|
for region in gitgutter#diff_highlight#process(a:body)
|
||||||
|
let group = region[1] == '+' ? 'GitGutterAddIntraLine' : 'GitGutterDeleteIntraLine'
|
||||||
|
call nvim_buf_add_highlight(winbufnr(s:winid), ns_id, group, region[0]-1, region[2]-1, region[3])
|
||||||
|
endfor
|
||||||
|
|
||||||
call nvim_win_set_cursor(s:winid, [1,0])
|
call nvim_win_set_cursor(s:winid, [1,0])
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if exists('*popup_create')
|
if exists('*popup_create')
|
||||||
call popup_settext(s:winid, a:body)
|
call popup_settext(s:winid, a:body)
|
||||||
|
" TODO add intra line highlights
|
||||||
endif
|
endif
|
||||||
|
|
||||||
else
|
else
|
||||||
@@ -472,6 +481,13 @@ function! s:populate_hunk_preview_window(header, body)
|
|||||||
%delete _
|
%delete _
|
||||||
call setline(1, a:body)
|
call setline(1, a:body)
|
||||||
setlocal nomodified
|
setlocal nomodified
|
||||||
|
|
||||||
|
call clearmatches()
|
||||||
|
for region in gitgutter#diff_highlight#process(a:body)
|
||||||
|
let group = region[1] == '+' ? 'GitGutterAddIntraLine' : 'GitGutterDeleteIntraLine'
|
||||||
|
call matchaddpos(group, [[region[0], region[2], region[3]-region[2]+1]])
|
||||||
|
endfor
|
||||||
|
|
||||||
1
|
1
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|||||||
@@ -60,6 +60,9 @@ function SetUp()
|
|||||||
execute ':cd' s:test_repo
|
execute ':cd' s:test_repo
|
||||||
edit! fixture.txt
|
edit! fixture.txt
|
||||||
call gitgutter#sign#reset()
|
call gitgutter#sign#reset()
|
||||||
|
|
||||||
|
" FIXME why won't vim autoload the file?
|
||||||
|
execute 'source' '../../autoload/gitgutter/diff_highlight.vim'
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function TearDown()
|
function TearDown()
|
||||||
@@ -910,3 +913,62 @@ function Test_quickfix()
|
|||||||
|
|
||||||
call s:assert_list_of_dicts(expected, getqflist())
|
call s:assert_list_of_dicts(expected, getqflist())
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
function Test_common_prefix()
|
||||||
|
" nothing in common
|
||||||
|
call assert_equal(0, gitgutter#diff_highlight#common_prefix('-abcde', '+pqrst'))
|
||||||
|
" something in common
|
||||||
|
call assert_equal(3, gitgutter#diff_highlight#common_prefix('-abcde', '+abcpq'))
|
||||||
|
" everything in common
|
||||||
|
call assert_equal(5, gitgutter#diff_highlight#common_prefix('-abcde', '+abcde'))
|
||||||
|
" different lengths
|
||||||
|
call assert_equal(2, gitgutter#diff_highlight#common_prefix('-abcde', '+abx'))
|
||||||
|
call assert_equal(2, gitgutter#diff_highlight#common_prefix('-abx', '+abcde'))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
function Test_common_suffix()
|
||||||
|
" nothing in common
|
||||||
|
call assert_equal([6,6], gitgutter#diff_highlight#common_suffix('-abcde', '+pqrst', 0))
|
||||||
|
" something in common
|
||||||
|
call assert_equal([3,3], gitgutter#diff_highlight#common_suffix('-abcde', '+pqcde', 0))
|
||||||
|
" everything in common
|
||||||
|
call assert_equal([5,5], gitgutter#diff_highlight#common_suffix('-abcde', '+abcde', 5))
|
||||||
|
" different lengths
|
||||||
|
call assert_equal([4,2], gitgutter#diff_highlight#common_suffix('-abcde', '+xde', 0))
|
||||||
|
call assert_equal([2,4], gitgutter#diff_highlight#common_suffix('-xde', '+abcde', 0))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
function Test_diff_highlight()
|
||||||
|
" Ignores mismatched number of added and removed lines.
|
||||||
|
call assert_equal([], gitgutter#diff_highlight#process(['-foo']))
|
||||||
|
call assert_equal([], gitgutter#diff_highlight#process(['+foo']))
|
||||||
|
call assert_equal([], gitgutter#diff_highlight#process(['-foo','-bar','+baz']))
|
||||||
|
|
||||||
|
" change in middle
|
||||||
|
let hunk = ['-foo bar baz', '+foo (bar) baz']
|
||||||
|
let expected = [[1, '-', 6, 8], [2, '+', 6, 10]]
|
||||||
|
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]]
|
||||||
|
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]]
|
||||||
|
call assert_equal(expected, gitgutter#diff_highlight#process(hunk))
|
||||||
|
|
||||||
|
" removed in middle
|
||||||
|
let hunk = ['-foo bar baz', '+foo baz']
|
||||||
|
let expected = [[1, '-', 8, 11]]
|
||||||
|
call assert_equal(expected, gitgutter#diff_highlight#process(hunk))
|
||||||
|
|
||||||
|
" added in middle
|
||||||
|
let hunk = ['-foo baz', '+foo bar baz']
|
||||||
|
let expected = [[2, '+', 8, 11]]
|
||||||
|
call assert_equal(expected, gitgutter#diff_highlight#process(hunk))
|
||||||
|
endfunction
|
||||||
|
|||||||
Reference in New Issue
Block a user