Add a new flags field to emit_diff_symbol, that will be used by
context lines for:
* white space rules that are applicable (The first 12 bits)
* how the rules are evaluated (actually this double encodes the sign
  of the line, but the code is easier to keep this way, bits 13,14,15)
* if the line a blank line at EOF (bit 16)


Signed-off-by: Stefan Beller <sbel...@google.com>
---
 cache.h |   1 +
 diff.c  | 112 ++++++++++++++++++++++++++++++++++++++++------------------------
 diff.h  |   6 ++--
 3 files changed, 75 insertions(+), 44 deletions(-)

diff --git a/cache.h b/cache.h
index e1f0e182ad..4d63c44f07 100644
--- a/cache.h
+++ b/cache.h
@@ -2168,6 +2168,7 @@ void shift_tree_by(const struct object_id *, const struct 
object_id *, struct ob
 #define WS_TRAILING_SPACE      (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
 #define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB|8)
 #define WS_TAB_WIDTH_MASK        077
+#define WS_RULE_MASK           07777
 extern unsigned whitespace_rule_cfg;
 extern unsigned whitespace_rule(const char *);
 extern unsigned parse_whitespace_rule(const char *);
diff --git a/diff.c b/diff.c
index 28be3226c2..42c9f48dc2 100644
--- a/diff.c
+++ b/diff.c
@@ -564,13 +564,50 @@ enum diff_symbol {
        DIFF_SYMBOL_CONTEXT_MARKER,
        DIFF_SYMBOL_CONTEXT_FRAGINFO,
        DIFF_SYMBOL_NO_LF_EOF,
+       DIFF_SYMBOL_CONTEXT,
+       DIFF_SYMBOL_PLUS,
+       DIFF_SYMBOL_MINUS,
 };
+/*
+ * Flags for content lines:
+ * 0..12 are whitespace rules
+ * 13-15 are WSEH_NEW | WSEH_OLD | WSEH_CONTEXT
+ * 16 is marking if the line is blank at EOF
+ */
+#define DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF (1<<16)
+#define DIFF_SYMBOL_CONTENT_WS_MASK (WSEH_NEW | WSEH_OLD | WSEH_CONTEXT | 
WS_RULE_MASK)
+
+static void emit_line_ws_markup(struct diff_options *o,
+                               const char *set, const char *reset,
+                               const char *line, int len, char sign,
+                               unsigned ws_rule, int blank_at_eof)
+{
+       const char *ws = NULL;
+
+       if (o->ws_error_highlight & ws_rule) {
+               ws = diff_get_color_opt(o, DIFF_WHITESPACE);
+               if (!*ws)
+                       ws = NULL;
+       }
+
+       if (!ws)
+               emit_line_0(o, set, reset, sign, line, len);
+       else if (blank_at_eof)
+               /* Blank line at EOF - paint '+' as well */
+               emit_line_0(o, ws, reset, sign, line, len);
+       else {
+               /* Emit just the prefix, then the rest. */
+               emit_line_0(o, set, reset, sign, "", 0);
+               ws_check_emit(line, len, ws_rule,
+                             o->file, set, reset, ws);
+       }
+}
 
 static void emit_diff_symbol(struct diff_options *o, enum diff_symbol s,
-                            const char *line, int len)
+                            const char *line, int len, unsigned flags)
 {
        static const char *nneof = " No newline at end of file\n";
-       const char *context, *reset;
+       const char *context, *reset, *set;
        switch (s) {
        case DIFF_SYMBOL_SEPARATOR:
                fprintf(o->file, "%s%c",
@@ -592,6 +629,25 @@ static void emit_diff_symbol(struct diff_options *o, enum 
diff_symbol s,
                emit_line_0(o, context, reset, '\\',
                            nneof, strlen(nneof));
                break;
+       case DIFF_SYMBOL_CONTEXT:
+               set = diff_get_color_opt(o, DIFF_CONTEXT);
+               reset = diff_get_color_opt(o, DIFF_RESET);
+               emit_line_ws_markup(o, set, reset, line, len, ' ',
+                                   flags & (DIFF_SYMBOL_CONTENT_WS_MASK), 0);
+               break;
+       case DIFF_SYMBOL_PLUS:
+               set = diff_get_color_opt(o, DIFF_FILE_NEW);
+               reset = diff_get_color_opt(o, DIFF_RESET);
+               emit_line_ws_markup(o, set, reset, line, len, '+',
+                                   flags & DIFF_SYMBOL_CONTENT_WS_MASK,
+                                   flags & DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF);
+               break;
+       case DIFF_SYMBOL_MINUS:
+               set = diff_get_color_opt(o, DIFF_FILE_OLD);
+               reset = diff_get_color_opt(o, DIFF_RESET);
+               emit_line_ws_markup(o, set, reset, line, len, '-',
+                                   flags & DIFF_SYMBOL_CONTENT_WS_MASK, 0);
+               break;
        default:
                die("BUG: unknown diff symbol");
        }
@@ -608,57 +664,31 @@ static int new_blank_line_at_eof(struct emit_callback 
*ecbdata, const char *line
        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)
 {
-       emit_line_checked(reset, ecbdata, line, len,
-                         DIFF_FILE_NEW, WSEH_NEW, '+');
+       unsigned flags = WSEH_NEW | ecbdata->ws_rule;
+       if (new_blank_line_at_eof(ecbdata, line, len))
+               flags |= DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF;
+
+       emit_diff_symbol(ecbdata->opt, DIFF_SYMBOL_PLUS, line, len, flags);
 }
 
 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, '-');
+       unsigned flags = WSEH_OLD | ecbdata->ws_rule;
+       emit_diff_symbol(ecbdata->opt, DIFF_SYMBOL_MINUS, line, len, flags);
 }
 
 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_CONTEXT, WSEH_CONTEXT, ' ');
