Skip to content

Commit

Permalink
diff --stat: use a maximum of 5/8 for the filename part
Browse files Browse the repository at this point in the history
The way that available columns are divided between the filename part
and the graph part is modified to use as many columns as necessary for
the filenames and the rest for the graph.

If there isn't enough columns to print both the filename and the
graph, at least 5/8 of available space is devoted to filenames. On a
standard 80 column terminal, or if not connected to a terminal and
using the default of 80 columns, this gives the same partition as
before.

The effect of this change is visible in the patch to the test vector
in t4052; with a small change with long filename, it stops truncating
the name part too short, and also allocates a bit more columns to the
graph for larger changes.

Signed-off-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Zbigniew Jędrzejewski-Szmek authored and Junio C Hamano committed Mar 1, 2012
1 parent 7a7159a commit 1b058bc
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 44 deletions.
14 changes: 8 additions & 6 deletions Documentation/diff-options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,15 @@ endif::git-format-patch[]
Generate a diff using the "patience diff" algorithm.

--stat[=<width>[,<name-width>[,<count>]]]::
Generate a diffstat. You can override the default
output width for 80-column terminal by `--stat=<width>`.
The width of the filename part can be controlled by
giving another width to it separated by a comma.
Generate a diffstat. By default, as much space as necessary
will be used for the filename part, and the rest for
the graph part. Maximum width defaults to terminal width,
or 80 columns if not connected to a terminal, and can be
overriden by `<width>`. The width of the filename part can be
limited by giving another width `<name-width>` after a comma.
By giving a third parameter `<count>`, you can limit the
output to the first `<count>` lines, followed by
`...` if there are more.
output to the first `<count>` lines, followed by `...` if
there are more.
+
These parameters can also be set individually with `--stat-width=<width>`,
`--stat-name-width=<name-width>` and `--stat-count=<count>`.
Expand Down
90 changes: 60 additions & 30 deletions diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -1329,7 +1329,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
int i, len, add, del, adds = 0, dels = 0;
uintmax_t max_change = 0, max_len = 0;
int total_files = data->nr;
int width, name_width, count;
int width, name_width, graph_width, number_width = 4, count;
const char *reset, *add_c, *del_c;
const char *line_prefix = "";
int extra_shown = 0;
Expand All @@ -1343,28 +1343,15 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
line_prefix = msg->buf;
}

if (options->stat_width == -1)
width = term_columns();
else
width = options->stat_width ? options->stat_width : 80;
name_width = options->stat_name_width ? options->stat_name_width : 50;
count = options->stat_count ? options->stat_count : data->nr;

/* Sanity: give at least 5 columns to the graph,
* but leave at least 10 columns for the name.
*/
if (width < 25)
width = 25;
if (name_width < 10)
name_width = 10;
else if (width < name_width + 15)
name_width = width - 15;

/* Find the longest filename and max number of changes */
reset = diff_get_color_opt(options, DIFF_RESET);
add_c = diff_get_color_opt(options, DIFF_FILE_NEW);
del_c = diff_get_color_opt(options, DIFF_FILE_OLD);

/*
* Find the longest filename and max number of changes
*/
for (i = 0; (i < count) && (i < data->nr); i++) {
struct diffstat_file *file = data->files[i];
uintmax_t change = file->added + file->deleted;
Expand All @@ -1385,19 +1372,62 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
}
count = i; /* min(count, data->nr) */

/* 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.
/*
* We have width = stat_width or term_columns() columns total.
* We want a maximum of min(max_len, stat_name_width) for the name part.
* We also need 1 for " " and 4 + decimal_width(max_change)
* for " | NNNN " and one the empty column at the end, altogether
* 6 + decimal_width(max_change).
*
* If there's not enough space, we will use the smaller of
* stat_name_width (if set) and 5/8*width for the filename,
* and the rest for constant elements + graph part.
* (5/8 gives 50 for filename and 30 for the constant parts + graph
* for the standard terminal size).
*
* From here on, name_width is the width of the name area,
* and width is the width of the graph area.
* In other words: stat_width limits the maximum width, and
* stat_name_width fixes the maximum width of the filename,
* and is also used to divide available columns if there
* aren't enough.
*/
name_width = (name_width < max_len) ? name_width : max_len;
if (width < (name_width + 10) + max_change)
width = width - (name_width + 10);

