Subject: [PATCH 2/2] WIP diff.c: clarify emit_line_0

From: Stefan Beller <[email-masked]>
Date: Tue, 10 Jul 2018 10:45:52 -0700

This breaks t4034 (word diffs), but all other tests pass.

emit_line_0 grew complicated again, so here is an attempt to make it
a bit simpler. emit_line_0 is called for all lines that are added,
removed or context lines, and it follows the format:

 <sign color> <sign> <main color> <content of length 'len'> <reset> <CR> <LF>

with each of the components optional. However a few rules apply:
* The CR/LF is passed to the function as part of line/len, so we have
  to figure out if we need to separate them
* As the sign color is a rather recent addition, we do not optimize it
  yet
* the main color insertion is new, as the color used to be inserted before
  the sign
* another follow up cleanup (that also touches the tests) could be
  a stricter check to consolidate with ws_check_emit (and not emit the
  color/reset twice)

Signed-off-by: Stefan Beller <[email-masked]>
---
 diff.c | 78 ++++++++++++++++++++++++++++------------------------------
 1 file changed, 37 insertions(+), 41 deletions(-)

diff --git a/diff.c b/diff.c
index 028d7d9a59c..7b649f57c27 100644
--- a/diff.c
+++ b/diff.c
@@ -563,44 +563,44 @@ static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2,
 }
 
 static void emit_line_0(struct diff_options *o,
-			const char *set, unsigned reverse, const char *reset,
-			int first, const char *line, int len)
+			const char *maincolor, const char *signcolor,
+			const char *reset, const char *sign,
+			const char *line, int len)
 {
 	int has_trailing_newline, has_trailing_carriage_return;
-	int nofirst;
 	FILE *file = o->file;
 
-	if (first)
-		fputs(diff_line_prefix(o), file);
-	else if (!len)
-		return;
+	fputs(diff_line_prefix(o), file);
 
-	if (len == 0) {
-		has_trailing_newline = (first == '\n');
-		has_trailing_carriage_return = (!has_trailing_newline &&
-						(first == '\r'));
-		nofirst = has_trailing_newline || has_trailing_carriage_return;
-	} else {
-		has_trailing_newline = (len > 0 && line[len-1] == '\n');
-		if (has_trailing_newline)
-			len--;
-		has_trailing_carriage_return = (len > 0 && line[len-1] == '\r');
-		if (has_trailing_carriage_return)
-			len--;
-		nofirst = 0;
-	}
+	has_trailing_newline = (len > 0 && line[len-1] == '\n');
+	if (has_trailing_newline)
+		len--;
+	has_trailing_carriage_return = (len > 0 && line[len-1] == '\r');
+	if (has_trailing_carriage_return)
+		len--;
 
-	if (len || !nofirst) {
-		if (reverse && want_color(o->use_color))
-			fputs(GIT_COLOR_REVERSE, file);
-		fputs(set, file);
-		if (first && !nofirst)
-			fputc(first, file);
+	if (signcolor)
+		fputs(signcolor, file);
+	else if (maincolor)
+		fputs(maincolor, file);
+
+
+	if (sign)
+		fputs(sign, file);
+
+	/* only put main color here if it we did not color the sign the same way */
+	if (signcolor && maincolor && signcolor != maincolor)
+		fputs(maincolor, file);
+
+	if (len)
 		fwrite(line, len, 1, file);
+
+	if ((signcolor || maincolor) && reset)
 		fputs(reset, file);
-	}
+
 	if (has_trailing_carriage_return)
 		fputc('\r', file);
+
 	if (has_trailing_newline)
 		fputc('\n', file);
 }
@@ -608,7 +608,7 @@ static void emit_line_0(struct diff_options *o,
 static void emit_line(struct diff_options *o, const char *set, const char *reset,
 		      const char *line, int len)
 {
-	emit_line_0(o, set, 0, reset, line[0], line+1, len-1);
+	emit_line_0(o, set, NULL, reset, NULL, line, len);
 }
 
 enum diff_symbol {
@@ -980,20 +980,16 @@ static void emit_line_ws_markup(struct diff_options *o,
 			ws = NULL;
 	}
 
-	if (!ws && !set_sign)
-		emit_line_0(o, set, 0, reset, sign[0], line, len);
-	else if (!ws) {
-		/* Emit just the prefix, then the rest. */
-		emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset,
-			    sign[0], "", 0);
-		emit_line_0(o, set, 0, reset, 0, line, len);
-	} else if (blank_at_eof)
+	if (!ws)
+		emit_line_0(o, set, set_sign, reset,
+			    sign, line, len);
+	else if (blank_at_eof)
 		/* Blank line at EOF - paint '+' as well */
-		emit_line_0(o, ws, 0, reset, sign[0], line, len);
+		emit_line_0(o, ws, set_sign, reset, sign, line, len);
 	else {
 		/* Emit just the prefix, then the rest. */
-		emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset,
-			    sign[0], "", 0);
+		emit_line_0(o, set, set_sign, reset,
+			    sign, "", 0);
 		ws_check_emit(line, len, ws_rule,
 			      o->file, set, reset, ws);
 	}
@@ -1016,7 +1012,7 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
 		context = diff_get_color_opt(o, DIFF_CONTEXT);
 		reset = diff_get_color_opt(o, DIFF_RESET);
 		putc('\n', o->file);
-		emit_line_0(o, context, 0, reset, '\\',
+		emit_line_0(o, context, 0, reset, "\\",
 			    nneof, strlen(nneof));
 		break;
 	case DIFF_SYMBOL_SUBMODULE_HEADER:
-- 
2.18.0.203.gfac676dfb9-goog