+       unsigned flags = WSEH_CONTEXT | ecbdata->ws_rule;
+       emit_diff_symbol(ecbdata->opt, DIFF_SYMBOL_CONTEXT, line, len, flags);
 }
 
 static void emit_hunk_header(struct emit_callback *ecbdata,
@@ -682,7 +712,7 @@ static void emit_hunk_header(struct emit_callback *ecbdata,
            memcmp(line, atat, 2) ||
            !(ep = memmem(line + 2, len - 2, atat, 2))) {
                emit_diff_symbol(ecbdata->opt,
-                                DIFF_SYMBOL_CONTEXT_MARKER, line, len);
+                                DIFF_SYMBOL_CONTEXT_MARKER, line, len, 0);
                return;
        }
        ep += 2; /* skip over @@ */
@@ -718,7 +748,7 @@ static void emit_hunk_header(struct emit_callback *ecbdata,
        strbuf_add(&msgbuf, line + len, org_len - len);
        strbuf_complete_line(&msgbuf);
        emit_diff_symbol(ecbdata->opt,
-                        DIFF_SYMBOL_CONTEXT_FRAGINFO, msgbuf.buf, msgbuf.len);
+                        DIFF_SYMBOL_CONTEXT_FRAGINFO, msgbuf.buf, msgbuf.len, 
0);
        strbuf_release(&msgbuf);
 }
 
@@ -777,7 +807,7 @@ static void emit_rewrite_lines(struct emit_callback *ecb,
                data += len;
        }
        if (!endp)
-               emit_diff_symbol(ecb->opt, DIFF_SYMBOL_NO_LF_EOF, NULL, 0);
+               emit_diff_symbol(ecb->opt, DIFF_SYMBOL_NO_LF_EOF, NULL, 0, 0);
 }
 
 static void emit_rewrite_diff(const char *name_a,
@@ -4866,7 +4896,7 @@ void diff_flush(struct diff_options *options)
 
        if (output_format & DIFF_FORMAT_PATCH) {
                if (separator) {
-                       emit_diff_symbol(options, DIFF_SYMBOL_SEPARATOR, NULL, 
0);
+                       emit_diff_symbol(options, DIFF_SYMBOL_SEPARATOR, NULL, 
0, 0);
                        if (options->stat_sep) {
                                /* attach patch instead of inline */
                                fputs(options->stat_sep, options->file);
diff --git a/diff.h b/diff.h
index 5be1ee77a7..8483ca0991 100644
--- a/diff.h
+++ b/diff.h
@@ -148,9 +148,9 @@ struct diff_options {
        int abbrev;
        int ita_invisible_in_index;
 /* white-space error highlighting */
-#define WSEH_NEW 1
-#define WSEH_CONTEXT 2
-#define WSEH_OLD 4
+#define WSEH_NEW (1<<12)
+#define WSEH_CONTEXT (1<<13)
+#define WSEH_OLD (1<<14)
        unsigned ws_error_highlight;
        const char *prefix;
        int prefix_length;
-- 
2.12.2.575.gb14f27f917

Reply via email to