if (options->stat_width == -1)
width = term_columns();
else
width = max_change;
width = options->stat_width ? options->stat_width : 80;

/*
* Guarantee 3/8*16==6 for the graph part
* and 5/8*16==10 for the filename part
*/
if (width < 16 + 6 + number_width)
width = 16 + 6 + number_width;

/*
* First assign sizes that are wanted, ignoring available width.
*/
graph_width = max_change;
name_width = (options->stat_name_width > 0 &&
options->stat_name_width < max_len) ?
options->stat_name_width : max_len;

/*
* Adjust adjustable widths not to exceed maximum width
*/
if (name_width + number_width + 6 + graph_width > width) {
if (graph_width > width * 3/8 - number_width - 6)
graph_width = width * 3/8 - number_width - 6;
if (name_width > width - number_width - 6 - graph_width)
name_width = width - number_width - 6 - graph_width;
else
graph_width = width - number_width - 6 - name_width;
}

/*
* From here name_width is the width of the name area,
* and graph_width is the width of the graph area.
* max_change is used to scale graph properly.
*/
for (i = 0; i < count; i++) {
const char *prefix = "";
char *name = data->files[i]->print_name;
Expand Down Expand Up @@ -1453,18 +1483,18 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
adds += add;
dels += del;

if (width <= max_change) {
if (graph_width <= max_change) {
int total = add + del;

total = scale_linear(add + del, width, max_change);
total = scale_linear(add + del, graph_width, max_change);
if (total < 2 && add && del)
/* width >= 2 due to the sanity check */
total = 2;
if (add < del) {
add = scale_linear(add, width, max_change);
add = scale_linear(add, graph_width, max_change);
del = total - add;
} else {
del = scale_linear(del, width, max_change);
del = scale_linear(del, graph_width, max_change);
add = total - del;
}
}
Expand Down
16 changes: 8 additions & 8 deletions t/t4052-stat-output.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@ test_expect_success 'preparation' '
while read cmd args
do
cat >expect <<-'EOF'
...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
EOF
test_expect_success "$cmd: a short graph bar does not extend to the full width" '
test_expect_success "$cmd: small change with long name gives more space to the name" '
git $cmd $args >output &&
grep " | " output >actual &&
test_cmp expect actual
'

cat >expect <<-'EOF'
...aaaaaaaaaaaaaaaaaaaaaa | 1 +
...aaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
EOF
test_expect_success "$cmd --stat=width: name is chopped to leave room to the right of a short bar" '
test_expect_success "$cmd --stat=width: a long name is given more room when the bar is short" '
git $cmd $args --stat=40 >output &&
grep " | " output >actual &&
test_cmp expect actual
Expand Down Expand Up @@ -131,11 +131,11 @@ test_expect_success 'preparation for long filename tests' '
'

cat >expect <<'EOF'
...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++
...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++
EOF
while read cmd args
do
test_expect_success "$cmd --stat=width with big change and long name favors name part" '
test_expect_success "$cmd --stat=width with big change is more balanced" '
git $cmd $args --stat-width=60 >output &&
grep " | " output >actual &&
test_cmp expect actual
Expand All @@ -151,7 +151,7 @@ cat >expect80 <<'EOF'
...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++
EOF
cat >expect200 <<'EOF'
...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EOF
while read verb expect cmd args
do
Expand All @@ -178,7 +178,7 @@ test_expect_success 'merge --stat respects COLUMNS (big change)' '
'

cat >expect <<'EOF'
...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++++++++++++++++++++++
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++
EOF
test_expect_success 'merge --stat respects COLUMNS (long filename)' '
COLUMNS=100 git merge --stat --no-ff master >output &&
Expand Down

0 comments on commit 1b058bc

Please sign in to comment.