diff --git a/src/diff.c b/src/diff.c index 21fb748381..d86dbf1530 100644 --- a/src/diff.c +++ b/src/diff.c @@ -3391,6 +3391,11 @@ diff_find_change_inline_diff( diff_T *orig_diff = curtab->tp_first_diff; curtab->tp_first_diff = NULL; + // diff_read() also uses curtab->tp_diffbuf to determine what's an active + // buffer + buf_T *(orig_diffbuf[DB_COUNT]); + memcpy(orig_diffbuf, curtab->tp_diffbuf, sizeof(orig_diffbuf)); + // Buffers to populate mmfile 1/2 that would be passed to xdiff as memory // files. Use a grow array as it is not obvious how much exact space we // need. @@ -3412,7 +3417,12 @@ diff_find_change_inline_diff( continue; // skip buffer that isn't loaded if (dp->df_count[i] == 0) - continue; // skip buffer that don't have any texts in this block + { + // skip buffers that don't have any texts in this block so we don't + // end up marking the entire block as modified in multi-buffer diff + curtab->tp_diffbuf[i] = NULL; + continue; + } if (file1_idx == -1) file1_idx = i; @@ -3626,7 +3636,7 @@ diff_find_change_inline_diff( CLEAR_FIELD(change); for (int i = 0; i < DB_COUNT; i++) { - if (new_diff->df_lnum[i] == 0) + if (new_diff->df_lnum[i] <= 0) // should never be < 0. Checking just for safety. continue; linenr_T diff_lnum = new_diff->df_lnum[i] - 1; // use zero-index linenr_T diff_lnum_end = diff_lnum + new_diff->df_count[i]; @@ -3675,6 +3685,7 @@ done: diff_clear(curtab); curtab->tp_first_diff = orig_diff; + memcpy(curtab->tp_diffbuf, orig_diffbuf, sizeof(orig_diffbuf)); ga_clear(&file1_str); ga_clear(&file2_str); diff --git a/src/testdir/dumps/Test_diff_inline_multibuffer_empty_block_01.dump b/src/testdir/dumps/Test_diff_inline_multibuffer_empty_block_01.dump new file mode 100644 index 0000000000..fad9aac399 --- /dev/null +++ b/src/testdir/dumps/Test_diff_inline_multibuffer_empty_block_01.dump @@ -0,0 +1,20 @@ +| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0|n|c|h|o|r|1| @10||+1&&| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0|n|c|h|o|r|1| @7||+1&&| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0|n|c|h|o|r|1| @8||+1&&| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0|n|c|h|o|r|1| @7 +| +0#0000e05#a8a8a8255@1|1+0#0000000#ffd7ff255|2+2&#ff404010|3|4|5|6|7|8|9|0+0&#ffd7ff255|a|b|c|d+2&#ff404010|e| +0&#ffd7ff255@2||+1&#ffffff0| +0#0000e05#a8a8a8255@1|1+0#0000000#ffd7ff255|2+2&#ff404010|3|4|5|6|7|-@1|0+0&#ffd7ff255|a|b|c|-+2&#ff404010|e||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@15||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|1+0#0000000#ffd7ff255|?+2&#ff404010@6|9|0+0&#ffd7ff255|a|b|c|d+2&#ff404010|? +| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0|n|c|h|o|r|2| @10||+1&&| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0|n|c|h|o|r|2| @7||+1&&| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0|n|c|h|o|r|2| @8||+1&&| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0|n|c|h|o|r|2| @7 +|~+0#4040ff13&| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|~| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|~| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|~| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|~| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|~| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|~| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|~| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|~| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|~| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|~| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|~| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|~| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|~| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|~| @18||+1#0000000&|~+0#4040ff13&| @15||+1#0000000&|~+0#4040ff13&| @16||+1#0000000&|~+0#4040ff13&| @15 +|X+3#0000000&|d|i|f|i|l|e|1| @1|1|,|1| @3|A|l@1| |<+1&&|d|i|f|i|l|e|2| |1|,|1| @1|A|l@1| |<|d|i|f|i|l|e|3| |1|,|1| @2|A|l@1| |<|d|i|f|i|l|e|4| |1|,|1| @1|A|l@1 +|:+0&&> @73 diff --git a/src/testdir/test_diffmode.vim b/src/testdir/test_diffmode.vim index dc5dcc9a5e..eee23729a1 100644 --- a/src/testdir/test_diffmode.vim +++ b/src/testdir/test_diffmode.vim @@ -2636,6 +2636,22 @@ func Test_diff_inline_multibuffer() call StopVimInTerminal(buf) endfunc +" Test that when using multi-buffer diff, an empty block would be correctly +" skipped in the result, without resulting in invalid states or crashes. +func Test_diff_inline_multibuffer_empty_block() + CheckScreendump + + call writefile(['anchor1', '1234567890abcde', 'anchor2'], 'Xdifile1') + call writefile(['anchor1', '1234567--0abc-e', 'anchor2'], 'Xdifile2') + call writefile(['anchor1', 'anchor2'], 'Xdifile3') + call writefile(['anchor1', '1???????90abcd?', 'anchor2'], 'Xdifile4') + + let buf = RunVimInTerminal('-d Xdifile1 Xdifile2 Xdifile3 Xdifile4', {}) + call VerifyInternal(buf, "Test_diff_inline_multibuffer_empty_block_01", " diffopt+=inline:char") + + call StopVimInTerminal(buf) +endfunc + func Test_diffget_diffput_linematch() CheckScreendump call delete('.Xdifile1.swp') diff --git a/src/version.c b/src/version.c index a908f1179a..3b3f8ac979 100644 --- a/src/version.c +++ b/src/version.c @@ -719,6 +719,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1567, /**/ 1566, /**/