diffstat does not show whether a file is added or deleted. I know --summary does. But the problem with --summary is it makes me look for information of a file in two places: diffstat and summary. And with a commit that adds/removes a lot, showing both --stat --summary can be long. This patch adds "(new)", "(gone)" or "(new mode)" to diffstat, with highlight, to easily catch file additions/removals. The extra text is chosen to be short enough so that it won't take up too much space for path names: .gitignore | 1 + Makefile | 3 + t/t3070-wildmatch.sh (new) | 188 ++++++++++++++++++++++++ t/t3070/wildtest.txt (gone) | 165 --------------------- test-wildmatch.c (new) | 14 ++ wildmatch.c | 5 +- 6 files changed, 210 insertions(+), 166 deletions(-) I don't put creation modes in there too because most of the time it does not matter much to me and I could look down to --summary for mode verification. But we could put "(new+x)" for 0755 and just "(new)" for 0644. "(new mode)" then could become "(+x)", "(-x)" or something like that. Coloring is to me an improvement over --summary. Probably the main point. Without it, perhaps it's not worth putting extra text to diffstat. Single patch for easy testing. Test suite probably breaks. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- diff.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++----------------- diff.h | 3 ++- utf8.c | 33 +++++++++++++++++++++++++++ utf8.h | 2 ++ 4 files changed, 97 insertions(+), 22 deletions(-) diff --git a/diff.c b/diff.c index 35d3f07..f9217e6 100644 --- a/diff.c +++ b/diff.c @@ -45,6 +45,7 @@ static char diff_colors[][COLOR_MAXLEN] = { GIT_COLOR_YELLOW, /* COMMIT */ GIT_COLOR_BG_RED, /* WHITESPACE */ GIT_COLOR_NORMAL, /* FUNCINFO */ + GIT_COLOR_YELLOW, /* STATUSINFO */ }; static int parse_diff_color_slot(const char *var, int ofs) @@ -65,6 +66,8 @@ static int parse_diff_color_slot(const char *var, int ofs) return DIFF_WHITESPACE; if (!strcasecmp(var+ofs, "func")) return DIFF_FUNCINFO; + if (!strcasecmp(var+ofs, "status")) + return DIFF_STATUSINFO; return -1; } @@ -1223,7 +1226,8 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) } } -static char *pprint_rename(const char *a, const char *b) +static char *pprint_rename(struct diff_options *options, + const char *a, const char *b) { const char *old = a; const char *new = b; @@ -1237,7 +1241,9 @@ static char *pprint_rename(const char *a, const char *b) if (qlen_a || qlen_b) { quote_c_style(a, &name, NULL, 0); - strbuf_addstr(&name, " => "); + strbuf_addf(&name, " %s=>%s ", + diff_get_color_opt(options, DIFF_STATUSINFO), + diff_get_color_opt(options, DIFF_RESET)); quote_c_style(b, &name, NULL, 0); return strbuf_detach(&name, NULL); } @@ -1278,13 +1284,19 @@ static char *pprint_rename(const char *a, const char *b) strbuf_grow(&name, pfx_length + a_midlen + b_midlen + sfx_length + 7); if (pfx_length + sfx_length) { strbuf_add(&name, a, pfx_length); - strbuf_addch(&name, '{'); + strbuf_addf(&name, "%s{%s", + diff_get_color_opt(options, DIFF_STATUSINFO), + diff_get_color_opt(options, DIFF_RESET)); } strbuf_add(&name, a + pfx_length, a_midlen); - strbuf_addstr(&name, " => "); + strbuf_addf(&name, " %s=>%s ", + diff_get_color_opt(options, DIFF_STATUSINFO), + diff_get_color_opt(options, DIFF_RESET)); strbuf_add(&name, b + pfx_length, b_midlen); if (pfx_length + sfx_length) { - strbuf_addch(&name, '}'); + strbuf_addf(&name, "%s}%s", + diff_get_color_opt(options, DIFF_STATUSINFO), + diff_get_color_opt(options, DIFF_RESET)); strbuf_add(&name, a + len_a - sfx_length, sfx_length); } return strbuf_detach(&name, NULL); @@ -1300,6 +1312,7 @@ struct diffstat_t { unsigned is_unmerged:1; unsigned is_binary:1; unsigned is_renamed:1; + char status; uintmax_t added, deleted; } **files; }; @@ -1357,7 +1370,8 @@ static int scale_linear(int it, int width, int max_change) static void show_name(FILE *file, const char *prefix, const char *name, int len) { - fprintf(file, " %s%-*s |", prefix, len, name); + fprintf(file, " %s%-*s |", prefix, + len + strlen_ansi(name), name); } static void show_graph(FILE *file, char ch, int cnt, const char *set, const char *reset) @@ -1370,7 +1384,8 @@ static void show_graph(FILE *file, char ch, int cnt, const char *set, const char fprintf(file, "%s", reset); } -static void fill_print_name(struct diffstat_file *file) +static void fill_print_name(struct diff_options *options, + struct diffstat_file *file) { char *pname; @@ -1379,14 +1394,32 @@ static void fill_print_name(struct diffstat_file *file) if (!file->is_renamed) { struct strbuf buf = STRBUF_INIT; - if (quote_c_style(file->name, &buf, NULL, 0)) { + if (quote_c_style(file->name, &buf, NULL, 0) || + file->status) { + const char *str = NULL; + switch (file->status) { + case DIFF_STATUS_ADDED: + str = "new"; + break; + case DIFF_STATUS_DELETED: + str = "gone"; + break; + case DIFF_STATUS_TYPE_CHANGED: + str = "new mode"; + break; + } + if (str) + strbuf_addf(&buf, " (%s%s%s)", + diff_get_color_opt(options, DIFF_STATUSINFO), + str, + diff_get_color_opt(options, DIFF_RESET)); pname = strbuf_detach(&buf, NULL); } else { pname = file->name; strbuf_release(&buf); } } else { - pname = pprint_rename(file->from_name, file->name); + pname = pprint_rename(options, file->from_name, file->name); } file->print_name = pname; } @@ -1474,8 +1507,8 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) count++; /* not shown == room for one more */ continue; } - fill_print_name(file); - len = strlen(file->print_name); + fill_print_name(options, file); + len = strlen_no_ansi(file->print_name); if (max_len < len) max_len = len; @@ -1599,7 +1632,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) * "scale" the filename */ len = name_width; - name_len = strlen(name); + name_len = strlen_no_ansi(name); if (name_width < name_len) { char *slash; prefix = "..."; @@ -1737,7 +1770,7 @@ static void show_numstat(struct diffstat_t *data, struct diff_options *options) "%"PRIuMAX"\t%"PRIuMAX"\t", file->added, file->deleted); if (options->line_termination) { - fill_print_name(file); + fill_print_name(options, file); if (!file->is_renamed) write_name_quoted(file->name, options->file, options->line_termination); @@ -2397,13 +2430,15 @@ static void builtin_diffstat(const char *name_a, const char *name_b, struct diff_filespec *two, struct diffstat_t *diffstat, struct diff_options *o, - int complete_rewrite) + int complete_rewrite, + char status) { mmfile_t mf1, mf2; struct diffstat_file *data; int same_contents; data = diffstat_add(diffstat, name_a, name_b); + data->status = status; if (!one || !two) { data->is_unmerged = 1; @@ -3118,7 +3153,8 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o, if (DIFF_PAIR_UNMERGED(p)) { /* unmerged */ - builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, 0); + builtin_diffstat(p->one->path, NULL, NULL, NULL, + diffstat, o, 0, 0); return; } @@ -3133,7 +3169,8 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o, if (p->status == DIFF_STATUS_MODIFIED && p->score) complete_rewrite = 1; - builtin_diffstat(name, other, p->one, p->two, diffstat, o, complete_rewrite); + builtin_diffstat(name, other, p->one, p->two, diffstat, + o, complete_rewrite, p->status); } static void run_checkdiff(struct diff_filepair *p, struct diff_options *o) @@ -4118,10 +4155,12 @@ static void show_mode_change(FILE *file, struct diff_filepair *p, int show_name, } } -static void show_rename_copy(FILE *file, const char *renamecopy, struct diff_filepair *p, - const char *line_prefix) +static void show_rename_copy(FILE *file, const char *renamecopy, + struct diff_filepair *p, + const char *line_prefix, + struct diff_options *options) { - char *names = pprint_rename(p->one->path, p->two->path); + char *names = pprint_rename(options, p->one->path, p->two->path); fprintf(file, " %s %s (%d%%)\n", renamecopy, names, similarity_index(p)); free(names); @@ -4149,11 +4188,11 @@ static void diff_summary(struct diff_options *opt, struct diff_filepair *p) break; case DIFF_STATUS_COPIED: fputs(line_prefix, file); - show_rename_copy(file, "copy", p, line_prefix); + show_rename_copy(file, "copy", p, line_prefix, opt); break; case DIFF_STATUS_RENAMED: fputs(line_prefix, file); - show_rename_copy(file, "rename", p, line_prefix); + show_rename_copy(file, "rename", p, line_prefix, opt); break; default: if (p->score) { diff --git a/diff.h b/diff.h index a658f85..c609512 100644 --- a/diff.h +++ b/diff.h @@ -167,7 +167,8 @@ enum color_diff { DIFF_FILE_NEW = 5, DIFF_COMMIT = 6, DIFF_WHITESPACE = 7, - DIFF_FUNCINFO = 8 + DIFF_FUNCINFO = 8, + DIFF_STATUSINFO = 9 }; const char *diff_get_color(int diff_use_color, enum color_diff ix); #define diff_get_color_opt(o, ix) \ diff --git a/utf8.c b/utf8.c index a544f15..10823fd 100644 --- a/utf8.c +++ b/utf8.c @@ -317,6 +317,39 @@ static size_t display_mode_esc_sequence_len(const char *s) return p - s; } +size_t strlen_no_ansi(const char *s) +{ + size_t len = 0; + for (;;) { + size_t skip; + + while ((skip = display_mode_esc_sequence_len(s))) + s += skip; + if (!*s) + break; + len++; + s++; + } + return len; +} + +size_t strlen_ansi(const char *s) +{ + size_t len = 0; + for (;;) { + size_t skip; + + while ((skip = display_mode_esc_sequence_len(s))) { + s += skip; + len += skip; + } + if (!*s) + break; + s++; + } + return len; +} + /* * Wrap the text, if necessary. The variable indent is the indent for the * first line, indent2 is the indent for all other lines. diff --git a/utf8.h b/utf8.h index 3c0ae76..fd4cfca 100644 --- a/utf8.h +++ b/utf8.h @@ -3,6 +3,8 @@ typedef unsigned int ucs_char_t; /* assuming 32bit int */ +size_t strlen_no_ansi(const char *s); +size_t strlen_ansi(const char *s); int utf8_width(const char **start, size_t *remainder_p); int utf8_strwidth(const char *string); int is_utf8(const char *text); -- 1.8.0.rc2.11.g2b79d01 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html