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

[PATCH] git blame --progress

From
Junio C Hamano <junkio@cox.net>
Date
Jan 29, 2007, 02:35 UTC
Message-ID
<7vfy9ublvj.fsf_-_@assigned-by-dhcp.cox.net>
In-Reply-To
<45BD40AE.9020603@lsrfire.ath.cx>
[PATCH] git blame --progress

With --progress option, the command shows a fairly useless but amusing eye-candy while making the user wait.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 René Scharfe <rene.scharfe@lsrfire.ath.cx> writes:
 > Junio C Hamano schrieb:
 >> Although I'd apply it anyway, strictly speaking, I think this
 >> patch should not matter because any real Porcelain would be
 >> using this as an upstream of a pipe to its drawing engine.
 >> 
 >> Well, unless that Porcelain drives --incremental through a pair
 >> of ptys, but I do not think it is likely ;-).
 >
 > Ha!, didn't think of that.  I still like it more without a pager
 > even if run on a terminal, because then you can *see* that it's
 > really incremental (without needing to unset PAGER).  I'm a
 > non-believer. ;-)
 builtin-blame.c |   87 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 84 insertions(+), 3 deletions(-)
diff --git a/builtin-blame.c b/builtin-blame.c
index 02bda5e..cd54acf 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -17,7 +17,7 @@
 #include "xdiff-interface.h"
 
 static char blame_usage[] =
-"git-blame [-c] [-l] [-t] [-f] [-n] [-p] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [commit] [--] file\n"
+"git-blame [-c] [-l] [-t] [-f] [-n] [-p] [--progress] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [commit] [--] file\n"
 "  -c, --compatibility Use the same output mode as git-annotate (Default: off)\n"
 "  -b                  Show blank SHA-1 for boundary commits (Default: off)\n"
 "  -l, --long          Show long commit SHA1 (Default: off)\n"
@@ -29,6 +29,7 @@ static char blame_usage[] =
 "  -L n,m              Process only line range n,m, counting from 1\n"
 "  -M, -C              Find line movements within and across files\n"
 "  --incremental       Show blame entries as we find them, incrementally\n"
+"  --progress          Show fairly useless progress display\n"
 "  -S revs-file        Use revisions from revs-file instead of calling git-rev-list\n";
 
 static int longest_file;
@@ -39,6 +40,7 @@ static int max_score_digits;
 static int show_root;
 static int blank_boundary;
 static int incremental;
+static int eye_candy;
 
 #ifndef DEBUG
 #define DEBUG 0
@@ -1189,7 +1191,80 @@ static void write_filename_info(const char *path)
 	putchar('\n');
 }
 
