diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt index b27a38f896..58f4bd6afa 100644 --- a/Documentation/diff-config.txt +++ b/Documentation/diff-config.txt @@ -193,3 +193,9 @@ diff.algorithm:: low-occurrence common elements". -- + + +diff.wsErrorHighlight:: + A comma separated list of `old`, `new`, `context`, that + specifies how whitespace errors on lines are highlighted + with `color.diff.whitespace`. Can be overridden by the + command line option `--ws-error-highlight=` diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 2d77a19626..29630c2389 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -308,6 +308,8 @@ ifndef::git-format-patch[] lines are highlighted. E.g. `--ws-error-highlight=new,old` highlights whitespace errors on both deleted and added lines. `all` can be used as a short-hand for `old,new,context`. + The `diff.wsErrorHighlight` configuration variable can be + used to specify the default behaviour. endif::git-format-patch[] diff --git a/diff.c b/diff.c index f5d6d7e4f6..569f615d3b 100644 --- a/diff.c +++ b/diff.c @@ -43,6 +43,7 @@ static int diff_stat_graph_width; static int diff_dirstat_permille_default = 30; static struct diff_options default_diff_options; static long diff_algorithm; +static unsigned ws_error_highlight_default = WSEH_NEW; static char diff_colors[][COLOR_MAXLEN] = { GIT_COLOR_RESET, @@ -172,6 +173,43 @@ long parse_algorithm_value(const char *value) return -1; } +static int parse_one_token(const char **arg, const char *token) +{ + const char *rest; + if (skip_prefix(*arg, token, &rest) && (!*rest || *rest == ',')) { + *arg = rest; + return 1; + } + return 0; +} + +static int parse_ws_error_highlight(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 { + return -1 - (int)(arg - orig_arg); + } + if (*arg) + arg++; + } + return val; +} + /* * These are to give UI layer defaults. * The core-level commands such as git-diff-files should @@ -256,6 +294,15 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) if (git_diff_heuristic_config(var, value, cb) < 0) return -1; + + if (!strcmp(var, "diff.wserrorhighlight")) { + int val = parse_ws_error_highlight(value); + if (val < 0) + return -1; + ws_error_highlight_default = val; + return 0; + } + if (git_color_config(var, value, cb) < 0) return -1; @@ -3307,7 +3354,7 @@ void diff_setup(struct diff_options *options) options->rename_limit = -1; options->dirstat_permille = diff_dirstat_permille_default; options->context = diff_context_default; - options->ws_error_highlight = WSEH_NEW; + options->ws_error_highlight = ws_error_highlight_default; DIFF_OPT_SET(options, RENAME_EMPTY); /* pathchange left =NULL by default */ @@ -3698,40 +3745,14 @@ static void enable_patch_output(int *fmt) { *fmt |= DIFF_FORMAT_PATCH; } -static int parse_one_token(const char **arg, const char *token) +static int parse_ws_error_highlight_opt(struct diff_options *opt, const char *arg) { - const char *rest; - if (skip_prefix(*arg, token, &rest) && (!*rest || *rest == ',')) { - *arg = rest; - return 1; - } - return 0; -} + int val = parse_ws_error_highlight(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++; + if (val < 0) { + error("unknown value after ws-error-highlight=%.*s", + -1 - val, arg); + return 0; } opt->ws_error_highlight = val; return 1; @@ -3950,7 +3971,7 @@ int diff_opt_parse(struct diff_options *options, 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); + return parse_ws_error_highlight_opt(options, arg); /* misc options */ else if (!strcmp(arg, "-z")) diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 2434157aa7..289806d0c7 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -869,7 +869,8 @@ test_expect_success 'diff that introduces and removes ws breakages' ' test_cmp expected current ' -test_expect_success 'the same with --ws-error-highlight' ' +test_expect_success 'ws-error-highlight test setup' ' + git reset --hard && { echo "0. blank-at-eol " && @@ -882,10 +883,7 @@ test_expect_success 'the same with --ws-error-highlight' ' echo "2. and a new line " } >x && - git -c color.diff=always diff --ws-error-highlight=default,old | - test_decode_color >current && - - cat >expected <<-\EOF && + cat >expect.default-old <<-\EOF && diff --git a/x b/x index d0233a2..700886e 100644 --- a/x @@ -897,12 +895,7 @@ test_expect_success 'the same with --ws-error-highlight' ' +2. and a new line EOF - test_cmp expected current && - - git -c color.diff=always diff --ws-error-highlight=all | - test_decode_color >current && - - cat >expected <<-\EOF && + cat >expect.all <<-\EOF && diff --git a/x b/x index d0233a2..700886e 100644 --- a/x @@ -914,12 +907,7 @@ test_expect_success 'the same with --ws-error-highlight' ' +2. and a new line EOF - test_cmp expected current && - - git -c color.diff=always diff --ws-error-highlight=none | - test_decode_color >current && - - cat >expected <<-\EOF && + cat >expect.none <<-\EOF diff --git a/x b/x index d0233a2..700886e 100644 --- a/x @@ -931,7 +919,57 @@ test_expect_success 'the same with --ws-error-highlight' ' +2. and a new line EOF - test_cmp expected current +' + +test_expect_success 'test --ws-error-highlight option' ' + + git -c color.diff=always diff --ws-error-highlight=default,old | + test_decode_color >current && + test_cmp expect.default-old current && + + git -c color.diff=always diff --ws-error-highlight=all | + test_decode_color >current && + test_cmp expect.all current && + + git -c color.diff=always diff --ws-error-highlight=none | + test_decode_color >current && + test_cmp expect.none current + +' + +test_expect_success 'test diff.wsErrorHighlight config' ' + + git -c color.diff=always -c diff.wsErrorHighlight=default,old diff | + test_decode_color >current && + test_cmp expect.default-old current && + + git -c color.diff=always -c diff.wsErrorHighlight=all diff | + test_decode_color >current && + test_cmp expect.all current && + + git -c color.diff=always -c diff.wsErrorHighlight=none diff | + test_decode_color >current && + test_cmp expect.none current + +' + +test_expect_success 'option overrides diff.wsErrorHighlight' ' + + git -c color.diff=always -c diff.wsErrorHighlight=none \ + diff --ws-error-highlight=default,old | + test_decode_color >current && + test_cmp expect.default-old current && + + git -c color.diff=always -c diff.wsErrorHighlight=default \ + diff --ws-error-highlight=all | + test_decode_color >current && + test_cmp expect.all current && + + git -c color.diff=always -c diff.wsErrorHighlight=all \ + diff --ws-error-highlight=none | + test_decode_color >current && + test_cmp expect.none current + ' test_done