[PATCH] git blame --progress

Subsystems: the rest

DORMANTno replies

6 messages, 6 authors, 2016-06-15 · open the first message on its own page

[PATCH] git blame --progress

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:42:51

[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 <redacted>
---
 René Scharfe [off-list ref] 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)

Re: [PATCH] git blame --progress

From: Simon 'corecode' Schubert <hidden>
Date: 2016-06-15 22:42:51

Junio C Hamano wrote:
+	fprintf(stderr, "\033[2JAssigning blame for %s\n", sb->path);
are you sure that you want to hard code the escape sequence?  I guess the correct way would be to query terminfo.

cheers
  simon

-- 
Serve - BSD     +++  RENT this banner advert  +++    ASCII Ribbon   /"\
Work - Mac      +++  space for low €€€ NOW!1  +++      Campaign     \ /
Party Enjoy Relax   |   http://dragonflybsd.org      Against  HTML   \
Dude 2c 2 the max   !   http://golden-apple.biz       Mail + News   / \

Re: [PATCH] git blame --progress

From: Alex Riesen <hidden>
Date: 2016-06-15 22:42:51

On 1/29/07, Junio C Hamano [off-list ref] wrote:
[PATCH] git blame --progress

With  --progress option, the command shows a fairly useless but
amusing eye-candy while making the user wait.
It is not only amusing - it also gives the user a visual
information (not precise, but interesting) about something happening,
how fast is it happening and how long to wait.
I like it, even though I seldom use git-blame myself, it's the kind of
nice thing you have a fond memories afterwards.
Like the ascii graphics :)

Re: [PATCH] git blame --progress

From: Matthias Lederhofer <hidden>
Date: 2016-06-15 22:42:51

Junio C Hamano [off-list ref] wrote:
With  --progress option, the command shows a fairly useless but
amusing eye-candy while making the user wait.
Looks nice :)  It makes it much more comfortable to wait for the real
output.  Perhaps there should be a config option to enable the
eye-candy when git-blame is run on a terminal (e.g. (configoption &&
stdout is a tty && stderr is a tty) || --progress)?  Typing --progress
is annoying.

I also noticed that git-blame with --progress is slowed down a bit by
the terminal here; the output on stderr was ~400kb.

Re: [PATCH] git blame --progress

From: René Scharfe <hidden>
Date: 2016-06-15 22:42:51

Junio C Hamano schrieb:
[PATCH] git blame --progress

With  --progress option, the command shows a fairly useless but 
amusing eye-candy while making the user wait.
Nicely done, I like it.  Well, then again, I used to watch the progress
of filesystem defragmentors as a kid.  Ahem. :-P

The problem here is, of course, that we don't know how beforehand much
work needs to be done.  The indicator could be full of stars long before
the start of history is reached.

This could be helped somewhat by having three states instead of two:
unblamed (.), blamed (o) and just-now-blamed (*).  Each time new stars
are written you'd demote the other stars in the field to o's.  This way
you'll at least see something moving until the end, no matter how often
blame is pushed further down for already blamed lines.

This increases terminal bandwidth usage and on-screen activity, but not
necessarily the usefulness of this thing. :)

René

diff --git a/builtin-blame.c b/builtin-blame.c
index cd54acf..9bed52f 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -1229,18 +1229,9 @@ static int eye_candy_spot(struct scoreboard *sb, int lno)
 	return lno * cnt / sb->num_lines;
 }
 
-static void update_eye_candy(struct scoreboard *sb, struct blame_entry *ent)
+static void update_eye_candy_spots(int cnt, int spot_lo, int spot_hi, char c)
 {
-	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);
+	int spot;
 
 	for (spot = spot_lo; spot <= spot_hi; spot++) {
 		int spot_x, spot_y;
@@ -1257,13 +1248,35 @@ static void update_eye_candy(struct scoreboard *sb, struct blame_entry *ent)
 			fprintf(stderr, "\033[%dA", spot_y);
 		if (spot_x)
 			fprintf(stderr, "\033[%dC", spot_x);
-		fputc('*', stderr);
+		fputc(c, stderr);
 		fprintf(stderr, "\033[%dD", spot_x + 1);
 		if (spot_y)
 			fprintf(stderr, "\033[%dB", spot_y);
 	}
 }
 
+static void update_eye_candy(struct scoreboard *sb, struct blame_entry *ent)
+{
+	int cnt = eye_candy_spots(sb);
+	int spot_lo, spot_hi;
+	struct blame_entry *lo, *hi;
+	static int prev_cnt, prev_spot_lo, prev_spot_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);
+
+	update_eye_candy_spots(prev_cnt, prev_spot_lo, prev_spot_hi, 'o');
+	update_eye_candy_spots(cnt, spot_lo, spot_hi, '*');
+
+	prev_cnt = cnt;
+	prev_spot_lo = spot_lo;
+	prev_spot_hi = spot_hi;
+}
+
 static void found_guilty_entry(struct scoreboard *sb, struct blame_entry *ent)
 {
 	if (ent->guilty)

Re: [PATCH] git blame --progress

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2016-06-15 22:42:51


On Mon, 29 Jan 2007, René Scharfe wrote:
The problem here is, of course, that we don't know how beforehand much
work needs to be done.  The indicator could be full of stars long before
the start of history is reached.
Well, we do have an approximation for it: we know how many lines the file 
has, and we do know (although we don't actually track) how many lines 
we've blamed so far.

So it would be fairly easy to give at least a *rough* indication of 
"percent blamed" - although it doesn't necessarily say anything about how 
expensive that last 1% is going to be..

		Linus
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help