|
|
@ -20,12 +20,13 @@ static int diff_use_color_default; |
|
|
|
|
|
|
|
|
|
|
|
static char diff_colors[][COLOR_MAXLEN] = { |
|
|
|
static char diff_colors[][COLOR_MAXLEN] = { |
|
|
|
"\033[m", /* reset */ |
|
|
|
"\033[m", /* reset */ |
|
|
|
"", /* normal */ |
|
|
|
"", /* PLAIN (normal) */ |
|
|
|
"\033[1m", /* bold */ |
|
|
|
"\033[1m", /* METAINFO (bold) */ |
|
|
|
"\033[36m", /* cyan */ |
|
|
|
"\033[36m", /* FRAGINFO (cyan) */ |
|
|
|
"\033[31m", /* red */ |
|
|
|
"\033[31m", /* OLD (red) */ |
|
|
|
"\033[32m", /* green */ |
|
|
|
"\033[32m", /* NEW (green) */ |
|
|
|
"\033[33m" /* yellow */ |
|
|
|
"\033[33m", /* COMMIT (yellow) */ |
|
|
|
|
|
|
|
"\033[41m", /* WHITESPACE (red background) */ |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
static int parse_diff_color_slot(const char *var, int ofs) |
|
|
|
static int parse_diff_color_slot(const char *var, int ofs) |
|
|
@ -42,6 +43,8 @@ static int parse_diff_color_slot(const char *var, int ofs) |
|
|
|
return DIFF_FILE_NEW; |
|
|
|
return DIFF_FILE_NEW; |
|
|
|
if (!strcasecmp(var+ofs, "commit")) |
|
|
|
if (!strcasecmp(var+ofs, "commit")) |
|
|
|
return DIFF_COMMIT; |
|
|
|
return DIFF_COMMIT; |
|
|
|
|
|
|
|
if (!strcasecmp(var+ofs, "whitespace")) |
|
|
|
|
|
|
|
return DIFF_WHITESPACE; |
|
|
|
die("bad config variable '%s'", var); |
|
|
|
die("bad config variable '%s'", var); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -383,9 +386,89 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix) |
|
|
|
return ""; |
|
|
|
return ""; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void emit_line(const char *set, const char *reset, const char *line, int len) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (len > 0 && line[len-1] == '\n') |
|
|
|
|
|
|
|
len--; |
|
|
|
|
|
|
|
fputs(set, stdout); |
|
|
|
|
|
|
|
fwrite(line, len, 1, stdout); |
|
|
|
|
|
|
|
puts(reset); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int col0 = ecbdata->nparents; |
|
|
|
|
|
|
|
int last_tab_in_indent = -1; |
|
|
|
|
|
|
|
int last_space_in_indent = -1; |
|
|
|
|
|
|
|
int i; |
|
|
|
|
|
|
|
int tail = len; |
|
|
|
|
|
|
|
int need_highlight_leading_space = 0; |
|
|
|
|
|
|
|
const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE); |
|
|
|
|
|
|
|
const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!*ws) { |
|
|
|
|
|
|
|
emit_line(set, reset, line, len); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The line is a newly added line. Does it have funny leading |
|
|
|
|
|
|
|
* whitespaces? In indent, SP should never precede a TAB. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
for (i = col0; i < len; i++) { |
|
|
|
|
|
|
|
if (line[i] == '\t') { |
|
|
|
|
|
|
|
last_tab_in_indent = i; |
|
|
|
|
|
|
|
if (0 <= last_space_in_indent) |
|
|
|
|
|
|
|
need_highlight_leading_space = 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (line[i] == ' ') |
|
|
|
|
|
|
|
last_space_in_indent = i; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
fputs(set, stdout); |
|
|
|
|
|
|
|
fwrite(line, col0, 1, stdout); |
|
|
|
|
|
|
|
fputs(reset, stdout); |
|
|
|
|
|
|
|
if (((i == len) || line[i] == '\n') && i != col0) { |
|
|
|
|
|
|
|
/* The whole line was indent */ |
|
|
|
|
|
|
|
emit_line(ws, reset, line + col0, len - col0); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
i = col0; |
|
|
|
|
|
|
|
if (need_highlight_leading_space) { |
|
|
|
|
|
|
|
while (i < last_tab_in_indent) { |
|
|
|
|
|
|
|
if (line[i] == ' ') { |
|
|
|
|
|
|
|
fputs(ws, stdout); |
|
|
|
|
|
|
|
putchar(' '); |
|
|
|
|
|
|
|
fputs(reset, stdout); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
putchar(line[i]); |
|
|
|
|
|
|
|
i++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
tail = len - 1; |
|
|
|
|
|
|
|
if (line[tail] == '\n' && i < tail) |
|
|
|
|
|
|
|
tail--; |
|
|
|
|
|
|
|
while (i < tail) { |
|
|
|
|
|
|
|
if (!isspace(line[tail])) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
tail--; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if ((i < tail && line[tail + 1] != '\n')) { |
|
|
|
|
|
|
|
/* This has whitespace between tail+1..len */ |
|
|
|
|
|
|
|
fputs(set, stdout); |
|
|
|
|
|
|
|
fwrite(line + i, tail - i + 1, 1, stdout); |
|
|
|
|
|
|
|
fputs(reset, stdout); |
|
|
|
|
|
|
|
emit_line(ws, reset, line + tail + 1, len - tail - 1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
emit_line(set, reset, line + i, len - i); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void fn_out_consume(void *priv, char *line, unsigned long len) |
|
|
|
static void fn_out_consume(void *priv, char *line, unsigned long len) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int i; |
|
|
|
int i; |
|
|
|
|
|
|
|
int color; |
|
|
|
struct emit_callback *ecbdata = priv; |
|
|
|
struct emit_callback *ecbdata = priv; |
|
|
|
const char *set = diff_get_color(ecbdata->color_diff, DIFF_METAINFO); |
|
|
|
const char *set = diff_get_color(ecbdata->color_diff, DIFF_METAINFO); |
|
|
|
const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET); |
|
|
|
const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET); |
|
|
@ -403,45 +486,52 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) |
|
|
|
; |
|
|
|
; |
|
|
|
if (2 <= i && i < len && line[i] == ' ') { |
|
|
|
if (2 <= i && i < len && line[i] == ' ') { |
|
|
|
ecbdata->nparents = i - 1; |
|
|
|
ecbdata->nparents = i - 1; |
|
|
|
set = diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO); |
|
|
|
emit_line(diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO), |
|
|
|
|
|
|
|
reset, line, len); |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (len < ecbdata->nparents) |
|
|
|
|
|
|
|
|
|
|
|
if (len < ecbdata->nparents) { |
|
|
|
set = reset; |
|
|
|
set = reset; |
|
|
|
else { |
|
|
|
emit_line(reset, reset, line, len); |
|
|
|
int nparents = ecbdata->nparents; |
|
|
|
return; |
|
|
|
int color = DIFF_PLAIN; |
|
|
|
|
|
|
|
if (ecbdata->diff_words && nparents != 1) |
|
|
|
|
|
|
|
/* fall back to normal diff */ |
|
|
|
|
|
|
|
free_diff_words_data(ecbdata); |
|
|
|
|
|
|
|
if (ecbdata->diff_words) { |
|
|
|
|
|
|
|
if (line[0] == '-') { |
|
|
|
|
|
|
|
diff_words_append(line, len, |
|
|
|
|
|
|
|
&ecbdata->diff_words->minus); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} else if (line[0] == '+') { |
|
|
|
|
|
|
|
diff_words_append(line, len, |
|
|
|
|
|
|
|
&ecbdata->diff_words->plus); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (ecbdata->diff_words->minus.text.size || |
|
|
|
|
|
|
|
ecbdata->diff_words->plus.text.size) |
|
|
|
|
|
|
|
diff_words_show(ecbdata->diff_words); |
|
|
|
|
|
|
|
line++; |
|
|
|
|
|
|
|
len--; |
|
|
|
|
|
|
|
} else |
|
|
|
|
|
|
|
for (i = 0; i < nparents && len; i++) { |
|
|
|
|
|
|
|
if (line[i] == '-') |
|
|
|
|
|
|
|
color = DIFF_FILE_OLD; |
|
|
|
|
|
|
|
else if (line[i] == '+') |
|
|
|
|
|
|
|
color = DIFF_FILE_NEW; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
set = diff_get_color(ecbdata->color_diff, color); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
if (len > 0 && line[len-1] == '\n') |
|
|
|
|
|
|
|
|
|
|
|
color = DIFF_PLAIN; |
|
|
|
|
|
|
|
if (ecbdata->diff_words && ecbdata->nparents != 1) |
|
|
|
|
|
|
|
/* fall back to normal diff */ |
|
|
|
|
|
|
|
free_diff_words_data(ecbdata); |
|
|
|
|
|
|
|
if (ecbdata->diff_words) { |
|
|
|
|
|
|
|
if (line[0] == '-') { |
|
|
|
|
|
|
|
diff_words_append(line, len, |
|
|
|
|
|
|
|
&ecbdata->diff_words->minus); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} else if (line[0] == '+') { |
|
|
|
|
|
|
|
diff_words_append(line, len, |
|
|
|
|
|
|
|
&ecbdata->diff_words->plus); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (ecbdata->diff_words->minus.text.size || |
|
|
|
|
|
|
|
ecbdata->diff_words->plus.text.size) |
|
|
|
|
|
|
|
diff_words_show(ecbdata->diff_words); |
|
|
|
|
|
|
|
line++; |
|
|
|
len--; |
|
|
|
len--; |
|
|
|
fputs (set, stdout); |
|
|
|
emit_line(set, reset, line, len); |
|
|
|
fwrite (line, len, 1, stdout); |
|
|
|
return; |
|
|
|
puts (reset); |
|
|
|
} |
|
|
|
|
|
|
|
for (i = 0; i < ecbdata->nparents && len; i++) { |
|
|
|
|
|
|
|
if (line[i] == '-') |
|
|
|
|
|
|
|
color = DIFF_FILE_OLD; |
|
|
|
|
|
|
|
else if (line[i] == '+') |
|
|
|
|
|
|
|
color = DIFF_FILE_NEW; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (color != DIFF_FILE_NEW) { |
|
|
|
|
|
|
|
emit_line(diff_get_color(ecbdata->color_diff, color), |
|
|
|
|
|
|
|
reset, line, len); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
emit_add_line(reset, ecbdata, line, len); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static char *pprint_rename(const char *a, const char *b) |
|
|
|
static char *pprint_rename(const char *a, const char *b) |
|
|
|