Skip to content

Commit af05021

Browse files
committed
Merge branch 'zj/diff-stat-dyncol'
By Zbigniew Jędrzejewski-Szmek (8) and Junio C Hamano (1) * zj/diff-stat-dyncol: : This breaks tests. Perhaps it is not worth using the decimal-width stuff : for this series, at least initially. diff --stat: add config option to limit graph width diff --stat: enable limiting of the graph part diff --stat: add a test for output with COLUMNS=40 diff --stat: use a maximum of 5/8 for the filename part merge --stat: use the full terminal width log --stat: use the full terminal width show --stat: use the full terminal width diff --stat: use the full terminal width diff --stat: tests for long filenames and big change counts
2 parents 556c5e0 + df44483 commit af05021

File tree

9 files changed

+335
-33
lines changed

9 files changed

+335
-33
lines changed

Documentation/diff-config.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ directories with less than 10% of the total amount of changed files,
5252
and accumulating child directory counts in the parent directories:
5353
`files,10,cumulative`.
5454

55+
diff.statGraphWidth::
56+
Limit the width of the graph part in --stat output. If set, applies
57+
to all commands generating --stat outuput except format-patch.
58+
5559
diff.external::
5660
If this config variable is set, diff generation is not
5761
performed using the internal diff machinery, but using the

Documentation/diff-options.txt

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,19 @@ endif::git-format-patch[]
5656
Generate a diff using the "histogram diff" algorithm.
5757

5858
--stat[=<width>[,<name-width>[,<count>]]]::
59-
Generate a diffstat. You can override the default
60-
output width for 80-column terminal by `--stat=<width>`.
61-
The width of the filename part can be controlled by
62-
giving another width to it separated by a comma.
59+
Generate a diffstat. By default, as much space as necessary
60+
will be used for the filename part, and the rest for the graph
61+
part. Maximum width defaults to terminal width, or 80 columns
62+
if not connected to a terminal, and can be overriden by
63+
`<width>`. The width of the filename part can be limited by
64+
giving another width `<name-width>` after a comma. The width
65+
of the graph part can be limited by using
66+
`--stat-graph-width=<width>` (affects all commands generating
67+
a stat graph) or by setting `diff.statGraphWidth=<width>`
68+
(does not affect `git format-patch`).
6369
By giving a third parameter `<count>`, you can limit the
64-
output to the first `<count>` lines, followed by
65-
`...` if there are more.
70+
output to the first `<count>` lines, followed by `...` if
71+
there are more.
6672
+
6773
These parameters can also be set individually with `--stat-width=<width>`,
6874
`--stat-name-width=<name-width>` and `--stat-count=<count>`.

builtin/diff.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
285285
/* Otherwise, we are doing the usual "git" diff */
286286
rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
287287

288+
/* Scale to real terminal size and respect statGraphWidth config */
289+
rev.diffopt.stat_width = -1;
290+
rev.diffopt.stat_graph_width = -1;
291+
288292
/* Default to let external and textconv be used */
289293
DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
290294
DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);

builtin/log.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ static void cmd_log_init_defaults(struct rev_info *rev)
7777
get_commit_format(fmt_pretty, rev);
7878
rev->verbose_header = 1;
7979
DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
80+
rev->diffopt.stat_width = -1; /* use full terminal width */
81+
rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */
8082
rev->abbrev_commit = default_abbrev_commit;
8183
rev->show_root_diff = default_show_root;
8284
rev->subject_prefix = fmt_patch_subject_prefix;
@@ -447,6 +449,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)
447449
rev.diff = 1;
448450
rev.always_show_header = 1;
449451
rev.no_walk = 1;
452+
rev.diffopt.stat_width = -1; /* Scale to real terminal size */
453+
450454
memset(&opt, 0, sizeof(opt));
451455
opt.def = "HEAD";
452456
opt.tweak = show_rev_tweak_rev;

