changeset 25709:d5142d87f898 v8.2.3390

patch 8.2.3390: included xdiff code is outdated Commit: https://github.com/vim/vim/commit/ba02e4720f863fdb456e7023520f0a354eec0dcf Author: Christian Brabandt <cb@256bit.org> Date: Tue Aug 31 20:46:39 2021 +0200 patch 8.2.3390: included xdiff code is outdated Problem: Included xdiff code is outdated. Solution: Sync with xdiff in git 2.33. (Christian Brabandt, closes https://github.com/vim/vim/issues/8431)
author Bram Moolenaar <Bram@vim.org>
date Tue, 31 Aug 2021 21:00:05 +0200
parents a1f90f486bf7
children 3d6603826015
files src/diff.c src/version.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
diffstat 16 files changed, 239 insertions(+), 144 deletions(-) [+]
line wrap: on
line diff
--- a/src/diff.c
+++ b/src/diff.c
@@ -1095,7 +1095,7 @@ diff_file_internal(diffio_T *diffio)
 
     emit_cfg.ctxlen = 0; // don't need any diff_context here
     emit_cb.priv = &diffio->dio_diff;
-    emit_cb.outf = xdiff_out;
+    emit_cb.out_line = xdiff_out;
     if (xdl_diff(&diffio->dio_orig.din_mmfile,
 		&diffio->dio_new.din_mmfile,
 		&param, &emit_cfg, &emit_cb) < 0)
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3390,
+/**/
     3389,
 /**/
     3388,
