diff --git a/Documentation/config.txt b/Documentation/config.txt index af2ae4cc02..fc78139c21 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -170,6 +170,9 @@ The position of any attributes with respect to the colors be turned off by prefixing them with `no` or `no-` (e.g., `noreverse`, `no-ul`, etc). + +An empty color string produces no color effect at all. This can be used +to avoid coloring specific elements without disabling color entirely. ++ For git's pre-defined color slots, the attributes are meant to be reset at the beginning of each item in the colored output. So setting `color.decorate.branch` to `black` will paint that branch name in a @@ -2036,6 +2039,10 @@ log.follow:: i.e. it cannot be used to follow multiple files and does not work well on non-linear history. +log.graphColors:: + A list of colors, separated by commas, that can be used to draw + history lines in `git log --graph`. + log.showRoot:: If true, the initial commit will be shown as a big creation event. This is equivalent to a diff against an empty tree. diff --git a/color.c b/color.c index 1b95e6b2a7..dee61557e0 100644 --- a/color.c +++ b/color.c @@ -207,7 +207,17 @@ int color_parse_mem(const char *value, int value_len, char *dst) struct color fg = { COLOR_UNSPECIFIED }; struct color bg = { COLOR_UNSPECIFIED }; - if (!strncasecmp(value, "reset", len)) { + while (len > 0 && isspace(*ptr)) { + ptr++; + len--; + } + + if (!len) { + dst[0] = '\0'; + return 0; + } + + if (!strncasecmp(ptr, "reset", len)) { xsnprintf(dst, end - dst, GIT_COLOR_RESET); return 0; } diff --git a/graph.c b/graph.c index d4e8519c90..0649007704 100644 --- a/graph.c +++ b/graph.c @@ -3,6 +3,7 @@ #include "color.h" #include "graph.h" #include "revision.h" +#include "argv-array.h" /* Internal API */ @@ -79,6 +80,26 @@ static void graph_show_line_prefix(const struct diff_options *diffopt) static const char **column_colors; static unsigned short column_colors_max; +static void parse_graph_colors_config(struct argv_array *colors, const char *string) +{ + const char *end, *start; + + start = string; + end = string + strlen(string); + while (start < end) { + const char *comma = strchrnul(start, ','); + char color[COLOR_MAXLEN]; + + if (!color_parse_mem(start, comma - start, color)) + argv_array_push(colors, color); + else + warning(_("ignore invalid color '%.*s' in log.graphColors"), + (int)(comma - start), start); + start = comma + 1; + } + argv_array_push(colors, GIT_COLOR_RESET); +} + void graph_set_column_colors(const char **colors, unsigned short colors_max) { column_colors = colors; @@ -238,9 +259,22 @@ struct git_graph *graph_init(struct rev_info *opt) { struct git_graph *graph = xmalloc(sizeof(struct git_graph)); - if (!column_colors) - graph_set_column_colors(column_colors_ansi, - column_colors_ansi_max); + if (!column_colors) { + char *string; + if (git_config_get_string("log.graphcolors", &string)) { + /* not configured -- use default */ + graph_set_column_colors(column_colors_ansi, + column_colors_ansi_max); + } else { + static struct argv_array custom_colors = ARGV_ARRAY_INIT; + argv_array_clear(&custom_colors); + parse_graph_colors_config(&custom_colors, string); + free(string); + /* graph_set_column_colors takes a max-index, not a count */ + graph_set_column_colors(custom_colors.argv, + custom_colors.argc - 1); + } + } graph->commit = NULL; graph->revs = opt; diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index deae948c76..5ffe78e920 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -380,4 +380,18 @@ test_expect_success 'patch mode ignores unmerged entries' ' test_cmp expected diff ' +test_expect_success 'diffs can be colorized' ' + git reset --hard && + + # force color even though the test script has no terminal + test_config color.ui always && + + echo content >test && + printf y | git add -p >output 2>&1 && + + # We do not want to depend on the exact coloring scheme + # git uses for diffs, so just check that we saw some kind of color. + grep "$(printf "\\033")" output +' + test_done diff --git a/t/t4026-color.sh b/t/t4026-color.sh index ec78c5e3ac..671e951ee5 100755 --- a/t/t4026-color.sh +++ b/t/t4026-color.sh @@ -6,10 +6,11 @@ test_description='Test diff/status color escape codes' . ./test-lib.sh +ESC=$(printf '\033') color() { actual=$(git config --get-color no.such.slot "$1") && - test "$actual" = "$2" + test "$actual" = "${2:+$ESC}$2" } invalid_color() @@ -21,6 +22,10 @@ test_expect_success 'reset' ' color "reset" "[m" ' +test_expect_success 'empty color is empty' ' + color "" "" +' + test_expect_success 'attribute before color name' ' color "bold red" "[1;31m" ' diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 1ccbd5948a..08ea725de3 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -359,6 +359,28 @@ test_expect_success 'log --graph --line-prefix="| | | " with merge' ' test_cmp expect actual ' +cat > expect.colors <<\EOF +* Merge branch 'side' +|\ +| * side-2 +| * side-1 +* | Second +* | sixth +* | fifth +* | fourth +|/ +* third +* second +* initial +EOF + +test_expect_success 'log --graph with merge with log.graphColors' ' + test_config log.graphColors " blue,invalid-color, cyan, red , " && + git log --color=always --graph --date-order --pretty=tformat:%s | + test_decode_color | sed "s/ *\$//" >actual && + test_cmp expect.colors actual +' + test_expect_success 'log --raw --graph -m with merge' ' git log --raw --graph --oneline -m master | head -n 500 >actual && grep "initial" actual