color: allow colors to be prefixed with "reset"
"reset" was previously treated as a standalone special color name representing `\e[m`. Now, it can apply to other color properties, allowing exact specifications without implicit attribute inheritance. For example, "reset green" now renders `\e[;32m`, which is interpreted as "reset everything; then set foreground to green". This means the background and other attributes are also reset to their defaults. Previously, this was impossible to represent in a single color: "reset" could be specified alone, or a color with attributes, but some thing like clearing a background color were impossible. There is a separate change that introduces the "default" color name to assist with that, but even then, the above could only to be represented by explicitly disabling each of the attributes: green default no-bold no-dim no-italic no-ul no-blink no-reverse no-strike Signed-off-by: Robert Estelle <robertestelle@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
05f1f41c9b
commit
de658515ae
@ -288,6 +288,11 @@ The position of any attributes with respect to the colors
|
|||||||
be turned off by prefixing them with `no` or `no-` (e.g., `noreverse`,
|
be turned off by prefixing them with `no` or `no-` (e.g., `noreverse`,
|
||||||
`no-ul`, etc).
|
`no-ul`, etc).
|
||||||
+
|
+
|
||||||
|
The pseudo-attribute `reset` resets all colors and attributes before
|
||||||
|
applying the specified coloring. For example, `reset green` will result
|
||||||
|
in a green foreground and default background without any active
|
||||||
|
attributes.
|
||||||
|
+
|
||||||
An empty color string produces no color effect at all. This can be used
|
An empty color string produces no color effect at all. This can be used
|
||||||
to avoid coloring specific elements without disabling color entirely.
|
to avoid coloring specific elements without disabling color entirely.
|
||||||
+
|
+
|
||||||
|
18
color.c
18
color.c
@ -255,6 +255,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
|
|||||||
const char *ptr = value;
|
const char *ptr = value;
|
||||||
int len = value_len;
|
int len = value_len;
|
||||||
char *end = dst + COLOR_MAXLEN;
|
char *end = dst + COLOR_MAXLEN;
|
||||||
|
unsigned int has_reset = 0;
|
||||||
unsigned int attr = 0;
|
unsigned int attr = 0;
|
||||||
struct color fg = { COLOR_UNSPECIFIED };
|
struct color fg = { COLOR_UNSPECIFIED };
|
||||||
struct color bg = { COLOR_UNSPECIFIED };
|
struct color bg = { COLOR_UNSPECIFIED };
|
||||||
@ -269,12 +270,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncasecmp(ptr, "reset", len)) {
|
/* [reset] [fg [bg]] [attr]... */
|
||||||
xsnprintf(dst, end - dst, GIT_COLOR_RESET);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [fg [bg]] [attr]... */
|
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
const char *word = ptr;
|
const char *word = ptr;
|
||||||
struct color c = { COLOR_UNSPECIFIED };
|
struct color c = { COLOR_UNSPECIFIED };
|
||||||
@ -291,6 +287,11 @@ int color_parse_mem(const char *value, int value_len, char *dst)
|
|||||||
len--;
|
len--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (match_word(word, wordlen, "reset")) {
|
||||||
|
has_reset = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!parse_color(&c, word, wordlen)) {
|
if (!parse_color(&c, word, wordlen)) {
|
||||||
if (fg.type == COLOR_UNSPECIFIED) {
|
if (fg.type == COLOR_UNSPECIFIED) {
|
||||||
fg = c;
|
fg = c;
|
||||||
@ -316,13 +317,16 @@ int color_parse_mem(const char *value, int value_len, char *dst)
|
|||||||
*dst++ = (x); \
|
*dst++ = (x); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
if (attr || !color_empty(&fg) || !color_empty(&bg)) {
|
if (has_reset || attr || !color_empty(&fg) || !color_empty(&bg)) {
|
||||||
int sep = 0;
|
int sep = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
OUT('\033');
|
OUT('\033');
|
||||||
OUT('[');
|
OUT('[');
|
||||||
|
|
||||||
|
if (has_reset)
|
||||||
|
sep++;
|
||||||
|
|
||||||
for (i = 0; attr; i++) {
|
for (i = 0; attr; i++) {
|
||||||
unsigned bit = (1 << i);
|
unsigned bit = (1 << i);
|
||||||
if (!(attr & bit))
|
if (!(attr & bit))
|
||||||
|
1
color.h
1
color.h
@ -6,6 +6,7 @@ struct strbuf;
|
|||||||
/*
|
/*
|
||||||
* The maximum length of ANSI color sequence we would generate:
|
* The maximum length of ANSI color sequence we would generate:
|
||||||
* - leading ESC '[' 2
|
* - leading ESC '[' 2
|
||||||
|
* - reset ';' .................1
|
||||||
* - attr + ';' 2 * num_attr (e.g. "1;")
|
* - attr + ';' 2 * num_attr (e.g. "1;")
|
||||||
* - no-attr + ';' 3 * num_attr (e.g. "22;")
|
* - no-attr + ';' 3 * num_attr (e.g. "22;")
|
||||||
* - fg color + ';' 17 (e.g. "38;2;255;255;255;")
|
* - fg color + ';' 17 (e.g. "38;2;255;255;255;")
|
||||||
|
@ -60,6 +60,10 @@ test_expect_success 'fg bg attr...' '
|
|||||||
color "blue bold dim ul blink reverse" "[1;2;4;5;7;34m"
|
color "blue bold dim ul blink reverse" "[1;2;4;5;7;34m"
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reset fg bg attr...' '
|
||||||
|
color "reset blue bold dim ul blink reverse" "[;1;2;4;5;7;34m"
|
||||||
|
'
|
||||||
|
|
||||||
# note that nobold and nodim are the same code (22)
|
# note that nobold and nodim are the same code (22)
|
||||||
test_expect_success 'attr negation' '
|
test_expect_success 'attr negation' '
|
||||||
color "nobold nodim noul noblink noreverse" "[22;24;25;27m"
|
color "nobold nodim noul noblink noreverse" "[22;24;25;27m"
|
||||||
|
Loading…
Reference in New Issue
Block a user