--- a/src/xdiff/README.txt
+++ b/src/xdiff/README.txt
@@ -1,6 +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.
+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
--- a/src/xdiff/xdiff.h
+++ b/src/xdiff/xdiff.h
@@ -25,9 +25,9 @@
 
 #ifdef __cplusplus
 extern "C" {
-#endif // #ifdef __cplusplus
+#endif /* #ifdef __cplusplus */
 
-// xpparm_t.flags
+/* xpparm_t.flags */
 #define XDF_NEED_MINIMAL (1 << 0)
 
 #define XDF_IGNORE_WHITESPACE (1 << 1)
@@ -48,22 +48,23 @@ extern "C" {
 
 #define XDF_INDENT_HEURISTIC (1 << 23)
 
-// xdemitconf_t.flags
+/* 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
+/* 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
+/* merge favor modes */
 #define XDL_MERGE_FAVOR_OURS 1
 #define XDL_MERGE_FAVOR_THEIRS 2
 #define XDL_MERGE_FAVOR_UNION 3
 
-// merge output styles
+/* merge output styles */
 #define XDL_MERGE_DIFF3 1
 
 typedef struct s_mmfile {
@@ -79,14 +80,24 @@ typedef struct s_mmbuffer {
 typedef struct s_xpparam {
 	unsigned long flags;
 
-	// See Documentation/diff-options.txt.
+	/* -I<regex> */
+ #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 (*outf)(void *, mmbuffer_t *, int);
+	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,9 +141,9 @@ typedef struct s_xmparam {
 	int level;
 	int favor;
 	int style;
-	const char *ancestor;	// label for orig
-	const char *file1;	// label for mf1
-	const char *file2;	// label for mf2
+	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,6 +153,6 @@ int xdl_merge(mmfile_t *orig, mmfile_t *
 
 #ifdef __cplusplus
 }
-#endif // #ifdef __cplusplus
+#endif /* #ifdef __cplusplus */
 
-#endif // #if !defined(XDIFF_H)
+#endif /* #if !defined(XDIFF_H) */
--- a/src/xdiff/xdiffi.c
+++ b/src/xdiff/xdiffi.c
@@ -38,9 +38,9 @@ typedef struct s_xdpsplit {
  * 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.
+ * 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,11 +63,13 @@ static long xdl_split(unsigned long cons
 		int got_snake = 0;
 
 		/*
-		 * We need to extent the diagonal "domain" by one. If the next
+		 * 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.
+		 * 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.
+		 * avoid extra conditions in the check inside the core loop.
 		 */
 		if (fmin > dmin)
 			kvdf[--fmin - 1] = -1;
@@ -98,11 +100,13 @@ static long xdl_split(unsigned long cons
 		}
 
 		/*
-		 * We need to extent the diagonal "domain" by one. If the next
+		 * 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.
+		 * 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.
+		 * avoid extra conditions in the check inside the core loop.
 		 */
 		if (bmin > dmin)
 			kvdb[--bmin - 1] = XDL_LINE_MAX;
@@ -138,7 +142,7 @@ static long xdl_split(unsigned long cons
 		/*
 		 * 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
+		 * 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,8 +200,9 @@ static long xdl_split(unsigned long cons
 		}
 
 		/*
-		 * Enough is enough. We spent too much time here and now we collect
-		 * the furthest reaching path using the (i1 + i2) measure.
+		 * 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,9 +249,9 @@ static long xdl_split(unsigned long cons
 
 
 /*
- * 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.
+ * 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,7 +328,9 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t 
 	}
 
 	/*
-	 * Allocate and setup K vectors to be used by the differential algorithm.
+	 * 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,13 +425,13 @@ static int xget_indent(xrecord_t *rec)
 			ret += 1;
 		else if (c == '\t')
 			ret += 8 - ret % 8;
-		// ignore other whitespace characters
+		/* ignore other whitespace characters */
 
 		if (ret >= MAX_INDENT)
 			return MAX_INDENT;
 	}
 
-	// The line contains only whitespace.
+	/* The line contains only whitespace. */
 	return -1;
 }
 
@@ -435,7 +442,7 @@ static int xget_indent(xrecord_t *rec)
  */
 #define MAX_BLANKS 20
 
-// Characteristics measured about a hypothetical split position.
+/* 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,8 +450,8 @@ struct split_measurement {
 	int end_of_file;
 
 	/*
-	 * How much is the line immediately following the split indented (or -1 if
-	 * the line is blank):
+	 * How much is the line immediately following the split indented (or -1
+	 * if the line is blank):
 	 */
 	int indent;
 
@@ -454,8 +461,8 @@ struct split_measurement {
 	int pre_blank;
 
 	/*
-	 * How much is the nearest non-blank line above the split indented (or -1
-	 * if there is no such line)?
+	 * How much is the nearest non-blank line above the split indented (or
+	 * -1 if there is no such line)?
 	 */
 	int pre_indent;
 
@@ -472,10 +479,10 @@ struct split_measurement {
 };
 
 struct split_score {
-	// The effective indent of this split (smaller is preferred).
+	/* The effective indent of this split (smaller is preferred). */
 	int effective_indent;
 
-	// Penalty for this split (smaller is preferred).
+	/* Penalty for this split (smaller is preferred). */
 	int penalty;
 };
 
@@ -534,16 +541,16 @@ static void measure_split(const xdfile_t
  * integer math.
  */
 
-// Penalty if there are no non-blank lines before the split
+/* 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
+/* 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
+/* 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
+/* Multiplier for the number of blank lines after the split */
 #define POST_BLANK_WEIGHT 6
 
 /*
@@ -581,13 +588,13 @@ static void measure_split(const xdfile_t
 
 /*
  * 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
+ * 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.
+ * 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,7 +617,7 @@ static void score_add_split(const struct
 	post_blank = (m->indent == -1) ? 1 + m->post_blank : 0;
 	total_blank = m->pre_blank + post_blank;
 
-	// Penalties based on nearby blank lines:
+	/* Penalties based on nearby blank lines: */
 	s->penalty += TOTAL_BLANK_WEIGHT * total_blank;
 	s->penalty += POST_BLANK_WEIGHT * post_blank;
 
@@ -621,13 +628,13 @@ static void score_add_split(const struct
 
 	any_blanks = (total_blank != 0);
 
-	// Note that the effective indent is -1 at the end of the file:
+	/* Note that the effective indent is -1 at the end of the file: */
 	s->effective_indent += indent;
 
 	if (indent == -1) {
-		// No additional adjustments needed.
+		/* No additional adjustments needed. */
 	} else if (m->pre_indent == -1) {
-		// No additional adjustments needed.
+		/* No additional adjustments needed. */
 	} else if (indent > m->pre_indent) {
 		/*
 		 * The line is indented more than its predecessor.
@@ -669,7 +676,7 @@ static void score_add_split(const struct
 
 static int score_cmp(struct split_score *s1, struct split_score *s2)
 {
-	// -1 if s1.effective_indent < s2->effective_indent, etc.
+	/* -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,13 +816,16 @@ int xdl_change_compact(xdfile_t *xdf, xd
 	group_init(xdfo, &go);
 
 	while (1) {
-		// If the group is empty in the to-be-compacted file, skip it:
+		/*
+		 * 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.
+		 * each direction. If it bumps into any other changes, merge
+		 * them.
 		 */
 		do {
 			groupsize = g.end - g.start;
@@ -828,7 +838,7 @@ int xdl_change_compact(xdfile_t *xdf, xd
 			 */
 			end_matching_other = -1;
 
-			// Shift the group backward as much as possible:
+			/* 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,7 +852,7 @@ int xdl_change_compact(xdfile_t *xdf, xd
 			if (go.end > go.start)
 				end_matching_other = g.end;
 
-			// Now shift the group forward as far as possible:
+			/* Now shift the group forward as far as possible: */
 			while (1) {
 				if (group_slide_down(xdf, &g, flags))
 					break;
@@ -858,17 +868,17 @@ int xdl_change_compact(xdfile_t *xdf, xd
 		 * 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.
+		 * 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
+			/* 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.
+			 * 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,14 +889,15 @@ int xdl_change_compact(xdfile_t *xdf, xd
 		} 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.
+			 * 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,7 +932,7 @@ int xdl_change_compact(xdfile_t *xdf, xd
 		}
 
 	next:
-		// Move past the just-processed group:
+		/* Move past the just-processed group: */
 		if (group_next(xdf, &g))
 			break;
 		if (group_next(xdfo, &go))
@@ -987,7 +998,7 @@ static int xdl_call_hunk_func(xdfenv_t *
 	return 0;
 }
 
-static void xdl_mark_ignorable(xdchange_t *xscr, xdfenv_t *xe, long flags)
+static void xdl_mark_ignorable_lines(xdchange_t *xscr, xdfenv_t *xe, long flags)
 {
 	xdchange_t *xch;
 
@@ -1008,6 +1019,48 @@ static void xdl_mark_ignorable(xdchange_
 	}
 }
 
+#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,
+				 &regmatch, 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,7 +1080,12 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf
 	}
 	if (xscr) {
 		if (xpp->flags & XDF_IGNORE_BLANK_LINES)
-			xdl_mark_ignorable(xscr, &xe, xpp->flags);
+			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) {
 
--- a/src/xdiff/xdiffi.h
+++ b/src/xdiff/xdiffi.h
@@ -61,4 +61,4 @@ int xdl_do_patience_diff(mmfile_t *mf1, 
 int xdl_do_histogram_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
 		xdfenv_t *env);
 
-#endif // #if !defined(XDIFFI_H)
+#endif /* #if !defined(XDIFFI_H) */
--- a/src/xdiff/xemit.c
+++ b/src/xdiff/xemit.c
@@ -31,7 +31,7 @@ static long xdl_get_rec(xdfile_t *xdf, l
 
 
 static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *ecb) {
-	long size, psize = (long)strlen(pre);
+	long size, psize = strlen(pre);
 	char const *rec;
 
 	size = xdl_get_rec(xdf, ri, &rec);
@@ -54,9 +54,9 @@ xdchange_t *xdl_get_hunk(xdchange_t **xs
 	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
+	unsigned long ignored = 0; /* number of ignored blank lines */
 
-	// remove ignorable changes that are too far before other changes
+	/* remove ignorable changes that are too far before other changes */
 	for (xchp = *xscr; xchp && xchp->ignore; xchp = xchp->next) {
 		xch = xchp->next;
 
@@ -99,9 +99,9 @@ xdchange_t *xdl_get_hunk(xdchange_t **xs
 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
+			(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,7 +197,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange
 		if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) {
 			long fs1, i1 = xch->i1;
 
-			// Appended chunk?
+			/* Appended chunk? */
 			if (i1 >= xe->xdf1.nrec) {
 				long i2 = xch->i2;
 
@@ -225,8 +225,23 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange
 			if (fs1 < 0)
 				fs1 = 0;
 			if (fs1 < s1) {
-				s2 -= s1 - fs1;
+				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,7 +264,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange
 			if (fe1 < 0)
 				fe1 = xe->xdf1.nrec;
 			if (fe1 > e1) {
-				e2 += fe1 - e1;
+				e2 = XDL_MIN(e2 + (fe1 - e1), xe->xdf2.nrec);
 				e1 = fe1;
 			}
 
@@ -281,7 +296,8 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange
 			funclineprev = s1 - 1;
 		}
 #endif
-		if (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2,
+		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;
 
--- a/src/xdiff/xemit.h
+++ b/src/xdiff/xemit.h
@@ -33,4 +33,4 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange
 
 
 
-#endif // #if !defined(XEMIT_H)
+#endif /* #if !defined(XEMIT_H) */
--- a/src/xdiff/xhistogram.c
+++ b/src/xdiff/xhistogram.c
@@ -42,8 +42,6 @@
  */
 
 #include "xinclude.h"
-#include "xtypes.h"
-#include "xdiff.h"
 
 #define MAX_PTR	INT_MAX
 #define MAX_CNT	INT_MAX
@@ -55,8 +53,8 @@ struct histindex {
 	struct record {
 		unsigned int ptr, cnt;
 		struct record *next;
-	} **records, // an occurrence
-	  **line_map; // map of line to record chain
+	} **records, /* an occurrence */
+	  **line_map; /* map of line to record chain */
 	chastore_t rcha;
 	unsigned int *next_ptrs;
 	unsigned int table_bits,
@@ -128,7 +126,7 @@ static int scanA(struct histindex *index
 				 */
 				NEXT_PTR(index, ptr) = rec->ptr;
 				rec->ptr = ptr;
-				// cap rec->cnt at MAX_CNT
+				/* cap rec->cnt at MAX_CNT */
 				rec->cnt = XDL_MIN(MAX_CNT, rec->cnt + 1);
 				LINE_MAP(index, ptr) = rec;
 				goto continue_scan;
@@ -154,7 +152,7 @@ static int scanA(struct histindex *index
 		LINE_MAP(index, ptr) = rec;
 
 continue_scan:
-		; // no op
+		; /* no op */
 	}
 
 	return 0;
@@ -237,6 +235,8 @@ static int fall_back_to_classic_diff(xpp
 		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,7 +266,7 @@ static int find_lcs(xpparam_t const *xpp
 
 	index.records = NULL;
 	index.line_map = NULL;
-	// in case of early xdl_cha_free()
+	/* in case of early xdl_cha_free() */
 	index.rcha.head = NULL;
 
 	index.table_bits = xdl_hashbits(count1);
@@ -288,7 +288,7 @@ static int find_lcs(xpparam_t const *xpp
 		goto cleanup;
 	memset(index.next_ptrs, 0, sz);
 
-	// lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx()
+	/* 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;
 
--- a/src/xdiff/xinclude.h
+++ b/src/xdiff/xinclude.h
@@ -20,6 +20,8 @@
  *
  */
 
+// The following includes come from Vim:
+
 // defines HAVE_ATTRIBUTE_UNUSED
 #ifdef HAVE_CONFIG_H
 # ifdef VMS
@@ -44,6 +46,7 @@
 #if !defined(XINCLUDE_H)
 #define XINCLUDE_H
 
+// This effectively re-verts b46054b3746271d23feab0 from git
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -52,7 +55,10 @@
 #endif
 #include <string.h>
 #include <limits.h>
-
+// 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,4 +68,4 @@
 #include "xemit.h"
 
 
-#endif // #if !defined(XINCLUDE_H)
+#endif /* #if !defined(XINCLUDE_H) */
--- a/src/xdiff/xmacros.h
+++ b/src/xdiff/xmacros.h
@@ -51,4 +51,4 @@ do { \
 } while (0)
 
 
-#endif // #if !defined(XMACROS_H)
+#endif /* #if !defined(XMACROS_H) */
--- a/src/xdiff/xpatience.c
+++ b/src/xdiff/xpatience.c
@@ -20,8 +20,6 @@
  *
  */
 #include "xinclude.h"
-#include "xtypes.h"
-#include "xdiff.h"
 
 /*
  * The basic idea of patience diff is to find lines that are unique in
@@ -69,7 +67,7 @@ struct hashmap {
 		 */
 		unsigned anchor : 1;
 	} *entries, *first, *last;
-	// were common records found?
+	/* were common records found? */
 	unsigned long has_matches;
 	mmfile_t *file1, *file2;
 	xdfenv_t *env;
@@ -78,21 +76,21 @@ struct hashmap {
 
 static int is_anchor(xpparam_t const *xpp, const char *line)
 {
-	size_t i;
-	for (i = 0; i < xpp->anchors_nr; i++) {
+	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.
+/* 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;
+	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,11 +104,7 @@ static void insert_record(xpparam_t cons
 	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 (map->entries[index].hash != record->ha) {
 			if (++index >= map->alloc)
 				index = 0;
 			continue;
@@ -155,7 +149,7 @@ static int fill_hashmap(mmfile_t *file1,
 	result->xpp = xpp;
 	result->env = env;
 
-	// We know exactly how large we want the hash map
+	/* 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,11 +157,11 @@ static int fill_hashmap(mmfile_t *file1,
 		return -1;
 	memset(result->entries, 0, result->alloc * sizeof(struct entry));
 
-	// First, fill with entries from the first file
+	/* First, fill with entries from the first file */
 	while (count1--)
 		insert_record(xpp, line1++, result, 1);
 
-	// Then search for matches in the second file
+	/* Then search for matches in the second file */
 	while (count2--)
 		insert_record(xpp, line2++, result, 2);
 
@@ -185,13 +179,13 @@ static int binary_search(struct entry **
 
 	while (left + 1 < right) {
 		int middle = left + (right - left) / 2;
-		// by construction, no two entries can be equal
+		/* 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 the index in "sequence", _not_ the sequence length */
 	return left;
 }
 
@@ -206,9 +200,10 @@ static int binary_search(struct entry **
  */
 static struct entry *find_longest_common_sequence(struct hashmap *map)
 {
-	struct entry **sequence = (struct entry **)xdl_malloc(map->nr * sizeof(struct entry *));
+	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,13 +232,13 @@ static struct entry *find_longest_common
 		}
 	}
 
-	// No common unique lines were found
+	/* No common unique lines were found */
 	if (!longest) {
 		xdl_free(sequence);
 		return NULL;
 	}
 
-	// Iterate starting at the last element, adjusting the "next" members
+	/* Iterate starting at the last element, adjusting the "next" members */
 	entry = sequence[longest - 1];
 	entry->next = NULL;
 	while (entry->previous) {
@@ -258,8 +253,7 @@ static int match(struct hashmap *map, in
 {
 	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);
+	return record1->ha == record2->ha;
 }
 
 static int patience_diff(mmfile_t *file1, mmfile_t *file2,
@@ -273,7 +267,7 @@ static int walk_common_sequence(struct h
 	int next1, next2;
 
 	for (;;) {
-		// Try to grow the line ranges of common lines
+		/* Try to grow the line ranges of common lines */
 		if (first) {
 			next1 = first->line1;
 			next2 = first->line2;
@@ -292,11 +286,8 @@ static int walk_common_sequence(struct h
 			line2++;
 		}
 
-		// Recurse
+		/* 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,
@@ -323,6 +314,8 @@ static int fall_back_to_classic_diff(str
 		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,7 +336,7 @@ static int patience_diff(mmfile_t *file1
 	struct entry *first;
 	int result = 0;
 
-	// trivial case: one side is empty
+	/* trivial case: one side is empty */
 	if (!count1) {
 		while(count2--)
 			env->xdf2.rchg[line2++ - 1] = 1;
@@ -359,7 +352,7 @@ static int patience_diff(mmfile_t *file1
 			line1, count1, line2, count2))
 		return -1;
 
-	// are there any matching lines at all?
+	/* are there any matching lines at all? */
 	if (!map.has_matches) {
 		while(count1--)
 			env->xdf1.rchg[line1++ - 1] = 1;
@@ -387,7 +380,7 @@ int xdl_do_patience_diff(mmfile_t *file1
 	if (xdl_prepare_env(file1, file2, xpp, env) < 0)
 		return -1;
 
-	// environment is cleaned up in xdl_diff()
+	/* environment is cleaned up in xdl_diff() */
 	return patience_diff(file1, file2, xpp, env,
 			1, env->xdf1.nrec, 1, env->xdf2.nrec);
 }
--- a/src/xdiff/xprepare.h
+++ b/src/xdiff/xprepare.h
@@ -31,4 +31,4 @@ void xdl_free_env(xdfenv_t *xe);
 
 
 
-#endif // #if !defined(XPREPARE_H)
+#endif /* #if !defined(XPREPARE_H) */
--- a/src/xdiff/xtypes.h
+++ b/src/xdiff/xtypes.h
@@ -64,4 +64,4 @@ typedef struct s_xdfenv {
 
 
 
-#endif // #if !defined(XTYPES_H)
+#endif /* #if !defined(XTYPES_H) */
--- a/src/xdiff/xutils.c
+++ b/src/xdiff/xutils.c
@@ -20,13 +20,9 @@
  *
  */
 
-#include <limits.h>
-#include <assert.h>
 #include "xinclude.h"
 
 
-
-
 long xdl_bogosqrt(long n) {
 	long i;
 
@@ -51,10 +47,10 @@ int xdl_emit_diffrec(char const *rec, lo
 	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);
+		mb[2].size = strlen(mb[2].ptr);
 		i++;
 	}
-	if (ecb->outf(ecb->priv, mb, i) < 0) {
+	if (ecb->out_line(ecb->priv, mb, i) < 0) {
 
 		return -1;
 	}
@@ -168,7 +164,7 @@ static int ends_with_optional_cr(const c
 		s--;
 	if (s == i)
 		return 1;
-	// do not ignore CR at the end of an incomplete line
+	/* do not ignore CR at the end of an incomplete line */
 	if (complete && s == i + 1 && l[i] == '\r')
 		return 1;
 	return 0;
@@ -208,7 +204,7 @@ int xdl_recmatch(const char *l1, long s1
 	} 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
+				/* Skip matching spaces and try again */
 				while (i1 < s1 && XDL_ISSPACE(l1[i1]))
 					i1++;
 				while (i2 < s2 && XDL_ISSPACE(l2[i2]))
@@ -224,7 +220,7 @@ int xdl_recmatch(const char *l1, long s1
 			i2++;
 		}
 	} else if (flags & XDF_IGNORE_CR_AT_EOL) {
-		// Find the first difference and see how the line ends
+		/* Find the first difference and see how the line ends */
 		while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) {
 			i1++;
 			i2++;
@@ -261,7 +257,7 @@ static unsigned long xdl_hash_record_wit
 
 	for (; ptr < top && *ptr != '\n'; ptr++) {
 		if (cr_at_eol_only) {
-			// do not ignore CR at the end of an incomplete line
+			/* do not ignore CR at the end of an incomplete line */
 			if (*ptr == '\r' &&
 			    (ptr + 1 < top && ptr[1] == '\n'))
 				continue;
@@ -274,7 +270,7 @@ static unsigned long xdl_hash_record_wit
 				ptr++;
 			at_eol = (top <= ptr + 1 || ptr[1] == '\n');
 			if (flags & XDF_IGNORE_WHITESPACE)
-				; // already handled
+				; /* already handled */
 			else if (flags & XDF_IGNORE_WHITESPACE_CHANGE
 				 && !at_eol) {
 				ha += (ha << 5);
@@ -344,8 +340,9 @@ int xdl_num_out(char *out, long val) {
 	return str - out;
 }
 
-int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
-		      const char *func, long funclen, xdemitcb_t *ecb) {
+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,9 +384,21 @@ int xdl_emit_hunk_hdr(long s1, long c1, 
 
 	mb.ptr = buf;
 	mb.size = nb;
-	if (ecb->outf(ecb->priv, &mb, 1) < 0)
+	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;
 }
 
--- a/src/xdiff/xutils.h
+++ b/src/xdiff/xutils.h
@@ -44,4 +44,4 @@ int xdl_fall_back_diff(xdfenv_t *diff_en
 
 
 
-#endif // #if !defined(XUTILS_H)
+#endif /* #if !defined(XUTILS_H) */