From: Stefan Beller <sbeller@google.com>
To: sbeller@google.com
Cc: git@vger.kernel.org
Subject: [PATCHv2] builtin/blame: highlight interesting things
Date: Wed, 26 Jul 2017 16:04:25 -0700 [thread overview]
Message-ID: <20170726230425.24307-1-sbeller@google.com> (raw)
In-Reply-To: <20170613023151.9688-1-sbeller@google.com>
When using git-blame lots of lines contain redundant information, for
example in hunks that consist of multiple lines, the metadata (commit name,
author) are repeated. A reader may not be interested in those, so darken
(commit, author) information that is the same as in the previous line.
Choose a different approach for dates and imitate a 'temperature cool down'
for the dates. Compute the time range of all involved blamed commits
and then color
* lines of old commits dark (aged 0-50% in that time range)
* lines of medium age normal (50-80%)
* lines of new age red (80-95%)
* lines just introduced bright yellow (95-100%)
Signed-off-by: Stefan Beller <sbeller@google.com>
---
I played around with it a bit more, using a different color scheme
for dates, http://i.imgur.com/redhaLi.png
builtin/blame.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++----------
color.h | 1 +
2 files changed, 118 insertions(+), 23 deletions(-)
diff --git a/builtin/blame.c b/builtin/blame.c
index bda1a78726..552ea8e6f7 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -7,6 +7,7 @@
#include "cache.h"
#include "config.h"
+#include "color.h"
#include "builtin.h"
#include "commit.h"
#include "diff.h"
@@ -283,11 +284,14 @@ static void found_guilty_entry(struct blame_entry *ent, void *data)
}
static const char *format_time(timestamp_t time, const char *tz_str,
- int show_raw_time)
+ int show_raw_time, const char *color,
+ const char *reset)
{
static struct strbuf time_buf = STRBUF_INIT;
strbuf_reset(&time_buf);
+ if (color)
+ strbuf_addstr(&time_buf, color);
if (show_raw_time) {
strbuf_addf(&time_buf, "%"PRItime" %s", time, tz_str);
}
@@ -307,6 +311,8 @@ static const char *format_time(timestamp_t time, const char *tz_str,
time_width++)
strbuf_addch(&time_buf, ' ');
}
+ if (reset)
+ strbuf_addstr(&time_buf, reset);
return time_buf.buf;
}
@@ -319,7 +325,8 @@ static const char *format_time(timestamp_t time, const char *tz_str,
#define OUTPUT_SHOW_SCORE 0100
#define OUTPUT_NO_AUTHOR 0200
#define OUTPUT_SHOW_EMAIL 0400
-#define OUTPUT_LINE_PORCELAIN 01000
+#define OUTPUT_LINE_PORCELAIN 01000
+#define OUTPUT_SHOW_HIGHLIGHT 02000
static void emit_porcelain_details(struct blame_origin *suspect, int repeat)
{
@@ -367,19 +374,62 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
putchar('\n');
}
-static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int opt)
+static void emit_other(struct blame_scoreboard *sb,
+ struct blame_entry *ent,
+ struct blame_entry *prev,
+ int opt,
+ timestamp_t min_t,
+ timestamp_t max_t)
{
int cnt;
const char *cp;
struct blame_origin *suspect = ent->suspect;
- struct commit_info ci;
+ struct commit_info ci, prev_ci;
char hex[GIT_MAX_HEXSZ + 1];
int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);
+ int prev_same_field = 0;
+ const char *use_color, *reset_color = GIT_COLOR_RESET;
+ const char *date_color = NULL;
get_commit_info(suspect->commit, &ci, 1);
oid_to_hex_r(hex, &suspect->commit->object.oid);
cp = blame_nth_line(sb, ent->lno);
+
+ commit_info_init(&prev_ci);
+ if ((opt & OUTPUT_SHOW_HIGHLIGHT) && prev) {
+ get_commit_info(prev->suspect->commit, &prev_ci, 1);
+ if ((opt & OUTPUT_SHOW_SCORE) && ent->score == prev->score)
+ prev_same_field |= OUTPUT_SHOW_SCORE;
+ if ((opt & OUTPUT_SHOW_NAME) && prev->suspect && !strcmp(suspect->path, prev->suspect->path))
+ prev_same_field |= OUTPUT_SHOW_NAME;
+ if ((opt & OUTPUT_SHOW_NUMBER) &&
+ ent->s_lno == prev->s_lno + prev->num_lines - 1)
+ prev_same_field |= OUTPUT_SHOW_NUMBER;
+ if (!(opt & OUTPUT_NO_AUTHOR)) {
+ if (((opt & OUTPUT_SHOW_EMAIL) &&
+ !strcmp(ci.author_mail.buf, prev_ci.author_mail.buf)) ||
+ !strcmp(ci.author.buf, prev_ci.author.buf))
+ prev_same_field |= OUTPUT_NO_AUTHOR;
+ }
+ }
+ if (opt & OUTPUT_SHOW_HIGHLIGHT) {
+ if (max_t == min_t) {
+ date_color = GIT_COLOR_NORMAL;
+ } else {
+ float score = 1.0 * (ci.author_time - min_t);
+ score /= (1.0 * (max_t - min_t));
+ if (score > 0.95)
+ date_color = GIT_COLOR_BOLD_YELLOW;
+ else if (score > 0.8)
+ date_color = GIT_COLOR_RED;
+ else if (score > 0.5)
+ date_color = GIT_COLOR_NORMAL;
+ else
+ date_color = GIT_COLOR_DARK;
+ }
+ }
+
for (cnt = 0; cnt < ent->num_lines; cnt++) {
char ch;
int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev;
@@ -392,8 +442,12 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
putchar('^');
}
}
+ use_color = GIT_COLOR_NORMAL;
+ if ((opt & OUTPUT_SHOW_HIGHLIGHT) && cnt > 0)
+ use_color = GIT_COLOR_DARK;
+
+ printf("%s%.*s%s", use_color, length, hex, reset_color);
- printf("%.*s", length, hex);
if (opt & OUTPUT_ANNOTATE_COMPAT) {
const char *name;
if (opt & OUTPUT_SHOW_EMAIL)
@@ -402,20 +456,36 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
name = ci.author.buf;
printf("\t(%10s\t%10s\t%d)", name,
format_time(ci.author_time, ci.author_tz.buf,
- show_raw_time),
+ show_raw_time, NULL, NULL),
ent->lno + 1 + cnt);
} else {
- if (opt & OUTPUT_SHOW_SCORE)
- printf(" %*d %02d",
+ if (opt & OUTPUT_SHOW_SCORE) {
+ use_color = GIT_COLOR_NORMAL;
+ if ((opt & OUTPUT_SHOW_HIGHLIGHT) &&
+ (cnt > 0 || prev_same_field & OUTPUT_SHOW_SCORE))
+ use_color = GIT_COLOR_DARK;
+ printf(" %s%*d %02d%s", use_color,
max_score_digits, ent->score,
- ent->suspect->refcnt);
- if (opt & OUTPUT_SHOW_NAME)
- printf(" %-*.*s", longest_file, longest_file,
- suspect->path);
- if (opt & OUTPUT_SHOW_NUMBER)
- printf(" %*d", max_orig_digits,
- ent->s_lno + 1 + cnt);
-
+ ent->suspect->refcnt, reset_color);
+ }
+ if (opt & OUTPUT_SHOW_NAME) {
+ use_color = GIT_COLOR_NORMAL;
+ if ((opt & OUTPUT_SHOW_HIGHLIGHT) &&
+ (cnt > 0 || prev_same_field & OUTPUT_SHOW_NAME))
+ use_color = GIT_COLOR_DARK;
+ printf(" %s%-*.*s%s", use_color, longest_file,
+ longest_file,
+ suspect->path,
+ reset_color);
+ }
+ if (opt & OUTPUT_SHOW_NUMBER) {
+ use_color = GIT_COLOR_NORMAL;
+ if ((opt & OUTPUT_SHOW_HIGHLIGHT) &&
+ (cnt > 0 || prev_same_field & OUTPUT_SHOW_NUMBER))
+ use_color = GIT_COLOR_DARK;
+ printf(" %s%*d%s", use_color, max_orig_digits,
+ ent->s_lno + 1 + cnt, reset_color);
+ }
if (!(opt & OUTPUT_NO_AUTHOR)) {
const char *name;
int pad;
@@ -423,12 +493,21 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
name = ci.author_mail.buf;
else
name = ci.author.buf;
+
+ use_color = GIT_COLOR_NORMAL;
+ if ((opt & OUTPUT_SHOW_HIGHLIGHT) &&
+ (cnt > 0 || prev_same_field & OUTPUT_NO_AUTHOR))
+ use_color = GIT_COLOR_DARK;
+
pad = longest_author - utf8_strwidth(name);
- printf(" (%s%*s %10s",
- name, pad, "",
- format_time(ci.author_time,
- ci.author_tz.buf,
- show_raw_time));
+ printf(" %s(%s%*s%s", use_color,
+ name, pad, "",
+ reset_color);
+ printf(" %10s", format_time(ci.author_time,
+ ci.author_tz.buf,
+ show_raw_time,
+ date_color,
+ reset_color));
}
printf(" %*d) ",
max_digits, ent->lno + 1 + cnt);
@@ -448,7 +527,8 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
static void output(struct blame_scoreboard *sb, int option)
{
- struct blame_entry *ent;
+ struct blame_entry *ent, *prev = NULL;
+ timestamp_t min_t = TIME_MAX, max_t = 0;
if (option & OUTPUT_PORCELAIN) {
for (ent = sb->ent; ent; ent = ent->next) {
@@ -466,11 +546,24 @@ static void output(struct blame_scoreboard *sb, int option)
}
}
+ if (option & OUTPUT_SHOW_HIGHLIGHT) {
+ /* find oldest and youngest date for timestamp coloring */
+ struct commit_info ci;
+ for (ent = sb->ent; ent; ent = ent->next) {
+ get_commit_info(ent->suspect->commit, &ci, 1);
+ if (ci.author_time < min_t)
+ min_t = ci.author_time;
+ if (ci.author_time > max_t)
+ max_t = ci.author_time;
+ }
+ }
+
for (ent = sb->ent; ent; ent = ent->next) {
if (option & OUTPUT_PORCELAIN)
emit_porcelain(sb, ent, option);
else {
- emit_other(sb, ent, option);
+ emit_other(sb, ent, prev, option, min_t, max_t);
+ prev = ent;
}
}
}
@@ -681,6 +774,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
OPT_BIT('s', NULL, &output_option, N_("Suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR),
OPT_BIT('e', "show-email", &output_option, N_("Show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL),
OPT_BIT('w', NULL, &xdl_opts, N_("Ignore whitespace differences"), XDF_IGNORE_WHITESPACE),
+ OPT_BIT('h', "highlights", &output_option, N_("darken redundancy from previous line; highlight dates (Default: off)"), OUTPUT_SHOW_HIGHLIGHT),
/*
* The following two options are parsed by parse_revision_opt()
diff --git a/color.h b/color.h
index 90627650fc..bad2d7e29c 100644
--- a/color.h
+++ b/color.h
@@ -30,6 +30,7 @@ struct strbuf;
#define GIT_COLOR_BLUE "\033[34m"
#define GIT_COLOR_MAGENTA "\033[35m"
#define GIT_COLOR_CYAN "\033[36m"
+#define GIT_COLOR_DARK "\033[1;30m"
#define GIT_COLOR_BOLD_RED "\033[1;31m"
#define GIT_COLOR_BOLD_GREEN "\033[1;32m"
#define GIT_COLOR_BOLD_YELLOW "\033[1;33m"
--
2.14.0.rc0.3.g6c2e499285
next prev parent reply other threads:[~2017-07-26 23:04 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-06-13 2:31 [RFC/PATCH] builtin/blame: darken redundant line information Stefan Beller
2017-06-13 15:25 ` Junio C Hamano
2017-06-13 16:21 ` Stefan Beller
2017-06-13 17:00 ` Junio C Hamano
2017-06-13 17:13 ` Stefan Beller
2017-06-13 17:19 ` Junio C Hamano
2017-06-13 17:30 ` Stefan Beller
2017-06-13 17:33 ` Junio C Hamano
2017-06-13 17:44 ` Stefan Beller
2017-06-13 17:48 ` Junio C Hamano
2017-06-13 18:00 ` Stefan Beller
2017-06-13 18:06 ` Junio C Hamano
2017-06-13 23:42 ` Jonathan Tan
2017-06-14 0:33 ` Stefan Beller
2017-07-26 23:04 ` Stefan Beller [this message]
2017-07-26 23:29 ` [PATCHv2] builtin/blame: highlight interesting things Junio C Hamano
2017-07-26 23:57 ` Stefan Beller
2017-07-27 18:27 ` Junio C Hamano
2017-07-27 18:57 ` Stefan Beller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170726230425.24307-1-sbeller@google.com \
--to=sbeller@google.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).