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

[PATCH 5/5] progress: break too long progress bar lines

From
SZEDER Gábor <szeder.dev@gmail.com>
Date
Mar 25, 2019, 10:38 UTC
Message-ID
<20190325103844.26749-6-szeder.dev@gmail.com>
In-Reply-To
<20190325103844.26749-1-szeder.dev@gmail.com>

Some of the recently added progress indicators have quite long titles, which might be even longer when translated to some languages, and when they are shown while operating on bigger repositories, then the progress bar grows longer than the default 80 column terminal width.

When the progress bar exceeds the width of the terminal it gets line-wrapped, and after that the CR at the end doesn't return to the beginning of the progress bar, but to the first column of its last line. Consequently, the first line of the previously shown progress bar is not overwritten by the next, and we end up with a bunch of truncated progress bar lines scrolling past:

  $ LANG=es_ES.UTF-8 git commit-graph write
  Encontrando commits para commit graph entre los objetos empaquetados:   2% (1599
  Encontrando commits para commit graph entre los objetos empaquetados:   3% (1975
  Encontrando commits para commit graph entre los objetos empaquetados:   4% (2633
  Encontrando commits para commit graph entre los objetos empaquetados:   5% (3292
  [...]

Prevent this by breaking progress bars after the title once they exceed the width of the terminal, so the counter and optional percentage and throughput, i.e. all changing parts, are on the last line. Subsequent updates will from then on only refresh the changing parts, but not the title, and it will look like this:

  $ LANG=es_ES.UTF-8 ~/src/git/git commit-graph write
  Encontrando commits para commit graph entre los objetos empaquetados:
    100% (6584502/6584502), listo.
  Calculando números de generación de commit graph: 100% (824705/824705), listo.
  Escribiendo commit graph en 4 pasos: 100% (3298820/3298820), listo.

Note that the number of columns in the terminal is cached by term_columns(), so this might not kick in when it should when a terminal window is resized while the operation is running. Furthermore, this change won't help if the terminal is so narrow that the counters don't fit on one line, but I would put this in the "If it hurts, don't do it" box.

Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
---
 progress.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/progress.c b/progress.c
index b37a5398c5..36aaeea340 100644
--- a/progress.c
+++ b/progress.c
@@ -8,7 +8,7 @@
  * published by the Free Software Foundation.
  */
 
-#include "git-compat-util.h"
+#include "cache.h"
 #include "gettext.h"
 #include "progress.h"
 #include "strbuf.h"
@@ -37,6 +37,8 @@ struct progress {
 	struct throughput *throughput;
 	uint64_t start_ns;
 	struct strbuf counters_sb;
+	int title_len;
+	int split;
 };
 
 static volatile sig_atomic_t progress_update;
@@ -119,8 +121,22 @@ static void display(struct progress *progress, uint64_t n, const char *done)
 		const char *eol = done ? done : "\r";
 		int clear_len = counters_sb->len < last_count_len ?
 				last_count_len - counters_sb->len : 0;
-		fprintf(stderr, "%s: %s%-*s", progress->title,
-			counters_sb->buf, clear_len, eol);
+		int cols = term_columns();
+
+		if (progress->split) {
+			fprintf(stderr, "  %s%-*s", counters_sb->buf, clear_len,
+				eol);
+		} else if (!done &&
+			   cols < progress->title_len + counters_sb->len + 2) {
+			clear_len = progress->title_len + 1 < cols ?
+				    cols - progress->title_len - 1 : 0;
+			fprintf(stderr, "%s:%*s\n  %s%s", progress->title,
+					clear_len, "", counters_sb->buf, eol);
+			progress->split = 1;
+		} else {
+			fprintf(stderr, "%s: %s%-*s", progress->title,
+				counters_sb->buf, clear_len, eol);
+		}
 		fflush(stderr);
 		progress_update = 0;
 	}
@@ -225,6 +241,8 @@ static struct progress *start_progress_delay(const char *title, uint64_t total,
 	progress->throughput = NULL;
 	progress->start_ns = getnanotime();
 	strbuf_init(&progress->counters_sb, 0);
+	progress->title_len = strlen(title);
+	progress->split = 0;
 	set_progress_signal();
 	return progress;
 }
-- 
2.21.0.539.g07239c3a71.dirty
Previous: Jeff KingNext: Duy Nguyen
Message 13 of 38 in “Progress display fixes”
  1. 0/5 Progress display fixesSZEDER Gábor, Mar 25, 2019
  2. 1/5 progress: make display_progress() return voidSZEDER Gábor, Mar 25, 2019
  3. 3/5 progress: assemble percentage and counters in a strbuf before printingSZEDER Gábor, Mar 25, 2019
  4. Jeff KingMar 26, 2019
  5. SZEDER GáborMar 27, 2019
  6. Jeff KingMar 28, 2019
  7. 4/5 progress: clear previous progress update dynamicallySZEDER Gábor, Mar 25, 2019
  8. 2/5 progress: return early when in the backgroundSZEDER Gábor, Mar 25, 2019
  9. Ævar Arnfjörð BjarmasonMar 25, 2019
  10. SZEDER GáborMar 25, 2019
  11. Luke MewburnMar 26, 2019
  12. Jeff KingMar 26, 2019
  13. 5/5 progress: break too long progress bar linesSZEDER Gábor, Mar 25, 2019
  14. Duy NguyenMar 25, 2019
  15. SZEDER GáborMar 25, 2019
  16. Jeff KingMar 26, 2019
  17. 0/4 Progress display fixesSZEDER Gábor, Apr 1, 2019
  18. 1/4 progress: make display_progress() return voidSZEDER Gábor, Apr 1, 2019
  19. Eric SunshineApr 2, 2019
  20. 2/4 progress: assemble percentage and counters in a strbuf before printingSZEDER Gábor, Apr 1, 2019
  21. Eric SunshineApr 2, 2019
  22. Eric SunshineApr 2, 2019
  23. 4/4 progress: break too long progress bar linesSZEDER Gábor, Apr 1, 2019
  24. 3/4 progress: clear previous progress update dynamicallySZEDER Gábor, Apr 1, 2019
  25. Jeff KingApr 1, 2019
  26. SZEDER GáborApr 1, 2019
  27. Jeff KingApr 2, 2019
  28. 0/4 Progress display fixesSZEDER Gábor, Apr 5, 2019
  29. 1/4 progress: make display_progress() return voidSZEDER Gábor, Apr 5, 2019
  30. 2/4 progress: assemble percentage and counters in a strbuf before printingSZEDER Gábor, Apr 5, 2019
  31. 3/4 progress: clear previous progress update dynamicallySZEDER Gábor, Apr 5, 2019
  32. 4/4 progress: break too long progress bar linesSZEDER Gábor, Apr 5, 2019
  33. Jeff KingApr 5, 2019
  34. 0/4 Progress display fixesSZEDER Gábor, Apr 12, 2019
  35. 1/4 progress: make display_progress() return voidSZEDER Gábor, Apr 12, 2019
  36. 2/4 progress: assemble percentage and counters in a strbuf before printingSZEDER Gábor, Apr 12, 2019
  37. 3/4 progress: clear previous progress update dynamicallySZEDER Gábor, Apr 12, 2019
  38. 4/4 progress: break too long progress bar linesSZEDER Gábor, Apr 12, 2019

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.