24
#include "dir.h"
25
#include "progress.h"
26
#include "blame.h"
27
+#include "string-list.h"
28
29
static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
30
324
#define OUTPUT_SHOW_EMAIL 0400
325
#define OUTPUT_LINE_PORCELAIN 01000
326
#define OUTPUT_COLOR_LINE 02000
327
+#define OUTPUT_SHOW_AGE_WITH_COLOR 04000
328
329
static void emit_porcelain_details(struct blame_origin *suspect, int repeat)
330
{
372
putchar('\n');
373
}
374
375
+static struct color_field {
376
+ timestamp_t hop;
377
+ char col[COLOR_MAXLEN];
378
+} *colorfield;
379
+static int colorfield_nr, colorfield_alloc;
380
+
381
+static void parse_color_fields(const char *s)
382
+{
383
+ struct string_list l = STRING_LIST_INIT_DUP;
384
+ struct string_list_item *item;
385
+ enum { EXPECT_DATE, EXPECT_COLOR } next = EXPECT_COLOR;
386
+
387
+ colorfield_nr = 0;
388
+
389
+ /* Ideally this would be stripped and split at the same time? */
390
+ string_list_split(&l, s, ',', -1);
391
+ ALLOC_GROW(colorfield, colorfield_nr + 1, colorfield_alloc);
392
+
393
+ for_each_string_list_item(item, &l) {
394
+ switch (next) {
395
+ case EXPECT_DATE:
396
+ colorfield[colorfield_nr].hop = approxidate(item->string);
397
+ next = EXPECT_COLOR;
398
+ colorfield_nr++;
399
+ ALLOC_GROW(colorfield, colorfield_nr + 1, colorfield_alloc);
400
+ break;
401
+ case EXPECT_COLOR:
402
+ if (color_parse(item->string, colorfield[colorfield_nr].col))
403
+ die(_("expecting a color: %s"), item->string);
404
+ next = EXPECT_DATE;
405
+ break;
406
+ }
407
+ }
408
+
409
+ if (next == EXPECT_COLOR)
410
+ die (_("must end with a color"));
411
+
412
+ colorfield[colorfield_nr].hop = TIME_MAX;
413
+}
414
+
415
+static void setup_default_color_by_age(void)
416
+{
417
+ parse_color_fields("blue,12 month ago,white,1 month ago,red");
418
+}
419
+
420
+static void determine_line_heat(struct blame_entry *ent, const char **dest_color)
421
+{
422
+ int i = 0;
423
+ struct commit_info ci;
424
+ get_commit_info(ent->suspect->commit, &ci, 1);
425
+
426
+ while (i < colorfield_nr && ci.author_time > colorfield[i].hop)
427
+ i++;
428
+
429
+ *dest_color = colorfield[i].col;
430
+}
431
+
432
static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int opt)
433
{
434
int cnt;
437
struct commit_info ci;
438
char hex[GIT_MAX_HEXSZ + 1];
439
int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);
381
- const char *color = NULL, *reset = NULL;
440
+ const char *default_color = NULL, *color = NULL, *reset = NULL;
441
442
get_commit_info(suspect->commit, &ci, 1);
443
oid_to_hex_r(hex, &suspect->commit->object.oid);
444
445
cp = blame_nth_line(sb, ent->lno);
446
+
447
+ if (opt & OUTPUT_SHOW_AGE_WITH_COLOR) {
448
+ determine_line_heat(ent, &default_color);
449
+ color = default_color;
450
+ reset = GIT_COLOR_RESET;
451
+ }
452
+
453
for (cnt = 0; cnt < ent->num_lines; cnt++) {
454
char ch;
455
int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev;
459
color = repeated_meta_color;
460
reset = GIT_COLOR_RESET;
461
} else {
396
- color = NULL;
397
- reset = NULL;
462
+ color = default_color ? default_color : NULL;
463
+ reset = default_color ? GIT_COLOR_RESET : NULL;
464
}
465
}
466
if (color)
697
value);
698
return 0;
699
}
700
+ if (!strcmp(var, "color.blame.highlightrecent")) {
701
+ parse_color_fields(value);
702
+ return 0;
703
+ }
704
705
if (git_diff_heuristic_config(var, value, cb) < 0)
706
return -1;
776
OPT_BIT('e', "show-email", &output_option, N_("Show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL),
777
OPT_BIT('w', NULL, &xdl_opts, N_("Ignore whitespace differences"), XDF_IGNORE_WHITESPACE),
778
OPT_BIT(0, "color-lines", &output_option, N_("color redundant metadata from previous line differently"), OUTPUT_COLOR_LINE),
779
+ OPT_BIT(0, "color-by-age", &output_option, N_("color lines by age"), OUTPUT_SHOW_AGE_WITH_COLOR),
780
781
/*
782
* The following two options are parsed by parse_revision_opt()
801
unsigned int range_i;
802
long anchor;
803
804
+ setup_default_color_by_age();
805
git_config(git_blame_config, &output_option);
806
init_revisions(&revs, NULL);
807
revs.date_mode = blame_date_mode;
1044
strcpy(repeated_meta_color, GIT_COLOR_CYAN);
1045
}
1046
if (output_option & OUTPUT_ANNOTATE_COMPAT)
975
- output_option &= ~OUTPUT_COLOR_LINE;
1047
+ output_option &= ~(OUTPUT_COLOR_LINE | OUTPUT_SHOW_AGE_WITH_COLOR);
1048
1049
output(&sb, output_option);
1050
free((void *)sb.final_buf);