Skip to content

Commit be156a3

Browse files
yegappanchrisbra
authored andcommitted
patch 9.1.0096: diff() function uses 'diffexpr'
Problem: diff() function uses 'diffexpr' (rickhowe) Solution: Make diff() always use internal diff(), add support for unified diff context length, sort diff() options in help (Yegappan Lakshmanan) fixes: #13989 closes: #14010 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
1 parent 52eb0b8 commit be156a3

4 files changed

Lines changed: 95 additions & 46 deletions

File tree

runtime/doc/builtin.txt

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*builtin.txt* For Vim version 9.1. Last change: 2024 Feb 01
1+
*builtin.txt* For Vim version 9.1. Last change: 2024 Feb 11
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -2074,20 +2074,22 @@ diff({fromlist}, {tolist} [, {options}]) *diff()*
20742074

20752075
The {options} Dict argument also specifies diff options
20762076
(similar to 'diffopt') and supports the following items:
2077+
algorithm Dict specifying the diff algorithm to
2078+
use. Supported boolean items are
2079+
"myers", "minimal", "patience" and
2080+
"histogram".
2081+
context unified diff context length. Default
2082+
is 1.
20772083
iblank ignore changes where lines are all
20782084
blank.
20792085
icase ignore changes in case of text.
2086+
indent-heuristic use the indent heuristic for the
2087+
internal diff library.
20802088
iwhite ignore changes in amount of white
20812089
space.
20822090
iwhiteall ignore all white space changes.
20832091
iwhiteeol ignore white space changes at end of
20842092
line.
2085-
indent-heuristic use the indent heuristic for the
2086-
internal diff library.
2087-
algorithm Dict specifying the diff algorithm to
2088-
use. Supported boolean items are
2089-
"myers", "minimal", "patience" and
2090-
"histogram".
20912093
For more information about these options, refer to 'diffopt'.
20922094

20932095
Returns an empty List or String if {fromlist} and {tolist} are

src/diff.c

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,6 @@ static int diff_flags = DIFF_INTERNAL | DIFF_FILLER | DIFF_CLOSE_OFF;
4242

4343
static long diff_algorithm = 0;
4444

45-
#define DIFF_INTERNAL_OUTPUT_UNIFIED 1
46-
#define DIFF_INTERNAL_OUTPUT_INDICES 2
47-
static int diff_internal_output_fmt = DIFF_INTERNAL_OUTPUT_INDICES;
48-
4945
#define LBUFLEN 50 // length of line in diff file
5046

5147
static int diff_a_works = MAYBE; // TRUE when "diff -a" works, FALSE when it
@@ -76,12 +72,19 @@ typedef struct {
7672
long count_new;
7773
} diffhunk_T;
7874

75+
typedef enum {
76+
DIO_OUTPUT_INDICES = 0, // default
77+
DIO_OUTPUT_UNIFIED = 1 // unified diff format
78+
} dio_outfmt_T;
79+
7980
// two diff inputs and one result
8081
typedef struct {
81-
diffin_T dio_orig; // original file input
82-
diffin_T dio_new; // new file input
83-
diffout_T dio_diff; // diff result
84-
int dio_internal; // using internal diff
82+
diffin_T dio_orig; // original file input
83+
diffin_T dio_new; // new file input
84+
diffout_T dio_diff; // diff result
85+
int dio_internal; // using internal diff
86+
dio_outfmt_T dio_outfmt; // internal diff output format
87+
int dio_ctxlen; // unified diff context length
8588
} diffio_T;
8689

8790
static int diff_buf_idx(buf_T *buf);
@@ -1145,9 +1148,9 @@ diff_file_internal(diffio_T *diffio)
11451148
if (diff_flags & DIFF_IBLANK)
11461149
param.flags |= XDF_IGNORE_BLANK_LINES;
11471150

