Skip to content

Commit 709cd91

Browse files
committed
Merge branch 'jc/diff-ws-error-highlight'
Allow whitespace breakages in deleted and context lines to be also painted in the output. * jc/diff-ws-error-highlight: diff.c: --ws-error-highlight=<kind> option diff.c: add emit_del_line() and emit_context_line() t4015: separate common setup and per-test expectation t4015: modernise style
2 parents 7974889 + b8767f7 commit 709cd91

File tree

4 files changed

+385
-260
lines changed

4 files changed

+385
-260
lines changed

Documentation/diff-options.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,16 @@ ifndef::git-format-patch[]
291291
initial indent of the line are considered whitespace errors.
292292
Exits with non-zero status if problems are found. Not compatible
293293
with --exit-code.
294+
295+
--ws-error-highlight=<kind>::
296+
Highlight whitespace errors on lines specified by <kind>
297+
in the color specified by `color.diff.whitespace`. <kind>
298+
is a comma separated list of `old`, `new`, `context`. When
299+
this option is not given, only whitespace errors in `new`
300+
lines are highlighted. E.g. `--ws-error-highlight=new,old`
301+
highlights whitespace errors on both deleted and added lines.
302+
`all` can be used as a short-hand for `old,new,context`.
303+
294304
endif::git-format-patch[]
295305

296306
--full-index::

diff.c

Lines changed: 100 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -478,26 +478,59 @@ static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line
478478
return ws_blank_line(line, len, ecbdata->ws_rule);
479479
}
480480

481-
static void emit_add_line(const char *reset,
482-
struct emit_callback *ecbdata,
483-
const char *line, int len)
481+
static void emit_line_checked(const char *reset,
482+
struct emit_callback *ecbdata,
483+
const char *line, int len,
484+
enum color_diff color,
485+
unsigned ws_error_highlight,
486+
char sign)
484487
{
485-
const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
486-
const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
488+
const char *set = diff_get_color(ecbdata->color_diff, color);
489+
const char *ws = NULL;
487490

488-
if (!*ws)
489-
emit_line_0(ecbdata->opt, set, reset, '+', line, len);
490-
else if (new_blank_line_at_eof(ecbdata, line, len))
491+
if (ecbdata->opt->ws_error_highlight & ws_error_highlight) {
492+
ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
493+
if (!*ws)
494+
ws = NULL;
495+
}
496+
497+
if (!ws)
498+
emit_line_0(ecbdata->opt, set, reset, sign, line, len);
499+
else if (sign == '+' && new_blank_line_at_eof(ecbdata, line, len))
491500
/* Blank line at EOF - paint '+' as well */
492-
emit_line_0(ecbdata->opt, ws, reset, '+', line, len);
501+
emit_line_0(ecbdata->opt, ws, reset, sign, line, len);
493502
else {
494503
/* Emit just the prefix, then the rest. */
495-
emit_line_0(ecbdata->opt, set, reset, '+', "", 0);
504+
emit_line_0(ecbdata->opt, set, reset, sign, "", 0);
496505
ws_check_emit(line, len, ecbdata->ws_rule,
497506
ecbdata->opt->file, set, reset, ws);
498507
}
499508
}
500509

