git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v3] diff --stat: use the full terminal width

From
Junio C Hamano <gitster@pobox.com>
Date
Feb 14, 2012, 01:08 UTC
Message-ID
<7vsjie9q77.fsf@alter.siamese.dyndns.org>
In-Reply-To
<1329057019-29983-1-git-send-email-zbyszek@in.waw.pl>
Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> writes:
Show 6 quoted lines
> Use as many columns as necessary for filenames, as few columns as
> necessary for change counts, and up to 40 columns for the histogram.
>
> Some projects (especially in Java), have long filename paths, with
> nested directories or long individual filenames. When files are
> renamed, the stat output can be almost useless. If the middle part
s/the stat output/the name part in &/;
Show 11 quoted lines
> 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.
>
> If commits changing a lot of lines are displayed in a wide terminal
> window (200 or more columns), and the +- graph would use the full
> width, the output would look bad. Messages wrapped to about 80
> columns would be interspersed with very long +- lines. It makes
> sense to limit the width of the histogram to a fixed value, even if more

I do not think the graph ++++++--- part is "histogram", which is a name for a specific type of graph that depicts a distribution of data.

We show the number of lines changed in a graph. Unless people come up with a better name, I would suggest calling it just "the graph part", or simply "the graph", throughout the patch.

Show 39 quoted lines
> columns are available. This fixed value is subjectively hard-coded to
> be 40 columns, which seems to work well for git.git and linux-2.6.git and
> some other repositories.
>
> If there isn't enough columns to print both the filename and the histogram,
> 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.
>
> Number of columns required for change counts is computed based on
> the maximum number of changed lines. This means that usually a few more
> columns will be available for the filenames and the histogram.
>
> Tests are added for various combinations of long filename and big change
> count and ways to specify widths.
>
> Signed-off-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
> ---
> ...
> diff --git a/diff.c b/diff.c
> index 7e15426..7abcbe9 100644
> --- a/diff.c
> +++ b/diff.c
> @@ -1327,7 +1327,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, count;
>  	const char *reset, *add_c, *del_c;
>  	const char *line_prefix = "";
>  	int extra_shown = 0;
> @@ -1341,25 +1341,13 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
>  		line_prefix = msg->buf;
>  	}
>  
> -	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;

It was somewhat distracting that you moved this "count =" below, which I do not think was necessary.

Show 9 quoted lines
> -	/* 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;

Removal of this sanity check is fine as long as sanity is kept by the new code in the later part. This was primarily so that people won't specify impossible values (e.g. what happens when name_width that is wider than the total width is given).

Show 10 quoted lines
> ...
> +	count = options->stat_count ? options->stat_count : data->nr;
> +
> @@ -1380,19 +1368,63 @@ 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.
Just a style, but in the more recent part of the codebase,
	/*
         * We have width = ....
is preferred.
Show 5 quoted lines
> +	 * We want a maximum of min(max_len, stat_name_width) for the name part.
> +	 * We want a maximum of min(max_change, 40) for the +- part.
> +	 * We also need 1 for " " and 4 + decimal_width(max_change)
> +	 * for " | NNNN " and one for " " at the end, altogether
> +	 * 6 + decimal_width(max_change).

The math looks correct but 'one for " " at the end' sounds as if you are printing a SP, but I think we simply avoid printing anything, so perhaps rewrite it to "we leave one column at the end" or something.

> +	 * If there's not enough space, we will use stat_name_width
> +	 * or 5/8*width for filename, and the rest for constant
"A or B for filename"---unclear how it picks between A or B.
"A or B, whichever is shorter, for filename", perhaps?
Show 19 quoted lines
> +	 * elements + histogram, but no more than 40 for the histogram.
> +	 * (5/8 gives 50 for filename and 30 for constant parts and
> +	 * histogram 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);
> -	else
> -		width = max_change;
> +	width = options->stat_width ? options->stat_width : term_columns();
> +	number_width = decimal_width(max_change);
> +	/* first sizes that are wanted */
Missing verb; "first, compute sizes that are ..."?
> +	graph_width = max_change < 40 ? max_change : 40;
> +	name_width = (options->stat_name_width > 0 &&
> +		      options->stat_name_width < max_len) ?
> +		options->stat_name_width : max_len;

mental note: name_width can be limited to max_len, and graph_width may be quite small when max_change is small. The total graph may be much smaller than the terminal width in such a case (and it is not a wasted space on the right hand side of the terminal).

Show 16 quoted lines
> +	/* sanity: guarantee a minimum and maximum width */
> +	if (width < 25)
> +		width = 25;
> +
> +	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 (graph_width > 40)
> +			graph_width =  40;
> +		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;
> +	}
>  
> +	/* More sanity: give at least 5 columns to the graph,

Hrm, having to have a separate "More sanity" is ugly, and you seem to already know it "This should already be satisfied...".

Can the logic above be tightened to make this "mopping up" unnecessary?
Show 8 quoted lines
> +	 * but leave at least 10 columns for the name.
> +	 *
> +	 * This should already be satisfied, unless max_change is
> +	 * really huge. If the window is extemely narrow, this might
> +	 * overflow available columns.
> +	 */
> +	if (name_width < 10 && max_len >= 10)
> +		name_width = 10;

