Subject: [PATCH 1/5] Allow explicit ANSI codes for colors

From: Mark Lodato <[email-masked]>
Date: Fri, 26 Feb 2010 23:57:46 -0500

Allow explicit ANSI codes to be used in configuration options expecting
a color.  The form is "[...m", where "..." are characters in the ASCII
range 0x30 to 0x3f.  This allows users to specify more complex colors
(generically, SGR attributes) than our color language allows.  For
example, to get blinking, bold, underlined, italic, red text,
use "[5;1;4;3;31m".

Signed-off-by: Mark Lodato <[email-masked]>
---
 Documentation/config.txt |    4 ++++
 color.c                  |   16 ++++++++++++++++
 t/t4026-color.sh         |   18 ++++++++++++++++++
 3 files changed, 38 insertions(+), 0 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 664de6b..fed18cb 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -663,6 +663,10 @@ accepted are `normal`, `black`, `red`, `green`, `yellow`, `blue`,
 `blink` and `reverse`.  The first color given is the foreground; the
 second is the background.  The position of the attribute, if any,
 doesn't matter.
++
+Alternatively, a raw ANSI color code (SGR attribute) may be specified, in the
+form `[...m` (no escape character).  The `...` is a set of characters in the
+ASCII range 0x30 to 0x3f.
 
 color.diff::
 	When set to `always`, always use colors in patch.
diff --git a/color.c b/color.c
index 62977f4..1b42d9a 100644
--- a/color.c
+++ b/color.c
@@ -56,6 +56,22 @@ void color_parse_mem(const char *value, int value_len, const char *var,
 		return;
 	}
 
+	/* If "[...m", use this as the attribute string directly */
+	if (value_len >= 2 && value[0] == '[' && value[value_len-1] == 'm') {
+		int i;
+		for (i = 1; i < value_len-1; i++)
+			if (value[i] < 0x30 || value[i] >= 0x40)
+				goto parse;
+		if (value_len + 2 > COLOR_MAXLEN)
+			die("color value '%.*s' too long for variable '%s'",
+			    value_len, value, var);
+		*dst = '\033';
+		memcpy(dst+1, value, value_len);
+		*(dst+1+value_len) = 0;
+		return;
+	}
+
+parse:
 	/* [fg [bg]] [attr] */
 	while (len > 0) {
 		const char *word = ptr;
diff --git a/t/t4026-color.sh b/t/t4026-color.sh
index 5ade44c..754716f 100755
--- a/t/t4026-color.sh
+++ b/t/t4026-color.sh
@@ -46,6 +46,14 @@ test_expect_success '256 colors' '
 	color "254 bold 255" "[1;38;5;254;48;5;255m"
 '
 
+test_expect_success 'explicit attribute' '
+	color "[123;456;7890m" "[123;456;7890m"
+'
+
+test_expect_success 'explicit attribute maximum length' '
+	color "[00000000000000000000m" "[00000000000000000000m"
+'
+
 test_expect_success 'color too small' '
 	invalid_color "-2"
 '
@@ -66,6 +74,16 @@ test_expect_success 'extra character after attribute' '
 	invalid_color "dimX"
 '
 
+test_expect_success 'explicit attribute invalid characters' '
+	invalid_color "[/m" &&
+	invalid_color "[@m" &&
+	invalid_color "[mm"
+'
+
+test_expect_success 'explicit attribute too long' '
+	invalid_color "[000000000000000000000m"
+'
+
 test_expect_success 'unknown color slots are ignored (diff)' '
 	git config --unset diff.color.new
 	git config color.diff.nosuchslotwilleverbedefined white &&
-- 
1.7.0