builtin/merge.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,8 @@ static void finish(struct commit *head_commit,
399399
if (new_head && show_diffstat) {
400400
struct diff_options opts;
401401
diff_setup(&opts);
402+
opts.stat_width = -1; /* use full terminal width */
403+
opts.stat_graph_width = -1; /* respect statGraphWidth config */
402404
opts.output_format |=
403405
DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
404406
opts.detect_rename = DIFF_DETECT_RENAME;

contrib/completion/git-completion.bash

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,7 @@ _git_config ()
20922092
core.whitespace
20932093
core.worktree
20942094
diff.autorefreshindex
2095+
diff.statGraphWidth
20952096
diff.external
20962097
diff.ignoreSubmodules
20972098
diff.mnemonicprefix

diff.c

Lines changed: 87 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ static const char *external_diff_cmd_cfg;
3131
int diff_auto_refresh_index = 1;
3232
static int diff_mnemonic_prefix;
3333
static int diff_no_prefix;
34+
static int diff_stat_graph_width;
3435
static int diff_dirstat_permille_default = 30;
3536
static struct diff_options default_diff_options;
3637

@@ -156,6 +157,10 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
156157
diff_no_prefix = git_config_bool(var, value);
157158
return 0;
158159
}
160+
if (!strcmp(var, "diff.statgraphwidth")) {
161+
diff_stat_graph_width = git_config_int(var, value);
162+
return 0;
163+
}
159164
if (!strcmp(var, "diff.external"))
160165
return git_config_string(&external_diff_cmd_cfg, var, value);
161166
if (!strcmp(var, "diff.wordregex"))
@@ -1375,7 +1380,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
13751380
int i, len, add, del, adds = 0, dels = 0;
13761381
uintmax_t max_change = 0, max_len = 0;
13771382
int total_files = data->nr;
1378-
int width, name_width, count;
1383+
int width, name_width, graph_width, number_width = 4, count;
13791384
const char *reset, *add_c, *del_c;
13801385
const char *line_prefix = "";
13811386
int extra_shown = 0;
@@ -1389,25 +1394,15 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
13891394
line_prefix = msg->buf;
13901395
}
13911396

1392-
width = options->stat_width ? options->stat_width : 80;
1393-
name_width = options->stat_name_width ? options->stat_name_width : 50;
13941397
count = options->stat_count ? options->stat_count : data->nr;
13951398

1396-
/* Sanity: give at least 5 columns to the graph,
1397-
* but leave at least 10 columns for the name.
1398-
*/
1399-
if (width < 25)
1400-
width = 25;
1401-
if (name_width < 10)
1402-
name_width = 10;
1403-
else if (width < name_width + 15)
1404-
name_width = width - 15;
1405-
1406-
/* Find the longest filename and max number of changes */
14071399
reset = diff_get_color_opt(options, DIFF_RESET);
14081400
add_c = diff_get_color_opt(options, DIFF_FILE_NEW);
14091401
del_c = diff_get_color_opt(options, DIFF_FILE_OLD);
14101402

1403+
/*
1404+
* Find the longest filename and max number of changes
1405+
*/
14111406
for (i = 0; (i < count) && (i < data->nr); i++) {
14121407
struct diffstat_file *file = data->files[i];
14131408
uintmax_t change = file->added + file->deleted;
@@ -1428,19 +1423,72 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
14281423
}
14291424
count = i; /* min(count, data->nr) */
14301425

1431-
/* Compute the width of the graph part;
1432-
* 10 is for one blank at the beginning of the line plus
1433-
* " | count " between the name and the graph.
1426+
/*
1427+
* We have width = stat_width or term_columns() columns total.
1428+
* We want a maximum of min(max_len, stat_name_width) for the name part.
1429+
* We want a maximum of min(max_change, stat_graph_width) for the +- part.
1430+
* We also need 1 for " " and 4 + decimal_width(max_change)
1431+
* for " | NNNN " and one the empty column at the end, altogether
1432+
* 6 + decimal_width(max_change).
1433+
*
1434+
* If there's not enough space, we will use the smaller of
1435+
* stat_name_width (if set) and 5/8*width for the filename,
1436+
* and the rest for constant elements + graph part, but no more
1437+
* than stat_graph_width for the graph part.
1438+
* (5/8 gives 50 for filename and 30 for the constant parts + graph
1439+
* for the standard terminal size).
14341440
*
1435-
* From here on, name_width is the width of the name area,
1436-
* and width is the width of the graph area.
1441+
* In other words: stat_width limits the maximum width, and
1442+
* stat_name_width fixes the maximum width of the filename,
1443+
* and is also used to divide available columns if there
1444+
* aren't enough.
14371445
*/
1438-
name_width = (name_width < max_len) ? name_width : max_len;
1439-
if (width < (name_width + 10) + max_change)
1440-
width = width - (name_width + 10);
1446+
1447+
if (options->stat_width == -1)
1448+
width = term_columns();
14411449
else
1442-
width = max_change;
1450+
width = options->stat_width ? options->stat_width : 80;
1451+
1452+
if (options->stat_graph_width == -1)
1453+
options->stat_graph_width = diff_stat_graph_width;
14431454

