@ -24,6 +24,7 @@
@@ -24,6 +24,7 @@
#include "dir.h"
#include "progress.h"
#include "blame.h"
#include "string-list.h"
static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
@ -323,6 +324,7 @@ static const char *format_time(timestamp_t time, const char *tz_str,
@@ -323,6 +324,7 @@ static const char *format_time(timestamp_t time, const char *tz_str,
#define OUTPUT_SHOW_EMAIL 0400
#define OUTPUT_LINE_PORCELAIN 01000
#define OUTPUT_COLOR_LINE 02000
#define OUTPUT_SHOW_AGE_WITH_COLOR 04000
static void emit_porcelain_details(struct blame_origin *suspect, int repeat)
{
@ -370,6 +372,63 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
@@ -370,6 +372,63 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
putchar('\n');
}
static struct color_field {
timestamp_t hop;
char col[COLOR_MAXLEN];
} *colorfield;
static int colorfield_nr, colorfield_alloc;
static void parse_color_fields(const char *s)
{
struct string_list l = STRING_LIST_INIT_DUP;
struct string_list_item *item;
enum { EXPECT_DATE, EXPECT_COLOR } next = EXPECT_COLOR;
colorfield_nr = 0;
/* Ideally this would be stripped and split at the same time? */
string_list_split(&l, s, ',', -1);
ALLOC_GROW(colorfield, colorfield_nr + 1, colorfield_alloc);
for_each_string_list_item(item, &l) {
switch (next) {
case EXPECT_DATE:
colorfield[colorfield_nr].hop = approxidate(item->string);
next = EXPECT_COLOR;
colorfield_nr++;
ALLOC_GROW(colorfield, colorfield_nr + 1, colorfield_alloc);
break;
case EXPECT_COLOR:
if (color_parse(item->string, colorfield[colorfield_nr].col))
die(_("expecting a color: %s"), item->string);
next = EXPECT_DATE;
break;
}
}
if (next == EXPECT_COLOR)
die (_("must end with a color"));
colorfield[colorfield_nr].hop = TIME_MAX;
}
static void setup_default_color_by_age(void)
{
parse_color_fields("blue,12 month ago,white,1 month ago,red");
}
static void determine_line_heat(struct blame_entry *ent, const char **dest_color)
{
int i = 0;
struct commit_info ci;
get_commit_info(ent->suspect->commit, &ci, 1);
while (i < colorfield_nr && ci.author_time > colorfield[i].hop)
i++;
*dest_color = colorfield[i].col;
}
static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int opt)
{
int cnt;
@ -378,12 +437,19 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
@@ -378,12 +437,19 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
struct commit_info ci;
char hex[GIT_MAX_HEXSZ + 1];
int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);
const char *color = NULL, *reset = NULL;
const char *default_color = NULL, *color = NULL, *reset = NULL;
get_commit_info(suspect->commit, &ci, 1);
oid_to_hex_r(hex, &suspect->commit->object.oid);
cp = blame_nth_line(sb, ent->lno);
if (opt & OUTPUT_SHOW_AGE_WITH_COLOR) {
determine_line_heat(ent, &default_color);
color = default_color;
reset = GIT_COLOR_RESET;
}
for (cnt = 0; cnt < ent->num_lines; cnt++) {
char ch;
int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev;
@ -393,8 +459,8 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
@@ -393,8 +459,8 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
color = repeated_meta_color;
reset = GIT_COLOR_RESET;
} else {
color = NULL;
reset = NULL;
color = default_color ? default_color : NULL;
reset = default_color ? GIT_COLOR_RESET : NULL;
}
}
if (color)
@ -631,6 +697,10 @@ static int git_blame_config(const char *var, const char *value, void *cb)
@@ -631,6 +697,10 @@ static int git_blame_config(const char *var, const char *value, void *cb)
value);
return 0;
}
if (!strcmp(var, "color.blame.highlightrecent")) {
parse_color_fields(value);
return 0;
}
if (git_diff_heuristic_config(var, value, cb) < 0)
return -1;
@ -706,6 +776,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
@@ -706,6 +776,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
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(0, "color-lines", &output_option, N_("color redundant metadata from previous line differently"), OUTPUT_COLOR_LINE),
OPT_BIT(0, "color-by-age", &output_option, N_("color lines by age"), OUTPUT_SHOW_AGE_WITH_COLOR),
/*
* The following two options are parsed by parse_revision_opt()
@ -730,6 +801,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
@@ -730,6 +801,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
unsigned int range_i;
long anchor;
setup_default_color_by_age();
git_config(git_blame_config, &output_option);
init_revisions(&revs, NULL);
revs.date_mode = blame_date_mode;
@ -972,7 +1044,7 @@ parse_done:
@@ -972,7 +1044,7 @@ parse_done:
strcpy(repeated_meta_color, GIT_COLOR_CYAN);
}
if (output_option & OUTPUT_ANNOTATE_COMPAT)
output_option &= ~OUTPUT_COLOR_LINE;
output_option &= ~(OUTPUT_COLOR_LINE | OUTPUT_SHOW_AGE_WITH_COLOR);
output(&sb, output_option);
free((void *)sb.final_buf);