}
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);
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");
}
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,
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 @@ */
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);
}
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,
{
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))
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);