X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=diff.c;h=13b216f2733763b4e6cc6a3c37ff2624d7f55266;hb=ac58c7b18ecf1c2ef41c848879e8b1838162db54;hp=46e8529a649d493b4f5a6a4ddb80912290ac8a2e;hpb=cbdda024049947366804d60bdc5e5fc3ab3ee3a5;p=git.git diff --git a/diff.c b/diff.c index 46e8529a..13b216f2 100644 --- a/diff.c +++ b/diff.c @@ -195,6 +195,56 @@ static int fn_out(void *priv, mmbuffer_t *mb, int nbuf) return 0; } +static char *pprint_rename(const char *a, const char *b) +{ + const char *old = a; + const char *new = b; + char *name = NULL; + int pfx_length, sfx_length; + int len_a = strlen(a); + int len_b = strlen(b); + + /* Find common prefix */ + pfx_length = 0; + while (*old && *new && *old == *new) { + if (*old == '/') + pfx_length = old - a + 1; + old++; + new++; + } + + /* Find common suffix */ + old = a + len_a; + new = b + len_b; + sfx_length = 0; + while (a <= old && b <= new && *old == *new) { + if (*old == '/') + sfx_length = len_a - (old - a); + old--; + new--; + } + + /* + * pfx{mid-a => mid-b}sfx + * {pfx-a => pfx-b}sfx + * pfx{sfx-a => sfx-b} + * name-a => name-b + */ + if (pfx_length + sfx_length) { + name = xmalloc(len_a + len_b - pfx_length - sfx_length + 7); + sprintf(name, "%.*s{%.*s => %.*s}%s", + pfx_length, a, + len_a - pfx_length - sfx_length, a + pfx_length, + len_b - pfx_length - sfx_length, b + pfx_length, + a + len_a - sfx_length); + } + else { + name = xmalloc(len_a + len_b + 5); + sprintf(name, "%s => %s", a, b); + } + return name; +} + struct diffstat_t { struct xdiff_emit_state xm; @@ -204,12 +254,14 @@ struct diffstat_t { char *name; unsigned is_unmerged:1; unsigned is_binary:1; + unsigned is_renamed:1; unsigned int added, deleted; } **files; }; static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat, - const char *name) + const char *name_a, + const char *name_b) { struct diffstat_file *x; x = xcalloc(sizeof (*x), 1); @@ -219,7 +271,12 @@ static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat, diffstat->alloc * sizeof(x)); } diffstat->files[diffstat->nr++] = x; - x->name = strdup(name); + if (name_b) { + x->name = pprint_rename(name_a, name_b); + x->is_renamed = 1; + } + else + x->name = strdup(name_a); return x; } @@ -250,13 +307,14 @@ static void show_stats(struct diffstat_t* data) for (i = 0; i < data->nr; i++) { struct diffstat_file *file = data->files[i]; + len = strlen(file->name); + if (max_len < len) + max_len = len; + if (file->is_binary || file->is_unmerged) continue; if (max_change < file->added + file->deleted) max_change = file->added + file->deleted; - len = strlen(file->name); - if (max_len < len) - max_len = len; } for (i = 0; i < data->nr; i++) { @@ -304,7 +362,8 @@ static void show_stats(struct diffstat_t* data) printf(" %s%-*s | Unmerged\n", prefix, len, name); goto free_diffstat_file; } - else if (added + deleted == 0) { + else if (!data->files[i]->is_renamed && + (added + deleted == 0)) { total_files--; goto free_diffstat_file; } @@ -424,13 +483,14 @@ static void builtin_diff(const char *name_a, } static void builtin_diffstat(const char *name_a, const char *name_b, - struct diff_filespec *one, struct diff_filespec *two, - struct diffstat_t *diffstat) + struct diff_filespec *one, + struct diff_filespec *two, + struct diffstat_t *diffstat) { mmfile_t mf1, mf2; struct diffstat_file *data; - data = diffstat_add(diffstat, name_a ? name_a : name_b); + data = diffstat_add(diffstat, name_a, name_b); if (!one || !two) { data->is_unmerged = 1; @@ -991,7 +1051,7 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o) } static void run_diffstat(struct diff_filepair *p, struct diff_options *o, - struct diffstat_t *diffstat) + struct diffstat_t *diffstat) { const char *name; const char *other; @@ -1029,6 +1089,15 @@ int diff_setup_done(struct diff_options *options) options->detect_rename != DIFF_DETECT_COPY) || (0 <= options->rename_limit && !options->detect_rename)) return -1; + + /* + * These cases always need recursive; we do not drop caller-supplied + * recursive bits for other formats here. + */ + if ((options->output_format == DIFF_FORMAT_PATCH) || + (options->output_format == DIFF_FORMAT_DIFFSTAT)) + options->recursive = 1; + if (options->detect_rename && options->rename_limit < 0) options->rename_limit = diff_rename_limit_default; if (options->setup & DIFF_SETUP_USE_CACHE) { @@ -1060,6 +1129,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) } else if (!strcmp(arg, "--stat")) options->output_format = DIFF_FORMAT_DIFFSTAT; + else if (!strcmp(arg, "--patch-with-stat")) { + options->output_format = DIFF_FORMAT_PATCH; + options->with_stat = 1; + } else if (!strcmp(arg, "-z")) options->line_termination = 0; else if (!strncmp(arg, "-l", 2)) @@ -1360,7 +1433,7 @@ static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o) } static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o, - struct diffstat_t *diffstat) + struct diffstat_t *diffstat) { if (diff_unmodified_pair(p)) return; @@ -1529,7 +1602,7 @@ void diff_flush(struct diff_options *options) int diff_output_format = options->output_format; struct diffstat_t *diffstat = NULL; - if (diff_output_format == DIFF_FORMAT_DIFFSTAT) { + if (diff_output_format == DIFF_FORMAT_DIFFSTAT || options->with_stat) { diffstat = xcalloc(sizeof (struct diffstat_t), 1); diffstat->xm.consume = diffstat_consume; } @@ -1541,6 +1614,17 @@ void diff_flush(struct diff_options *options) } putchar(options->line_termination); } + if (options->with_stat) { + for (i = 0; i < q->nr; i++) { + struct diff_filepair *p = q->queue[i]; + flush_one_pair(p, DIFF_FORMAT_DIFFSTAT, options, + diffstat); + } + show_stats(diffstat); + free(diffstat); + diffstat = NULL; + putchar(options->line_termination); + } for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; flush_one_pair(p, diff_output_format, options, diffstat);