1455+
/*
1456+
* Guarantee 3/8*16==6 for the graph part
1457+
* and 5/8*16==10 for the filename part
1458+
*/
1459+
if (width < 16 + 6 + number_width)
1460+
width = 16 + 6 + number_width;
1461+
1462+
/*
1463+
* First assign sizes that are wanted, ignoring available width.
1464+
*/
1465+
graph_width = (options->stat_graph_width &&
1466+
options->stat_graph_width < max_change) ?
1467+
options->stat_graph_width : max_change;
1468+
name_width = (options->stat_name_width > 0 &&
1469+
options->stat_name_width < max_len) ?
1470+
options->stat_name_width : max_len;
1471+
1472+
/*
1473+
* Adjust adjustable widths not to exceed maximum width
1474+
*/
1475+
if (name_width + number_width + 6 + graph_width > width) {
1476+
if (graph_width > width * 3/8 - number_width - 6)
1477+
graph_width = width * 3/8 - number_width - 6;
1478+
if (options->stat_graph_width &&
1479+
graph_width > options->stat_graph_width)
1480+
graph_width = options->stat_graph_width;
1481+
if (name_width > width - number_width - 6 - graph_width)
1482+
name_width = width - number_width - 6 - graph_width;
1483+
else
1484+
graph_width = width - number_width - 6 - name_width;
1485+
}
1486+
1487+
/*
1488+
* From here name_width is the width of the name area,
1489+
* and graph_width is the width of the graph area.
1490+
* max_change is used to scale graph properly.
1491+
*/
14441492
for (i = 0; i < count; i++) {
14451493
const char *prefix = "";
14461494
char *name = data->files[i]->print_name;
@@ -1496,18 +1544,18 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
14961544
adds += add;
14971545
dels += del;
14981546

1499-
if (width <= max_change) {
1547+
if (graph_width <= max_change) {
15001548
int total = add + del;
15011549

1502-
total = scale_linear(add + del, width, max_change);
1550+
total = scale_linear(add + del, graph_width, max_change);
15031551
if (total < 2 && add && del)
15041552
/* width >= 2 due to the sanity check */
15051553
total = 2;
15061554
if (add < del) {
1507-
add = scale_linear(add, width, max_change);
1555+
add = scale_linear(add, graph_width, max_change);
15081556
del = total - add;
15091557
} else {
1510-
del = scale_linear(del, width, max_change);
1558+
del = scale_linear(del, graph_width, max_change);
15111559
add = total - del;
15121560
}
15131561
}
@@ -3299,6 +3347,7 @@ static int stat_opt(struct diff_options *options, const char **av)
32993347
char *end;
33003348
int width = options->stat_width;
33013349
int name_width = options->stat_name_width;
3350+
int graph_width = options->stat_graph_width;
33023351
int count = options->stat_count;
33033352
int argcount = 1;
33043353

@@ -3327,6 +3376,16 @@ static int stat_opt(struct diff_options *options, const char **av)
33273376
name_width = strtoul(av[1], &end, 10);
33283377
argcount = 2;
33293378
}
3379+
} else if (!prefixcmp(arg, "-graph-width")) {
3380+
arg += strlen("-graph-width");
3381+
if (*arg == '=')
3382+
graph_width = strtoul(arg + 1, &end, 10);
3383+
else if (!*arg && !av[1])
3384+
die("Option '--stat-graph-width' requires a value");
3385+
else if (!*arg) {
3386+
graph_width = strtoul(av[1], &end, 10);
3387+
argcount = 2;
3388+
}
33303389
} else if (!prefixcmp(arg, "-count")) {
33313390
arg += strlen("-count");
33323391
if (*arg == '=')
@@ -3352,6 +3411,7 @@ static int stat_opt(struct diff_options *options, const char **av)
33523411
return 0;
33533412
options->output_format |= DIFF_FORMAT_DIFFSTAT;
33543413
options->stat_name_width = name_width;
3414+
options->stat_graph_width = graph_width;
33553415
options->stat_width = width;
33563416
options->stat_count = count;
33573417
return argcount;

diff.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ struct diff_options {
129129

130130
int stat_width;
131131
int stat_name_width;
132+
int stat_graph_width;
132133
int stat_count;
133134
const char *word_regex;
134135
enum diff_words_type word_diff;

0 commit comments

Comments
 (0)