diff.c: migrate emit_line_checked to use emit_diff_symbol
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index 488096b757377b4f86109253e3b275ea54254087..e5430d56da79f56eacb55226c69778563dbc5355 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -561,17 +561,54 @@ static void emit_line(struct diff_options *o, const char *set, const char *reset
 }
 
 enum diff_symbol {
+       DIFF_SYMBOL_CONTEXT,
+       DIFF_SYMBOL_PLUS,
+       DIFF_SYMBOL_MINUS,
        DIFF_SYMBOL_NO_LF_EOF,
        DIFF_SYMBOL_CONTEXT_FRAGINFO,
        DIFF_SYMBOL_CONTEXT_MARKER,
        DIFF_SYMBOL_SEPARATOR
 };
+/*
+ * 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_NO_LF_EOF:
                context = diff_get_color_opt(o, DIFF_CONTEXT);
@@ -593,6 +630,25 @@ static void emit_diff_symbol(struct diff_options *o, enum diff_symbol s,
                        diff_line_prefix(o),
                        o->line_termination);
                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");
        }
@@ -609,57 +665,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,
@@ -683,7 +713,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 @@ */
@@ -719,7 +749,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);
 }
 
@@ -778,7 +808,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,
@@ -4771,6 +4801,10 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)
 {
        int i;
        struct diff_queue_struct *q = &diff_queued_diff;
+
+       if (WSEH_NEW & WS_RULE_MASK)
+               die("BUG: WS rules bit mask overlaps with diff symbol flags");
+
        for (i = 0; i < q->nr; i++) {
                struct diff_filepair *p = q->queue[i];
                if (check_pair_status(p))
@@ -4861,7 +4895,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);