510+
static void emit_add_line(const char *reset,
511+
struct emit_callback *ecbdata,
512+
const char *line, int len)
513+
{
514+
emit_line_checked(reset, ecbdata, line, len,
515+
DIFF_FILE_NEW, WSEH_NEW, '+');
516+
}
517+
518+
static void emit_del_line(const char *reset,
519+
struct emit_callback *ecbdata,
520+
const char *line, int len)
521+
{
522+
emit_line_checked(reset, ecbdata, line, len,
523+
DIFF_FILE_OLD, WSEH_OLD, '-');
524+
}
525+
526+
static void emit_context_line(const char *reset,
527+
struct emit_callback *ecbdata,
528+
const char *line, int len)
529+
{
530+
emit_line_checked(reset, ecbdata, line, len,
531+
DIFF_PLAIN, WSEH_CONTEXT, ' ');
532+
}
533+
501534
static void emit_hunk_header(struct emit_callback *ecbdata,
502535
const char *line, int len)
503536
{
@@ -603,7 +636,6 @@ static void emit_rewrite_lines(struct emit_callback *ecb,
603636
{
604637
const char *endp = NULL;
605638
static const char *nneof = " No newline at end of file\n";
606-
const char *old = diff_get_color(ecb->color_diff, DIFF_FILE_OLD);
607639
const char *reset = diff_get_color(ecb->color_diff, DIFF_RESET);
608640

609641
while (0 < size) {
@@ -613,8 +645,7 @@ static void emit_rewrite_lines(struct emit_callback *ecb,
613645
len = endp ? (endp - data + 1) : size;
614646
if (prefix != '+') {
615647
ecb->lno_in_preimage++;
616-
emit_line_0(ecb->opt, old, reset, '-',
617-
data, len);
648+
emit_del_line(reset, ecb, data, len);
618649
} else {
619650
ecb->lno_in_postimage++;
620651
emit_add_line(reset, ecb, data, len);
@@ -1250,17 +1281,27 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
12501281
return;
12511282
}
12521283

1253-
if (line[0] != '+') {
1254-
const char *color =
1255-
diff_get_color(ecbdata->color_diff,
1256-
line[0] == '-' ? DIFF_FILE_OLD : DIFF_PLAIN);
1257-
ecbdata->lno_in_preimage++;
1258-
if (line[0] == ' ')
1259-
ecbdata->lno_in_postimage++;
1260-
emit_line(ecbdata->opt, color, reset, line, len);
1261-
} else {
1284+
switch (line[0]) {
1285+
case '+':
12621286
ecbdata->lno_in_postimage++;
12631287
emit_add_line(reset, ecbdata, line + 1, len - 1);
1288+
break;
1289+
case '-':
1290+
ecbdata->lno_in_preimage++;
1291+
emit_del_line(reset, ecbdata, line + 1, len - 1);
1292+
break;
1293+
case ' ':
1294+
ecbdata->lno_in_postimage++;
1295+
ecbdata->lno_in_preimage++;
1296+
emit_context_line(reset, ecbdata, line + 1, len - 1);
1297+
break;
1298+
default:
1299+
/* incomplete line at the end */
1300+
ecbdata->lno_in_preimage++;
1301+
emit_line(ecbdata->opt,
1302+
diff_get_color(ecbdata->color_diff, DIFF_PLAIN),
1303+
reset, line, len);
1304+
break;
12641305
}
12651306
}
12661307

@@ -3223,6 +3264,7 @@ void diff_setup(struct diff_options *options)
32233264
options->rename_limit = -1;
32243265
options->dirstat_permille = diff_dirstat_permille_default;
32253266
options->context = diff_context_default;
3267+
options->ws_error_highlight = WSEH_NEW;
32263268
DIFF_OPT_SET(options, RENAME_EMPTY);
32273269

32283270
/* pathchange left =NULL by default */
@@ -3609,6 +3651,40 @@ static void enable_patch_output(int *fmt) {
36093651
*fmt |= DIFF_FORMAT_PATCH;
36103652
}
36113653

3654+
static int parse_one_token(const char **arg, const char *token)
3655+
{
3656+
return skip_prefix(*arg, token, arg) && (!**arg || **arg == ',');
3657+
}
3658+
3659+
static int parse_ws_error_highlight(struct diff_options *opt, const char *arg)
3660+
{
3661+
const char *orig_arg = arg;
3662+
unsigned val = 0;
3663+
while (*arg) {
3664+
if (parse_one_token(&arg, "none"))
3665+
val = 0;
3666+
else if (parse_one_token(&arg, "default"))
3667+
val = WSEH_NEW;
3668+
else if (parse_one_token(&arg, "all"))
3669+
val = WSEH_NEW | WSEH_OLD | WSEH_CONTEXT;
3670+
else if (parse_one_token(&arg, "new"))
3671+
val |= WSEH_NEW;
3672+
else if (parse_one_token(&arg, "old"))
3673+
val |= WSEH_OLD;
3674+
else if (parse_one_token(&arg, "context"))
3675+
val |= WSEH_CONTEXT;
3676+
else {
3677+
error("unknown value after ws-error-highlight=%.*s",
3678+
(int)(arg - orig_arg), orig_arg);
3679+
return 0;
3680+
}
3681+
if (*arg)
3682+
arg++;
3683+
}
3684+
opt->ws_error_highlight = val;
3685+
return 1;
3686+
}
3687+
36123688
int diff_opt_parse(struct diff_options *options, const char **av, int ac)
36133689
{
36143690
const char *arg = av[0];
@@ -3806,6 +3882,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
38063882
DIFF_OPT_SET(options, SUBMODULE_LOG);
38073883
else if (skip_prefix(arg, "--submodule=", &arg))
38083884
return parse_submodule_opt(options, arg);
3885+
else if (skip_prefix(arg, "--ws-error-highlight=", &arg))
3886+
return parse_ws_error_highlight(options, arg);
38093887

38103888
/* misc options */
38113889
else if (!strcmp(arg, "-z"))

diff.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ struct diff_options {
138138
int dirstat_permille;
139139
int setup;
140140
int abbrev;
141+
/* white-space error highlighting */
142+
#define WSEH_NEW 1
143+
#define WSEH_CONTEXT 2
144+
#define WSEH_OLD 4
145+
unsigned ws_error_highlight;
141146
const char *prefix;
142147
int prefix_length;
143148
const char *stat_sep;

0 commit comments

Comments
 (0)