-static void found_guilty_entry(struct blame_entry *ent)
+#define NUM_EC_SPOT 500
+#define NUM_EC_SPOT_PER_GROUP 10
+#define NUM_EC_SPOT_PER_ROW 50
+
+static int eye_candy_spots(struct scoreboard *sb)
+{
+	int num_lines = sb->num_lines;
+	if (NUM_EC_SPOT < num_lines)
+		return NUM_EC_SPOT;
+	return num_lines;
+}
+
+static void initialize_eye_candy(struct scoreboard *sb)
+{
+	int cnt = eye_candy_spots(sb);
+	int i, j;
+
+	fprintf(stderr, "\033[2JAssigning blame for %s\n", sb->path);
+	for (i = j = 0; i < cnt; i++) {
+		fputc('.', stderr);
+		j++;
+		if (NUM_EC_SPOT_PER_ROW <= j) {
+			j = 0;
+			fputc('\n', stderr);
+		}
+		else if ((j % NUM_EC_SPOT_PER_GROUP) == 0)
+			fputc(' ', stderr);
+	}
+	if (j)
+		fputc('\n', stderr);
+}
+
+static int eye_candy_spot(struct scoreboard *sb, int lno)
+{
+	int cnt = eye_candy_spots(sb);
+	return lno * cnt / sb->num_lines;
+}
+
+static void update_eye_candy(struct scoreboard *sb, struct blame_entry *ent)
+{
+	int cnt = eye_candy_spots(sb);
+	int spot_lo, spot_hi, spot;
+	struct blame_entry *lo, *hi;
+
+	for (lo = ent; lo->prev && lo->prev->guilty; lo = lo->prev)
+		;
+	spot_lo = eye_candy_spot(sb, lo->lno);
+	for (hi = ent; hi->next && hi->next->guilty; hi = hi->next)
+		;
+	spot_hi = eye_candy_spot(sb, hi->lno + hi->num_lines - 1);
+
+	for (spot = spot_lo; spot <= spot_hi; spot++) {
+		int spot_x, spot_y;
+
+		spot_x = spot % NUM_EC_SPOT_PER_ROW;
+		spot_x = spot_x + spot_x / NUM_EC_SPOT_PER_GROUP;
+
+		spot_y = spot / NUM_EC_SPOT_PER_ROW;
+		spot_y = (cnt / NUM_EC_SPOT_PER_ROW) - spot_y;
+		if (cnt < NUM_EC_SPOT && (cnt % NUM_EC_SPOT_PER_ROW))
+			spot_y++;
+
+		if (spot_y)
+			fprintf(stderr, "\033[%dA", spot_y);
+		if (spot_x)
+			fprintf(stderr, "\033[%dC", spot_x);
+		fputc('*', stderr);
+		fprintf(stderr, "\033[%dD", spot_x + 1);
+		if (spot_y)
+			fprintf(stderr, "\033[%dB", spot_y);
+	}
+}
+
+static void found_guilty_entry(struct scoreboard *sb, struct blame_entry *ent)
 {
 	if (ent->guilty)
 		return;
@@ -1218,6 +1293,8 @@ static void found_guilty_entry(struct blame_entry *ent)
 		}
 		write_filename_info(suspect->path);
 	}
+	else if (eye_candy)
+		update_eye_candy(sb, ent);
 }
 
 static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt)
@@ -1253,7 +1330,7 @@ static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt)
 		/* Take responsibility for the remaining entries */
 		for (ent = sb->ent; ent; ent = ent->next)
 			if (!cmp_suspect(ent->suspect, suspect))
-				found_guilty_entry(ent);
+				found_guilty_entry(sb, ent);
 		origin_decref(suspect);
 
 		if (DEBUG) /* sanity */
@@ -1768,6 +1845,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 		else if (!strcmp("-n", arg) ||
 			 !strcmp("--show-number", arg))
 			output_option |= OUTPUT_SHOW_NUMBER;
+		else if (!strcmp("--progress", arg))
+			eye_candy = 1;
 		else if (!strcmp("-p", arg) ||
 			 !strcmp("--porcelain", arg))
 			output_option |= OUTPUT_PORCELAIN;
@@ -1951,6 +2030,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 		die("reading graft file %s failed: %s",
 		    revs_file, strerror(errno));
 
+	if (eye_candy)
+		initialize_eye_candy(&sb);
 	assign_blame(&sb, &revs, opt);
 
 	if (incremental)
