Merge branch 're/color-default-reset'

"default" and "reset" colors have been added to our palette.

* re/color-default-reset:
  color: allow colors to be prefixed with "reset"
  color: support "default" to restore fg/bg color
  color: add missing GIT_COLOR_* white/black constants
This commit is contained in:
Junio C Hamano 2021-12-15 09:39:53 -08:00
commit 15209c8612
4 changed files with 80 additions and 13 deletions

View File

@ -262,11 +262,19 @@ color::
colors (at most two, one for foreground and one for background) colors (at most two, one for foreground and one for background)
and attributes (as many as you want), separated by spaces. and attributes (as many as you want), separated by spaces.
+ +
The basic colors accepted are `normal`, `black`, `red`, `green`, `yellow`, The basic colors accepted are `normal`, `black`, `red`, `green`,
`blue`, `magenta`, `cyan` and `white`. The first color given is the `yellow`, `blue`, `magenta`, `cyan`, `white` and `default`. The first
foreground; the second is the background. All the basic colors except color given is the foreground; the second is the background. All the
`normal` have a bright variant that can be specified by prefixing the basic colors except `normal` and `default` have a bright variant that can
color with `bright`, like `brightred`. be specified by prefixing the color with `bright`, like `brightred`.
+
The color `normal` makes no change to the color. It is the same as an
empty string, but can be used as the foreground color when specifying a
background color alone (for example, "normal red").
+
The color `default` explicitly resets the color to the terminal default,
for example to specify a cleared background. Although it varies between
terminals, this is usually not the same as setting to "white black".
+ +
Colors may also be given as numbers between 0 and 255; these use ANSI Colors may also be given as numbers between 0 and 255; these use ANSI
256-color mode (but note that not all terminals may support this). If 256-color mode (but note that not all terminals may support this). If
@ -280,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.
+ +

41
color.c
View File

@ -40,7 +40,7 @@ struct color {
enum { enum {
COLOR_UNSPECIFIED = 0, COLOR_UNSPECIFIED = 0,
COLOR_NORMAL, COLOR_NORMAL,
COLOR_ANSI, /* basic 0-7 ANSI colors */ COLOR_ANSI, /* basic 0-7 ANSI colors + "default" (value = 9) */
COLOR_256, COLOR_256,
COLOR_RGB COLOR_RGB
} type; } type;
@ -83,6 +83,27 @@ static int parse_ansi_color(struct color *out, const char *name, int len)
int i; int i;
int color_offset = COLOR_FOREGROUND_ANSI; int color_offset = COLOR_FOREGROUND_ANSI;
if (match_word(name, len, "default")) {
/*
* Restores to the terminal's default color, which may not be
* the same as explicitly setting "white" or "black".
*
* ECMA-48 - Control Functions \
* for Coded Character Sets, 5th edition (June 1991):
* > 39 default display colour (implementation-defined)
* > 49 default background colour (implementation-defined)
*
* Although not supported /everywhere/--according to terminfo,
* some terminals define "op" (original pair) as a blunt
* "set to white on black", or even "send full SGR reset"--
* it's standard and well-supported enough that if a user
* asks for it in their config this will do the right thing.
*/
out->type = COLOR_ANSI;
out->value = 9 + color_offset;
return 0;
}
if (strncasecmp(name, "bright", 6) == 0) { if (strncasecmp(name, "bright", 6) == 0) {
color_offset = COLOR_FOREGROUND_BRIGHT_ANSI; color_offset = COLOR_FOREGROUND_BRIGHT_ANSI;
name += 6; name += 6;
@ -234,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 };
@ -248,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 };
@ -270,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;
@ -295,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))

13
color.h
View File

