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 <sbeller@xxxxxxxxxx> --- 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