Previous: René ScharfeNext: Simon 'corecode' Schubert
Message 27 of 92 in “More precise tag following”
  1. Junio C HamanoJan 26, 2007
  2. Junio C HamanoJan 26, 2007
  3. Shawn O. PearceJan 27, 2007
  4. Junio C HamanoJan 27, 2007
  5. Jeff KingJan 27, 2007
  6. Nicolas PitreJan 27, 2007
  7. Simon 'corecode' SchubertJan 27, 2007
  8. Johannes SchindelinJan 27, 2007
  9. Simon 'corecode' SchubertJan 27, 2007
  10. Jakub NarebskiJan 27, 2007
  11. Linus TorvaldsJan 27, 2007
  12. Johannes SchindelinJan 27, 2007
  13. Simon 'corecode' SchubertJan 27, 2007
  14. Johannes SchindelinJan 27, 2007
  15. Simon 'corecode' SchubertJan 27, 2007
  16. Nicolas PitreJan 27, 2007
  17. Linus TorvaldsJan 27, 2007
  18. Linus TorvaldsJan 27, 2007
  19. Junio C HamanoJan 27, 2007
  20. Linus TorvaldsJan 27, 2007
  21. Junio C HamanoJan 28, 2007
  22. git-blame --porcelain: quote filename in c-style when needed.Junio C Hamano, Jan 28, 2007
  23. git-blame --incremental: don't use pagerRené Scharfe, Jan 28, 2007
  24. Junio C HamanoJan 28, 2007
  25. Junio C HamanoJan 28, 2007
  26. René ScharfeJan 29, 2007
  27. git blame --progressJunio C Hamano, Jan 29, 2007
  28. Simon 'corecode' SchubertJan 29, 2007
  29. Alex RiesenJan 29, 2007
  30. Matthias LederhoferJan 29, 2007
  31. Junio C HamanoJan 29, 2007
  32. René ScharfeJan 29, 2007
  33. Linus TorvaldsJan 29, 2007
  34. Junio C HamanoJan 30, 2007
  35. Linus TorvaldsJan 28, 2007
  36. Junio C HamanoJan 28, 2007
  37. Linus TorvaldsJan 28, 2007
  38. Junio C HamanoJan 28, 2007
  39. document 'blame --incremental'Junio C Hamano, Jan 28, 2007
  40. Junio C HamanoJan 28, 2007
  41. Jeff KingJan 28, 2007
  42. Junio C HamanoJan 30, 2007
  43. Shawn O. PearceJan 30, 2007
  44. Linus TorvaldsJan 30, 2007
  45. Junio C HamanoJan 28, 2007
  46. Shawn O. PearceJan 29, 2007
  47. Junio C HamanoJan 29, 2007
  48. Shawn O. PearceJan 29, 2007
  49. Linus TorvaldsJan 29, 2007
  50. Simon 'corecode' SchubertJan 29, 2007
  51. Theodore TsoJan 29, 2007
  52. Linus TorvaldsJan 29, 2007
  53. Jakub NarebskiJan 29, 2007
  54. Shawn O. PearceJan 29, 2007
  55. Jakub NarebskiJan 29, 2007
  56. Shawn O. PearceFeb 9, 2007
  57. David KågedalJan 31, 2007
  58. David KågedalJan 31, 2007
  59. Peter EriksenJan 31, 2007
  60. David KågedalJan 31, 2007
  61. Peter EriksenJan 31, 2007
  62. Jakub NarebskiJan 31, 2007
  63. David KågedalJan 31, 2007
  64. Simon 'corecode' SchubertJan 27, 2007
  65. Johannes SchindelinJan 27, 2007
  66. Simon 'corecode' SchubertJan 27, 2007
  67. Johannes SchindelinJan 27, 2007
  68. Jakub NarebskiJan 27, 2007
  69. Linus TorvaldsJan 27, 2007
  70. Linus TorvaldsJan 27, 2007
  71. Jakub NarebskiJan 27, 2007
  72. Linus TorvaldsJan 27, 2007
  73. Chris LeeJan 27, 2007
  74. Theodore TsoJan 28, 2007
  75. Linus TorvaldsJan 28, 2007
  76. David LangJan 28, 2007
  77. Nicolas PitreJan 29, 2007
  78. Linus TorvaldsJan 29, 2007
  79. Nicolas PitreJan 29, 2007
  80. Chris LeeJan 29, 2007
  81. Eric WongJan 29, 2007
  82. Eric WongJan 30, 2007
  83. Eric WongJan 30, 2007
  84. Eric WongJan 30, 2007
  85. Jakub NarebskiJan 27, 2007
  86. Jeff KingJan 27, 2007
  87. Linus TorvaldsJan 27, 2007
  88. Jeff KingJan 27, 2007
  89. Theodore TsoJan 28, 2007
  90. Randal L. SchwartzJan 28, 2007
  91. Jeff KingJan 28, 2007
  92. Shawn O. PearceJan 28, 2007

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.