Commit Diff


commit - 227cd87e537c560f428629cf170b0f19422b1c56
commit + 26595c7df947f97507904fa391034b6a52bfca7d
blob - 5c8fd1fc7ae45e166e7af7a09a3e9b4cfa0f47b9
blob + 0450a007a948e500aa26ebd54a8aa533da5bbd63
--- lib/diff_internal.h
+++ lib/diff_internal.h
@@ -178,6 +178,16 @@ diff_chunk_type(const struct diff_chunk *chunk)
 	return CHUNK_SAME;
 }
 
+struct diff_chunk_context;
+
+bool
+diff_chunk_contexts_touch(const struct diff_chunk_context *cc,
+			  const struct diff_chunk_context *other);
+
+void
+diff_chunk_contexts_merge(struct diff_chunk_context *cc,
+			  const struct diff_chunk_context *other);
+
 struct diff_state {
 	/* The final result passed to the original diff caller. */
 	struct diff_result *result;
blob - 65ef9ad4da6435426210a1e93aeda9c7e57539c3
blob + 38053a9163403e9b1871f8d864aec3d3d8460956
--- lib/diff_output_edscript.c
+++ lib/diff_output_edscript.c
@@ -31,7 +31,7 @@ static int
 output_edscript_chunk(struct diff_output_info *outinfo,
     FILE *dest, const struct diff_input_info *info,
     const struct diff_result *result,
-    struct diff_chunk_context *cc, enum diff_chunk_type chunk_type)
+    struct diff_chunk_context *cc)
 {
 	off_t outoff = 0, *offp;
 	int left_start, left_len, right_start, right_len;
@@ -57,23 +57,38 @@ output_edscript_chunk(struct diff_output_info *outinfo
 	else
 		right_start = cc->right.start + 1;
 
-	if (chunk_type == CHUNK_MINUS) {
+	if (left_len == 0) {
+		/* addition */
+		if (right_len == 1) {
+			rc = fprintf(dest, "%da%d\n", left_start, right_start);
+		} else {
+			rc = fprintf(dest, "%da%d,%d\n", left_start,
+			    right_start, cc->right.end);
+		}
+	} else if (right_len == 0) {
+		/* deletion */
 		if (left_len == 1) {
-			rc = fprintf(dest, "%dd%d\n", left_start, right_start);
+			rc = fprintf(dest, "%dd%d\n", left_start,
+			    right_start);
 		} else {
 			rc = fprintf(dest, "%d,%dd%d\n", left_start,
 			    cc->left.end, right_start);
 		}
-	} else if (chunk_type == CHUNK_PLUS) {
-		if (right_len == 1) {
-			rc = fprintf(dest, "%da%d\n", left_start, right_start);
-		} else {
-			rc = fprintf(dest, "%da%d,%d\n", left_start,
+	} else {
+		/* change */
+		if (left_len == 1 && right_len == 1) {
+			rc = fprintf(dest, "%dc%d\n", left_start, right_start);
+		} else if (left_len == 1) {
+			rc = fprintf(dest, "%dc%d,%d\n", left_start,
 			    right_start, cc->right.end);
+		} else if (right_len == 1) {
+			rc = fprintf(dest, "%d,%dc%d\n", left_start,
+			    cc->left.end, right_start);
+		} else {
+			rc = fprintf(dest, "%d,%dc%d,%d\n", left_start,
+			    cc->left.end, right_start, cc->right.end);
 		}
-	} else
-		return EINVAL;
-
+	}
 	if (rc < 0)
 		return errno;
 	if (outinfo) {
@@ -93,6 +108,7 @@ diff_output_edscript(struct diff_output_info **output_
     const struct diff_result *result)
 {
 	struct diff_output_info *outinfo = NULL;
+	struct diff_chunk_context cc = {};
 	int i, rc;
 
 	if (!result)
@@ -110,20 +126,37 @@ diff_output_edscript(struct diff_output_info **output_
 	for (i = 0; i < result->chunks.len; i++) {
 		struct diff_chunk *chunk = &result->chunks.head[i];
 		enum diff_chunk_type t = diff_chunk_type(chunk);
-		struct diff_chunk_context cc = {};
+		struct diff_chunk_context next;
 
 		if (t != CHUNK_MINUS && t != CHUNK_PLUS)
 			continue;
 
-		diff_chunk_context_get(&cc, result, i, 0);
+		if (diff_range_empty(&cc.chunk)) {
+			/* Note down the start point, any number of subsequent
+			 * chunks may be joined up to this chunk by being
+			 * directly adjacent. */
+			diff_chunk_context_get(&cc, result, i, 0);
+			continue;
+		}
 
-		if (diff_range_empty(&cc.chunk))
+		/* There already is a previous chunk noted down for being
+		 * printed. Does it join up with this one? */
+		diff_chunk_context_get(&next, result, i, 0);
+
+		if (diff_chunk_contexts_touch(&cc, &next)) {
+			/* This next context touches or overlaps the previous
+			 * one, join. */
+			diff_chunk_contexts_merge(&cc, &next);
 			continue;
+		}
 
-		rc = output_edscript_chunk(outinfo, dest, info, result, &cc, t);
+		rc = output_edscript_chunk(outinfo, dest, info, result, &cc);
 		if (rc != DIFF_RC_OK)
 			return rc;
+		cc = next;
 	}
 
+	if (!diff_range_empty(&cc.chunk))
+		return output_edscript_chunk(outinfo, dest, info, result, &cc);
 	return DIFF_RC_OK;
 }
blob - d4dfc359e4f14a7a3d3593b4b5d252865abd5e57
blob + eaea44c1044a8f6ee273c5559c2945e50f2475c9
--- lib/diff_output_unidiff.c
+++ lib/diff_output_unidiff.c
@@ -94,18 +94,18 @@ diff_chunk_context_get(struct diff_chunk_context *cc, 
 	};
 }
 
-static bool
-chunk_contexts_touch(const struct diff_chunk_context *cc,
-		     const struct diff_chunk_context *other)
+bool
+diff_chunk_contexts_touch(const struct diff_chunk_context *cc,
+			  const struct diff_chunk_context *other)
 {
 	return diff_ranges_touch(&cc->chunk, &other->chunk)
 		|| diff_ranges_touch(&cc->left, &other->left)
 		|| diff_ranges_touch(&cc->right, &other->right);
 }
 
-static void
-chunk_contexts_merge(struct diff_chunk_context *cc,
-		     const struct diff_chunk_context *other)
+void
+diff_chunk_contexts_merge(struct diff_chunk_context *cc,
+			  const struct diff_chunk_context *other)
 {
 	diff_ranges_merge(&cc->chunk, &other->chunk);
 	diff_ranges_merge(&cc->left, &other->left);
@@ -380,10 +380,10 @@ diff_output_unidiff(struct diff_output_info **output_i
 		      next.left.start, next.left.end,
 		      next.right.start, next.right.end);
 
-		if (chunk_contexts_touch(&cc, &next)) {
+		if (diff_chunk_contexts_touch(&cc, &next)) {
 			/* This next context touches or overlaps the previous
 			 * one, join. */
-			chunk_contexts_merge(&cc, &next);
+			diff_chunk_contexts_merge(&cc, &next);
 			debug("new chunk to be printed touches previous chunk,"
 			      " now: left %d-%d right %d-%d\n",
 			      cc.left.start, cc.left.end,