@ -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;")
@ -24,30 +25,42 @@ struct strbuf;
#define GIT_COLOR_NORMAL "" #define GIT_COLOR_NORMAL ""
#define GIT_COLOR_RESET "\033[m" #define GIT_COLOR_RESET "\033[m"
#define GIT_COLOR_BOLD "\033[1m" #define GIT_COLOR_BOLD "\033[1m"
#define GIT_COLOR_BLACK "\033[30m"
#define GIT_COLOR_RED "\033[31m" #define GIT_COLOR_RED "\033[31m"
#define GIT_COLOR_GREEN "\033[32m" #define GIT_COLOR_GREEN "\033[32m"
#define GIT_COLOR_YELLOW "\033[33m" #define GIT_COLOR_YELLOW "\033[33m"
#define GIT_COLOR_BLUE "\033[34m" #define GIT_COLOR_BLUE "\033[34m"
#define GIT_COLOR_MAGENTA "\033[35m" #define GIT_COLOR_MAGENTA "\033[35m"
#define GIT_COLOR_CYAN "\033[36m" #define GIT_COLOR_CYAN "\033[36m"
#define GIT_COLOR_WHITE "\033[37m"
#define GIT_COLOR_DEFAULT "\033[39m"
#define GIT_COLOR_BOLD_BLACK "\033[1;30m"
#define GIT_COLOR_BOLD_RED "\033[1;31m" #define GIT_COLOR_BOLD_RED "\033[1;31m"
#define GIT_COLOR_BOLD_GREEN "\033[1;32m" #define GIT_COLOR_BOLD_GREEN "\033[1;32m"
#define GIT_COLOR_BOLD_YELLOW "\033[1;33m" #define GIT_COLOR_BOLD_YELLOW "\033[1;33m"
#define GIT_COLOR_BOLD_BLUE "\033[1;34m" #define GIT_COLOR_BOLD_BLUE "\033[1;34m"
#define GIT_COLOR_BOLD_MAGENTA "\033[1;35m" #define GIT_COLOR_BOLD_MAGENTA "\033[1;35m"
#define GIT_COLOR_BOLD_CYAN "\033[1;36m" #define GIT_COLOR_BOLD_CYAN "\033[1;36m"
#define GIT_COLOR_BOLD_WHITE "\033[1;37m"
#define GIT_COLOR_BOLD_DEFAULT "\033[1;39m"
#define GIT_COLOR_FAINT_BLACK "\033[2;30m"
#define GIT_COLOR_FAINT_RED "\033[2;31m" #define GIT_COLOR_FAINT_RED "\033[2;31m"
#define GIT_COLOR_FAINT_GREEN "\033[2;32m" #define GIT_COLOR_FAINT_GREEN "\033[2;32m"
#define GIT_COLOR_FAINT_YELLOW "\033[2;33m" #define GIT_COLOR_FAINT_YELLOW "\033[2;33m"
#define GIT_COLOR_FAINT_BLUE "\033[2;34m" #define GIT_COLOR_FAINT_BLUE "\033[2;34m"
#define GIT_COLOR_FAINT_MAGENTA "\033[2;35m" #define GIT_COLOR_FAINT_MAGENTA "\033[2;35m"
#define GIT_COLOR_FAINT_CYAN "\033[2;36m" #define GIT_COLOR_FAINT_CYAN "\033[2;36m"
#define GIT_COLOR_FAINT_WHITE "\033[2;37m"
#define GIT_COLOR_FAINT_DEFAULT "\033[2;39m"
#define GIT_COLOR_BG_BLACK "\033[40m"
#define GIT_COLOR_BG_RED "\033[41m" #define GIT_COLOR_BG_RED "\033[41m"
#define GIT_COLOR_BG_GREEN "\033[42m" #define GIT_COLOR_BG_GREEN "\033[42m"
#define GIT_COLOR_BG_YELLOW "\033[43m" #define GIT_COLOR_BG_YELLOW "\033[43m"
#define GIT_COLOR_BG_BLUE "\033[44m" #define GIT_COLOR_BG_BLUE "\033[44m"
#define GIT_COLOR_BG_MAGENTA "\033[45m" #define GIT_COLOR_BG_MAGENTA "\033[45m"
#define GIT_COLOR_BG_CYAN "\033[46m" #define GIT_COLOR_BG_CYAN "\033[46m"
#define GIT_COLOR_BG_WHITE "\033[47m"
#define GIT_COLOR_BG_DEFAULT "\033[49m"
#define GIT_COLOR_FAINT "\033[2m" #define GIT_COLOR_FAINT "\033[2m"
#define GIT_COLOR_FAINT_ITALIC "\033[2;3m" #define GIT_COLOR_FAINT_ITALIC "\033[2;3m"
#define GIT_COLOR_REVERSE "\033[7m" #define GIT_COLOR_REVERSE "\033[7m"

View File

@ -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"
@ -96,6 +100,18 @@ test_expect_success '24-bit colors' '
color "#ff00ff black" "[38;2;255;0;255;40m" color "#ff00ff black" "[38;2;255;0;255;40m"
' '
test_expect_success '"default" foreground' '
color "default" "[39m"
'
test_expect_success '"normal default" to clear background' '
color "normal default" "[49m"
'
test_expect_success '"default" can be combined with attributes' '
color "default default no-reverse bold" "[1;27;39;49m"
'
test_expect_success '"normal" yields no color at all"' ' test_expect_success '"normal" yields no color at all"' '
color "normal black" "[40m" color "normal black" "[40m"
' '