diff --stat: allow custom diffstat output width.

This adds two parameters to "diff --stat".

 . --stat-width=72 tells that the page should fit on 72-column output.

 . --stat-name-width=30 tells that the filename part is limited
   to 30 columns.

Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Junio C Hamano 2006-09-26 18:53:02 -07:00
parent 4a0641b7cf
commit a2540023dc
2 changed files with 96 additions and 38 deletions

131
diff.c
View File

@ -545,21 +545,64 @@ static void diffstat_consume(void *priv, char *line, unsigned long len)
x->deleted++; x->deleted++;
} }
static const char pluses[] = "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
static const char minuses[]= "----------------------------------------------------------------------";
const char mime_boundary_leader[] = "------------"; const char mime_boundary_leader[] = "------------";
static void show_stats(struct diffstat_t* data) static int scale_linear(int it, int width, int max_change)
{
/*
* round(width * it / max_change);
*/
return (it * width * 2 + max_change) / (max_change * 2);
}
static void show_name(const char *prefix, const char *name, int len)
{
printf(" %s%-*s |", prefix, len, name);
}
static void show_graph(char ch, int cnt)
{
if (cnt <= 0)
return;
while (cnt--)
putchar(ch);
}
static void show_stats(struct diffstat_t* data, struct diff_options *options)
{ {
int i, len, add, del, total, adds = 0, dels = 0; int i, len, add, del, total, adds = 0, dels = 0;
int max, max_change = 0, max_len = 0; int max_change = 0, max_len = 0;
int total_files = data->nr; int total_files = data->nr;
int width, name_width;
if (data->nr == 0) if (data->nr == 0)
return; return;
width = options->stat_width ? options->stat_width : 80;
name_width = options->stat_name_width ? options->stat_name_width : 50;
/* Sanity: give at least 5 columns to the graph,
* but leave at least 10 columns for the name.
*/
if (width < name_width + 15) {
if (name_width <= 25)
width = name_width + 15;
else
name_width = width - 15;
}
/* Find the longest filename and max number of changes */
for (i = 0; i < data->nr; i++) { for (i = 0; i < data->nr; i++) {
struct diffstat_file *file = data->files[i]; struct diffstat_file *file = data->files[i];
int change = file->added + file->deleted;
len = quote_c_style(file->name, NULL, NULL, 0);
if (len) {
char *qname = xmalloc(len + 1);
quote_c_style(file->name, qname, NULL, 0);
free(file->name);
file->name = qname;
}
len = strlen(file->name); len = strlen(file->name);
if (max_len < len) if (max_len < len)
@ -567,54 +610,53 @@ static void show_stats(struct diffstat_t* data)
if (file->is_binary || file->is_unmerged) if (file->is_binary || file->is_unmerged)
continue; continue;
if (max_change < file->added + file->deleted) if (max_change < change)
max_change = file->added + file->deleted; max_change = change;
} }
/* Compute the width of the graph part;
* 10 is for one blank at the beginning of the line plus
* " | count " between the name and the graph.
*
* From here on, name_width is the width of the name area,
* and width is the width of the graph area.
*/
name_width = (name_width < max_len) ? name_width : max_len;
if (width < (name_width + 10) + max_change)
width = width - (name_width + 10);
else
width = max_change;
for (i = 0; i < data->nr; i++) { for (i = 0; i < data->nr; i++) {
const char *prefix = ""; const char *prefix = "";
char *name = data->files[i]->name; char *name = data->files[i]->name;
int added = data->files[i]->added; int added = data->files[i]->added;
int deleted = data->files[i]->deleted; int deleted = data->files[i]->deleted;
int name_len;
if (0 < (len = quote_c_style(name, NULL, NULL, 0))) {
char *qname = xmalloc(len + 1);
quote_c_style(name, qname, NULL, 0);
free(name);
data->files[i]->name = name = qname;
}
/* /*
* "scale" the filename * "scale" the filename
*/ */
len = strlen(name); len = name_width;
max = max_len; name_len = strlen(name);
if (max > 50) if (name_width < name_len) {
max = 50;
if (len > max) {
char *slash; char *slash;
prefix = "..."; prefix = "...";
max -= 3; len -= 3;
name += len - max; name += name_len - len;
slash = strchr(name, '/'); slash = strchr(name, '/');
if (slash) if (slash)
name = slash; name = slash;
} }
len = max;
/*
* scale the add/delete
*/
max = max_change;
if (max + len > 70)
max = 70 - len;
if (data->files[i]->is_binary) { if (data->files[i]->is_binary) {
printf(" %s%-*s | Bin\n", prefix, len, name); show_name(prefix, name, len);
printf(" Bin\n");
goto free_diffstat_file; goto free_diffstat_file;
} }
else if (data->files[i]->is_unmerged) { else if (data->files[i]->is_unmerged) {
printf(" %s%-*s | Unmerged\n", prefix, len, name); show_name(prefix, name, len);
printf(" Unmerged\n");
goto free_diffstat_file; goto free_diffstat_file;
} }
else if (!data->files[i]->is_renamed && else if (!data->files[i]->is_renamed &&
@ -623,27 +665,32 @@ static void show_stats(struct diffstat_t* data)
goto free_diffstat_file; goto free_diffstat_file;
} }
/*
* scale the add/delete
*/
add = added; add = added;
del = deleted; del = deleted;
total = add + del; total = add + del;
adds += add; adds += add;
dels += del; dels += del;
if (max_change > 0) { if (width <= max_change) {
total = (total * max + max_change / 2) / max_change; total = scale_linear(total, width, max_change);
add = (add * max + max_change / 2) / max_change; add = scale_linear(add, width, max_change);
del = total - add; del = total - add;
} }
printf(" %s%-*s |%5d %.*s%.*s\n", prefix, show_name(prefix, name, len);
len, name, added + deleted, printf("%5d ", added + deleted);
add, pluses, del, minuses); show_graph('+', add);
show_graph('-', del);
putchar('\n');
free_diffstat_file: free_diffstat_file:
free(data->files[i]->name); free(data->files[i]->name);
free(data->files[i]); free(data->files[i]);
} }
free(data->files); free(data->files);
printf(" %d files changed, %d insertions(+), %d deletions(-)\n", printf(" %d files changed, %d insertions(+), %d deletions(-)\n",
total_files, adds, dels); total_files, adds, dels);
} }
struct checkdiff_t { struct checkdiff_t {
@ -1681,6 +1728,14 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
} }
else if (!strcmp(arg, "--stat")) else if (!strcmp(arg, "--stat"))
options->output_format |= DIFF_FORMAT_DIFFSTAT; options->output_format |= DIFF_FORMAT_DIFFSTAT;
else if (!strncmp(arg, "--stat-width=", 13)) {
options->stat_width = strtoul(arg + 13, NULL, 10);
options->output_format |= DIFF_FORMAT_DIFFSTAT;
}
else if (!strncmp(arg, "--stat-name-width=", 18)) {
options->stat_name_width = strtoul(arg + 18, NULL, 10);
options->output_format |= DIFF_FORMAT_DIFFSTAT;
}
else if (!strcmp(arg, "--check")) else if (!strcmp(arg, "--check"))
options->output_format |= DIFF_FORMAT_CHECKDIFF; options->output_format |= DIFF_FORMAT_CHECKDIFF;
else if (!strcmp(arg, "--summary")) else if (!strcmp(arg, "--summary"))
@ -2438,7 +2493,7 @@ void diff_flush(struct diff_options *options)
if (check_pair_status(p)) if (check_pair_status(p))
diff_flush_stat(p, options, &diffstat); diff_flush_stat(p, options, &diffstat);
} }
show_stats(&diffstat); show_stats(&diffstat, options);
separator++; separator++;
} }

3
diff.h
View File

@ -69,6 +69,9 @@ struct diff_options {
const char *stat_sep; const char *stat_sep;
long xdl_opts; long xdl_opts;
int stat_width;
int stat_name_width;
int nr_paths; int nr_paths;
const char **paths; const char **paths;
int *pathlens; int *pathlens;