Add italics, dim, reverse video to set_color (#3650)

* Add italics and dim modifier to set_color

* update documentation for set_color

* add reverse mode to set_color

* Use standout mode as fallback for reverse mode

* Apply patch from @Darkshadow2 adding additional modes
This commit is contained in:
Anders Rasmussen 2016-12-31 06:33:25 +11:00 committed by Aaron Gyes
parent 834fdf8666
commit b22842a52f
5 changed files with 170 additions and 8 deletions

View file

@ -21,15 +21,18 @@ The following options are available:
- `-b`, `--background` *COLOR* sets the background color.
- `-c`, `--print-colors` prints a list of the 16 named colors.
- `-o`, `--bold` sets bold mode.
- `-d`, `--dim` sets dim mode.
- `-i`, `--italics` sets italics mode.
- `-r`, `--reverse` sets reverse mode.
- `-u`, `--underline` sets underlined mode.
Using the *normal* keyword will reset foreground, background, and all formatting back to default.
Using the *normal* keyword will reset foreground, background, and all formatting back to default.
\subsection set_color-notes Notes
1. Using the *normal* keyword will reset both background and foreground colors to whatever is the default for the terminal.
2. Setting the background color only affects subsequently written characters. Fish provides no way to set the background color for the entire terminal window. Configuring the window background color (and other attributes such as its opacity) has to be done using whatever mechanisms the terminal provides.
3. Some terminals use the `--bold` escape sequence to switch to a brighter color set rather than increasing the weight of text.
3. Some terminals use the `--bold` escape sequence to switch to a brighter color set rather than increasing the weight of text.
4. `set_color` works by printing sequences of characters to *stdout*. If used in command substitution or a pipe, these characters will also be captured. This may or may not be desirable. Checking the exit code of `isatty stdout` before using `set_color` can be useful to decide not to colorize output in a script.
\subsection set_color-example Examples
@ -50,3 +53,5 @@ If terminfo reports 256 color support for a terminal, support will always be ena
Many terminals support 24-bit (i.e., true-color) color escape sequences. This includes modern xterm, Gnome Terminal, Konsole, and iTerm2. Fish attempts to detect such terminals through various means in `config.fish` You can explicitly force that support via `set fish_term24bit 1`.
The `set_color` command uses the terminfo database to look up how to change terminal colors on whatever terminal is in use. Some systems have old and incomplete terminfo databases, and may lack color information for terminals that support it. Fish will assume that all terminals can use the [ANSI X3.64](https://en.wikipedia.org/wiki/ANSI_escape_code) escape sequences if the terminfo definition indicates a color below 16 is not supported.
Support for italics, dim, reverse, and other modes is not guaranteed in all terminal emulators. Fish attempts to determine if the terminal supports these modes even if the terminfo database may not be up-to-date.

View file

@ -56,11 +56,14 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
{L"help", no_argument, 0, 'h'},
{L"bold", no_argument, 0, 'o'},
{L"underline", no_argument, 0, 'u'},
{L"italics", no_argument, 0, 'i'},
{L"dim", no_argument, 0, 'd'},
{L"reverse", no_argument, 0, 'r'},
{L"version", no_argument, 0, 'v'},
{L"print-colors", no_argument, 0, 'c'},
{0, 0, 0, 0}};
const wchar_t *short_options = L"b:hvocu";
const wchar_t *short_options = L"b:hvoidrcu";
int argc = builtin_count_args(argv);
@ -71,7 +74,7 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
}
const wchar_t *bgcolor = NULL;
bool bold = false, underline = false;
bool bold = false, underline = false, italics = false, dim = false, reverse = false;
int errret;
// Parse options to obtain the requested operation and the modifiers.
@ -99,6 +102,18 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
bold = true;
break;
}
case 'i': {
italics = true;
break;
}
case 'd': {
dim = true;
break;
}
case 'r': {
reverse = true;
break;
}
case 'u': {
underline = true;
break;
@ -128,7 +143,7 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
fgcolors.push_back(fg);
}
if (fgcolors.empty() && bgcolor == NULL && !bold && !underline) {
if (fgcolors.empty() && bgcolor == NULL && !bold && !underline && !italics && !dim && !reverse) {
streams.err.append_format(_(L"%ls: Expected an argument\n"), argv[0]);
return STATUS_BUILTIN_ERROR;
}
@ -171,6 +186,20 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
writembs(enter_underline_mode);
}
if (italics && enter_italics_mode) {
writembs(enter_italics_mode);
}
if (dim && enter_dim_mode) {
writembs(enter_dim_mode);
}
if (reverse && enter_reverse_mode) {
writembs(enter_reverse_mode);
} else if (reverse && enter_standout_mode) {
writembs(enter_standout_mode);
}
if (bgcolor != NULL && bg.is_normal()) {
write_color(rgb_color_t::black(), false /* not is_fg */);
writembs(tparm(exit_attribute_mode));

View file

@ -19,8 +19,8 @@ class rgb_color_t {
unsigned char type : 4;
// Flags
enum { flag_bold = 1 << 0, flag_underline = 1 << 1 };
unsigned char flags : 4;
enum { flag_bold = 1 << 0, flag_underline = 1 << 1, flag_italics = 1 << 2, flag_dim = 1 << 3, flag_reverse = 1 << 4 };
unsigned char flags : 5;
union {
unsigned char name_idx; // 0-10
@ -117,6 +117,39 @@ class rgb_color_t {
flags &= ~flag_underline;
}
/// Returns whether the color is italics.
bool is_italics() const { return static_cast<bool>(flags & flag_italics); }
/// Set whether the color is italics.
void set_italics(bool x) {
if (x)
flags |= flag_italics;
else
flags &= ~flag_italics;
}
/// Returns whether the color is dim.
bool is_dim() const { return static_cast<bool>(flags & flag_dim); }
/// Set whether the color is dim.
void set_dim(bool x) {
if (x)
flags |= flag_dim;
else
flags &= ~flag_dim;
}
/// Returns whether the color is reverse.
bool is_reverse() const { return static_cast<bool>(flags & flag_reverse); }
/// Set whether the color is reverse.
void set_reverse(bool x) {
if (x)
flags |= flag_reverse;
else
flags &= ~flag_reverse;
}
/// Compare two colors for equality.
bool operator==(const rgb_color_t &other) const {
return type == other.type && !memcmp(&data, &other.data, sizeof data);

View file

@ -275,6 +275,9 @@ rgb_color_t highlight_get_color(highlight_spec_t highlight, bool is_background)
else {
if (result2.is_bold()) result.set_bold(true);
if (result2.is_underline()) result.set_underline(true);
if (result2.is_italics()) result.set_italics(true);
if (result2.is_dim()) result.set_dim(true);
if (result2.is_reverse()) result.set_reverse(true);
}
}

View file

@ -173,9 +173,15 @@ void set_color(rgb_color_t c, rgb_color_t c2) {
static rgb_color_t last_color2 = rgb_color_t::normal();
static bool was_bold = false;
static bool was_underline = false;
static bool was_italics = false;
static bool was_dim = false;
static bool was_reverse = false;
bool bg_set = false, last_bg_set = false;
bool is_bold = false;
bool is_underline = false;
bool is_italics = false;
bool is_dim = false;
bool is_reverse = false;
// Test if we have at least basic support for setting fonts, colors and related bits - otherwise
// just give up...
@ -189,10 +195,22 @@ void set_color(rgb_color_t c, rgb_color_t c2) {
is_underline |= c.is_underline();
is_underline |= c2.is_underline();
is_italics |= c.is_italics();
is_italics |= c2.is_italics();
is_dim |= c.is_dim();
is_dim |= c2.is_dim();
is_reverse |= c.is_reverse();
is_reverse |= c2.is_reverse();
if (c.is_reset() || c2.is_reset()) {
c = c2 = normal;
was_bold = false;
was_underline = false;
was_italics = false;
was_dim = false;
was_reverse = false;
// If we exit attibute mode, we must first set a color, or previously coloured text might
// lose it's color. Terminals are weird...
write_foreground_color(0);
@ -207,6 +225,33 @@ void set_color(rgb_color_t c, rgb_color_t c2) {
last_color2 = normal;
was_bold = false;
was_underline = false;
was_italics = false;
was_dim = false;
was_reverse = false;
}
if (was_dim && !is_dim ) {
// Only way to exit dim mode is a reset of all attributes.
writembs(exit_attribute_mode);
last_color = normal;
last_color2 = normal;
was_bold = false;
was_underline = false;
was_italics = false;
was_dim = false;
was_reverse = false;
}
if (was_reverse && !is_reverse ) {
// Only way to exit reverse mode is a reset of all attributes.
writembs(exit_attribute_mode);
last_color = normal;
last_color2 = normal;
was_bold = false;
was_underline = false;
was_italics = false;
was_dim = false;
was_reverse = false;
}
if (!last_color2.is_normal() && !last_color2.is_reset()) {
@ -231,6 +276,9 @@ void set_color(rgb_color_t c, rgb_color_t c2) {
writembs(exit_attribute_mode);
was_bold = false;
was_underline = false;
was_italics = false;
was_dim = false;
was_reverse = false;
// We don't know if exit_attribute_mode resets colors, so we set it to something known.
if (write_foreground_color(0)) {
last_color = rgb_color_t::black();
@ -246,6 +294,9 @@ void set_color(rgb_color_t c, rgb_color_t c2) {
last_color2 = rgb_color_t::normal();
was_bold = false;
was_underline = false;
was_italics = false;
was_dim = false;
was_reverse = false;
} else if (!c.is_special()) {
write_color(c, true /* foreground */);
}
@ -264,6 +315,9 @@ void set_color(rgb_color_t c, rgb_color_t c2) {
was_bold = false;
was_underline = false;
was_italics = false;
was_dim = false;
was_reverse = false;
last_color2 = c2;
} else if (!c2.is_special()) {
write_color(c2, false /* not foreground */);
@ -271,7 +325,7 @@ void set_color(rgb_color_t c, rgb_color_t c2) {
}
}
// Lastly, we set bold mode and underline mode correctly.
// Lastly, we set bold, underline, italics, dim, and reverse modes correctly.
if (is_bold && !was_bold && enter_bold_mode && strlen(enter_bold_mode) > 0 && !bg_set) {
writembs(tparm(enter_bold_mode));
was_bold = is_bold;
@ -285,6 +339,32 @@ void set_color(rgb_color_t c, rgb_color_t c2) {
writembs(enter_underline_mode);
}
was_underline = is_underline;
if (was_italics && !is_italics && enter_italics_mode && strlen(enter_italics_mode) > 0) {
writembs(exit_italics_mode);
was_italics = is_italics;
}
if (!was_italics && is_italics && enter_italics_mode && strlen(enter_italics_mode) > 0) {
writembs(enter_italics_mode);
was_italics = is_italics;
}
if (is_dim && !was_dim && enter_dim_mode && strlen(enter_dim_mode) > 0) {
writembs(enter_dim_mode);
was_dim = is_dim;
}
if (is_reverse && !was_reverse) {
// Some terms do not have a reverse mode set, so standout mode is a fallback.
if (enter_reverse_mode && strlen(enter_reverse_mode) > 0) {
writembs(enter_reverse_mode);
was_reverse = is_reverse;
} else if (enter_standout_mode && strlen(enter_standout_mode) > 0) {
writembs(enter_standout_mode);
was_reverse = is_reverse;
}
}
}
/// Default output method, simply calls write() on stdout.
@ -405,6 +485,9 @@ rgb_color_t best_color(const std::vector<rgb_color_t> &candidates, color_support
rgb_color_t parse_color(const wcstring &val, bool is_background) {
int is_bold = 0;
int is_underline = 0;
int is_italics = 0;
int is_dim = 0;
int is_reverse = 0;
std::vector<rgb_color_t> candidates;
@ -425,6 +508,12 @@ rgb_color_t parse_color(const wcstring &val, bool is_background) {
is_bold = true;
else if (next == L"--underline" || next == L"-u")
is_underline = true;
else if (next == L"--italics" || next == L"-i")
is_italics = true;
else if (next == L"--dim" || next == L"-d")
is_dim = true;
else if (next == L"--reverse" || next == L"-r")
is_reverse = true;
else
color_name = next;
}
@ -442,6 +531,9 @@ rgb_color_t parse_color(const wcstring &val, bool is_background) {
result.set_bold(is_bold);
result.set_underline(is_underline);
result.set_italics(is_italics);
result.set_dim(is_dim);
result.set_reverse(is_reverse);
#if 0
wcstring desc = result.description();