To: vim_dev@googlegroups.com Subject: Patch 8.2.3390 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3390 Problem: Included xdiff code is outdated. Solution: Sync with xdiff in git 2.33. (Christian Brabandt, closes #8431) Files: src/diff.c, src/xdiff/README.txt, src/xdiff/xdiff.h, src/xdiff/xdiffi.c, src/xdiff/xdiffi.h, src/xdiff/xemit.c, src/xdiff/xemit.h, src/xdiff/xhistogram.c, src/xdiff/xinclude.h, src/xdiff/xmacros.h, src/xdiff/xpatience.c, src/xdiff/xprepare.h, src/xdiff/xtypes.h, src/xdiff/xutils.c, src/xdiff/xutils.h *** ../vim-8.2.3389/src/diff.c 2021-07-27 22:00:39.741712405 +0200 --- src/diff.c 2021-08-31 20:27:29.074489143 +0200 *************** *** 1095,1101 **** emit_cfg.ctxlen = 0; // don't need any diff_context here emit_cb.priv = &diffio->dio_diff; ! emit_cb.outf = xdiff_out; if (xdl_diff(&diffio->dio_orig.din_mmfile, &diffio->dio_new.din_mmfile, ¶m, &emit_cfg, &emit_cb) < 0) --- 1095,1101 ---- emit_cfg.ctxlen = 0; // don't need any diff_context here emit_cb.priv = &diffio->dio_diff; ! emit_cb.out_line = xdiff_out; if (xdl_diff(&diffio->dio_orig.din_mmfile, &diffio->dio_new.din_mmfile, ¶m, &emit_cfg, &emit_cb) < 0) *** ../vim-8.2.3389/src/xdiff/README.txt 2018-09-10 21:17:33.000000000 +0200 --- src/xdiff/README.txt 2021-08-31 20:27:29.074489143 +0200 *************** *** 1,6 **** The files in this directory come from the xdiff implementation in git. You can find it here: https://github.com/git/git/tree/master/xdiff ! The files were last updated 2018 September 10. This is originally based on libxdiff, which can be found here: http://www.xmailserver.org/xdiff-lib.html --- 1,6 ---- The files in this directory come from the xdiff implementation in git. You can find it here: https://github.com/git/git/tree/master/xdiff ! The files were last updated August 31, 2021 from git release v.2.33.0 This is originally based on libxdiff, which can be found here: http://www.xmailserver.org/xdiff-lib.html *** ../vim-8.2.3389/src/xdiff/xdiff.h 2019-12-04 22:12:40.000000000 +0100 --- src/xdiff/xdiff.h 2021-08-31 20:27:29.074489143 +0200 *************** *** 25,33 **** #ifdef __cplusplus extern "C" { ! #endif // #ifdef __cplusplus ! // xpparm_t.flags #define XDF_NEED_MINIMAL (1 << 0) #define XDF_IGNORE_WHITESPACE (1 << 1) --- 25,33 ---- #ifdef __cplusplus extern "C" { ! #endif /* #ifdef __cplusplus */ ! /* xpparm_t.flags */ #define XDF_NEED_MINIMAL (1 << 0) #define XDF_IGNORE_WHITESPACE (1 << 1) *************** *** 48,69 **** #define XDF_INDENT_HEURISTIC (1 << 23) ! // xdemitconf_t.flags #define XDL_EMIT_FUNCNAMES (1 << 0) #define XDL_EMIT_FUNCCONTEXT (1 << 2) ! // merge simplification levels #define XDL_MERGE_MINIMAL 0 #define XDL_MERGE_EAGER 1 #define XDL_MERGE_ZEALOUS 2 #define XDL_MERGE_ZEALOUS_ALNUM 3 ! // merge favor modes #define XDL_MERGE_FAVOR_OURS 1 #define XDL_MERGE_FAVOR_THEIRS 2 #define XDL_MERGE_FAVOR_UNION 3 ! // merge output styles #define XDL_MERGE_DIFF3 1 typedef struct s_mmfile { --- 48,70 ---- #define XDF_INDENT_HEURISTIC (1 << 23) ! /* xdemitconf_t.flags */ #define XDL_EMIT_FUNCNAMES (1 << 0) + #define XDL_EMIT_NO_HUNK_HDR (1 << 1) #define XDL_EMIT_FUNCCONTEXT (1 << 2) ! /* merge simplification levels */ #define XDL_MERGE_MINIMAL 0 #define XDL_MERGE_EAGER 1 #define XDL_MERGE_ZEALOUS 2 #define XDL_MERGE_ZEALOUS_ALNUM 3 ! /* merge favor modes */ #define XDL_MERGE_FAVOR_OURS 1 #define XDL_MERGE_FAVOR_THEIRS 2 #define XDL_MERGE_FAVOR_UNION 3 ! /* merge output styles */ #define XDL_MERGE_DIFF3 1 typedef struct s_mmfile { *************** *** 79,92 **** typedef struct s_xpparam { unsigned long flags; ! // See Documentation/diff-options.txt. char **anchors; size_t anchors_nr; } xpparam_t; typedef struct s_xdemitcb { void *priv; ! int (*outf)(void *, mmbuffer_t *, int); } xdemitcb_t; typedef long (*find_func_t)(const char *line, long line_len, char *buffer, long buffer_size, void *priv); --- 80,103 ---- typedef struct s_xpparam { unsigned long flags; ! /* -I */ ! #if 0 // unused by Vim ! regex_t **ignore_regex; ! size_t ignore_regex_nr; ! #endif ! ! /* See Documentation/diff-options.txt. */ char **anchors; size_t anchors_nr; } xpparam_t; typedef struct s_xdemitcb { void *priv; ! int (*out_hunk)(void *, ! long old_begin, long old_nr, ! long new_begin, long new_nr, ! const char *func, long funclen); ! int (*out_line)(void *, mmbuffer_t *, int); } xdemitcb_t; typedef long (*find_func_t)(const char *line, long line_len, char *buffer, long buffer_size, void *priv); *************** *** 130,138 **** int level; int favor; int style; ! const char *ancestor; // label for orig ! const char *file1; // label for mf1 ! const char *file2; // label for mf2 } xmparam_t; #define DEFAULT_CONFLICT_MARKER_SIZE 7 --- 141,149 ---- int level; int favor; int style; ! const char *ancestor; /* label for orig */ ! const char *file1; /* label for mf1 */ ! const char *file2; /* label for mf2 */ } xmparam_t; #define DEFAULT_CONFLICT_MARKER_SIZE 7 *************** *** 142,147 **** #ifdef __cplusplus } ! #endif // #ifdef __cplusplus ! #endif // #if !defined(XDIFF_H) --- 153,158 ---- #ifdef __cplusplus } ! #endif /* #ifdef __cplusplus */ ! #endif /* #if !defined(XDIFF_H) */ *** ../vim-8.2.3389/src/xdiff/xdiffi.c 2019-12-04 22:10:52.000000000 +0100 --- src/xdiff/xdiffi.c 2021-08-31 20:27:29.074489143 +0200 *************** *** 38,46 **** * Basically considers a "box" (off1, off2, lim1, lim2) and scan from both * the forward diagonal starting from (off1, off2) and the backward diagonal * starting from (lim1, lim2). If the K values on the same diagonal crosses ! * returns the furthest point of reach. We might end up having to expensive ! * cases using this algorithm is full, so a little bit of heuristic is needed ! * to cut the search and to return a suboptimal point. */ static long xdl_split(unsigned long const *ha1, long off1, long lim1, unsigned long const *ha2, long off2, long lim2, --- 38,46 ---- * Basically considers a "box" (off1, off2, lim1, lim2) and scan from both * the forward diagonal starting from (off1, off2) and the backward diagonal * starting from (lim1, lim2). If the K values on the same diagonal crosses ! * returns the furthest point of reach. We might encounter expensive edge cases ! * using this algorithm, so a little bit of heuristic is needed to cut the ! * search and to return a suboptimal point. */ static long xdl_split(unsigned long const *ha1, long off1, long lim1, unsigned long const *ha2, long off2, long lim2, *************** *** 63,73 **** int got_snake = 0; /* ! * We need to extent the diagonal "domain" by one. If the next * values exits the box boundaries we need to change it in the ! * opposite direction because (max - min) must be a power of two. * Also we initialize the external K value to -1 so that we can ! * avoid extra conditions check inside the core loop. */ if (fmin > dmin) kvdf[--fmin - 1] = -1; --- 63,75 ---- int got_snake = 0; /* ! * We need to extend the diagonal "domain" by one. If the next * values exits the box boundaries we need to change it in the ! * opposite direction because (max - min) must be a power of ! * two. ! * * Also we initialize the external K value to -1 so that we can ! * avoid extra conditions in the check inside the core loop. */ if (fmin > dmin) kvdf[--fmin - 1] = -1; *************** *** 98,108 **** } /* ! * We need to extent the diagonal "domain" by one. If the next * values exits the box boundaries we need to change it in the ! * opposite direction because (max - min) must be a power of two. * Also we initialize the external K value to -1 so that we can ! * avoid extra conditions check inside the core loop. */ if (bmin > dmin) kvdb[--bmin - 1] = XDL_LINE_MAX; --- 100,112 ---- } /* ! * We need to extend the diagonal "domain" by one. If the next * values exits the box boundaries we need to change it in the ! * opposite direction because (max - min) must be a power of ! * two. ! * * Also we initialize the external K value to -1 so that we can ! * avoid extra conditions in the check inside the core loop. */ if (bmin > dmin) kvdb[--bmin - 1] = XDL_LINE_MAX; *************** *** 138,144 **** /* * If the edit cost is above the heuristic trigger and if * we got a good snake, we sample current diagonals to see ! * if some of the, have reached an "interesting" path. Our * measure is a function of the distance from the diagonal * corner (i1 + i2) penalized with the distance from the * mid diagonal itself. If this value is above the current --- 142,148 ---- /* * If the edit cost is above the heuristic trigger and if * we got a good snake, we sample current diagonals to see ! * if some of them have reached an "interesting" path. Our * measure is a function of the distance from the diagonal * corner (i1 + i2) penalized with the distance from the * mid diagonal itself. If this value is above the current *************** *** 196,203 **** } /* ! * Enough is enough. We spent too much time here and now we collect ! * the furthest reaching path using the (i1 + i2) measure. */ if (ec >= xenv->mxcost) { long fbest, fbest1, bbest, bbest1; --- 200,208 ---- } /* ! * Enough is enough. We spent too much time here and now we ! * collect the furthest reaching path using the (i1 + i2) ! * measure. */ if (ec >= xenv->mxcost) { long fbest, fbest1, bbest, bbest1; *************** *** 244,252 **** /* ! * Rule: "Divide et Impera". Recursively split the box in sub-boxes by calling ! * the box splitting function. Note that the real job (marking changed lines) ! * is done in the two boundary reaching checks. */ int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1, diffdata_t *dd2, long off2, long lim2, --- 249,257 ---- /* ! * Rule: "Divide et Impera" (divide & conquer). Recursively split the box in ! * sub-boxes by calling the box splitting function. Note that the real job ! * (marking changed lines) is done in the two boundary reaching checks. */ int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1, diffdata_t *dd2, long off2, long lim2, *************** *** 323,329 **** } /* ! * Allocate and setup K vectors to be used by the differential algorithm. * One is to store the forward path and one to store the backward path. */ ndiags = xe->xdf1.nreff + xe->xdf2.nreff + 3; --- 328,336 ---- } /* ! * Allocate and setup K vectors to be used by the differential ! * algorithm. ! * * One is to store the forward path and one to store the backward path. */ ndiags = xe->xdf1.nreff + xe->xdf2.nreff + 3; *************** *** 418,430 **** ret += 1; else if (c == '\t') ret += 8 - ret % 8; ! // ignore other whitespace characters if (ret >= MAX_INDENT) return MAX_INDENT; } ! // The line contains only whitespace. return -1; } --- 425,437 ---- ret += 1; else if (c == '\t') ret += 8 - ret % 8; ! /* ignore other whitespace characters */ if (ret >= MAX_INDENT) return MAX_INDENT; } ! /* The line contains only whitespace. */ return -1; } *************** *** 435,441 **** */ #define MAX_BLANKS 20 ! // Characteristics measured about a hypothetical split position. struct split_measurement { /* * Is the split at the end of the file (aside from any blank lines)? --- 442,448 ---- */ #define MAX_BLANKS 20 ! /* Characteristics measured about a hypothetical split position. */ struct split_measurement { /* * Is the split at the end of the file (aside from any blank lines)? *************** *** 443,450 **** int end_of_file; /* ! * How much is the line immediately following the split indented (or -1 if ! * the line is blank): */ int indent; --- 450,457 ---- int end_of_file; /* ! * How much is the line immediately following the split indented (or -1 ! * if the line is blank): */ int indent; *************** *** 454,461 **** int pre_blank; /* ! * How much is the nearest non-blank line above the split indented (or -1 ! * if there is no such line)? */ int pre_indent; --- 461,468 ---- int pre_blank; /* ! * How much is the nearest non-blank line above the split indented (or ! * -1 if there is no such line)? */ int pre_indent; *************** *** 472,481 **** }; struct split_score { ! // The effective indent of this split (smaller is preferred). int effective_indent; ! // Penalty for this split (smaller is preferred). int penalty; }; --- 479,488 ---- }; struct split_score { ! /* The effective indent of this split (smaller is preferred). */ int effective_indent; ! /* Penalty for this split (smaller is preferred). */ int penalty; }; *************** *** 534,549 **** * integer math. */ ! // Penalty if there are no non-blank lines before the split #define START_OF_FILE_PENALTY 1 ! // Penalty if there are no non-blank lines after the split #define END_OF_FILE_PENALTY 21 ! // Multiplier for the number of blank lines around the split #define TOTAL_BLANK_WEIGHT (-30) ! // Multiplier for the number of blank lines after the split #define POST_BLANK_WEIGHT 6 /* --- 541,556 ---- * integer math. */ ! /* Penalty if there are no non-blank lines before the split */ #define START_OF_FILE_PENALTY 1 ! /* Penalty if there are no non-blank lines after the split */ #define END_OF_FILE_PENALTY 21 ! /* Multiplier for the number of blank lines around the split */ #define TOTAL_BLANK_WEIGHT (-30) ! /* Multiplier for the number of blank lines after the split */ #define POST_BLANK_WEIGHT 6 /* *************** *** 581,593 **** /* * Compute a badness score for the hypothetical split whose measurements are ! * stored in m. The weight factors were determined empirically using the tools and ! * corpus described in * * https://github.com/mhagger/diff-slider-tools * ! * Also see that project if you want to improve the weights based on, for example, ! * a larger or more diverse corpus. */ static void score_add_split(const struct split_measurement *m, struct split_score *s) { --- 588,600 ---- /* * Compute a badness score for the hypothetical split whose measurements are ! * stored in m. The weight factors were determined empirically using the tools ! * and corpus described in * * https://github.com/mhagger/diff-slider-tools * ! * Also see that project if you want to improve the weights based on, for ! * example, a larger or more diverse corpus. */ static void score_add_split(const struct split_measurement *m, struct split_score *s) { *************** *** 610,616 **** post_blank = (m->indent == -1) ? 1 + m->post_blank : 0; total_blank = m->pre_blank + post_blank; ! // Penalties based on nearby blank lines: s->penalty += TOTAL_BLANK_WEIGHT * total_blank; s->penalty += POST_BLANK_WEIGHT * post_blank; --- 617,623 ---- post_blank = (m->indent == -1) ? 1 + m->post_blank : 0; total_blank = m->pre_blank + post_blank; ! /* Penalties based on nearby blank lines: */ s->penalty += TOTAL_BLANK_WEIGHT * total_blank; s->penalty += POST_BLANK_WEIGHT * post_blank; *************** *** 621,633 **** any_blanks = (total_blank != 0); ! // Note that the effective indent is -1 at the end of the file: s->effective_indent += indent; if (indent == -1) { ! // No additional adjustments needed. } else if (m->pre_indent == -1) { ! // No additional adjustments needed. } else if (indent > m->pre_indent) { /* * The line is indented more than its predecessor. --- 628,640 ---- any_blanks = (total_blank != 0); ! /* Note that the effective indent is -1 at the end of the file: */ s->effective_indent += indent; if (indent == -1) { ! /* No additional adjustments needed. */ } else if (m->pre_indent == -1) { ! /* No additional adjustments needed. */ } else if (indent > m->pre_indent) { /* * The line is indented more than its predecessor. *************** *** 669,675 **** static int score_cmp(struct split_score *s1, struct split_score *s2) { ! // -1 if s1.effective_indent < s2->effective_indent, etc. int cmp_indents = ((s1->effective_indent > s2->effective_indent) - (s1->effective_indent < s2->effective_indent)); --- 676,682 ---- static int score_cmp(struct split_score *s1, struct split_score *s2) { ! /* -1 if s1.effective_indent < s2->effective_indent, etc. */ int cmp_indents = ((s1->effective_indent > s2->effective_indent) - (s1->effective_indent < s2->effective_indent)); *************** *** 809,821 **** group_init(xdfo, &go); while (1) { ! // If the group is empty in the to-be-compacted file, skip it: if (g.end == g.start) goto next; /* * Now shift the change up and then down as far as possible in ! * each direction. If it bumps into any other changes, merge them. */ do { groupsize = g.end - g.start; --- 816,831 ---- group_init(xdfo, &go); while (1) { ! /* ! * If the group is empty in the to-be-compacted file, skip it: ! */ if (g.end == g.start) goto next; /* * Now shift the change up and then down as far as possible in ! * each direction. If it bumps into any other changes, merge ! * them. */ do { groupsize = g.end - g.start; *************** *** 828,834 **** */ end_matching_other = -1; ! // Shift the group backward as much as possible: while (!group_slide_up(xdf, &g, flags)) if (group_previous(xdfo, &go)) xdl_bug("group sync broken sliding up"); --- 838,844 ---- */ end_matching_other = -1; ! /* Shift the group backward as much as possible: */ while (!group_slide_up(xdf, &g, flags)) if (group_previous(xdfo, &go)) xdl_bug("group sync broken sliding up"); *************** *** 842,848 **** if (go.end > go.start) end_matching_other = g.end; ! // Now shift the group forward as far as possible: while (1) { if (group_slide_down(xdf, &g, flags)) break; --- 852,858 ---- if (go.end > go.start) end_matching_other = g.end; ! /* Now shift the group forward as far as possible: */ while (1) { if (group_slide_down(xdf, &g, flags)) break; *************** *** 858,874 **** * If the group can be shifted, then we can possibly use this * freedom to produce a more intuitive diff. * ! * The group is currently shifted as far down as possible, so the ! * heuristics below only have to handle upwards shifts. */ if (g.end == earliest_end) { ! // no shifting was possible } else if (end_matching_other != -1) { /* ! * Move the possibly merged group of changes back to line ! * up with the last group of changes from the other file ! * that it can align with. */ while (go.end == go.start) { if (group_slide_up(xdf, &g, flags)) --- 868,884 ---- * If the group can be shifted, then we can possibly use this * freedom to produce a more intuitive diff. * ! * The group is currently shifted as far down as possible, so ! * the heuristics below only have to handle upwards shifts. */ if (g.end == earliest_end) { ! /* no shifting was possible */ } else if (end_matching_other != -1) { /* ! * Move the possibly merged group of changes back to ! * line up with the last group of changes from the ! * other file that it can align with. */ while (go.end == go.start) { if (group_slide_up(xdf, &g, flags)) *************** *** 879,892 **** } else if (flags & XDF_INDENT_HEURISTIC) { /* * Indent heuristic: a group of pure add/delete lines ! * implies two splits, one between the end of the "before" ! * context and the start of the group, and another between ! * the end of the group and the beginning of the "after" ! * context. Some splits are aesthetically better and some ! * are worse. We compute a badness "score" for each split, ! * and add the scores for the two splits to define a ! * "score" for each position that the group can be shifted ! * to. Then we pick the shift with the lowest score. */ long shift, best_shift = -1; struct split_score best_score; --- 889,903 ---- } else if (flags & XDF_INDENT_HEURISTIC) { /* * Indent heuristic: a group of pure add/delete lines ! * implies two splits, one between the end of the ! * "before" context and the start of the group, and ! * another between the end of the group and the ! * beginning of the "after" context. Some splits are ! * aesthetically better and some are worse. We compute ! * a badness "score" for each split, and add the scores ! * for the two splits to define a "score" for each ! * position that the group can be shifted to. Then we ! * pick the shift with the lowest score. */ long shift, best_shift = -1; struct split_score best_score; *************** *** 921,927 **** } next: ! // Move past the just-processed group: if (group_next(xdf, &g)) break; if (group_next(xdfo, &go)) --- 932,938 ---- } next: ! /* Move past the just-processed group: */ if (group_next(xdf, &g)) break; if (group_next(xdfo, &go)) *************** *** 987,993 **** return 0; } ! static void xdl_mark_ignorable(xdchange_t *xscr, xdfenv_t *xe, long flags) { xdchange_t *xch; --- 998,1004 ---- return 0; } ! static void xdl_mark_ignorable_lines(xdchange_t *xscr, xdfenv_t *xe, long flags) { xdchange_t *xch; *************** *** 1008,1013 **** --- 1019,1066 ---- } } + #if 0 // unused by Vim + static int record_matches_regex(xrecord_t *rec, xpparam_t const *xpp) { + regmatch_t regmatch; + int i; + + for (i = 0; i < xpp->ignore_regex_nr; i++) + if (!regexec_buf(xpp->ignore_regex[i], rec->ptr, rec->size, 1, + ®match, 0)) + return 1; + + return 0; + } + + static void xdl_mark_ignorable_regex(xdchange_t *xscr, const xdfenv_t *xe, + xpparam_t const *xpp) + { + xdchange_t *xch; + + for (xch = xscr; xch; xch = xch->next) { + xrecord_t **rec; + int ignore = 1; + long i; + + /* + * Do not override --ignore-blank-lines. + */ + if (xch->ignore) + continue; + + rec = &xe->xdf1.recs[xch->i1]; + for (i = 0; i < xch->chg1 && ignore; i++) + ignore = record_matches_regex(rec[i], xpp); + + rec = &xe->xdf2.recs[xch->i2]; + for (i = 0; i < xch->chg2 && ignore; i++) + ignore = record_matches_regex(rec[i], xpp); + + xch->ignore = ignore; + } + } + #endif + int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb) { xdchange_t *xscr; *************** *** 1027,1033 **** } if (xscr) { if (xpp->flags & XDF_IGNORE_BLANK_LINES) ! xdl_mark_ignorable(xscr, &xe, xpp->flags); if (ef(&xe, xscr, ecb, xecfg) < 0) { --- 1080,1091 ---- } if (xscr) { if (xpp->flags & XDF_IGNORE_BLANK_LINES) ! xdl_mark_ignorable_lines(xscr, &xe, xpp->flags); ! ! #if 0 ! if (xpp->ignore_regex) ! xdl_mark_ignorable_regex(xscr, &xe, xpp); ! #endif if (ef(&xe, xscr, ecb, xecfg) < 0) { *** ../vim-8.2.3389/src/xdiff/xdiffi.h 2019-12-04 22:12:58.000000000 +0100 --- src/xdiff/xdiffi.h 2021-08-31 20:27:29.074489143 +0200 *************** *** 61,64 **** int xdl_do_histogram_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdfenv_t *env); ! #endif // #if !defined(XDIFFI_H) --- 61,64 ---- int xdl_do_histogram_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdfenv_t *env); ! #endif /* #if !defined(XDIFFI_H) */ *** ../vim-8.2.3389/src/xdiff/xemit.c 2019-12-04 22:11:15.000000000 +0100 --- src/xdiff/xemit.c 2021-08-31 20:27:29.074489143 +0200 *************** *** 31,37 **** static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *ecb) { ! long size, psize = (long)strlen(pre); char const *rec; size = xdl_get_rec(xdf, ri, &rec); --- 31,37 ---- static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *ecb) { ! long size, psize = strlen(pre); char const *rec; size = xdl_get_rec(xdf, ri, &rec); *************** *** 54,62 **** xdchange_t *xch, *xchp, *lxch; long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen; long max_ignorable = xecfg->ctxlen; ! unsigned long ignored = 0; // number of ignored blank lines ! // remove ignorable changes that are too far before other changes for (xchp = *xscr; xchp && xchp->ignore; xchp = xchp->next) { xch = xchp->next; --- 54,62 ---- xdchange_t *xch, *xchp, *lxch; long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen; long max_ignorable = xecfg->ctxlen; ! unsigned long ignored = 0; /* number of ignored blank lines */ ! /* remove ignorable changes that are too far before other changes */ for (xchp = *xscr; xchp && xchp->ignore; xchp = xchp->next) { xch = xchp->next; *************** *** 99,107 **** static long def_ff(const char *rec, long len, char *buf, long sz, void *priv UNUSED) { if (len > 0 && ! (isalpha((unsigned char)*rec) || // identifier? ! *rec == '_' || // also identifier? ! *rec == '$')) { // identifiers from VMS and other esoterico if (len > sz) len = sz; while (0 < len && isspace((unsigned char)rec[len - 1])) --- 99,107 ---- static long def_ff(const char *rec, long len, char *buf, long sz, void *priv UNUSED) { if (len > 0 && ! (isalpha((unsigned char)*rec) || /* identifier? */ ! *rec == '_' || /* also identifier? */ ! *rec == '$')) { /* identifiers from VMS and other esoterico */ if (len > sz) len = sz; while (0 < len && isspace((unsigned char)rec[len - 1])) *************** *** 197,203 **** if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) { long fs1, i1 = xch->i1; ! // Appended chunk? if (i1 >= xe->xdf1.nrec) { long i2 = xch->i2; --- 197,203 ---- if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) { long fs1, i1 = xch->i1; ! /* Appended chunk? */ if (i1 >= xe->xdf1.nrec) { long i2 = xch->i2; *************** *** 225,232 **** if (fs1 < 0) fs1 = 0; if (fs1 < s1) { ! s2 -= s1 - fs1; s1 = fs1; } } --- 225,247 ---- if (fs1 < 0) fs1 = 0; if (fs1 < s1) { ! s2 = XDL_MAX(s2 - (s1 - fs1), 0); s1 = fs1; + + /* + * Did we extend context upwards into an + * ignored change? + */ + while (xchp != xch && + xchp->i1 + xchp->chg1 <= s1 && + xchp->i2 + xchp->chg2 <= s2) + xchp = xchp->next; + + /* If so, show it after all. */ + if (xchp != xch) { + xch = xchp; + goto pre_context_calculation; + } } } *************** *** 249,255 **** if (fe1 < 0) fe1 = xe->xdf1.nrec; if (fe1 > e1) { ! e2 += fe1 - e1; e1 = fe1; } --- 264,270 ---- if (fe1 < 0) fe1 = xe->xdf1.nrec; if (fe1 > e1) { ! e2 = XDL_MIN(e2 + (fe1 - e1), xe->xdf2.nrec); e1 = fe1; } *************** *** 281,287 **** funclineprev = s1 - 1; } #endif ! if (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2, func_line.buf, func_line.len, ecb) < 0) return -1; --- 296,303 ---- funclineprev = s1 - 1; } #endif ! if (!(xecfg->flags & XDL_EMIT_NO_HUNK_HDR) && ! xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2, func_line.buf, func_line.len, ecb) < 0) return -1; *** ../vim-8.2.3389/src/xdiff/xemit.h 2019-12-04 22:13:10.000000000 +0100 --- src/xdiff/xemit.h 2021-08-31 20:27:29.078489138 +0200 *************** *** 33,36 **** ! #endif // #if !defined(XEMIT_H) --- 33,36 ---- ! #endif /* #if !defined(XEMIT_H) */ *** ../vim-8.2.3389/src/xdiff/xhistogram.c 2019-12-04 22:11:36.000000000 +0100 --- src/xdiff/xhistogram.c 2021-08-31 20:27:29.078489138 +0200 *************** *** 42,49 **** */ #include "xinclude.h" - #include "xtypes.h" - #include "xdiff.h" #define MAX_PTR INT_MAX #define MAX_CNT INT_MAX --- 42,47 ---- *************** *** 55,62 **** struct record { unsigned int ptr, cnt; struct record *next; ! } **records, // an occurrence ! **line_map; // map of line to record chain chastore_t rcha; unsigned int *next_ptrs; unsigned int table_bits, --- 53,60 ---- struct record { unsigned int ptr, cnt; struct record *next; ! } **records, /* an occurrence */ ! **line_map; /* map of line to record chain */ chastore_t rcha; unsigned int *next_ptrs; unsigned int table_bits, *************** *** 128,134 **** */ NEXT_PTR(index, ptr) = rec->ptr; rec->ptr = ptr; ! // cap rec->cnt at MAX_CNT rec->cnt = XDL_MIN(MAX_CNT, rec->cnt + 1); LINE_MAP(index, ptr) = rec; goto continue_scan; --- 126,132 ---- */ NEXT_PTR(index, ptr) = rec->ptr; rec->ptr = ptr; ! /* cap rec->cnt at MAX_CNT */ rec->cnt = XDL_MIN(MAX_CNT, rec->cnt + 1); LINE_MAP(index, ptr) = rec; goto continue_scan; *************** *** 154,160 **** LINE_MAP(index, ptr) = rec; continue_scan: ! ; // no op } return 0; --- 152,158 ---- LINE_MAP(index, ptr) = rec; continue_scan: ! ; /* no op */ } return 0; *************** *** 237,242 **** --- 235,242 ---- int line1, int count1, int line2, int count2) { xpparam_t xpparam; + + memset(&xpparam, 0, sizeof(xpparam)); xpparam.flags = xpp->flags & ~XDF_DIFF_ALGORITHM_MASK; return xdl_fall_back_diff(env, &xpparam, *************** *** 266,272 **** index.records = NULL; index.line_map = NULL; ! // in case of early xdl_cha_free() index.rcha.head = NULL; index.table_bits = xdl_hashbits(count1); --- 266,272 ---- index.records = NULL; index.line_map = NULL; ! /* in case of early xdl_cha_free() */ index.rcha.head = NULL; index.table_bits = xdl_hashbits(count1); *************** *** 288,294 **** goto cleanup; memset(index.next_ptrs, 0, sz); ! // lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx() if (xdl_cha_init(&index.rcha, sizeof(struct record), count1 / 4 + 1) < 0) goto cleanup; --- 288,294 ---- goto cleanup; memset(index.next_ptrs, 0, sz); ! /* lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx() */ if (xdl_cha_init(&index.rcha, sizeof(struct record), count1 / 4 + 1) < 0) goto cleanup; *** ../vim-8.2.3389/src/xdiff/xinclude.h 2019-12-04 22:13:26.000000000 +0100 --- src/xdiff/xinclude.h 2021-08-31 20:27:29.078489138 +0200 *************** *** 20,25 **** --- 20,27 ---- * */ + // The following includes come from Vim: + // defines HAVE_ATTRIBUTE_UNUSED #ifdef HAVE_CONFIG_H # ifdef VMS *************** *** 44,49 **** --- 46,52 ---- #if !defined(XINCLUDE_H) #define XINCLUDE_H + // This effectively re-verts b46054b3746271d23feab0 from git #include #include #include *************** *** 52,58 **** #endif #include #include ! #include "xmacros.h" #include "xdiff.h" #include "xtypes.h" --- 55,64 ---- #endif #include #include ! // This include comes from git, so uncomment it ! #if 0 ! #include "git-compat-util.h" ! #endif #include "xmacros.h" #include "xdiff.h" #include "xtypes.h" *************** *** 62,65 **** #include "xemit.h" ! #endif // #if !defined(XINCLUDE_H) --- 68,71 ---- #include "xemit.h" ! #endif /* #if !defined(XINCLUDE_H) */ *** ../vim-8.2.3389/src/xdiff/xmacros.h 2019-12-04 22:13:37.000000000 +0100 --- src/xdiff/xmacros.h 2021-08-31 20:27:29.078489138 +0200 *************** *** 51,54 **** } while (0) ! #endif // #if !defined(XMACROS_H) --- 51,54 ---- } while (0) ! #endif /* #if !defined(XMACROS_H) */ *** ../vim-8.2.3389/src/xdiff/xpatience.c 2019-12-04 22:11:56.000000000 +0100 --- src/xdiff/xpatience.c 2021-08-31 20:27:29.078489138 +0200 *************** *** 20,27 **** * */ #include "xinclude.h" - #include "xtypes.h" - #include "xdiff.h" /* * The basic idea of patience diff is to find lines that are unique in --- 20,25 ---- *************** *** 69,75 **** */ unsigned anchor : 1; } *entries, *first, *last; ! // were common records found? unsigned long has_matches; mmfile_t *file1, *file2; xdfenv_t *env; --- 67,73 ---- */ unsigned anchor : 1; } *entries, *first, *last; ! /* were common records found? */ unsigned long has_matches; mmfile_t *file1, *file2; xdfenv_t *env; *************** *** 78,98 **** static int is_anchor(xpparam_t const *xpp, const char *line) { ! size_t i; ! for (i = 0; i < xpp->anchors_nr; i++) { if (!strncmp(line, xpp->anchors[i], strlen(xpp->anchors[i]))) return 1; } return 0; } ! // The argument "pass" is 1 for the first file, 2 for the second. static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map, int pass) { xrecord_t **records = pass == 1 ? map->env->xdf1.recs : map->env->xdf2.recs; ! xrecord_t *record = records[line - 1], *other; /* * After xdl_prepare_env() (or more precisely, due to * xdl_classify_record()), the "ha" member of the records (AKA lines) --- 76,96 ---- static int is_anchor(xpparam_t const *xpp, const char *line) { ! int i; ! for (i = 0; i < (int)xpp->anchors_nr; i++) { if (!strncmp(line, xpp->anchors[i], strlen(xpp->anchors[i]))) return 1; } return 0; } ! /* The argument "pass" is 1 for the first file, 2 for the second. */ static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map, int pass) { xrecord_t **records = pass == 1 ? map->env->xdf1.recs : map->env->xdf2.recs; ! xrecord_t *record = records[line - 1]; /* * After xdl_prepare_env() (or more precisely, due to * xdl_classify_record()), the "ha" member of the records (AKA lines) *************** *** 106,116 **** int index = (int)((record->ha << 1) % map->alloc); while (map->entries[index].line1) { ! other = map->env->xdf1.recs[map->entries[index].line1 - 1]; ! if (map->entries[index].hash != record->ha || ! !xdl_recmatch(record->ptr, record->size, ! other->ptr, other->size, ! map->xpp->flags)) { if (++index >= map->alloc) index = 0; continue; --- 104,110 ---- int index = (int)((record->ha << 1) % map->alloc); while (map->entries[index].line1) { ! if (map->entries[index].hash != record->ha) { if (++index >= map->alloc) index = 0; continue; *************** *** 155,161 **** result->xpp = xpp; result->env = env; ! // We know exactly how large we want the hash map result->alloc = count1 * 2; result->entries = (struct entry *) xdl_malloc(result->alloc * sizeof(struct entry)); --- 149,155 ---- result->xpp = xpp; result->env = env; ! /* We know exactly how large we want the hash map */ result->alloc = count1 * 2; result->entries = (struct entry *) xdl_malloc(result->alloc * sizeof(struct entry)); *************** *** 163,173 **** return -1; memset(result->entries, 0, result->alloc * sizeof(struct entry)); ! // First, fill with entries from the first file while (count1--) insert_record(xpp, line1++, result, 1); ! // Then search for matches in the second file while (count2--) insert_record(xpp, line2++, result, 2); --- 157,167 ---- return -1; memset(result->entries, 0, result->alloc * sizeof(struct entry)); ! /* First, fill with entries from the first file */ while (count1--) insert_record(xpp, line1++, result, 1); ! /* Then search for matches in the second file */ while (count2--) insert_record(xpp, line2++, result, 2); *************** *** 185,197 **** while (left + 1 < right) { int middle = left + (right - left) / 2; ! // by construction, no two entries can be equal if (sequence[middle]->line2 > entry->line2) right = middle; else left = middle; } ! // return the index in "sequence", _not_ the sequence length return left; } --- 179,191 ---- while (left + 1 < right) { int middle = left + (right - left) / 2; ! /* by construction, no two entries can be equal */ if (sequence[middle]->line2 > entry->line2) right = middle; else left = middle; } ! /* return the index in "sequence", _not_ the sequence length */ return left; } *************** *** 206,214 **** */ static struct entry *find_longest_common_sequence(struct hashmap *map) { ! struct entry **sequence = (struct entry **)xdl_malloc(map->nr * sizeof(struct entry *)); int longest = 0, i; struct entry *entry; /* * If not -1, this entry in sequence must never be overridden. * Therefore, overriding entries before this has no effect, so --- 200,209 ---- */ static struct entry *find_longest_common_sequence(struct hashmap *map) { ! struct entry **sequence = xdl_malloc(map->nr * sizeof(struct entry *)); int longest = 0, i; struct entry *entry; + /* * If not -1, this entry in sequence must never be overridden. * Therefore, overriding entries before this has no effect, so *************** *** 237,249 **** } } ! // No common unique lines were found if (!longest) { xdl_free(sequence); return NULL; } ! // Iterate starting at the last element, adjusting the "next" members entry = sequence[longest - 1]; entry->next = NULL; while (entry->previous) { --- 232,244 ---- } } ! /* No common unique lines were found */ if (!longest) { xdl_free(sequence); return NULL; } ! /* Iterate starting at the last element, adjusting the "next" members */ entry = sequence[longest - 1]; entry->next = NULL; while (entry->previous) { *************** *** 258,265 **** { xrecord_t *record1 = map->env->xdf1.recs[line1 - 1]; xrecord_t *record2 = map->env->xdf2.recs[line2 - 1]; ! return xdl_recmatch(record1->ptr, record1->size, ! record2->ptr, record2->size, map->xpp->flags); } static int patience_diff(mmfile_t *file1, mmfile_t *file2, --- 253,259 ---- { xrecord_t *record1 = map->env->xdf1.recs[line1 - 1]; xrecord_t *record2 = map->env->xdf2.recs[line2 - 1]; ! return record1->ha == record2->ha; } static int patience_diff(mmfile_t *file1, mmfile_t *file2, *************** *** 273,279 **** int next1, next2; for (;;) { ! // Try to grow the line ranges of common lines if (first) { next1 = first->line1; next2 = first->line2; --- 267,273 ---- int next1, next2; for (;;) { ! /* Try to grow the line ranges of common lines */ if (first) { next1 = first->line1; next2 = first->line2; *************** *** 292,302 **** line2++; } ! // Recurse if (next1 > line1 || next2 > line2) { - struct hashmap submap; - - memset(&submap, 0, sizeof(submap)); if (patience_diff(map->file1, map->file2, map->xpp, map->env, line1, next1 - line1, --- 286,293 ---- line2++; } ! /* Recurse */ if (next1 > line1 || next2 > line2) { if (patience_diff(map->file1, map->file2, map->xpp, map->env, line1, next1 - line1, *************** *** 323,328 **** --- 314,321 ---- int line1, int count1, int line2, int count2) { xpparam_t xpp; + + memset(&xpp, 0, sizeof(xpp)); xpp.flags = map->xpp->flags & ~XDF_DIFF_ALGORITHM_MASK; return xdl_fall_back_diff(map->env, &xpp, *************** *** 343,349 **** struct entry *first; int result = 0; ! // trivial case: one side is empty if (!count1) { while(count2--) env->xdf2.rchg[line2++ - 1] = 1; --- 336,342 ---- struct entry *first; int result = 0; ! /* trivial case: one side is empty */ if (!count1) { while(count2--) env->xdf2.rchg[line2++ - 1] = 1; *************** *** 359,365 **** line1, count1, line2, count2)) return -1; ! // are there any matching lines at all? if (!map.has_matches) { while(count1--) env->xdf1.rchg[line1++ - 1] = 1; --- 352,358 ---- line1, count1, line2, count2)) return -1; ! /* are there any matching lines at all? */ if (!map.has_matches) { while(count1--) env->xdf1.rchg[line1++ - 1] = 1; *************** *** 387,393 **** if (xdl_prepare_env(file1, file2, xpp, env) < 0) return -1; ! // environment is cleaned up in xdl_diff() return patience_diff(file1, file2, xpp, env, 1, env->xdf1.nrec, 1, env->xdf2.nrec); } --- 380,386 ---- if (xdl_prepare_env(file1, file2, xpp, env) < 0) return -1; ! /* environment is cleaned up in xdl_diff() */ return patience_diff(file1, file2, xpp, env, 1, env->xdf1.nrec, 1, env->xdf2.nrec); } *** ../vim-8.2.3389/src/xdiff/xprepare.h 2019-12-04 22:13:59.000000000 +0100 --- src/xdiff/xprepare.h 2021-08-31 20:27:29.078489138 +0200 *************** *** 31,34 **** ! #endif // #if !defined(XPREPARE_H) --- 31,34 ---- ! #endif /* #if !defined(XPREPARE_H) */ *** ../vim-8.2.3389/src/xdiff/xtypes.h 2019-12-04 22:14:03.000000000 +0100 --- src/xdiff/xtypes.h 2021-08-31 20:27:29.078489138 +0200 *************** *** 64,67 **** ! #endif // #if !defined(XTYPES_H) --- 64,67 ---- ! #endif /* #if !defined(XTYPES_H) */ *** ../vim-8.2.3389/src/xdiff/xutils.c 2019-12-04 22:12:23.000000000 +0100 --- src/xdiff/xutils.c 2021-08-31 20:27:29.078489138 +0200 *************** *** 20,32 **** * */ - #include - #include #include "xinclude.h" - - long xdl_bogosqrt(long n) { long i; --- 20,28 ---- *************** *** 51,60 **** mb[1].size = size; if (size > 0 && rec[size - 1] != '\n') { mb[2].ptr = (char *) "\n\\ No newline at end of file\n"; ! mb[2].size = (long)strlen(mb[2].ptr); i++; } ! if (ecb->outf(ecb->priv, mb, i) < 0) { return -1; } --- 47,56 ---- mb[1].size = size; if (size > 0 && rec[size - 1] != '\n') { mb[2].ptr = (char *) "\n\\ No newline at end of file\n"; ! mb[2].size = strlen(mb[2].ptr); i++; } ! if (ecb->out_line(ecb->priv, mb, i) < 0) { return -1; } *************** *** 168,174 **** s--; if (s == i) return 1; ! // do not ignore CR at the end of an incomplete line if (complete && s == i + 1 && l[i] == '\r') return 1; return 0; --- 164,170 ---- s--; if (s == i) return 1; ! /* do not ignore CR at the end of an incomplete line */ if (complete && s == i + 1 && l[i] == '\r') return 1; return 0; *************** *** 208,214 **** } else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) { while (i1 < s1 && i2 < s2) { if (XDL_ISSPACE(l1[i1]) && XDL_ISSPACE(l2[i2])) { ! // Skip matching spaces and try again while (i1 < s1 && XDL_ISSPACE(l1[i1])) i1++; while (i2 < s2 && XDL_ISSPACE(l2[i2])) --- 204,210 ---- } else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) { while (i1 < s1 && i2 < s2) { if (XDL_ISSPACE(l1[i1]) && XDL_ISSPACE(l2[i2])) { ! /* Skip matching spaces and try again */ while (i1 < s1 && XDL_ISSPACE(l1[i1])) i1++; while (i2 < s2 && XDL_ISSPACE(l2[i2])) *************** *** 224,230 **** i2++; } } else if (flags & XDF_IGNORE_CR_AT_EOL) { ! // Find the first difference and see how the line ends while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) { i1++; i2++; --- 220,226 ---- i2++; } } else if (flags & XDF_IGNORE_CR_AT_EOL) { ! /* Find the first difference and see how the line ends */ while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) { i1++; i2++; *************** *** 261,267 **** for (; ptr < top && *ptr != '\n'; ptr++) { if (cr_at_eol_only) { ! // do not ignore CR at the end of an incomplete line if (*ptr == '\r' && (ptr + 1 < top && ptr[1] == '\n')) continue; --- 257,263 ---- for (; ptr < top && *ptr != '\n'; ptr++) { if (cr_at_eol_only) { ! /* do not ignore CR at the end of an incomplete line */ if (*ptr == '\r' && (ptr + 1 < top && ptr[1] == '\n')) continue; *************** *** 274,280 **** ptr++; at_eol = (top <= ptr + 1 || ptr[1] == '\n'); if (flags & XDF_IGNORE_WHITESPACE) ! ; // already handled else if (flags & XDF_IGNORE_WHITESPACE_CHANGE && !at_eol) { ha += (ha << 5); --- 270,276 ---- ptr++; at_eol = (top <= ptr + 1 || ptr[1] == '\n'); if (flags & XDF_IGNORE_WHITESPACE) ! ; /* already handled */ else if (flags & XDF_IGNORE_WHITESPACE_CHANGE && !at_eol) { ha += (ha << 5); *************** *** 344,351 **** return str - out; } ! int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2, ! const char *func, long funclen, xdemitcb_t *ecb) { int nb = 0; mmbuffer_t mb; char buf[128]; --- 340,348 ---- return str - out; } ! static int xdl_format_hunk_hdr(long s1, long c1, long s2, long c2, ! const char *func, long funclen, ! xdemitcb_t *ecb) { int nb = 0; mmbuffer_t mb; char buf[128]; *************** *** 387,395 **** mb.ptr = buf; mb.size = nb; ! if (ecb->outf(ecb->priv, &mb, 1) < 0) return -1; return 0; } --- 384,404 ---- mb.ptr = buf; mb.size = nb; ! if (ecb->out_line(ecb->priv, &mb, 1) < 0) return -1; + return 0; + } + int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2, + const char *func, long funclen, + xdemitcb_t *ecb) { + if (!ecb->out_hunk) + return xdl_format_hunk_hdr(s1, c1, s2, c2, func, funclen, ecb); + if (ecb->out_hunk(ecb->priv, + c1 ? s1 : s1 - 1, c1, + c2 ? s2 : s2 - 1, c2, + func, funclen) < 0) + return -1; return 0; } *** ../vim-8.2.3389/src/xdiff/xutils.h 2019-12-04 22:14:23.000000000 +0100 --- src/xdiff/xutils.h 2021-08-31 20:27:29.078489138 +0200 *************** *** 44,47 **** ! #endif // #if !defined(XUTILS_H) --- 44,47 ---- ! #endif /* #if !defined(XUTILS_H) */ *** ../vim-8.2.3389/src/version.c 2021-08-31 19:12:47.757554157 +0200 --- src/version.c 2021-08-31 20:29:21.482296266 +0200 *************** *** 757,758 **** --- 757,760 ---- { /* Add new patch number below this line */ + /**/ + 3390, /**/ -- Never under any circumstances take a sleeping pill and a laxative on the same night. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///