From 31c2373d39558f98222a1fd8b83ed74ccaa87161 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 1 Mar 2012 13:26:38 +0100 Subject: diff --stat: tests for long filenames and big change counts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for updates to the "diff --stat" that updates the logic to split the allotted columns into the name part and the graph part to make the output more readable, add a handful of tests to document the corner case behaviour in which long filenames and big changes are shown. When a pathname is so long that it cannot fit on the column, the current code truncates it to make sure that the graph part has enough room to show a meaningful graph. If the actual change is small (e.g. only one line changed), this results in the final output that is shorter than the width we aim for. Signed-off-by: Zbigniew Jędrzejewski-Szmek Signed-off-by: Junio C Hamano --- t/t4052-stat-output.sh | 182 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100755 t/t4052-stat-output.sh diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh new file mode 100755 index 0000000000..f766c47682 --- /dev/null +++ b/t/t4052-stat-output.sh @@ -0,0 +1,182 @@ +#!/bin/sh +# +# Copyright (c) 2012 Zbigniew Jędrzejewski-Szmek +# + +test_description='test --stat output of various commands' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-terminal.sh + +# 120 character name +name=aaaaaaaaaa +name=$name$name$name$name$name$name$name$name$name$name$name$name +test_expect_success 'preparation' ' + >"$name" && + git add "$name" && + git commit -m message && + echo a >"$name" && + git commit -m message "$name" +' + +while read cmd args +do + cat >expect <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + + EOF + test_expect_success "$cmd: a short graph bar does not extend to the full width" ' + git $cmd $args >output && + grep " | " output >actual && + test_cmp expect actual + ' + + cat >expect <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaa | 1 + + EOF + test_expect_success "$cmd --stat=width: name is chopped to leave room to the right of a short bar" ' + git $cmd $args --stat=40 >output && + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-width=width with long name" ' + git $cmd $args --stat-width=40 >output && + grep " | " output >actual && + test_cmp expect actual + ' + + cat >expect <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + + EOF + test_expect_success "$cmd --stat=...,name-width with long name" ' + git $cmd $args --stat=60,30 >output && + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-name-width with long name" ' + git $cmd $args --stat-name-width=30 >output && + grep " | " output >actual && + test_cmp expect actual + ' +done <<\EOF +format-patch -1 --stdout +diff HEAD^ HEAD --stat +show --stat +log -1 --stat +EOF + + +test_expect_success 'preparation for big change tests' ' + >abcd && + git add abcd && + git commit -m message && + i=0 && + while test $i -lt 1000 + do + echo $i && i=$(($i + 1)) + done >abcd && + git commit -m message abcd +' + +cat >expect80 <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF + +while read verb expect cmd args +do + test_expect_success "$cmd $verb COLUMNS (big change)" ' + COLUMNS=200 git $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' +done <<\EOF +ignores expect80 format-patch -1 --stdout +ignores expect80 diff HEAD^ HEAD --stat +ignores expect80 show --stat +ignores expect80 log -1 --stat +EOF + +cat >expect <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++ +EOF +while read cmd args +do + test_expect_success "$cmd --stat=width with big change" ' + git $cmd $args --stat=40 >output + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-width=width with big change" ' + git $cmd $args --stat-width=40 >output + grep " | " output >actual && + test_cmp expect actual + ' +done <<\EOF +format-patch -1 --stdout +diff HEAD^ HEAD --stat +show --stat +log -1 --stat +EOF + +test_expect_success 'preparation for long filename tests' ' + cp abcd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && + git add aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && + git commit -m message +' + +cat >expect <<'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++ +EOF +while read cmd args +do + test_expect_success "$cmd --stat=width with big change and long name favors name part" ' + git $cmd $args --stat-width=60 >output && + grep " | " output >actual && + test_cmp expect actual + ' +done <<\EOF +format-patch -1 --stdout +diff HEAD^ HEAD --stat +show --stat +log -1 --stat +EOF + +cat >expect80 <<'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++ +EOF +while read verb expect cmd args +do + test_expect_success "$cmd $verb COLUMNS (long filename)" ' + COLUMNS=200 git $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' +done <<\EOF +ignores expect80 format-patch -1 --stdout +ignores expect80 diff HEAD^ HEAD --stat +ignores expect80 show --stat +ignores expect80 log -1 --stat +EOF + +cat >expect <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF +test_expect_success 'merge --stat ignores COLUMNS (big change)' ' + git checkout -b branch HEAD^^ && + COLUMNS=100 git merge --stat --no-ff master^ >output && + grep " | " output >actual + test_cmp expect actual +' + +cat >expect <<'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++ +EOF +test_expect_success 'merge --stat ignores COLUMNS (long filename)' ' + COLUMNS=100 git merge --stat --no-ff master >output && + grep " | " output >actual + test_cmp expect actual +' + +test_done -- cgit v1.2.1 From af9fedc12873bf331019a502ed1fc944fa986713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 1 Mar 2012 13:26:39 +0100 Subject: diff --stat: use the full terminal width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Default to the real terminal width for diff --stat output, instead of the hard-coded 80 columns. Some projects (especially in Java), have long filename paths, with nested directories or long individual filenames. When files are renamed, the filename part in stat output can be almost useless. If the middle part between { and } is long (because the file was moved to a completely different directory), then most of the path would be truncated. It makes sense to detect and use the full terminal width and display full filenames if possible. The are commands like diff, show, and log, which can adapt the output to the terminal width. There are also commands like format-patch, whose output should be independent of the terminal width. Since it is safer to use the 80-column default, the real terminal width is only used if requested by the calling code by setting diffopts.stat_width=-1. Normally this value is 0, and can be set by the user only to a non-negative value, so -1 is safe to use internally. This patch only changes the diff builtin to use the full terminal width. Signed-off-by: Zbigniew Jędrzejewski-Szmek Signed-off-by: Junio C Hamano --- builtin/diff.c | 3 +++ diff.c | 5 ++++- t/t4052-stat-output.sh | 11 +++++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/builtin/diff.c b/builtin/diff.c index 387afa7568..81b6baec74 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -285,6 +285,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix) /* Otherwise, we are doing the usual "git" diff */ rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index; + /* Scale to real terminal size */ + rev.diffopt.stat_width = -1; + /* Default to let external and textconv be used */ DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL); DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV); diff --git a/diff.c b/diff.c index e0590a3056..74782770bc 100644 --- a/diff.c +++ b/diff.c @@ -1343,7 +1343,10 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) line_prefix = msg->buf; } - width = options->stat_width ? options->stat_width : 80; + 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; diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh index f766c47682..29c06e59a6 100755 --- a/t/t4052-stat-output.sh +++ b/t/t4052-stat-output.sh @@ -83,6 +83,10 @@ cat >expect80 <<'EOF' abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ EOF +cat >expect200 <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF + while read verb expect cmd args do test_expect_success "$cmd $verb COLUMNS (big change)" ' @@ -92,7 +96,7 @@ do ' done <<\EOF ignores expect80 format-patch -1 --stdout -ignores expect80 diff HEAD^ HEAD --stat +respects expect200 diff HEAD^ HEAD --stat ignores expect80 show --stat ignores expect80 log -1 --stat EOF @@ -146,6 +150,9 @@ EOF cat >expect80 <<'EOF' ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++ EOF +cat >expect200 <<'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF while read verb expect cmd args do test_expect_success "$cmd $verb COLUMNS (long filename)" ' @@ -155,7 +162,7 @@ do ' done <<\EOF ignores expect80 format-patch -1 --stdout -ignores expect80 diff HEAD^ HEAD --stat +respects expect200 diff HEAD^ HEAD --stat ignores expect80 show --stat ignores expect80 log -1 --stat EOF -- cgit v1.2.1 From 666c92a229de10f8bbfc33cf6f92aad8733f0002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 1 Mar 2012 13:26:40 +0100 Subject: show --stat: use the full terminal width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make show --stat behave like diff --stat and use the full terminal width. Signed-off-by: Zbigniew Jędrzejewski-Szmek Signed-off-by: Junio C Hamano --- builtin/log.c | 2 ++ t/t4052-stat-output.sh | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/builtin/log.c b/builtin/log.c index 7d1f6f88a0..d37ae2606e 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -447,6 +447,8 @@ int cmd_show(int argc, const char **argv, const char *prefix) rev.diff = 1; rev.always_show_header = 1; rev.no_walk = 1; + rev.diffopt.stat_width = -1; /* Scale to real terminal size */ + memset(&opt, 0, sizeof(opt)); opt.def = "HEAD"; opt.tweak = show_rev_tweak_rev; diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh index 29c06e59a6..56d3899d92 100755 --- a/t/t4052-stat-output.sh +++ b/t/t4052-stat-output.sh @@ -97,7 +97,7 @@ do done <<\EOF ignores expect80 format-patch -1 --stdout respects expect200 diff HEAD^ HEAD --stat -ignores expect80 show --stat +respects expect200 show --stat ignores expect80 log -1 --stat EOF @@ -163,7 +163,7 @@ do done <<\EOF ignores expect80 format-patch -1 --stdout respects expect200 diff HEAD^ HEAD --stat -ignores expect80 show --stat +respects expect200 show --stat ignores expect80 log -1 --stat EOF -- cgit v1.2.1 From 5e0ec15eb131075d0c3e61b33bcc7931bbc8bc08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 1 Mar 2012 13:26:41 +0100 Subject: log --stat: use the full terminal width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make log --stat behave like diff --stat and use the full terminal width. Signed-off-by: Zbigniew Jędrzejewski-Szmek Signed-off-by: Junio C Hamano --- builtin/log.c | 1 + t/t4052-stat-output.sh | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/builtin/log.c b/builtin/log.c index d37ae2606e..075a427b71 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -77,6 +77,7 @@ static void cmd_log_init_defaults(struct rev_info *rev) get_commit_format(fmt_pretty, rev); rev->verbose_header = 1; DIFF_OPT_SET(&rev->diffopt, RECURSIVE); + rev->diffopt.stat_width = -1; /* use full terminal width */ rev->abbrev_commit = default_abbrev_commit; rev->show_root_diff = default_show_root; rev->subject_prefix = fmt_patch_subject_prefix; diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh index 56d3899d92..f81d427db5 100755 --- a/t/t4052-stat-output.sh +++ b/t/t4052-stat-output.sh @@ -98,7 +98,7 @@ done <<\EOF ignores expect80 format-patch -1 --stdout respects expect200 diff HEAD^ HEAD --stat respects expect200 show --stat -ignores expect80 log -1 --stat +respects expect200 log -1 --stat EOF cat >expect <<'EOF' @@ -164,7 +164,7 @@ done <<\EOF ignores expect80 format-patch -1 --stdout respects expect200 diff HEAD^ HEAD --stat respects expect200 show --stat -ignores expect80 log -1 --stat +respects expect200 log -1 --stat EOF cat >expect <<'EOF' -- cgit v1.2.1 From 7a7159ace6c93ea6c55086dfc7ba7533a3e3c07d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 1 Mar 2012 13:26:42 +0100 Subject: merge --stat: use the full terminal width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make merge --stat behave like diff --stat and use the full terminal width. Signed-off-by: Zbigniew Jędrzejewski-Szmek Signed-off-by: Junio C Hamano --- builtin/merge.c | 1 + t/t4052-stat-output.sh | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/builtin/merge.c b/builtin/merge.c index b4fbc60e6d..b1cd90ccc3 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -399,6 +399,7 @@ static void finish(struct commit *head_commit, if (new_head && show_diffstat) { struct diff_options opts; diff_setup(&opts); + opts.stat_width = -1; /* use full terminal width */ opts.output_format |= DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; opts.detect_rename = DIFF_DETECT_RENAME; diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh index f81d427db5..954c16f0ac 100755 --- a/t/t4052-stat-output.sh +++ b/t/t4052-stat-output.sh @@ -168,9 +168,9 @@ respects expect200 log -1 --stat EOF cat >expect <<'EOF' - abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ EOF -test_expect_success 'merge --stat ignores COLUMNS (big change)' ' +test_expect_success 'merge --stat respects COLUMNS (big change)' ' git checkout -b branch HEAD^^ && COLUMNS=100 git merge --stat --no-ff master^ >output && grep " | " output >actual @@ -178,9 +178,9 @@ test_expect_success 'merge --stat ignores COLUMNS (big change)' ' ' cat >expect <<'EOF' - ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++ + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++++++++++++++++++++++ EOF -test_expect_success 'merge --stat ignores COLUMNS (long filename)' ' +test_expect_success 'merge --stat respects COLUMNS (long filename)' ' COLUMNS=100 git merge --stat --no-ff master >output && grep " | " output >actual test_cmp expect actual -- cgit v1.2.1 From 1b058bc30df5f79fe7449cacd8ae7128944327f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 1 Mar 2012 13:26:43 +0100 Subject: diff --stat: use a maximum of 5/8 for the filename part MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Junio C Hamano --- Documentation/diff-options.txt | 14 ++++--- diff.c | 90 ++++++++++++++++++++++++++++-------------- t/t4052-stat-output.sh | 16 ++++---- 3 files changed, 76 insertions(+), 44 deletions(-) diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 9f7cba2be6..6b9408fdd9 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -53,13 +53,15 @@ endif::git-format-patch[] Generate a diff using the "patience diff" algorithm. --stat[=[,[,]]]:: - Generate a diffstat. You can override the default - output width for 80-column terminal by `--stat=`. - 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 ``. The width of the filename part can be + limited by giving another width `` after a comma. By giving a third parameter ``, you can limit the - output to the first `` lines, followed by - `...` if there are more. + output to the first `` lines, followed by `...` if + there are more. + These parameters can also be set individually with `--stat-width=`, `--stat-name-width=` and `--stat-count=`. diff --git a/diff.c b/diff.c index 74782770bc..1656310ddc 100644 --- a/diff.c +++ b/diff.c @@ -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; @@ -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; @@ -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; @@ -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; } } diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh index 954c16f0ac..d0ed0dc403 100755 --- a/t/t4052-stat-output.sh +++ b/t/t4052-stat-output.sh @@ -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 @@ -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 @@ -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 @@ -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 && -- cgit v1.2.1 From c4432d5511f2897b56cd921632c86c1e2ca78159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 1 Mar 2012 13:26:44 +0100 Subject: diff --stat: add a test for output with COLUMNS=40 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for the introduction on the limit of the width of the graph part, a new test with COLUMNS=40 is added to check that the environment variable influences diff, show, log, but not format-patch. A new test is added because limiting the graph part makes COLUMNS=200 stop influencing diff --stat behaviour, which isn't wide enough now. The old test with COLUMNS=200 is retained to check for regressions. Signed-off-by: Zbigniew Jędrzejewski-Szmek Signed-off-by: Junio C Hamano --- t/t4052-stat-output.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh index d0ed0dc403..9a8f62dde3 100755 --- a/t/t4052-stat-output.sh +++ b/t/t4052-stat-output.sh @@ -101,6 +101,25 @@ respects expect200 show --stat respects expect200 log -1 --stat EOF +cat >expect40 <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++ +EOF + +while read verb expect cmd args +do + test_expect_success "$cmd $verb not enough COLUMNS (big change)" ' + COLUMNS=40 git $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' +done <<\EOF +ignores expect80 format-patch -1 --stdout +respects expect40 diff HEAD^ HEAD --stat +respects expect40 show --stat +respects expect40 log -1 --stat +EOF + + cat >expect <<'EOF' abcd | 1000 ++++++++++++++++++++++++++ EOF -- cgit v1.2.1 From 969fe57b844a514747c1d5d66e0698dc53ed473d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 1 Mar 2012 13:26:45 +0100 Subject: diff --stat: enable limiting of the graph part MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A new option --stat-graph-width= can be used to limit the width of the graph part even is more space is available. Up to columns will be used for the graph. If commits changing a lot of lines are displayed in a wide terminal window (200 or more columns), and the +- graph uses the full width, the output can be hard to comfortably scan with a horizontal movement of human eyes. Messages wrapped to about 80 columns would be interspersed with very long +- lines. It makes sense to limit the width of the graph part to a fixed value (e.g. 70 columns), even if more columns are available. Signed-off-by: Zbigniew Jędrzejewski-Szmek Signed-off-by: Junio C Hamano --- Documentation/diff-options.txt | 2 ++ diff.c | 23 +++++++++++++++++++++-- diff.h | 1 + t/t4052-stat-output.sh | 6 ++++++ 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 6b9408fdd9..d34efd5218 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -59,6 +59,8 @@ endif::git-format-patch[] or 80 columns if not connected to a terminal, and can be overriden by ``. The width of the filename part can be limited by giving another width `` after a comma. + The width of the graph part can be limited by using + `--stat-graph-width=`. By giving a third parameter ``, you can limit the output to the first `` lines, followed by `...` if there are more. diff --git a/diff.c b/diff.c index 1656310ddc..8f2abc8fe4 100644 --- a/diff.c +++ b/diff.c @@ -1375,13 +1375,15 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) /* * 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 want a maximum of min(max_change, stat_graph_width) for the +- 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. + * and the rest for constant elements + graph part, but no more + * than stat_graph_width for the graph part. * (5/8 gives 50 for filename and 30 for the constant parts + graph * for the standard terminal size). * @@ -1406,7 +1408,9 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) /* * First assign sizes that are wanted, ignoring available width. */ - graph_width = max_change; + graph_width = (options->stat_graph_width && + options->stat_graph_width < max_change) ? + options->stat_graph_width : max_change; name_width = (options->stat_name_width > 0 && options->stat_name_width < max_len) ? options->stat_name_width : max_len; @@ -1417,6 +1421,9 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) 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 (options->stat_graph_width && + graph_width > options->stat_graph_width) + graph_width = options->stat_graph_width; if (name_width > width - number_width - 6 - graph_width) name_width = width - number_width - 6 - graph_width; else @@ -3289,6 +3296,7 @@ static int stat_opt(struct diff_options *options, const char **av) char *end; int width = options->stat_width; int name_width = options->stat_name_width; + int graph_width = options->stat_graph_width; int count = options->stat_count; int argcount = 1; @@ -3317,6 +3325,16 @@ static int stat_opt(struct diff_options *options, const char **av) name_width = strtoul(av[1], &end, 10); argcount = 2; } + } else if (!prefixcmp(arg, "-graph-width")) { + arg += strlen("-graph-width"); + if (*arg == '=') + graph_width = strtoul(arg + 1, &end, 10); + else if (!*arg && !av[1]) + die("Option '--stat-graph-width' requires a value"); + else if (!*arg) { + graph_width = strtoul(av[1], &end, 10); + argcount = 2; + } } else if (!prefixcmp(arg, "-count")) { arg += strlen("-count"); if (*arg == '=') @@ -3342,6 +3360,7 @@ static int stat_opt(struct diff_options *options, const char **av) return 0; options->output_format |= DIFF_FORMAT_DIFFSTAT; options->stat_name_width = name_width; + options->stat_graph_width = graph_width; options->stat_width = width; options->stat_count = count; return argcount; diff --git a/diff.h b/diff.h index ae71f4ccf9..2021a1dfe6 100644 --- a/diff.h +++ b/diff.h @@ -129,6 +129,7 @@ struct diff_options { int stat_width; int stat_name_width; + int stat_graph_width; int stat_count; const char *word_regex; enum diff_words_type word_diff; diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh index 9a8f62dde3..3d823af38f 100755 --- a/t/t4052-stat-output.sh +++ b/t/t4052-stat-output.sh @@ -136,6 +136,12 @@ do grep " | " output >actual && test_cmp expect actual ' + + test_expect_success "$cmd --stat-graph--width with big change" ' + git $cmd $args --stat-graph-width=26 >output + grep " | " output >actual && + test_cmp expect actual + ' done <<\EOF format-patch -1 --stdout diff HEAD^ HEAD --stat -- cgit v1.2.1 From df44483a5dde62f4b49c80fd90d7fe12ddcfb084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 1 Mar 2012 13:26:46 +0100 Subject: diff --stat: add config option to limit graph width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Config option diff.statGraphWidth= is equivalent to --stat-graph-width=, except that the config option is ignored by format-patch. For the graph-width limiting to be usable, it should happen 'automatically' once configured, hence the config option. Nevertheless, graph width limiting only makes sense when used on a wide terminal, so it should not influence the output of format-patch, which adheres to the 80-column standard. Signed-off-by: Zbigniew Jędrzejewski-Szmek Signed-off-by: Junio C Hamano --- Documentation/diff-config.txt | 4 ++++ Documentation/diff-options.txt | 16 +++++++++------- builtin/diff.c | 3 ++- builtin/log.c | 1 + builtin/merge.c | 1 + contrib/completion/git-completion.bash | 1 + diff.c | 8 ++++++++ t/t4052-stat-output.sh | 6 ++++++ 8 files changed, 32 insertions(+), 8 deletions(-) diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt index 1aed79e7dc..6aa1be0478 100644 --- a/Documentation/diff-config.txt +++ b/Documentation/diff-config.txt @@ -52,6 +52,10 @@ directories with less than 10% of the total amount of changed files, and accumulating child directory counts in the parent directories: `files,10,cumulative`. +diff.statGraphWidth:: + Limit the width of the graph part in --stat output. If set, applies + to all commands generating --stat outuput except format-patch. + diff.external:: If this config variable is set, diff generation is not performed using the internal diff machinery, but using the diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index d34efd5218..87f0a5fb8f 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -54,13 +54,15 @@ endif::git-format-patch[] --stat[=[,[,]]]:: 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 ``. The width of the filename part can be - limited by giving another width `` after a comma. - The width of the graph part can be limited by using - `--stat-graph-width=`. + 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 + ``. The width of the filename part can be limited by + giving another width `` after a comma. The width + of the graph part can be limited by using + `--stat-graph-width=` (affects all commands generating + a stat graph) or by setting `diff.statGraphWidth=` + (does not affect `git format-patch`). By giving a third parameter ``, you can limit the output to the first `` lines, followed by `...` if there are more. diff --git a/builtin/diff.c b/builtin/diff.c index 81b6baec74..424c815f9b 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -285,8 +285,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix) /* Otherwise, we are doing the usual "git" diff */ rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index; - /* Scale to real terminal size */ + /* Scale to real terminal size and respect statGraphWidth config */ rev.diffopt.stat_width = -1; + rev.diffopt.stat_graph_width = -1; /* Default to let external and textconv be used */ DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL); diff --git a/builtin/log.c b/builtin/log.c index 075a427b71..8a47012b0b 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -78,6 +78,7 @@ static void cmd_log_init_defaults(struct rev_info *rev) rev->verbose_header = 1; DIFF_OPT_SET(&rev->diffopt, RECURSIVE); rev->diffopt.stat_width = -1; /* use full terminal width */ + rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */ rev->abbrev_commit = default_abbrev_commit; rev->show_root_diff = default_show_root; rev->subject_prefix = fmt_patch_subject_prefix; diff --git a/builtin/merge.c b/builtin/merge.c index b1cd90ccc3..34a5034a76 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -400,6 +400,7 @@ static void finish(struct commit *head_commit, struct diff_options opts; diff_setup(&opts); opts.stat_width = -1; /* use full terminal width */ + opts.stat_graph_width = -1; /* respect statGraphWidth config */ opts.output_format |= DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; opts.detect_rename = DIFF_DETECT_RENAME; diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 78be195838..bacf40365b 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -2118,6 +2118,7 @@ _git_config () core.whitespace core.worktree diff.autorefreshindex + diff.statGraphWidth diff.external diff.ignoreSubmodules diff.mnemonicprefix diff --git a/diff.c b/diff.c index 8f2abc8fe4..4525cdadd8 100644 --- a/diff.c +++ b/diff.c @@ -31,6 +31,7 @@ static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; static int diff_mnemonic_prefix; static int diff_no_prefix; +static int diff_stat_graph_width; static int diff_dirstat_permille_default = 30; static struct diff_options default_diff_options; @@ -156,6 +157,10 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) diff_no_prefix = git_config_bool(var, value); return 0; } + if (!strcmp(var, "diff.statgraphwidth")) { + diff_stat_graph_width = git_config_int(var, value); + return 0; + } if (!strcmp(var, "diff.external")) return git_config_string(&external_diff_cmd_cfg, var, value); if (!strcmp(var, "diff.wordregex")) @@ -1398,6 +1403,9 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) else width = options->stat_width ? options->stat_width : 80; + if (options->stat_graph_width == -1) + options->stat_graph_width = diff_stat_graph_width; + /* * Guarantee 3/8*16==6 for the graph part * and 5/8*16==10 for the filename part diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh index 3d823af38f..328aa8f398 100755 --- a/t/t4052-stat-output.sh +++ b/t/t4052-stat-output.sh @@ -112,6 +112,12 @@ do grep " | " output >actual && test_cmp "$expect" actual ' + + test_expect_success "$cmd $verb statGraphWidth config" ' + git -c diff.statGraphWidth=26 $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' done <<\EOF ignores expect80 format-patch -1 --stdout respects expect40 diff HEAD^ HEAD --stat -- cgit v1.2.1