aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/diff.c14
-rw-r--r--src/nvim/testdir/test_diffmode.vim37
-rw-r--r--test/functional/ui/diff_spec.lua127
3 files changed, 174 insertions, 4 deletions
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index a6bbe40999..0b55fb877c 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -743,11 +743,16 @@ static int diff_write_buffer(buf_T *buf, diffin_T *din)
for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
for (char_u *s = ml_get_buf(buf, lnum, false); *s != NUL;) {
if (diff_flags & DIFF_ICASE) {
+ int c;
char_u cbuf[MB_MAXBYTES + 1];
- // xdiff doesn't support ignoring case, fold-case the text.
- int c = utf_ptr2char(s);
- c = utf_fold(c);
+ if (*s == NL) {
+ c = NUL;
+ } else {
+ // xdiff doesn't support ignoring case, fold-case the text.
+ c = utf_ptr2char(s);
+ c = utf_fold(c);
+ }
const int orig_len = utfc_ptr2len(s);
if (utf_char2bytes(c, cbuf) != orig_len) {
// TODO(Bram): handle byte length difference
@@ -759,7 +764,8 @@ static int diff_write_buffer(buf_T *buf, diffin_T *din)
s += orig_len;
len += orig_len;
} else {
- ptr[len++] = *s++;
+ ptr[len++] = *s == NL ? NUL : *s;
+ s++;
}
}
ptr[len++] = NL;
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index 10eb979b45..be9a77ee75 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -1295,4 +1295,41 @@ func Test_diff_filler_cursorcolumn()
endfunc
+func Test_diff_binary()
+ CheckScreendump
+
+ let content =<< trim END
+ call setline(1, ['a', 'b', "c\n", 'd', 'e', 'f', 'g'])
+ vnew
+ call setline(1, ['A', 'b', 'c', 'd', 'E', 'f', 'g'])
+ windo diffthis
+ wincmd p
+ norm! gg0
+ redraw!
+ END
+ call writefile(content, 'Xtest_diff_bin')
+ let buf = RunVimInTerminal('-S Xtest_diff_bin', {})
+
+ " Test using internal diff
+ call VerifyScreenDump(buf, 'Test_diff_bin_01', {})
+
+ " Test using internal diff and case folding
+ call term_sendkeys(buf, ":set diffopt+=icase\<cr>")
+ call term_sendkeys(buf, "\<C-l>")
+ call VerifyScreenDump(buf, 'Test_diff_bin_02', {})
+ " Test using external diff
+ call term_sendkeys(buf, ":set diffopt=filler\<cr>")
+ call term_sendkeys(buf, "\<C-l>")
+ call VerifyScreenDump(buf, 'Test_diff_bin_03', {})
+ " Test using external diff and case folding
+ call term_sendkeys(buf, ":set diffopt=filler,icase\<cr>")
+ call term_sendkeys(buf, "\<C-l>")
+ call VerifyScreenDump(buf, 'Test_diff_bin_04', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_diff_bin')
+ set diffopt&vim
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua
index 3a25d7e813..6f67dea2be 100644
--- a/test/functional/ui/diff_spec.lua
+++ b/test/functional/ui/diff_spec.lua
@@ -1226,3 +1226,130 @@ it('Align the filler lines when changing text in diff mode', function()
|
]]}
end)
+
+it('diff mode works properly if file contains NUL bytes vim-patch:8.2.3925', function()
+ clear()
+ local screen = Screen.new(40, 20)
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Gray};
+ [2] = {reverse = true};
+ [3] = {background = Screen.colors.LightBlue};
+ [4] = {background = Screen.colors.LightMagenta};
+ [5] = {background = Screen.colors.Red, bold = true};
+ [6] = {foreground = Screen.colors.Blue, bold = true};
+ [7] = {background = Screen.colors.Red, foreground = Screen.colors.Blue, bold = true};
+ [8] = {reverse = true, bold = true};
+ })
+ screen:attach()
+ exec([[
+ call setline(1, ['a', 'b', "c\n", 'd', 'e', 'f', 'g'])
+ vnew
+ call setline(1, ['A', 'b', 'c', 'd', 'E', 'f', 'g'])
+ windo diffthis
+ wincmd p
+ norm! gg0
+ redraw!
+ ]])
+
+ -- Test using internal diff
+ screen:expect([[
+ {1: }{5:^A}{4: }{2:│}{1: }{5:a}{4: }|
+ {1: }b {2:│}{1: }b |
+ {1: }{4:c }{2:│}{1: }{4:c}{7:^@}{4: }|
+ {1: }d {2:│}{1: }d |
+ {1: }{5:E}{4: }{2:│}{1: }{5:e}{4: }|
+ {1: }f {2:│}{1: }f |
+ {1: }g {2:│}{1: }g |
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {8:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+
+ -- Test using internal diff and case folding
+ command('set diffopt+=icase')
+ feed('<C-L>')
+ screen:expect([[
+ {1: }^A {2:│}{1: }a |
+ {1: }b {2:│}{1: }b |
+ {1: }{4:c }{2:│}{1: }{4:c}{7:^@}{4: }|
+ {1: }d {2:│}{1: }d |
+ {1: }E {2:│}{1: }e |
+ {1: }f {2:│}{1: }f |
+ {1: }g {2:│}{1: }g |
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {8:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+
+ -- Test using external diff
+ command('set diffopt=filler')
+ feed('<C-L>')
+ screen:expect([[
+ {1: }{5:^A}{4: }{2:│}{1: }{5:a}{4: }|
+ {1: }b {2:│}{1: }b |
+ {1: }{4:c }{2:│}{1: }{4:c}{7:^@}{4: }|
+ {1: }d {2:│}{1: }d |
+ {1: }{5:E}{4: }{2:│}{1: }{5:e}{4: }|
+ {1: }f {2:│}{1: }f |
+ {1: }g {2:│}{1: }g |
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {8:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+
+ -- Test using external diff and case folding
+ command('set diffopt+=filler,icase')
+ feed('<C-L>')
+ screen:expect([[
+ {1: }^A {2:│}{1: }a |
+ {1: }b {2:│}{1: }b |
+ {1: }{4:c }{2:│}{1: }{4:c}{7:^@}{4: }|
+ {1: }d {2:│}{1: }d |
+ {1: }E {2:│}{1: }e |
+ {1: }f {2:│}{1: }f |
+ {1: }g {2:│}{1: }g |
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {6:~ }{2:│}{6:~ }|
+ {8:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+end)