The logic up to this point uses the same "25 <= width, 10 <= name_width" as the original to ensure that graph and the fixed part can use at least 15 columns. And then you do this:

> +	if (graph_width < 5 && max_change >= 5)
> +		graph_width = 5;

which means you are allocating 10 columns for fixed part. In the original, it was OK to give fixed number of columns for fixed part like this, as it always gave fixed 5 columns to show the number. Don't you need to adjust that 10 depending on the decimal_width(max_change), now your number_width flexes?

This patch also breaks many existing tests that need to be adjusted for the change to use decimal_width(max_change), which I do not care to fix up for you. Perhaps that part of the change needs to be split out into a separate patch.

Among the tests it breaks is t1200-tutorial.sh, which means that the tutorial document that has illustration of the sample output also needs to be updated before the final round.

Thanks.
Previous: Zbigniew Jędrzejewski-SzmekNext: Zbigniew Jędrzejewski-Szmek
Message 28 of 46 in “(unknown)”
  1. Zbigniew Jędrzejewski-SzmekFeb 9, 2012
  2. 1/4 Move git_version_string to help.c in preparation for diff changesZbigniew Jędrzejewski-Szmek, Feb 9, 2012
  3. Junio C HamanoFeb 10, 2012
  4. 2/4 help.c: make term_columns() cached and export itZbigniew Jędrzejewski-Szmek, Feb 9, 2012
  5. Junio C HamanoFeb 10, 2012
  6. 3/4 diff --stat: use the real terminal widthZbigniew Jędrzejewski-Szmek, Feb 9, 2012
  7. Junio C HamanoFeb 10, 2012
  8. Nguyen Thai Ngoc DuyFeb 10, 2012
  9. Zbigniew Jędrzejewski-SzmekFeb 10, 2012
  10. Nguyen Thai Ngoc DuyFeb 10, 2012
  11. 0/3 diff --stat: use the real terminal widthZbigniew Jędrzejewski-Szmek, Feb 10, 2012
  12. 1/3 Move git_version_string to help.c before diff changesZbigniew Jędrzejewski-Szmek, Feb 10, 2012
  13. Junio C HamanoFeb 10, 2012
  14. 2/3 help.c: make term_columns() cached and export itZbigniew Jędrzejewski-Szmek, Feb 10, 2012
  15. Nguyen Thai Ngoc DuyFeb 11, 2012
  16. Zbigniew Jędrzejewski-SzmekFeb 11, 2012
  17. Junio C HamanoFeb 12, 2012
  18. 1/2 Save terminal width before setting up pager and export term_columns()Zbigniew Jędrzejewski-Szmek, Feb 12, 2012
  19. Junio C HamanoFeb 13, 2012
  20. Nguyen Thai Ngoc DuyFeb 14, 2012
  21. Zbigniew Jędrzejewski-SzmekFeb 14, 2012
  22. 2/2 Rename lineno_width to decimal_width and export itZbigniew Jędrzejewski-Szmek, Feb 12, 2012
  23. Junio C HamanoFeb 13, 2012
  24. make lineno_width() from blame reusable for othersZbigniew Jędrzejewski-Szmek, Feb 14, 2012
  25. 3/3 diff --stat: use the real terminal widthZbigniew Jędrzejewski-Szmek, Feb 10, 2012
  26. Junio C HamanoFeb 10, 2012
  27. diff --stat: use the full terminal widthZbigniew Jędrzejewski-Szmek, Feb 12, 2012
  28. Junio C HamanoFeb 14, 2012
  29. 1/3 diff --stat: use the full terminal widthZbigniew Jędrzejewski-Szmek, Feb 14, 2012
  30. 2/3 diff --stat: better alignment for binary filesZbigniew Jędrzejewski-Szmek, Feb 14, 2012
  31. 3/3 Update diff --stat output in tests and tutorialZbigniew Jędrzejewski-Szmek, Feb 14, 2012
  32. Junio C HamanoFeb 15, 2012
  33. 1/3 diff --stat: tests for long filenames and big change countsZbigniew Jędrzejewski-Szmek, Feb 15, 2012
  34. 2/3 diff --stat: use the full terminal widthZbigniew Jędrzejewski-Szmek, Feb 15, 2012
  35. Junio C HamanoFeb 15, 2012
  36. 3/3 diff --stat: use less columns for change countsZbigniew Jędrzejewski-Szmek, Feb 15, 2012
  37. Nguyen Thai Ngoc DuyFeb 15, 2012
  38. Junio C HamanoFeb 15, 2012
  39. Junio C HamanoFeb 15, 2012
  40. Zbigniew Jędrzejewski-SzmekFeb 16, 2012
  41. Junio C HamanoFeb 16, 2012
  42. Junio C HamanoFeb 15, 2012
  43. Junio C HamanoFeb 15, 2012
  44. Johannes SixtFeb 15, 2012
  45. 4/4 diff --stat: use most of the space for file namesZbigniew Jędrzejewski-Szmek, Feb 9, 2012
  46. Junio C HamanoFeb 10, 2012

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.