1148-
emit_cfg.ctxlen = 0; // don't need any diff_context here
1151+
emit_cfg.ctxlen = diffio->dio_ctxlen;
11491152
emit_cb.priv = &diffio->dio_diff;
1150-
if (diff_internal_output_fmt == DIFF_INTERNAL_OUTPUT_INDICES)
1153+
if (diffio->dio_outfmt == DIO_OUTPUT_INDICES)
11511154
emit_cfg.hunk_func = xdiff_out_indices;
11521155
else
11531156
emit_cb.out_line = xdiff_out_unified;
@@ -3473,10 +3476,11 @@ f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
34733476
*/
34743477
static int
34753478
parse_diff_optarg(
3476-
typval_T *opts,
3477-
int *diffopts,
3478-
long *diffalgo,
3479-
int *diff_output_fmt)
3479+
typval_T *opts,
3480+
int *diffopts,
3481+
long *diffalgo,
3482+
dio_outfmt_T *diff_output_fmt,
3483+
int *diff_ctxlen)
34803484
{
34813485
dict_T *d = opts->vval.v_dict;
34823486

@@ -3497,16 +3501,20 @@ parse_diff_optarg(
34973501
if (output_fmt != NULL)
34983502
{
34993503
if (STRNCMP(output_fmt, "unified", 7) == 0)
3500-
*diff_output_fmt = DIFF_INTERNAL_OUTPUT_UNIFIED;
3504+
*diff_output_fmt = DIO_OUTPUT_UNIFIED;
35013505
else if (STRNCMP(output_fmt, "indices", 7) == 0)
3502-
*diff_output_fmt = DIFF_INTERNAL_OUTPUT_INDICES;
3506+
*diff_output_fmt = DIO_OUTPUT_INDICES;
35033507
else
35043508
{
35053509
semsg(_(e_unsupported_diff_output_format_str), output_fmt);
35063510
return FAIL;
35073511
}
35083512
}
35093513

3514+
*diff_ctxlen = dict_get_number_def(d, "context", 1);
3515+
if (*diff_ctxlen < 0)
3516+
*diff_ctxlen = 1;
3517+
35103518
if (dict_get_bool(d, "iblank", FALSE))
35113519
*diffopts |= DIFF_IBLANK;
35123520
if (dict_get_bool(d, "icase", FALSE))
@@ -3602,33 +3610,43 @@ f_diff(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
36023610
// Save the 'diffopt' option value and restore it after getting the diff.
36033611
int save_diff_flags = diff_flags;
36043612
long save_diff_algorithm = diff_algorithm;
3605-
long save_diff_output_fmt = diff_internal_output_fmt;
36063613
diff_flags = DIFF_INTERNAL;
36073614
diff_algorithm = 0;
3608-
diff_internal_output_fmt = DIFF_INTERNAL_OUTPUT_UNIFIED;
3615+
dio.dio_outfmt = DIO_OUTPUT_UNIFIED;
36093616
if (argvars[2].v_type != VAR_UNKNOWN)
36103617
if (parse_diff_optarg(&argvars[2], &diff_flags, &diff_algorithm,
3611-
&diff_internal_output_fmt) == FAIL)
3612-
{
3613-
diff_internal_output_fmt = save_diff_output_fmt;
3618+
&dio.dio_outfmt, &dio.dio_ctxlen) == FAIL)
36143619
return;
3615-
}
36163620

36173621
// Concatenate the List of strings into a single string using newline
36183622
// separator. Internal diff library expects a single string.
36193623
list_to_diffin(orig_list, &dio.dio_orig, diff_flags & DIFF_ICASE);
36203624
list_to_diffin(new_list, &dio.dio_new, diff_flags & DIFF_ICASE);
36213625

3626+
// If 'diffexpr' is set, then the internal diff is not used. Set
3627+
// 'diffexpr' to an empty string temporarily.
3628+
int restore_diffexpr = FALSE;
3629+
char_u cc = *p_dex;
3630+
if (*p_dex != NUL)
3631+
{
3632+
restore_diffexpr = TRUE;
3633+
*p_dex = NUL;
3634+
}
3635+
36223636
// Compute the diff
36233637
int diff_status = diff_file(&dio);
36243638

3639+
// restore 'diffexpr'
3640+
if (restore_diffexpr)
3641+
*p_dex = cc;
3642+
36253643
if (diff_status == FAIL)
36263644
goto done;
36273645

36283646
int hunk_idx = 0;
36293647
dict_T *hunk_dict;
36303648

3631-
if (diff_internal_output_fmt == DIFF_INTERNAL_OUTPUT_INDICES)
3649+
if (dio.dio_outfmt == DIO_OUTPUT_INDICES)
36323650
{
36333651
if (rettv_list_alloc(rettv) != OK)
36343652
goto done;
@@ -3657,15 +3675,14 @@ f_diff(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
36573675

36583676
done:
36593677
clear_diffin(&dio.dio_new);
3660-
if (diff_internal_output_fmt == DIFF_INTERNAL_OUTPUT_INDICES)
3678+
if (dio.dio_outfmt == DIO_OUTPUT_INDICES)
36613679
clear_diffout(&dio.dio_diff);
36623680
else
36633681
ga_clear(&dio.dio_diff.dout_ga);
36643682
clear_diffin(&dio.dio_orig);
36653683
// Restore the 'diffopt' option value.
36663684
diff_flags = save_diff_flags;
36673685
diff_algorithm = save_diff_algorithm;
3668-
diff_internal_output_fmt = save_diff_output_fmt;
36693686
# endif
36703687
}
36713688

src/testdir/test_diffmode.vim

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1719,43 +1719,43 @@ endfunc
17191719
" Test for the diff() function
17201720
def Test_diff_func()
17211721
# string is added/removed/modified at the beginning
1722-
assert_equal("@@ -0,0 +1 @@\n+abc\n",
1722+
assert_equal("@@ -1 +1,2 @@\n+abc\n def\n",
17231723
diff(['def'], ['abc', 'def'], {output: 'unified'}))
17241724
assert_equal([{from_idx: 0, from_count: 0, to_idx: 0, to_count: 1}],
17251725
diff(['def'], ['abc', 'def'], {output: 'indices'}))
1726-
assert_equal("@@ -1 +0,0 @@\n-abc\n",
1726+
assert_equal("@@ -1,2 +1 @@\n-abc\n def\n",
17271727
diff(['abc', 'def'], ['def'], {output: 'unified'}))
17281728
assert_equal([{from_idx: 0, from_count: 1, to_idx: 0, to_count: 0}],
17291729
diff(['abc', 'def'], ['def'], {output: 'indices'}))
1730-
assert_equal("@@ -1 +1 @@\n-abc\n+abx\n",
1730+
assert_equal("@@ -1,2 +1,2 @@\n-abc\n+abx\n def\n",
17311731
diff(['abc', 'def'], ['abx', 'def'], {output: 'unified'}))
17321732
assert_equal([{from_idx: 0, from_count: 1, to_idx: 0, to_count: 1}],
17331733
diff(['abc', 'def'], ['abx', 'def'], {output: 'indices'}))
17341734

17351735
# string is added/removed/modified at the end
1736-
assert_equal("@@ -1,0 +2 @@\n+def\n",
1736+
assert_equal("@@ -1 +1,2 @@\n abc\n+def\n",
17371737
diff(['abc'], ['abc', 'def'], {output: 'unified'}))
17381738
assert_equal([{from_idx: 1, from_count: 0, to_idx: 1, to_count: 1}],
17391739
diff(['abc'], ['abc', 'def'], {output: 'indices'}))
1740-
assert_equal("@@ -2 +1,0 @@\n-def\n",
1740+
assert_equal("@@ -1,2 +1 @@\n abc\n-def\n",
17411741
diff(['abc', 'def'], ['abc'], {output: 'unified'}))
17421742
assert_equal([{from_idx: 1, from_count: 1, to_idx: 1, to_count: 0}],
17431743
diff(['abc', 'def'], ['abc'], {output: 'indices'}))
1744-
assert_equal("@@ -2 +2 @@\n-def\n+xef\n",
1744+
assert_equal("@@ -1,2 +1,2 @@\n abc\n-def\n+xef\n",
17451745
diff(['abc', 'def'], ['abc', 'xef'], {output: 'unified'}))
17461746
assert_equal([{from_idx: 1, from_count: 1, to_idx: 1, to_count: 1}],
17471747
diff(['abc', 'def'], ['abc', 'xef'], {output: 'indices'}))
17481748

17491749
# string is added/removed/modified in the middle
1750-
assert_equal("@@ -2,0 +3 @@\n+xxx\n",
1750+
assert_equal("@@ -2,2 +2,3 @@\n 222\n+xxx\n 333\n",
17511751
diff(['111', '222', '333'], ['111', '222', 'xxx', '333'], {output: 'unified'}))
17521752
assert_equal([{from_idx: 2, from_count: 0, to_idx: 2, to_count: 1}],
17531753
diff(['111', '222', '333'], ['111', '222', 'xxx', '333'], {output: 'indices'}))
1754-
assert_equal("@@ -3 +2,0 @@\n-333\n",
1754+
assert_equal("@@ -2,3 +2,2 @@\n 222\n-333\n 444\n",
17551755
diff(['111', '222', '333', '444'], ['111', '222', '444'], {output: 'unified'}))
17561756
assert_equal([{from_idx: 2, from_count: 1, to_idx: 2, to_count: 0}],
17571757
diff(['111', '222', '333', '444'], ['111', '222', '444'], {output: 'indices'}))
1758-
assert_equal("@@ -3 +3 @@\n-333\n+xxx\n",
1758+
assert_equal("@@ -2,3 +2,3 @@\n 222\n-333\n+xxx\n 444\n",
17591759
diff(['111', '222', '333', '444'], ['111', '222', 'xxx', '444'], {output: 'unified'}))
17601760
assert_equal([{from_idx: 2, from_count: 1, to_idx: 2, to_count: 1}],
17611761
diff(['111', '222', '333', '444'], ['111', '222', 'xxx', '444'], {output: 'indices'}))
@@ -1825,18 +1825,17 @@ def Test_diff_func()
18251825
three four
18261826
five six
18271827
END
1828-
assert_equal("@@ -1 +1 @@\n-one two\n+one abc two\n@@ -3 +3 @@\n-five abc six\n+five six\n",
1828+
assert_equal("@@ -1,3 +1,3 @@\n-one two\n+one abc two\n three four\n-five abc six\n+five six\n",
18291829
diff(fromlist, tolist, {output: 'unified'}))
1830-
assert_equal([{from_idx: 0, from_count: 1, to_idx: 0, to_count: 1},
1831-
{from_idx: 2, from_count: 1, to_idx: 2, to_count: 1}],
1830+
assert_equal([{from_idx: 0, from_count: 3, to_idx: 0, to_count: 3}],
18321831
diff(fromlist, tolist, {output: 'indices'}))
18331832

18341833
# add/remove blank lines
1835-
assert_equal("@@ -2,2 +1,0 @@\n-\n-\n",
1834+
assert_equal("@@ -1,4 +1,2 @@\n one\n-\n-\n two\n",
18361835
diff(['one', '', '', 'two'], ['one', 'two'], {output: 'unified'}))
18371836
assert_equal([{from_idx: 1, from_count: 2, to_idx: 1, to_count: 0}],
18381837
diff(['one', '', '', 'two'], ['one', 'two'], {output: 'indices'}))
1839-
assert_equal("@@ -1,0 +2,2 @@\n+\n+\n",
1838+
assert_equal("@@ -1,2 +1,4 @@\n one\n+\n+\n two\n",
18401839
diff(['one', 'two'], ['one', '', '', 'two'], {output: 'unified'}))
18411840
assert_equal([{'from_idx': 1, 'from_count': 0, 'to_idx': 1, 'to_count': 2}],
18421841
diff(['one', 'two'], ['one', '', '', 'two'], {output: 'indices'}))
@@ -1887,11 +1886,40 @@ def Test_diff_func()
18871886
assert_equal('', diff([], [], {output: 'unified'}))
18881887
assert_equal([], diff([], [], {output: 'indices'}))
18891888

1889+
# If 'diffexpr' is set, it should not be used for diff()
1890+
def MyDiffExpr()
1891+
enddef
1892+
var save_diffexpr = &diffexpr
1893+
:set diffexpr=MyDiffExpr()
1894+
assert_equal("@@ -1 +1 @@\n-abc\n+\n",
1895+
diff(['abc'], [''], {output: 'unified'}))
1896+
assert_equal([{'from_idx': 0, 'from_count': 1, 'to_idx': 0, 'to_count': 1}],
1897+
diff(['abc'], [''], {output: 'indices'}))
1898+
assert_equal('MyDiffExpr()', &diffexpr)
1899+
&diffexpr = save_diffexpr
1900+
1901+
# try different values for unified diff 'context'
1902+
assert_equal("@@ -0,0 +1 @@\n+x\n",
1903+
diff(['a', 'b', 'c'], ['x', 'a', 'b', 'c']))
1904+
assert_equal("@@ -0,0 +1 @@\n+x\n",
1905+
diff(['a', 'b', 'c'], ['x', 'a', 'b', 'c'], {context: 0}))
1906+
assert_equal("@@ -1 +1,2 @@\n+x\n a\n",
1907+
diff(['a', 'b', 'c'], ['x', 'a', 'b', 'c'], {context: 1}))
1908+
assert_equal("@@ -1,2 +1,3 @@\n+x\n a\n b\n",
1909+
diff(['a', 'b', 'c'], ['x', 'a', 'b', 'c'], {context: 2}))
1910+
assert_equal("@@ -1,3 +1,4 @@\n+x\n a\n b\n c\n",
1911+
diff(['a', 'b', 'c'], ['x', 'a', 'b', 'c'], {context: 3}))
1912+
assert_equal("@@ -1,3 +1,4 @@\n+x\n a\n b\n c\n",
1913+
diff(['a', 'b', 'c'], ['x', 'a', 'b', 'c'], {context: 4}))
1914+
assert_equal("@@ -1 +1,2 @@\n+x\n a\n",
1915+
diff(['a', 'b', 'c'], ['x', 'a', 'b', 'c'], {context: -1}))
1916+
18901917
# Error cases
18911918
assert_fails('call diff({}, ["a"])', 'E1211:')
18921919
assert_fails('call diff(["a"], {})', 'E1211:')
18931920
assert_fails('call diff(["a"], ["a"], [])', 'E1206:')
18941921
assert_fails('call diff(["a"], ["a"], {output: "xyz"})', 'E106: Unsupported diff output format: xyz')
1922+
assert_fails('call diff(["a"], ["a"], {context: []})', 'E745: Using a List as a Number')
18951923
enddef
18961924

18971925
" vim: shiftwidth=2 sts=2 expandtab

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,8 @@ static char *(features[]) =
704704

705705
static int included_patches[] =
706706
{ /* Add new patch number below this line */
707+
/**/
708+
96,
707709
/**/
708710
95,
709711
/**/

0 commit comments

Comments
 (0)