Merge branch 'jc/diff-ws-error-highlight'
authorJunio C Hamano <gitster@pobox.com>
Thu, 11 Jun 2015 16:29:51 +0000 (09:29 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 11 Jun 2015 16:29:51 +0000 (09:29 -0700)
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

1  2 
Documentation/diff-options.txt
diff.c
diff.h
index 3ad6404dbcf2915721ac963085bbc0269c1d7312,85a654777413c22505cd7534af9a4fb82d542c59..d56ca90998a740dbe4cc5c242326023b4cc769b3
@@@ -23,9 -23,7 +23,9 @@@ ifndef::git-format-patch[
  -u::
  --patch::
        Generate patch (see section on generating patches).
 -      {git-diff? This is the default.}
 +ifdef::git-diff[]
 +      This is the default.
 +endif::git-diff[]
  endif::git-format-patch[]
  
  -s::
@@@ -43,19 -41,8 +43,19 @@@ endif::git-format-patch[
  
  ifndef::git-format-patch[]
  --raw::
 -      Generate the raw format.
 -      {git-diff-core? This is the default.}
 +ifndef::git-log[]
 +      Generate the diff in raw format.
 +ifdef::git-diff-core[]
 +      This is the default.
 +endif::git-diff-core[]
 +endif::git-log[]
 +ifdef::git-log[]
 +      For each commit, show a summary of changes using the raw diff
 +      format. See the "RAW OUTPUT FORMAT" section of
 +      linkgit:git-diff[1]. This is different from showing the log
 +      itself in raw format, which you can achieve with
 +      `--format=raw`.
 +endif::git-log[]
  endif::git-format-patch[]
  
  ifndef::git-format-patch[]
@@@ -291,6 -278,16 +291,16 @@@ ifndef::git-format-patch[
        initial indent of the line are considered whitespace errors.
        Exits with non-zero status if problems are found. Not compatible
        with --exit-code.
+ --ws-error-highlight=<kind>::
+       Highlight whitespace errors on lines specified by <kind>
+       in the color specified by `color.diff.whitespace`.  <kind>
+       is a comma separated list of `old`, `new`, `context`.  When
+       this option is not given, only whitespace errors in `new`
+       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`.
  endif::git-format-patch[]
  
  --full-index::
@@@ -445,8 -442,8 +455,8 @@@ endif::git-format-patch[
  -O<orderfile>::
        Output the patch in the order specified in the
        <orderfile>, which has one shell glob pattern per line.
 -      This overrides the `diff.orderfile` configuration variable
 -      (see linkgit:git-config[1]).  To cancel `diff.orderfile`,
 +      This overrides the `diff.orderFile` configuration variable
 +      (see linkgit:git-config[1]).  To cancel `diff.orderFile`,
        use `-O/dev/null`.
  
  ifndef::git-format-patch[]
diff --combined diff.c
index 7500c5509550ccd9a86d620e06c51a71d61f8b6c,34012b4b6340d6b53d465d66aeb64a5d479baecc..324be1d9592537afd9f51080d3e7a9ab9c5214cf
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -478,26 -478,59 +478,59 @@@ static int new_blank_line_at_eof(struc
        return ws_blank_line(line, len, ecbdata->ws_rule);
  }
  
- static void emit_add_line(const char *reset,
-                         struct emit_callback *ecbdata,
-                         const char *line, int len)
+ 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 *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
-       const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
+       const char *set = diff_get_color(ecbdata->color_diff, color);
+       const char *ws = NULL;
  
-       if (!*ws)
-               emit_line_0(ecbdata->opt, set, reset, '+', line, len);
-       else if (new_blank_line_at_eof(ecbdata, line, len))
+       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, '+', line, len);
+               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, '+', "", 0);
+               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)
+ {
+       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)
+ {
+       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)
+ {
+       emit_line_checked(reset, ecbdata, line, len,
+                         DIFF_PLAIN, WSEH_CONTEXT, ' ');
+ }
  static void emit_hunk_header(struct emit_callback *ecbdata,
                             const char *line, int len)
  {
@@@ -603,7 -636,6 +636,6 @@@ static void emit_rewrite_lines(struct e
  {
        const char *endp = NULL;
        static const char *nneof = " No newline at end of file\n";
-       const char *old = diff_get_color(ecb->color_diff, DIFF_FILE_OLD);
        const char *reset = diff_get_color(ecb->color_diff, DIFF_RESET);
  
        while (0 < size) {
                len = endp ? (endp - data + 1) : size;
                if (prefix != '+') {
                        ecb->lno_in_preimage++;
-                       emit_line_0(ecb->opt, old, reset, '-',
-                                   data, len);
+                       emit_del_line(reset, ecb, data, len);
                } else {
                        ecb->lno_in_postimage++;
                        emit_add_line(reset, ecb, data, len);
@@@ -1250,17 -1281,27 +1281,27 @@@ static void fn_out_consume(void *priv, 
                return;
        }
  
-       if (line[0] != '+') {
-               const char *color =
-                       diff_get_color(ecbdata->color_diff,
-                                      line[0] == '-' ? DIFF_FILE_OLD : DIFF_PLAIN);
-               ecbdata->lno_in_preimage++;
-               if (line[0] == ' ')
-                       ecbdata->lno_in_postimage++;
-               emit_line(ecbdata->opt, color, reset, line, len);
-       } else {
+       switch (line[0]) {
+       case '+':
                ecbdata->lno_in_postimage++;
                emit_add_line(reset, ecbdata, line + 1, len - 1);
+               break;
+       case '-':
+               ecbdata->lno_in_preimage++;
+               emit_del_line(reset, ecbdata, line + 1, len - 1);
+               break;
+       case ' ':
+               ecbdata->lno_in_postimage++;
+               ecbdata->lno_in_preimage++;
+               emit_context_line(reset, ecbdata, line + 1, len - 1);
+               break;
+       default:
+               /* incomplete line at the end */
+               ecbdata->lno_in_preimage++;
+               emit_line(ecbdata->opt,
+                         diff_get_color(ecbdata->color_diff, DIFF_PLAIN),
+                         reset, line, len);
+               break;
        }
  }
  
@@@ -2093,6 -2134,7 +2134,6 @@@ static unsigned char *deflate_it(char *
        unsigned char *deflated;
        git_zstream stream;
  
 -      memset(&stream, 0, sizeof(stream));
        git_deflate_init(&stream, zlib_compression_level);
        bound = git_deflate_bound(&stream, size);
        deflated = xmalloc(bound);
@@@ -3223,6 -3265,7 +3264,7 @@@ void diff_setup(struct diff_options *op
        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 */
@@@ -3609,6 -3652,40 +3651,40 @@@ static void enable_patch_output(int *fm
        *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];
                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"))
@@@ -4540,7 -4619,7 +4618,7 @@@ void diff_flush(struct diff_options *op
                        show_stats(&diffstat, options);
                if (output_format & DIFF_FORMAT_SHORTSTAT)
                        show_shortstats(&diffstat, options);
 -              if (output_format & DIFF_FORMAT_DIRSTAT)
 +              if (output_format & DIFF_FORMAT_DIRSTAT && dirstat_by_line)
                        show_dirstat_by_line(&diffstat, options);
                free_diffstat_info(&diffstat);
                separator++;
diff --combined diff.h
index f6fdf49e14b7c0e2997e7516275013555555e908,90c7cd61f51252e90923e19cd0097ade342552be..57762ee8b1fe83f9242b331eb3a90f01b8af9448
--- 1/diff.h
--- 2/diff.h
+++ b/diff.h
@@@ -6,7 -6,6 +6,7 @@@
  
  #include "tree-walk.h"
  #include "pathspec.h"
 +#include "object.h"
  
  struct rev_info;
  struct diff_options;
@@@ -138,6 -137,11 +138,11 @@@ struct diff_options 
        int dirstat_permille;
        int setup;
        int abbrev;
+ /* white-space error highlighting */
+ #define WSEH_NEW 1
+ #define WSEH_CONTEXT 2
+ #define WSEH_OLD 4
+       unsigned ws_error_highlight;
        const char *prefix;
        int prefix_length;
        const char *stat_sep;
@@@ -208,11 -212,11 +213,11 @@@ struct combine_diff_path 
        struct combine_diff_path *next;
        char *path;
        unsigned int mode;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        struct combine_diff_parent {
                char status;
                unsigned int mode;
 -              unsigned char sha1[20];
 +              struct object_id oid;
        } parent[FLEX_ARRAY];
  };
  #define combine_diff_path_size(n, l) \