diff.c: --ws-error-highlight=<kind> option
Traditionally, we only cared about whitespace breakages introduced
in new lines. Some people want to paint whitespace breakages on old
lines, too. When they see a whitespace breakage on a new line, they
can spot the same kind of whitespace breakage on the corresponding
old line and want to say "Ah, those breakages are there but they
were inherited from the original, so let's not touch them for now."
Introduce `--ws-error-highlight=<kind>` option, that lets them pass
a comma separated list of `old`, `new`, and `context` to specify
what lines to highlight whitespace errors on.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff --git a/diff.c b/diff.c
index c575c45..34012b4 100644
--- a/diff.c
+++ b/diff.c
@@ -478,42 +478,57 @@
return ws_blank_line(line, len, ecbdata->ws_rule);
}
+static void emit_line_checked(const char *reset,
+ struct emit_callback *ecbdata,
+ const char *line, int len,
+ enum color_diff color,
+ unsigned ws_error_highlight,
+ char sign)
+{
+ const char *set = diff_get_color(ecbdata->color_diff, color);
+ const char *ws = NULL;
+
+ if (ecbdata->opt->ws_error_highlight & ws_error_highlight) {
+ ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
+ if (!*ws)
+ ws = NULL;
+ }
+
+ if (!ws)
+ emit_line_0(ecbdata->opt, set, reset, sign, line, len);
+ else if (sign == '+' && new_blank_line_at_eof(ecbdata, line, len))
+ /* Blank line at EOF - paint '+' as well */
+ emit_line_0(ecbdata->opt, ws, reset, sign, line, len);
+ else {
+ /* Emit just the prefix, then the rest. */
+ emit_line_0(ecbdata->opt, set, reset, sign, "", 0);
+ ws_check_emit(line, len, ecbdata->ws_rule,
+ ecbdata->opt->file, set, reset, ws);
+ }
+}
+
static void emit_add_line(const char *reset,
struct emit_callback *ecbdata,
const char *line, int len)
{
- const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
- const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
-
- if (!*ws)
- emit_line_0(ecbdata->opt, set, reset, '+', line, len);
- else if (new_blank_line_at_eof(ecbdata, line, len))
- /* Blank line at EOF - paint '+' as well */
- emit_line_0(ecbdata->opt, ws, reset, '+', line, len);
- else {
- /* Emit just the prefix, then the rest. */
- emit_line_0(ecbdata->opt, set, reset, '+', "", 0);
- ws_check_emit(line, len, ecbdata->ws_rule,
- ecbdata->opt->file, set, reset, ws);
- }
+ emit_line_checked(reset, ecbdata, line, len,
+ DIFF_FILE_NEW, WSEH_NEW, '+');
}
static void emit_del_line(const char *reset,
struct emit_callback *ecbdata,
const char *line, int len)
{
- const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_OLD);
-
- emit_line_0(ecbdata->opt, set, reset, '-', line, len);
+ emit_line_checked(reset, ecbdata, line, len,
+ DIFF_FILE_OLD, WSEH_OLD, '-');
}
static void emit_context_line(const char *reset,
struct emit_callback *ecbdata,
const char *line, int len)
{
- const char *set = diff_get_color(ecbdata->color_diff, DIFF_PLAIN);
-
- emit_line_0(ecbdata->opt, set, reset, ' ', line, len);
+ emit_line_checked(reset, ecbdata, line, len,
+ DIFF_PLAIN, WSEH_CONTEXT, ' ');
}
static void emit_hunk_header(struct emit_callback *ecbdata,
@@ -3250,6 +3265,7 @@
options->rename_limit = -1;
options->dirstat_permille = diff_dirstat_permille_default;
options->context = diff_context_default;
+ options->ws_error_highlight = WSEH_NEW;
DIFF_OPT_SET(options, RENAME_EMPTY);
/* pathchange left =NULL by default */
@@ -3636,6 +3652,40 @@
*fmt |= DIFF_FORMAT_PATCH;
}
+static int parse_one_token(const char **arg, const char *token)
+{
+ return skip_prefix(*arg, token, arg) && (!**arg || **arg == ',');
+}
+
+static int parse_ws_error_highlight(struct diff_options *opt, const char *arg)
+{
+ const char *orig_arg = arg;
+ unsigned val = 0;
+ while (*arg) {
+ if (parse_one_token(&arg, "none"))
+ val = 0;
+ else if (parse_one_token(&arg, "default"))
+ val = WSEH_NEW;
+ else if (parse_one_token(&arg, "all"))
+ val = WSEH_NEW | WSEH_OLD | WSEH_CONTEXT;
+ else if (parse_one_token(&arg, "new"))
+ val |= WSEH_NEW;
+ else if (parse_one_token(&arg, "old"))
+ val |= WSEH_OLD;
+ else if (parse_one_token(&arg, "context"))
+ val |= WSEH_CONTEXT;
+ else {
+ error("unknown value after ws-error-highlight=%.*s",
+ (int)(arg - orig_arg), orig_arg);
+ return 0;
+ }
+ if (*arg)
+ arg++;
+ }
+ opt->ws_error_highlight = val;
+ return 1;
+}
+
int diff_opt_parse(struct diff_options *options, const char **av, int ac)
{
const char *arg = av[0];
@@ -3833,6 +3883,8 @@
DIFF_OPT_SET(options, SUBMODULE_LOG);
else if (skip_prefix(arg, "--submodule=", &arg))
return parse_submodule_opt(options, arg);
+ else if (skip_prefix(arg, "--ws-error-highlight=", &arg))
+ return parse_ws_error_highlight(options, arg);
/* misc options */
else if (!strcmp(arg, "-z"))