color: allow multiple attributes

In configuration files (and "git config --color" command line), we
supported one and only one attribute after foreground and background
color.  Accept combinations of attributes, e.g.

    [diff.color]
            old = red reverse bold

Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Junio C Hamano 2010-02-27 18:56:38 -08:00
parent c5034673fd
commit 8b124135a9
3 changed files with 41 additions and 14 deletions

24
color.c
View File

@ -49,7 +49,7 @@ void color_parse_mem(const char *value, int value_len, const char *var,
{ {
const char *ptr = value; const char *ptr = value;
int len = value_len; int len = value_len;
int attr = -1; unsigned int attr = 0;
int fg = -2; int fg = -2;
int bg = -2; int bg = -2;
@ -58,7 +58,7 @@ void color_parse_mem(const char *value, int value_len, const char *var,
return; return;
} }
/* [fg [bg]] [attr] */ /* [fg [bg]] [attr]... */
while (len > 0) { while (len > 0) {
const char *word = ptr; const char *word = ptr;
int val, wordlen = 0; int val, wordlen = 0;
@ -87,19 +87,27 @@ void color_parse_mem(const char *value, int value_len, const char *var,
goto bad; goto bad;
} }
val = parse_attr(word, wordlen); val = parse_attr(word, wordlen);
if (val < 0 || attr != -1) if (0 <= val)
attr |= (1 << val);
else
goto bad; goto bad;
attr = val;
} }
if (attr >= 0 || fg >= 0 || bg >= 0) { if (attr || fg >= 0 || bg >= 0) {
int sep = 0; int sep = 0;
int i;
*dst++ = '\033'; *dst++ = '\033';
*dst++ = '['; *dst++ = '[';
if (attr >= 0) {
*dst++ = '0' + attr; for (i = 0; attr; i++) {
sep++; unsigned bit = (1 << i);
if (!(attr & bit))
continue;
attr &= ~bit;
if (sep++)
*dst++ = ';';
*dst++ = '0' + i;
} }
if (fg >= 0) { if (fg >= 0) {
if (sep++) if (sep++)

16
color.h
View File

@ -1,8 +1,20 @@
#ifndef COLOR_H #ifndef COLOR_H
#define COLOR_H #define COLOR_H
/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ /* 2 + (2 * num_attrs) + 8 + 1 + 8 + 'm' + NUL */
#define COLOR_MAXLEN 24 /* "\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
/* /*
* This variable stores the value of color.ui * This variable stores the value of color.ui

View File

@ -8,14 +8,13 @@ test_description='Test diff/status color escape codes'
color() color()
{ {
git config diff.color.new "$1" && actual=$(git config --get-color no.such.slot "$1") &&
test "`git config --get-color diff.color.new`" = "$2" test "$actual" = "$2"
} }
invalid_color() invalid_color()
{ {
git config diff.color.new "$1" && test_must_fail git config --get-color no.such.slot "$1"
test -z "`git config --get-color diff.color.new 2>/dev/null`"
} }
test_expect_success 'reset' ' test_expect_success 'reset' '
@ -42,6 +41,14 @@ test_expect_success 'fg bg attr' '
color "blue red ul" "[4;34;41m" 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' ' test_expect_success '256 colors' '
color "254 bold 255" "[1;38;5;254;48;5;255m" color "254 bold 255" "[1;38;5;254;48;5;255m"
' '