Skip to content

Commit f7c3b4e

Browse files
dschogitster
authored andcommitted
diff: add an internal option to dual-color diffs of diffs
When diffing diffs, it can be quite daunting to figure out what the heck is going on, as there are nested +/- signs. Let's make this easier by adding a flag in diff_options that allows color-coding the outer diff sign with inverted colors, so that the preimage and postimage is colored like the diff it is. Of course, this really only makes sense when the preimage and postimage *are* diffs. So let's not expose this flag via a command-line option for now. This is a feature that was invented by git-tbdiff, and it will be used by `git range-diff` in the next commit, by offering it via a new option: `--dual-color`. Signed-off-by: Johannes Schindelin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 7188260 commit f7c3b4e

File tree

2 files changed

+69
-15
lines changed

2 files changed

+69
-15
lines changed

diff.c

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -609,14 +609,18 @@ static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2,
609609
ecbdata->blank_at_eof_in_postimage = (at - l2) + 1;
610610
}
611611

612-
static void emit_line_0(struct diff_options *o, const char *set, const char *reset,
612+
static void emit_line_0(struct diff_options *o,
613+
const char *set, unsigned reverse, const char *reset,
613614
int first, const char *line, int len)
614615
{
615616
int has_trailing_newline, has_trailing_carriage_return;
616617
int nofirst;
617618
FILE *file = o->file;
618619

619-
fputs(diff_line_prefix(o), file);
620+
if (first)
621+
fputs(diff_line_prefix(o), file);
622+
else if (!len)
623+
return;
620624

621625
if (len == 0) {
622626
has_trailing_newline = (first == '\n');
@@ -634,8 +638,10 @@ static void emit_line_0(struct diff_options *o, const char *set, const char *res
634638
}
635639

636640
if (len || !nofirst) {
641+
if (reverse && want_color(o->use_color))
642+
fputs(GIT_COLOR_REVERSE, file);
637643
fputs(set, file);
638-
if (!nofirst)
644+
if (first && !nofirst)
639645
fputc(first, file);
640646
fwrite(line, len, 1, file);
641647
fputs(reset, file);
@@ -649,7 +655,7 @@ static void emit_line_0(struct diff_options *o, const char *set, const char *res
649655
static void emit_line(struct diff_options *o, const char *set, const char *reset,
650656
const char *line, int len)
651657
{
652-
emit_line_0(o, set, reset, line[0], line+1, len-1);
658+
emit_line_0(o, set, 0, reset, line[0], line+1, len-1);
653659
}
654660

655661
enum diff_symbol {
@@ -1168,7 +1174,8 @@ static void dim_moved_lines(struct diff_options *o)
11681174

11691175
static void emit_line_ws_markup(struct diff_options *o,
11701176
const char *set, const char *reset,
1171-
const char *line, int len, char sign,
1177+
const char *line, int len,
1178+
const char *set_sign, char sign,
11721179
unsigned ws_rule, int blank_at_eof)
11731180
{
11741181
const char *ws = NULL;
@@ -1179,14 +1186,20 @@ static void emit_line_ws_markup(struct diff_options *o,
11791186
ws = NULL;
11801187
}
11811188

1182-
if (!ws)
1183-
emit_line_0(o, set, reset, sign, line, len);
1184-
else if (blank_at_eof)
1189+
if (!ws && !set_sign)
1190+
emit_line_0(o, set, 0, reset, sign, line, len);
1191+
else if (!ws) {
1192+
/* Emit just the prefix, then the rest. */
1193+
emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset,
1194+
sign, "", 0);
1195+
emit_line_0(o, set, 0, reset, 0, line, len);
1196+
} else if (blank_at_eof)
11851197
/* Blank line at EOF - paint '+' as well */
1186-
emit_line_0(o, ws, reset, sign, line, len);
1198+
emit_line_0(o, ws, 0, reset, sign, line, len);
11871199
else {
11881200
/* Emit just the prefix, then the rest. */
1189-
emit_line_0(o, set, reset, sign, "", 0);
1201+
emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset,
1202+
sign, "", 0);
11901203
ws_check_emit(line, len, ws_rule,
11911204
o->file, set, reset, ws);
11921205
}
@@ -1196,7 +1209,7 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
11961209
struct emitted_diff_symbol *eds)
11971210
{
11981211
static const char *nneof = " No newline at end of file\n";
1199-
const char *context, *reset, *set, *meta, *fraginfo;
1212+
const char *context, *reset, *set, *set_sign, *meta, *fraginfo;
12001213
struct strbuf sb = STRBUF_INIT;
12011214

12021215
enum diff_symbol s = eds->s;
@@ -1209,7 +1222,7 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
12091222
context = diff_get_color_opt(o, DIFF_CONTEXT);
12101223
reset = diff_get_color_opt(o, DIFF_RESET);
12111224
putc('\n', o->file);
1212-
emit_line_0(o, context, reset, '\\',
1225+
emit_line_0(o, context, 0, reset, '\\',
12131226
nneof, strlen(nneof));
12141227
break;
12151228
case DIFF_SYMBOL_SUBMODULE_HEADER:
@@ -1236,7 +1249,18 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
12361249
case DIFF_SYMBOL_CONTEXT:
12371250
set = diff_get_color_opt(o, DIFF_CONTEXT);
12381251
reset = diff_get_color_opt(o, DIFF_RESET);
1239-
emit_line_ws_markup(o, set, reset, line, len, ' ',
1252+
set_sign = NULL;
1253+
if (o->flags.dual_color_diffed_diffs) {
1254+
char c = !len ? 0 : line[0];
1255+
1256+
if (c == '+')
1257+
set = diff_get_color_opt(o, DIFF_FILE_NEW);
1258+
else if (c == '@')
1259+
set = diff_get_color_opt(o, DIFF_FRAGINFO);
1260+
else if (c == '-')
1261+
set = diff_get_color_opt(o, DIFF_FILE_OLD);
1262+
}
1263+
emit_line_ws_markup(o, set, reset, line, len, set_sign, ' ',
12401264
flags & (DIFF_SYMBOL_CONTENT_WS_MASK), 0);
12411265
break;
12421266
case DIFF_SYMBOL_PLUS:
@@ -1263,7 +1287,20 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
12631287
set = diff_get_color_opt(o, DIFF_FILE_NEW);
12641288
}
12651289
reset = diff_get_color_opt(o, DIFF_RESET);
1266-
emit_line_ws_markup(o, set, reset, line, len, '+',
1290+
if (!o->flags.dual_color_diffed_diffs)
1291+
set_sign = NULL;
1292+
else {
1293+
char c = !len ? 0 : line[0];
1294+
1295+
set_sign = set;
1296+
if (c == '-')
1297+
set = diff_get_color_opt(o, DIFF_FILE_OLD);
1298+
else if (c == '@')
1299+
set = diff_get_color_opt(o, DIFF_FRAGINFO);
1300+
else if (c != '+')
1301+
set = diff_get_color_opt(o, DIFF_CONTEXT);
1302+
}
1303+
emit_line_ws_markup(o, set, reset, line, len, set_sign, '+',
12671304
flags & DIFF_SYMBOL_CONTENT_WS_MASK,
12681305
flags & DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF);
12691306
break;
@@ -1291,7 +1328,20 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
12911328
set = diff_get_color_opt(o, DIFF_FILE_OLD);
12921329
}
12931330
reset = diff_get_color_opt(o, DIFF_RESET);
1294-
emit_line_ws_markup(o, set, reset, line, len, '-',
1331+
if (!o->flags.dual_color_diffed_diffs)
1332+
set_sign = NULL;
1333+
else {
1334+
char c = !len ? 0 : line[0];
1335+
1336+
set_sign = set;
1337+
if (c == '+')
1338+
set = diff_get_color_opt(o, DIFF_FILE_NEW);
1339+
else if (c == '@')
1340+
set = diff_get_color_opt(o, DIFF_FRAGINFO);
1341+
else if (c != '-')
1342+
set = diff_get_color_opt(o, DIFF_CONTEXT);
1343+
}
1344+
emit_line_ws_markup(o, set, reset, line, len, set_sign, '-',
12951345
flags & DIFF_SYMBOL_CONTENT_WS_MASK, 0);
12961346
break;
12971347
case DIFF_SYMBOL_WORDS_PORCELAIN:
@@ -1482,6 +1532,7 @@ static void emit_hunk_header(struct emit_callback *ecbdata,
14821532
const char *frag = diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO);
14831533
const char *func = diff_get_color(ecbdata->color_diff, DIFF_FUNCINFO);
14841534
const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
1535+
const char *reverse = ecbdata->color_diff ? GIT_COLOR_REVERSE : "";
14851536
static const char atat[2] = { '@', '@' };
14861537
const char *cp, *ep;
14871538
struct strbuf msgbuf = STRBUF_INIT;
@@ -1502,6 +1553,8 @@ static void emit_hunk_header(struct emit_callback *ecbdata,
15021553
ep += 2; /* skip over @@ */
15031554

15041555
/* The hunk header in fraginfo color */
1556+
if (ecbdata->opt->flags.dual_color_diffed_diffs)
1557+
strbuf_addstr(&msgbuf, reverse);
15051558
strbuf_addstr(&msgbuf, frag);
15061559
strbuf_add(&msgbuf, line, ep - line);
15071560
strbuf_addstr(&msgbuf, reset);

diff.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ struct diff_flags {
9595
unsigned default_follow_renames:1;
9696
unsigned stat_with_summary:1;
9797
unsigned suppress_diff_headers:1;
98+
unsigned dual_color_diffed_diffs:1;
9899
};
99100

100101
static inline void diff_flags_or(struct diff_flags *a,

0 commit comments

Comments
 (0)