patch 9.1.0096: diff() function uses 'diffexpr' Commit: https://github.com/vim/vim/commit/be156a31c5400eb12025e480c477b1df88244801 Author: Yegappan Lakshmanan <yegap...@yahoo.com> Date: Sun Feb 11 17:08:29 2024 +0100
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 <yegap...@yahoo.com> Signed-off-by: Christian Brabandt <c...@256bit.org> diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index 062da08d6..0dca4679e 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -1,4 +1,4 @@ -*builtin.txt* For Vim version 9.1. Last change: 2024 Feb 01 +*builtin.txt* For Vim version 9.1. Last change: 2024 Feb 11 VIM REFERENCE MANUAL by Bram Moolenaar @@ -2074,20 +2074,22 @@ diff({fromlist}, {tolist} [, {options}]) *diff()* The {options} Dict argument also specifies diff options (similar to 'diffopt') and supports the following items: + algorithm Dict specifying the diff algorithm to + use. Supported boolean items are + "myers", "minimal", "patience" and + "histogram". + context unified diff context length. Default + is 1. iblank ignore changes where lines are all blank. icase ignore changes in case of text. + indent-heuristic use the indent heuristic for the + internal diff library. iwhite ignore changes in amount of white space. iwhiteall ignore all white space changes. iwhiteeol ignore white space changes at end of line. - indent-heuristic use the indent heuristic for the - internal diff library. - algorithm Dict specifying the diff algorithm to - use. Supported boolean items are - "myers", "minimal", "patience" and - "histogram". For more information about these options, refer to 'diffopt'. Returns an empty List or String if {fromlist} and {tolist} are diff --git a/src/diff.c b/src/diff.c index eedd76b13..a4f3f7e07 100644 --- a/src/diff.c +++ b/src/diff.c @@ -42,10 +42,6 @@ static int diff_flags = DIFF_INTERNAL | DIFF_FILLER | DIFF_CLOSE_OFF; static long diff_algorithm = 0; -#define DIFF_INTERNAL_OUTPUT_UNIFIED 1 -#define DIFF_INTERNAL_OUTPUT_INDICES 2 -static int diff_internal_output_fmt = DIFF_INTERNAL_OUTPUT_INDICES; - #define LBUFLEN 50 // length of line in diff file static int diff_a_works = MAYBE; // TRUE when "diff -a" works, FALSE when it @@ -76,12 +72,19 @@ typedef struct { long count_new; } diffhunk_T; +typedef enum { + DIO_OUTPUT_INDICES = 0, // default + DIO_OUTPUT_UNIFIED = 1 // unified diff format +} dio_outfmt_T; + // two diff inputs and one result typedef struct { - diffin_T dio_orig; // original file input - diffin_T dio_new; // new file input - diffout_T dio_diff; // diff result - int dio_internal; // using internal diff + diffin_T dio_orig; // original file input + diffin_T dio_new; // new file input + diffout_T dio_diff; // diff result + int dio_internal; // using internal diff + dio_outfmt_T dio_outfmt; // internal diff output format + int dio_ctxlen; // unified diff context length } diffio_T; static int diff_buf_idx(buf_T *buf); @@ -1145,9 +1148,9 @@ diff_file_internal(diffio_T *diffio) if (diff_flags & DIFF_IBLANK) param.flags |= XDF_IGNORE_BLANK_LINES; - emit_cfg.ctxlen = 0; // don't need any diff_context here + emit_cfg.ctxlen = diffio->dio_ctxlen; emit_cb.priv = &diffio->dio_diff; - if (diff_internal_output_fmt == DIFF_INTERNAL_OUTPUT_INDICES) + if (diffio->dio_outfmt == DIO_OUTPUT_INDICES) emit_cfg.hunk_func = xdiff_out_indices; else emit_cb.out_line = xdiff_out_unified; @@ -3473,10 +3476,11 @@ f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED) */ static int parse_diff_optarg( - typval_T *opts, - int *diffopts, - long *diffalgo, - int *diff_output_fmt) + typval_T *opts, + int *diffopts, + long *diffalgo, + dio_outfmt_T *diff_output_fmt, + int *diff_ctxlen) { dict_T *d = opts->vval.v_dict; @@ -3497,9 +3501,9 @@ parse_diff_optarg( if (output_fmt != NULL) { if (STRNCMP(output_fmt, "unified", 7) == 0) - *diff_output_fmt = DIFF_INTERNAL_OUTPUT_UNIFIED; + *diff_output_fmt = DIO_OUTPUT_UNIFIED; else if (STRNCMP(output_fmt, "indices", 7) == 0) - *diff_output_fmt = DIFF_INTERNAL_OUTPUT_INDICES; + *diff_output_fmt = DIO_OUTPUT_INDICES; else { semsg(_(e_unsupported_diff_output_format_str), output_fmt); @@ -3507,6 +3511,10 @@ parse_diff_optarg( } } + *diff_ctxlen = dict_get_number_def(d, "context", 1); + if (*diff_ctxlen < 0) + *diff_ctxlen = 1; + if (dict_get_bool(d, "iblank", FALSE)) *diffopts |= DIFF_IBLANK; if (dict_get_bool(d, "icase", FALSE)) @@ -3602,33 +3610,43 @@ f_diff(typval_T *argvars UNUSED, typval_T *rettv UNUSED) // Save the 'diffopt' option value and restore it after getting the diff. int save_diff_flags = diff_flags; long save_diff_algorithm = diff_algorithm; - long save_diff_output_fmt = diff_internal_output_fmt; diff_flags = DIFF_INTERNAL; diff_algorithm = 0; - diff_internal_output_fmt = DIFF_INTERNAL_OUTPUT_UNIFIED; + dio.dio_outfmt = DIO_OUTPUT_UNIFIED; if (argvars[2].v_type != VAR_UNKNOWN) if (parse_diff_optarg(&argvars[2], &diff_flags, &diff_algorithm, - &diff_internal_output_fmt) == FAIL) - { - diff_internal_output_fmt = save_diff_output_fmt; + &dio.dio_outfmt, &dio.dio_ctxlen) == FAIL) return; - } // Concatenate the List of strings into a single string using newline // separator. Internal diff library expects a single string. list_to_diffin(orig_list, &dio.dio_orig, diff_flags & DIFF_ICASE); list_to_diffin(new_list, &dio.dio_new, diff_flags & DIFF_ICASE); + // If 'diffexpr' is set, then the internal diff is not used. Set + // 'diffexpr' to an empty string temporarily. + int restore_diffexpr = FALSE; + char_u cc = *p_dex; + if (*p_dex != NUL) + { + restore_diffexpr = TRUE; + *p_dex = NUL; + } + // Compute the diff int diff_status = diff_file(&dio); + // restore 'diffexpr' + if (restore_diffexpr) + *p_dex = cc; + if (diff_status == FAIL) goto done; int hunk_idx = 0; dict_T *hunk_dict; - if (diff_internal_output_fmt == DIFF_INTERNAL_OUTPUT_INDICES) + if (dio.dio_outfmt == DIO_OUTPUT_INDICES) { if (rettv_list_alloc(rettv) != OK) goto done; @@ -3657,7 +3675,7 @@ f_diff(typval_T *argvars UNUSED, typval_T *rettv UNUSED) done: clear_diffin(&dio.dio_new); - if (diff_internal_output_fmt == DIFF_INTERNAL_OUTPUT_INDICES) + if (dio.dio_outfmt == DIO_OUTPUT_INDICES) clear_diffout(&dio.dio_diff); else ga_clear(&dio.dio_diff.dout_ga); @@ -3665,7 +3683,6 @@ done: // Restore the 'diffopt' option value. diff_flags = save_diff_flags; diff_algorithm = save_diff_algorithm; - diff_internal_output_fmt = save_diff_output_fmt; # endif } diff --git a/src/testdir/test_diffmode.vim b/src/testdir/test_diffmode.vim index 2211ba05a..d37a9a28a 100644 --- a/src/testdir/test_diffmode.vim +++ b/src/testdir/test_diffmode.vim @@ -1719,43 +1719,43 @@ endfunc " Test for the diff() function def Test_diff_func() # string is added/removed/modified at the beginning - assert_equal("@@ -0,0 +1 @@ +abc ", + assert_equal("@@ -1 +1,2 @@ +abc def ", diff(['def'], ['abc', 'def'], {output: 'unified'})) assert_equal([{from_idx: 0, from_count: 0, to_idx: 0, to_count: 1}], diff(['def'], ['abc', 'def'], {output: 'indices'})) - assert_equal("@@ -1 +0,0 @@ -abc ", + assert_equal("@@ -1,2 +1 @@ -abc def ", diff(['abc', 'def'], ['def'], {output: 'unified'})) assert_equal([{from_idx: 0, from_count: 1, to_idx: 0, to_count: 0}], diff(['abc', 'def'], ['def'], {output: 'indices'})) - assert_equal("@@ -1 +1 @@ -abc +abx ", + assert_equal("@@ -1,2 +1,2 @@ -abc +abx def ", diff(['abc', 'def'], ['abx', 'def'], {output: 'unified'})) assert_equal([{from_idx: 0, from_count: 1, to_idx: 0, to_count: 1}], diff(['abc', 'def'], ['abx', 'def'], {output: 'indices'})) # string is added/removed/modified at the end - assert_equal("@@ -1,0 +2 @@ +def ", + assert_equal("@@ -1 +1,2 @@ abc +def ", diff(['abc'], ['abc', 'def'], {output: 'unified'})) assert_equal([{from_idx: 1, from_count: 0, to_idx: 1, to_count: 1}], diff(['abc'], ['abc', 'def'], {output: 'indices'})) - assert_equal("@@ -2 +1,0 @@ -def ", + assert_equal("@@ -1,2 +1 @@ abc -def ", diff(['abc', 'def'], ['abc'], {output: 'unified'})) assert_equal([{from_idx: 1, from_count: 1, to_idx: 1, to_count: 0}], diff(['abc', 'def'], ['abc'], {output: 'indices'})) - assert_equal("@@ -2 +2 @@ -def +xef ", + assert_equal("@@ -1,2 +1,2 @@ abc -def +xef ", diff(['abc', 'def'], ['abc', 'xef'], {output: 'unified'})) assert_equal([{from_idx: 1, from_count: 1, to_idx: 1, to_count: 1}], diff(['abc', 'def'], ['abc', 'xef'], {output: 'indices'})) # string is added/removed/modified in the middle - assert_equal("@@ -2,0 +3 @@ +xxx ", + assert_equal("@@ -2,2 +2,3 @@ 222 +xxx 333 ", diff(['111', '222', '333'], ['111', '222', 'xxx', '333'], {output: 'unified'})) assert_equal([{from_idx: 2, from_count: 0, to_idx: 2, to_count: 1}], diff(['111', '222', '333'], ['111', '222', 'xxx', '333'], {output: 'indices'})) - assert_equal("@@ -3 +2,0 @@ -333 ", + assert_equal("@@ -2,3 +2,2 @@ 222 -333 444 ", diff(['111', '222', '333', '444'], ['111', '222', '444'], {output: 'unified'})) assert_equal([{from_idx: 2, from_count: 1, to_idx: 2, to_count: 0}], diff(['111', '222', '333', '444'], ['111', '222', '444'], {output: 'indices'})) - assert_equal("@@ -3 +3 @@ -333 +xxx ", + assert_equal("@@ -2,3 +2,3 @@ 222 -333 +xxx 444 ", diff(['111', '222', '333', '444'], ['111', '222', 'xxx', '444'], {output: 'unified'})) assert_equal([{from_idx: 2, from_count: 1, to_idx: 2, to_count: 1}], diff(['111', '222', '333', '444'], ['111', '222', 'xxx', '444'], {output: 'indices'})) @@ -1825,18 +1825,17 @@ def Test_diff_func() three four five six END - assert_equal("@@ -1 +1 @@ -one two +one abc two @@ -3 +3 @@ -five abc six +five six ", + assert_equal("@@ -1,3 +1,3 @@ -one two +one abc two three four -five abc six +five six ", diff(fromlist, tolist, {output: 'unified'})) - assert_equal([{from_idx: 0, from_count: 1, to_idx: 0, to_count: 1}, - {from_idx: 2, from_count: 1, to_idx: 2, to_count: 1}], + assert_equal([{from_idx: 0, from_count: 3, to_idx: 0, to_count: 3}], diff(fromlist, tolist, {output: 'indices'})) # add/remove blank lines - assert_equal("@@ -2,2 +1,0 @@ - - ", + assert_equal("@@ -1,4 +1,2 @@ one - - two ", diff(['one', '', '', 'two'], ['one', 'two'], {output: 'unified'})) assert_equal([{from_idx: 1, from_count: 2, to_idx: 1, to_count: 0}], diff(['one', '', '', 'two'], ['one', 'two'], {output: 'indices'})) - assert_equal("@@ -1,0 +2,2 @@ + + ", + assert_equal("@@ -1,2 +1,4 @@ one + + two ", diff(['one', 'two'], ['one', '', '', 'two'], {output: 'unified'})) assert_equal([{'from_idx': 1, 'from_count': 0, 'to_idx': 1, 'to_count': 2}], diff(['one', 'two'], ['one', '', '', 'two'], {output: 'indices'})) @@ -1887,11 +1886,40 @@ def Test_diff_func() assert_equal('', diff([], [], {output: 'unified'})) assert_equal([], diff([], [], {output: 'indices'})) + # If 'diffexpr' is set, it should not be used for diff() + def MyDiffExpr() + enddef + var save_diffexpr = &diffexpr + :set diffexpr=MyDiffExpr() + assert_equal("@@ -1 +1 @@ -abc + ", + diff(['abc'], [''], {output: 'unified'})) + assert_equal([{'from_idx': 0, 'from_count': 1, 'to_idx': 0, 'to_count': 1}], + diff(['abc'], [''], {output: 'indices'})) + assert_equal('MyDiffExpr()', &diffexpr) + &diffexpr = save_diffexpr + + # try different values for unified diff 'context' + assert_equal("@@ -0,0 +1 @@ +x ", + diff(['a', 'b', 'c'], ['x', 'a', 'b', 'c'])) + assert_equal("@@ -0,0 +1 @@ +x ", + diff(['a', 'b', 'c'], ['x', 'a', 'b', 'c'], {context: 0})) + assert_equal("@@ -1 +1,2 @@ +x a ", + diff(['a', 'b', 'c'], ['x', 'a', 'b', 'c'], {context: 1})) + assert_equal("@@ -1,2 +1,3 @@ +x a b ", + diff(['a', 'b', 'c'], ['x', 'a', 'b', 'c'], {context: 2})) + assert_equal("@@ -1,3 +1,4 @@ +x a b c ", + diff(['a', 'b', 'c'], ['x', 'a', 'b', 'c'], {context: 3})) + assert_equal("@@ -1,3 +1,4 @@ +x a b c ", + diff(['a', 'b', 'c'], ['x', 'a', 'b', 'c'], {context: 4})) + assert_equal("@@ -1 +1,2 @@ +x a ", + diff(['a', 'b', 'c'], ['x', 'a', 'b', 'c'], {context: -1})) + # Error cases assert_fails('call diff({}, ["a"])', 'E1211:') assert_fails('call diff(["a"], {})', 'E1211:') assert_fails('call diff(["a"], ["a"], [])', 'E1206:') assert_fails('call diff(["a"], ["a"], {output: "xyz"})', 'E106: Unsupported diff output format: xyz') + assert_fails('call diff(["a"], ["a"], {context: []})', 'E745: Using a List as a Number') enddef " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index ba44232e5..dbbb91305 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 96, /**/ 95, /**/ -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/vim_dev/E1rZCTy-0096Mt-1R%40256bit.org.