From: Junio C Hamano Date: Sat, 20 Mar 2010 18:29:36 +0000 (-0700) Subject: Merge branch 'jc/color-attrs' X-Git-Tag: v1.7.1-rc0~52 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/d7173d942ea897b67ac9ba3bab2a0cc374684ca6?ds=inline;hp=-c Merge branch 'jc/color-attrs' * jc/color-attrs: color: allow multiple attributes --- d7173d942ea897b67ac9ba3bab2a0cc374684ca6 diff --combined color.c index 8f07fc9547,90268fb3c6..bcf4e2c192 --- a/color.c +++ b/color.c @@@ -1,6 -1,8 +1,6 @@@ #include "cache.h" #include "color.h" -#define COLOR_RESET "\033[m" - int git_use_color_default = 0; static int parse_color(const char *name, int len) @@@ -47,16 -49,16 +47,16 @@@ void color_parse_mem(const char *value { const char *ptr = value; int len = value_len; - int attr = -1; + unsigned int attr = 0; int fg = -2; int bg = -2; if (!strncasecmp(value, "reset", len)) { - strcpy(dst, "\033[m"); + strcpy(dst, GIT_COLOR_RESET); return; } - /* [fg [bg]] [attr] */ + /* [fg [bg]] [attr]... */ while (len > 0) { const char *word = ptr; int val, wordlen = 0; @@@ -85,19 -87,27 +85,27 @@@ goto bad; } val = parse_attr(word, wordlen); - if (val < 0 || attr != -1) + if (0 <= val) + attr |= (1 << val); + else goto bad; - attr = val; } - if (attr >= 0 || fg >= 0 || bg >= 0) { + if (attr || fg >= 0 || bg >= 0) { int sep = 0; + int i; *dst++ = '\033'; *dst++ = '['; - if (attr >= 0) { - *dst++ = '0' + attr; - sep++; + + for (i = 0; attr; i++) { + unsigned bit = (1 << i); + if (!(attr & bit)) + continue; + attr &= ~bit; + if (sep++) + *dst++ = ';'; + *dst++ = '0' + i; } if (fg >= 0) { if (sep++) @@@ -138,9 -148,6 +146,9 @@@ int git_config_colorbool(const char *va goto auto_color; } + if (!var) + return -1; + /* Missing or explicit false to turn off colorization */ if (!git_config_bool(var, value)) return 0; @@@ -176,7 -183,7 +184,7 @@@ static int color_vfprintf(FILE *fp, con r += fprintf(fp, "%s", color); r += vfprintf(fp, fmt, args); if (*color) - r += fprintf(fp, "%s", COLOR_RESET); + r += fprintf(fp, "%s", GIT_COLOR_RESET); if (trail) r += fprintf(fp, "%s", trail); return r; @@@ -218,7 -225,7 +226,7 @@@ int color_fwrite_lines(FILE *fp, const char *p = memchr(buf, '\n', count); if (p != buf && (fputs(color, fp) < 0 || fwrite(buf, p ? p - buf : count, 1, fp) != 1 || - fputs(COLOR_RESET, fp) < 0)) + fputs(GIT_COLOR_RESET, fp) < 0)) return -1; if (!p) return 0; diff --combined color.h index 3cb4b7fc89,e2988f4e93..bcb28cf10f --- a/color.h +++ b/color.h @@@ -1,25 -1,21 +1,37 @@@ #ifndef COLOR_H #define COLOR_H - /* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ - #define COLOR_MAXLEN 24 + /* 2 + (2 * num_attrs) + 8 + 1 + 8 + 'm' + NUL */ + /* "\033[1;2;4;5;7;38;5;2xx;48;5;2xxm\0" */ + /* + * The maximum length of ANSI color sequence we would generate: + * - leading ESC '[' 2 + * - attr + ';' 2 * 8 (e.g. "1;") + * - fg color + ';' 9 (e.g. "38;5;2xx;") + * - fg color + ';' 9 (e.g. "48;5;2xx;") + * - terminating 'm' NUL 2 + * + * The above overcounts attr (we only use 5 not 8) and one semicolon + * but it is close enough. + */ + #define COLOR_MAXLEN 40 +/* + * IMPORTANT: Due to the way these color codes are emulated on Windows, + * write them only using printf(), fprintf(), and fputs(). In particular, + * do not use puts() or write(). + */ +#define GIT_COLOR_NORMAL "" +#define GIT_COLOR_RESET "\033[m" +#define GIT_COLOR_BOLD "\033[1m" +#define GIT_COLOR_RED "\033[31m" +#define GIT_COLOR_GREEN "\033[32m" +#define GIT_COLOR_YELLOW "\033[33m" +#define GIT_COLOR_BLUE "\033[34m" +#define GIT_COLOR_MAGENTA "\033[35m" +#define GIT_COLOR_CYAN "\033[36m" +#define GIT_COLOR_BG_RED "\033[41m" + /* * This variable stores the value of color.ui */ @@@ -34,9 -30,7 +46,9 @@@ int git_color_default_config(const cha int git_config_colorbool(const char *var, const char *value, int stdout_is_tty); void color_parse(const char *value, const char *var, char *dst); void color_parse_mem(const char *value, int len, const char *var, char *dst); +__attribute__((format (printf, 3, 4))) int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); +__attribute__((format (printf, 3, 4))) int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); diff --combined t/t4026-color.sh index 5ade44c043,49eced20e7..d5ccdd0cf8 --- a/t/t4026-color.sh +++ b/t/t4026-color.sh @@@ -8,14 -8,13 +8,13 @@@ test_description='Test diff/status colo color() { - git config diff.color.new "$1" && - test "`git config --get-color diff.color.new`" = "$2" + actual=$(git config --get-color no.such.slot "$1") && + test "$actual" = "$2" } invalid_color() { - git config diff.color.new "$1" && - test -z "`git config --get-color diff.color.new 2>/dev/null`" + test_must_fail git config --get-color no.such.slot "$1" } test_expect_success 'reset' ' @@@ -42,6 -41,14 +41,14 @@@ test_expect_success 'fg bg attr' color "blue red ul" "[4;34;41m" ' + test_expect_success 'fg bg attr...' ' + color "blue bold dim ul blink reverse" "[1;2;4;5;7;34m" + ' + + test_expect_success 'long color specification' ' + color "254 255 bold dim ul blink reverse" "[1;2;4;5;7;38;5;254;48;5;255m" + ' + test_expect_success '256 colors' ' color "254 bold 255" "[1;38;5;254;48;5;255m" ' @@@ -66,21 -73,4 +73,21 @@@ test_expect_success 'extra character af invalid_color "dimX" ' +test_expect_success 'unknown color slots are ignored (diff)' ' + git config --unset diff.color.new + git config color.diff.nosuchslotwilleverbedefined white && + git diff --color +' + +test_expect_success 'unknown color slots are ignored (branch)' ' + git config color.branch.nosuchslotwilleverbedefined white && + git branch -a +' + +test_expect_success 'unknown color slots are ignored (status)' ' + git config color.status.nosuchslotwilleverbedefined white || exit + git status + case $? in 0|1) : ok ;; *) false ;; esac +' + test_done