2016-04-05 07:55:40 +08:00
|
|
|
// Color class implementation.
|
2016-05-19 06:30:21 +08:00
|
|
|
#include "config.h" // IWYU pragma: keep
|
|
|
|
|
2019-10-14 06:50:48 +08:00
|
|
|
#include "color.h"
|
|
|
|
|
2019-11-19 09:11:16 +08:00
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <cstdlib>
|
2019-03-13 05:06:01 +08:00
|
|
|
#include <cwchar> // IWYU pragma: keep
|
2020-06-21 05:03:49 +08:00
|
|
|
#include <cwctype>
|
|
|
|
#include <algorithm>
|
2016-04-21 14:00:54 +08:00
|
|
|
|
|
|
|
#include "common.h"
|
2016-04-28 06:28:34 +08:00
|
|
|
#include "fallback.h" // IWYU pragma: keep
|
2012-02-13 10:05:59 +08:00
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
bool rgb_color_t::try_parse_special(const wcstring &special) {
|
2019-03-13 06:07:07 +08:00
|
|
|
std::memset(&data, 0, sizeof data);
|
2012-02-13 10:05:59 +08:00
|
|
|
const wchar_t *name = special.c_str();
|
2020-06-23 12:35:23 +08:00
|
|
|
|
|
|
|
// wcscasecmp is so slow that using it directly causes `try_parse_special` to consume up to
|
|
|
|
// 3% of all of fish's cpu time due to extremely inefficient invariant case lookups for wide
|
|
|
|
// characters (tested: Fedora Server 32 w/ glibc 2.31 with -O2). (This function is also called
|
|
|
|
// virtually non-stop while emitting output to determine colorization.)
|
|
|
|
|
|
|
|
// Take advantage of the fact that std::string length is O(1) to speed things up, and perform
|
|
|
|
// what amounts to a simple memcmp before needing to access the invariant case lookup tables.
|
|
|
|
static auto normal_len = wcslen(L"normal");
|
|
|
|
static auto reset_len = wcslen(L"reset");
|
|
|
|
this->type = type_none;
|
|
|
|
if (special.size() == normal_len) {
|
|
|
|
if (!wcscmp(name, L"normal") || !wcscasecmp(name, L"normal")) {
|
|
|
|
this->type = type_normal;
|
|
|
|
}
|
|
|
|
} else if (special.size() == reset_len) {
|
|
|
|
if (!wcscmp(name, L"reset") || !wcscasecmp(name, L"reset")) {
|
|
|
|
this->type = type_reset;
|
|
|
|
}
|
2012-02-13 10:05:59 +08:00
|
|
|
}
|
|
|
|
return this->type != type_none;
|
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
static int parse_hex_digit(wchar_t x) {
|
|
|
|
switch (x) {
|
|
|
|
case L'0': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0x0;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
|
|
|
case L'1': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0x1;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
|
|
|
case L'2': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0x2;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
|
|
|
case L'3': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0x3;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
|
|
|
case L'4': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0x4;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
|
|
|
case L'5': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0x5;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
|
|
|
case L'6': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0x6;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
|
|
|
case L'7': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0x7;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
|
|
|
case L'8': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0x8;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
|
|
|
case L'9': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0x9;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
2012-11-19 16:31:03 +08:00
|
|
|
case L'a':
|
2016-04-28 06:28:34 +08:00
|
|
|
case L'A': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0xA;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
2012-11-19 16:31:03 +08:00
|
|
|
case L'b':
|
2016-04-28 06:28:34 +08:00
|
|
|
case L'B': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0xB;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
2012-11-19 16:31:03 +08:00
|
|
|
case L'c':
|
2016-04-28 06:28:34 +08:00
|
|
|
case L'C': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0xC;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
2012-11-19 16:31:03 +08:00
|
|
|
case L'd':
|
2016-04-28 06:28:34 +08:00
|
|
|
case L'D': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0xD;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
2012-11-19 16:31:03 +08:00
|
|
|
case L'e':
|
2016-04-28 06:28:34 +08:00
|
|
|
case L'E': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0xE;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
2012-11-19 16:31:03 +08:00
|
|
|
case L'f':
|
2016-04-28 06:28:34 +08:00
|
|
|
case L'F': {
|
2012-11-19 16:31:03 +08:00
|
|
|
return 0xF;
|
2016-04-28 06:28:34 +08:00
|
|
|
}
|
2019-05-05 18:09:25 +08:00
|
|
|
default: {
|
|
|
|
return -1;
|
|
|
|
}
|
2012-02-13 10:05:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
static unsigned long squared_difference(long p1, long p2) {
|
2020-04-03 07:04:04 +08:00
|
|
|
auto diff = static_cast<unsigned long>(labs(p1 - p2));
|
2012-08-06 04:24:33 +08:00
|
|
|
return diff * diff;
|
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
static unsigned char convert_color(const unsigned char rgb[3], const uint32_t *colors,
|
|
|
|
size_t color_count) {
|
2012-02-13 10:05:59 +08:00
|
|
|
long r = rgb[0], g = rgb[1], b = rgb[2];
|
2020-04-03 07:04:04 +08:00
|
|
|
auto best_distance = static_cast<unsigned long>(-1);
|
|
|
|
auto best_index = static_cast<unsigned char>(-1);
|
2020-02-21 14:56:29 +08:00
|
|
|
for (size_t idx = 0; idx < color_count; idx++) {
|
2012-02-13 10:05:59 +08:00
|
|
|
uint32_t color = colors[idx];
|
2016-04-28 06:28:34 +08:00
|
|
|
long test_r = (color >> 16) & 0xFF, test_g = (color >> 8) & 0xFF,
|
|
|
|
test_b = (color >> 0) & 0xFF;
|
|
|
|
unsigned long distance = squared_difference(r, test_r) + squared_difference(g, test_g) +
|
|
|
|
squared_difference(b, test_b);
|
|
|
|
if (distance <= best_distance) {
|
2012-02-13 10:05:59 +08:00
|
|
|
best_index = idx;
|
|
|
|
best_distance = distance;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return best_index;
|
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
bool rgb_color_t::try_parse_rgb(const wcstring &name) {
|
2019-03-13 06:07:07 +08:00
|
|
|
std::memset(&data, 0, sizeof data);
|
2016-04-28 06:28:34 +08:00
|
|
|
// We support the following style of rgb formats (case insensitive):
|
|
|
|
// #FA3
|
|
|
|
// #F3A035
|
|
|
|
// FA3
|
|
|
|
// F3A035
|
2012-02-13 10:05:59 +08:00
|
|
|
size_t digit_idx = 0, len = name.size();
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
// Skip any leading #.
|
|
|
|
if (len > 0 && name.at(0) == L'#') digit_idx++;
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2012-02-13 10:05:59 +08:00
|
|
|
bool success = false;
|
|
|
|
size_t i;
|
2016-04-28 06:28:34 +08:00
|
|
|
if (len - digit_idx == 3) {
|
|
|
|
// Format: FA3
|
|
|
|
for (i = 0; i < 3; i++) {
|
2012-02-13 10:05:59 +08:00
|
|
|
int val = parse_hex_digit(name.at(digit_idx++));
|
|
|
|
if (val < 0) break;
|
2016-04-28 06:28:34 +08:00
|
|
|
data.color.rgb[i] = val * 16 + val;
|
2012-02-13 10:05:59 +08:00
|
|
|
}
|
|
|
|
success = (i == 3);
|
2016-04-28 06:28:34 +08:00
|
|
|
} else if (len - digit_idx == 6) {
|
|
|
|
// Format: F3A035
|
|
|
|
for (i = 0; i < 3; i++) {
|
2012-02-13 10:05:59 +08:00
|
|
|
int hi = parse_hex_digit(name.at(digit_idx++));
|
|
|
|
int lo = parse_hex_digit(name.at(digit_idx++));
|
|
|
|
if (lo < 0 || hi < 0) break;
|
2016-04-28 06:28:34 +08:00
|
|
|
data.color.rgb[i] = hi * 16 + lo;
|
2012-02-13 10:05:59 +08:00
|
|
|
}
|
|
|
|
success = (i == 3);
|
2012-11-18 18:23:22 +08:00
|
|
|
}
|
2016-04-28 06:28:34 +08:00
|
|
|
if (success) {
|
2012-02-13 10:05:59 +08:00
|
|
|
this->type = type_rgb;
|
|
|
|
}
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
struct named_color_t {
|
|
|
|
const wchar_t *name;
|
2020-06-21 05:03:49 +08:00
|
|
|
uint8_t idx;
|
2012-02-13 10:05:59 +08:00
|
|
|
unsigned char rgb[3];
|
Improve compatibility with 0-16 color terminals.
Fish assumed that it could use tparm to emit escapes to set colors
as long as the color was under 16 or max_colors from terminfo was 256::
if (idx < 16 || term256_support_is_native()) {
// Use tparm to emit color escape
writembs(tparm(todo, idx);
If a terminal has max_colors = 8, here is what happenened, except
inside fish:
> env TERM=xterm tput setaf 7 | xxd
00000000: 1b5b 3337 6d .[37m
> env TERM=xterm tput setaf 9 | xxd
00000000: 1b5b 3338 6d .[39m
The first escape is good, that second escape is not valid.
Bright colors should start at \e[90m:
> env TERM=xterm-16color tput setaf 9 | xxd
00000000: 1b5b 3931 6d .[91m
This is what caused "white" not to work in #3176 in Terminal.app, and
obviously isn't good for real low-color terminals either.
So we replace the term256_support_is_native(), which just checked if
max_colors is 256 or not, with a function that takes an argument and
checks terminfo for that to see if tparm can handle it. We only use this
test, because otherwise, tparm should be expected to output garbage:
/// Returns true if we think tparm can handle outputting a color index
static bool term_supports_color_natively(unsigned int c) { return max_colors >= c; }
...
if (term_supports_color_natively(idx) {
And if terminfo can't do it, the "forced" escapes no longer use the fancy
format when handling colors under 16, as this is not going to be compatible with
low color terminals. The code before used:
else {
char buff[16] = "";
snprintf(buff, sizeof buff, "\x1b[%d;5;%dm", is_fg ? 38 : 48, idx);
I added an intermediate format for colors 0-15:
else {
// We are attempting to bypass the term here. Generate the ANSI escape sequence ourself.
char buff[16] = "";
if (idx < 16) {
snprintf(buff, sizeof buff, "\x1b[%dm", ((idx > 7) ? 82 : 30) + idx + !is_fg * 10);
} else {
snprintf(buff, sizeof buff, "\x1b[%d;5;%dm", is_fg ? 38 : 48, idx);
}
Restores harmony to white, brwhite, brblack, black color names.
We don't want "white" to refer to color color #16, but to the
standard color #8. #16 is "brwhite".
Move comments from output.h to output.cpp
Nuke the config.fish set_color hack for linux VTs.
Sync up our various incomplete color lists and fix all color values.
Colors 0-8 are assumed to be brights - e.g. red was FF0000. Perplexing!
Using this table:
<http://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html>
Fixes #3176
2016-07-22 01:55:28 +08:00
|
|
|
bool hidden;
|
2012-02-13 10:05:59 +08:00
|
|
|
};
|
|
|
|
|
2020-06-21 05:03:49 +08:00
|
|
|
// Keep this sorted alphabetically
|
|
|
|
static const std::vector<named_color_t> named_colors {
|
|
|
|
{L"black", 0, {0x00, 0x00, 0x00}, false},
|
|
|
|
{L"blue", 4, {0x00, 0x00, 0x80}, false},
|
|
|
|
{L"brblack", 8, {0x80, 0x80, 0x80}, false},
|
|
|
|
{L"brblue", 12, {0x00, 0x00, 0xFF}, false},
|
|
|
|
{L"brbrown", 11, {0xFF, 0xFF, 0x00}, true},
|
|
|
|
{L"brcyan", 14, {0x00, 0xFF, 0xFF}, false},
|
|
|
|
{L"brgreen", 10, {0x00, 0xFF, 0x00}, false},
|
|
|
|
{L"brgrey", 8, {0x55, 0x55, 0x55}, true},
|
|
|
|
{L"brmagenta", 13, {0xFF, 0x00, 0xFF}, false},
|
|
|
|
{L"brown", 3, {0x72, 0x50, 0x00}, true},
|
|
|
|
{L"brpurple", 13, {0xFF, 0x00, 0xFF}, true},
|
|
|
|
{L"brred", 9, {0xFF, 0x00, 0x00}, false},
|
|
|
|
{L"brwhite", 15, {0xFF, 0xFF, 0xFF}, false},
|
|
|
|
{L"bryellow", 11, {0xFF, 0xFF, 0x00}, false},
|
|
|
|
{L"cyan", 6, {0x00, 0x80, 0x80}, false},
|
|
|
|
{L"green", 2, {0x00, 0x80, 0x00}, false},
|
|
|
|
{L"grey", 7, {0xE5, 0xE5, 0xE5}, true},
|
|
|
|
{L"magenta", 5, {0x80, 0x00, 0x80}, false},
|
|
|
|
{L"purple", 5, {0x80, 0x00, 0x80}, true},
|
|
|
|
{L"red", 1, {0x80, 0x00, 0x00}, false},
|
|
|
|
{L"white", 7, {0xC0, 0xC0, 0xC0}, false},
|
|
|
|
{L"yellow", 3, {0x80, 0x80, 0x00}, false},
|
2012-02-13 10:05:59 +08:00
|
|
|
};
|
|
|
|
|
2018-02-19 10:33:04 +08:00
|
|
|
wcstring_list_t rgb_color_t::named_color_names() {
|
2013-02-15 07:50:24 +08:00
|
|
|
wcstring_list_t result;
|
2020-06-21 05:03:49 +08:00
|
|
|
result.reserve(1 + named_colors.size());
|
2020-04-03 07:45:11 +08:00
|
|
|
for (const auto &named_color : named_colors) {
|
|
|
|
if (!named_color.hidden) {
|
|
|
|
result.push_back(named_color.name);
|
Improve compatibility with 0-16 color terminals.
Fish assumed that it could use tparm to emit escapes to set colors
as long as the color was under 16 or max_colors from terminfo was 256::
if (idx < 16 || term256_support_is_native()) {
// Use tparm to emit color escape
writembs(tparm(todo, idx);
If a terminal has max_colors = 8, here is what happenened, except
inside fish:
> env TERM=xterm tput setaf 7 | xxd
00000000: 1b5b 3337 6d .[37m
> env TERM=xterm tput setaf 9 | xxd
00000000: 1b5b 3338 6d .[39m
The first escape is good, that second escape is not valid.
Bright colors should start at \e[90m:
> env TERM=xterm-16color tput setaf 9 | xxd
00000000: 1b5b 3931 6d .[91m
This is what caused "white" not to work in #3176 in Terminal.app, and
obviously isn't good for real low-color terminals either.
So we replace the term256_support_is_native(), which just checked if
max_colors is 256 or not, with a function that takes an argument and
checks terminfo for that to see if tparm can handle it. We only use this
test, because otherwise, tparm should be expected to output garbage:
/// Returns true if we think tparm can handle outputting a color index
static bool term_supports_color_natively(unsigned int c) { return max_colors >= c; }
...
if (term_supports_color_natively(idx) {
And if terminfo can't do it, the "forced" escapes no longer use the fancy
format when handling colors under 16, as this is not going to be compatible with
low color terminals. The code before used:
else {
char buff[16] = "";
snprintf(buff, sizeof buff, "\x1b[%d;5;%dm", is_fg ? 38 : 48, idx);
I added an intermediate format for colors 0-15:
else {
// We are attempting to bypass the term here. Generate the ANSI escape sequence ourself.
char buff[16] = "";
if (idx < 16) {
snprintf(buff, sizeof buff, "\x1b[%dm", ((idx > 7) ? 82 : 30) + idx + !is_fg * 10);
} else {
snprintf(buff, sizeof buff, "\x1b[%d;5;%dm", is_fg ? 38 : 48, idx);
}
Restores harmony to white, brwhite, brblack, black color names.
We don't want "white" to refer to color color #16, but to the
standard color #8. #16 is "brwhite".
Move comments from output.h to output.cpp
Nuke the config.fish set_color hack for linux VTs.
Sync up our various incomplete color lists and fix all color values.
Colors 0-8 are assumed to be brights - e.g. red was FF0000. Perplexing!
Using this table:
<http://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html>
Fixes #3176
2016-07-22 01:55:28 +08:00
|
|
|
}
|
2013-02-15 07:50:24 +08:00
|
|
|
}
|
2015-12-08 10:41:17 +08:00
|
|
|
// "normal" isn't really a color and does not have a color palette index or
|
|
|
|
// RGB value. Therefore, it does not appear in the named_colors table.
|
|
|
|
// However, it is a legitimate color name for the "set_color" command so
|
|
|
|
// include it in the publicly known list of colors. This is primarily so it
|
|
|
|
// appears in the output of "set_color --print-colors".
|
|
|
|
result.push_back(L"normal");
|
2013-02-15 07:50:24 +08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
bool rgb_color_t::try_parse_named(const wcstring &str) {
|
2020-06-21 05:03:49 +08:00
|
|
|
static auto named_colors_begin = named_colors.begin();
|
|
|
|
static auto named_colors_end = named_colors.end();
|
2019-03-13 06:07:07 +08:00
|
|
|
std::memset(&data, 0, sizeof data);
|
2020-06-21 05:03:49 +08:00
|
|
|
|
|
|
|
if (str.size() == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Binary search
|
|
|
|
named_color_t search;
|
|
|
|
search.name = str.c_str();
|
|
|
|
|
|
|
|
// Optimized conversion to lowercase with early abort
|
|
|
|
maybe_t<wcstring> lowercase;
|
|
|
|
for (auto &c : str) {
|
|
|
|
if (c >= L'a' && c <= L'z') {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c >= L'A' && c <= L'Z') {
|
|
|
|
lowercase = str;
|
|
|
|
std::transform(lowercase.value().begin(), lowercase.value().end(), lowercase.value().begin(), std::towlower);
|
|
|
|
search.name = lowercase.value().c_str();
|
|
|
|
break;
|
2012-02-13 10:05:59 +08:00
|
|
|
}
|
2020-06-21 05:03:49 +08:00
|
|
|
// Cannot be a named color
|
|
|
|
return false;
|
2012-02-13 10:05:59 +08:00
|
|
|
}
|
2020-06-21 05:03:49 +08:00
|
|
|
|
|
|
|
auto result = std::lower_bound(named_colors_begin, named_colors_end, search,
|
|
|
|
[&](const named_color_t &c1, const named_color_t &c2) {
|
|
|
|
return wcscmp(c1.name, c2.name) < 0; });
|
|
|
|
|
|
|
|
if (result != named_colors_end && !(wcscmp(search.name, result->name) < 0)) {
|
|
|
|
data.name_idx = result->idx;
|
|
|
|
this->type = type_named;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-02-13 10:05:59 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
static const wchar_t *name_for_color_idx(unsigned char idx) {
|
2020-06-21 05:03:49 +08:00
|
|
|
if (idx < named_colors.size()) {
|
|
|
|
for (auto &color : named_colors) {
|
|
|
|
if (idx == color.idx) {
|
|
|
|
return color.name;
|
|
|
|
}
|
2012-03-11 08:15:56 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return L"unknown";
|
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
rgb_color_t::rgb_color_t(unsigned char t, unsigned char i) : type(t), flags(), data() {
|
2012-02-13 10:05:59 +08:00
|
|
|
data.name_idx = i;
|
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
rgb_color_t rgb_color_t::normal() { return rgb_color_t(type_normal); }
|
2016-04-05 07:55:40 +08:00
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
rgb_color_t rgb_color_t::reset() { return rgb_color_t(type_reset); }
|
2016-04-05 07:55:40 +08:00
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
rgb_color_t rgb_color_t::none() { return rgb_color_t(type_none); }
|
2016-04-05 07:55:40 +08:00
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
rgb_color_t rgb_color_t::white() { return rgb_color_t(type_named, 7); }
|
2016-04-05 07:55:40 +08:00
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
rgb_color_t rgb_color_t::black() { return rgb_color_t(type_named, 0); }
|
2012-02-13 10:05:59 +08:00
|
|
|
|
Improve compatibility with 0-16 color terminals.
Fish assumed that it could use tparm to emit escapes to set colors
as long as the color was under 16 or max_colors from terminfo was 256::
if (idx < 16 || term256_support_is_native()) {
// Use tparm to emit color escape
writembs(tparm(todo, idx);
If a terminal has max_colors = 8, here is what happenened, except
inside fish:
> env TERM=xterm tput setaf 7 | xxd
00000000: 1b5b 3337 6d .[37m
> env TERM=xterm tput setaf 9 | xxd
00000000: 1b5b 3338 6d .[39m
The first escape is good, that second escape is not valid.
Bright colors should start at \e[90m:
> env TERM=xterm-16color tput setaf 9 | xxd
00000000: 1b5b 3931 6d .[91m
This is what caused "white" not to work in #3176 in Terminal.app, and
obviously isn't good for real low-color terminals either.
So we replace the term256_support_is_native(), which just checked if
max_colors is 256 or not, with a function that takes an argument and
checks terminfo for that to see if tparm can handle it. We only use this
test, because otherwise, tparm should be expected to output garbage:
/// Returns true if we think tparm can handle outputting a color index
static bool term_supports_color_natively(unsigned int c) { return max_colors >= c; }
...
if (term_supports_color_natively(idx) {
And if terminfo can't do it, the "forced" escapes no longer use the fancy
format when handling colors under 16, as this is not going to be compatible with
low color terminals. The code before used:
else {
char buff[16] = "";
snprintf(buff, sizeof buff, "\x1b[%d;5;%dm", is_fg ? 38 : 48, idx);
I added an intermediate format for colors 0-15:
else {
// We are attempting to bypass the term here. Generate the ANSI escape sequence ourself.
char buff[16] = "";
if (idx < 16) {
snprintf(buff, sizeof buff, "\x1b[%dm", ((idx > 7) ? 82 : 30) + idx + !is_fg * 10);
} else {
snprintf(buff, sizeof buff, "\x1b[%d;5;%dm", is_fg ? 38 : 48, idx);
}
Restores harmony to white, brwhite, brblack, black color names.
We don't want "white" to refer to color color #16, but to the
standard color #8. #16 is "brwhite".
Move comments from output.h to output.cpp
Nuke the config.fish set_color hack for linux VTs.
Sync up our various incomplete color lists and fix all color values.
Colors 0-8 are assumed to be brights - e.g. red was FF0000. Perplexing!
Using this table:
<http://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html>
Fixes #3176
2016-07-22 01:55:28 +08:00
|
|
|
static unsigned char term16_color_for_rgb(const unsigned char rgb[3]) {
|
2016-04-28 06:28:34 +08:00
|
|
|
const uint32_t kColors[] = {
|
|
|
|
0x000000, // Black
|
Improve compatibility with 0-16 color terminals.
Fish assumed that it could use tparm to emit escapes to set colors
as long as the color was under 16 or max_colors from terminfo was 256::
if (idx < 16 || term256_support_is_native()) {
// Use tparm to emit color escape
writembs(tparm(todo, idx);
If a terminal has max_colors = 8, here is what happenened, except
inside fish:
> env TERM=xterm tput setaf 7 | xxd
00000000: 1b5b 3337 6d .[37m
> env TERM=xterm tput setaf 9 | xxd
00000000: 1b5b 3338 6d .[39m
The first escape is good, that second escape is not valid.
Bright colors should start at \e[90m:
> env TERM=xterm-16color tput setaf 9 | xxd
00000000: 1b5b 3931 6d .[91m
This is what caused "white" not to work in #3176 in Terminal.app, and
obviously isn't good for real low-color terminals either.
So we replace the term256_support_is_native(), which just checked if
max_colors is 256 or not, with a function that takes an argument and
checks terminfo for that to see if tparm can handle it. We only use this
test, because otherwise, tparm should be expected to output garbage:
/// Returns true if we think tparm can handle outputting a color index
static bool term_supports_color_natively(unsigned int c) { return max_colors >= c; }
...
if (term_supports_color_natively(idx) {
And if terminfo can't do it, the "forced" escapes no longer use the fancy
format when handling colors under 16, as this is not going to be compatible with
low color terminals. The code before used:
else {
char buff[16] = "";
snprintf(buff, sizeof buff, "\x1b[%d;5;%dm", is_fg ? 38 : 48, idx);
I added an intermediate format for colors 0-15:
else {
// We are attempting to bypass the term here. Generate the ANSI escape sequence ourself.
char buff[16] = "";
if (idx < 16) {
snprintf(buff, sizeof buff, "\x1b[%dm", ((idx > 7) ? 82 : 30) + idx + !is_fg * 10);
} else {
snprintf(buff, sizeof buff, "\x1b[%d;5;%dm", is_fg ? 38 : 48, idx);
}
Restores harmony to white, brwhite, brblack, black color names.
We don't want "white" to refer to color color #16, but to the
standard color #8. #16 is "brwhite".
Move comments from output.h to output.cpp
Nuke the config.fish set_color hack for linux VTs.
Sync up our various incomplete color lists and fix all color values.
Colors 0-8 are assumed to be brights - e.g. red was FF0000. Perplexing!
Using this table:
<http://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html>
Fixes #3176
2016-07-22 01:55:28 +08:00
|
|
|
0x800000, // Red
|
|
|
|
0x008000, // Green
|
|
|
|
0x808000, // Yellow
|
|
|
|
0x000080, // Blue
|
|
|
|
0x800080, // Magenta
|
|
|
|
0x008080, // Cyan
|
|
|
|
0xc0c0c0, // White
|
|
|
|
0x808080, // Bright Black
|
|
|
|
0xFF0000, // Bright Red
|
|
|
|
0x00FF00, // Bright Green
|
|
|
|
0xFFFF00, // Bright Yellow
|
|
|
|
0x0000FF, // Bright Blue
|
|
|
|
0xFF00FF, // Bright Magenta
|
|
|
|
0x00FFFF, // Bright Cyan
|
|
|
|
0xFFFFFF // Bright White
|
2012-02-13 10:05:59 +08:00
|
|
|
};
|
|
|
|
return convert_color(rgb, kColors, sizeof kColors / sizeof *kColors);
|
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
static unsigned char term256_color_for_rgb(const unsigned char rgb[3]) {
|
|
|
|
const uint32_t kColors[240] = {
|
|
|
|
0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f, 0x005f87,
|
|
|
|
0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, 0x008787, 0x0087af, 0x0087d7, 0x0087ff,
|
|
|
|
0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff, 0x00d700, 0x00d75f, 0x00d787,
|
|
|
|
0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f, 0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff,
|
|
|
|
0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af, 0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, 0x5f5f87,
|
|
|
|
0x5f5faf, 0x5f5fd7, 0x5f5fff, 0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff,
|
|
|
|
0x5faf00, 0x5faf5f, 0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, 0x5fd787,
|
|
|
|
0x5fd7af, 0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff,
|
|
|
|
0x870000, 0x87005f, 0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f, 0x875f87,
|
|
|
|
0x875faf, 0x875fd7, 0x875fff, 0x878700, 0x87875f, 0x878787, 0x8787af, 0x8787d7, 0x8787ff,
|
|
|
|
0x87af00, 0x87af5f, 0x87af87, 0x87afaf, 0x87afd7, 0x87afff, 0x87d700, 0x87d75f, 0x87d787,
|
|
|
|
0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f, 0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff,
|
|
|
|
0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af, 0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f, 0xaf5f87,
|
|
|
|
0xaf5faf, 0xaf5fd7, 0xaf5fff, 0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, 0xaf87d7, 0xaf87ff,
|
|
|
|
0xafaf00, 0xafaf5f, 0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, 0xafd787,
|
|
|
|
0xafd7af, 0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff,
|
|
|
|
0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f, 0xd75f87,
|
|
|
|
0xd75faf, 0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af, 0xd787d7, 0xd787ff,
|
|
|
|
0xd7af00, 0xd7af5f, 0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff, 0xd7d700, 0xd7d75f, 0xd7d787,
|
|
|
|
0xd7d7af, 0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f, 0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff,
|
|
|
|
0xff0000, 0xff005f, 0xff0087, 0xff00af, 0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87,
|
|
|
|
0xff5faf, 0xff5fd7, 0xff5fff, 0xff8700, 0xff875f, 0xff8787, 0xff87af, 0xff87d7, 0xff87ff,
|
|
|
|
0xffaf00, 0xffaf5f, 0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, 0xffd700, 0xffd75f, 0xffd787,
|
|
|
|
0xffd7af, 0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, 0xffffd7, 0xffffff,
|
|
|
|
0x080808, 0x121212, 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e, 0x585858,
|
|
|
|
0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e, 0xa8a8a8, 0xb2b2b2,
|
|
|
|
0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee};
|
2012-02-13 10:05:59 +08:00
|
|
|
return 16 + convert_color(rgb, kColors, sizeof kColors / sizeof *kColors);
|
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
unsigned char rgb_color_t::to_term256_index() const {
|
2012-02-13 10:05:59 +08:00
|
|
|
assert(type == type_rgb);
|
2014-09-20 06:37:31 +08:00
|
|
|
return term256_color_for_rgb(data.color.rgb);
|
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
color24_t rgb_color_t::to_color24() const {
|
2014-09-20 06:37:31 +08:00
|
|
|
assert(type == type_rgb);
|
|
|
|
return data.color;
|
2012-02-13 10:05:59 +08:00
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
unsigned char rgb_color_t::to_name_index() const {
|
2017-02-14 12:37:27 +08:00
|
|
|
// TODO: This should look for the nearest color.
|
2012-07-18 03:47:01 +08:00
|
|
|
assert(type == type_named || type == type_rgb);
|
2016-05-05 06:19:47 +08:00
|
|
|
if (type == type_named) return data.name_idx;
|
Improve compatibility with 0-16 color terminals.
Fish assumed that it could use tparm to emit escapes to set colors
as long as the color was under 16 or max_colors from terminfo was 256::
if (idx < 16 || term256_support_is_native()) {
// Use tparm to emit color escape
writembs(tparm(todo, idx);
If a terminal has max_colors = 8, here is what happenened, except
inside fish:
> env TERM=xterm tput setaf 7 | xxd
00000000: 1b5b 3337 6d .[37m
> env TERM=xterm tput setaf 9 | xxd
00000000: 1b5b 3338 6d .[39m
The first escape is good, that second escape is not valid.
Bright colors should start at \e[90m:
> env TERM=xterm-16color tput setaf 9 | xxd
00000000: 1b5b 3931 6d .[91m
This is what caused "white" not to work in #3176 in Terminal.app, and
obviously isn't good for real low-color terminals either.
So we replace the term256_support_is_native(), which just checked if
max_colors is 256 or not, with a function that takes an argument and
checks terminfo for that to see if tparm can handle it. We only use this
test, because otherwise, tparm should be expected to output garbage:
/// Returns true if we think tparm can handle outputting a color index
static bool term_supports_color_natively(unsigned int c) { return max_colors >= c; }
...
if (term_supports_color_natively(idx) {
And if terminfo can't do it, the "forced" escapes no longer use the fancy
format when handling colors under 16, as this is not going to be compatible with
low color terminals. The code before used:
else {
char buff[16] = "";
snprintf(buff, sizeof buff, "\x1b[%d;5;%dm", is_fg ? 38 : 48, idx);
I added an intermediate format for colors 0-15:
else {
// We are attempting to bypass the term here. Generate the ANSI escape sequence ourself.
char buff[16] = "";
if (idx < 16) {
snprintf(buff, sizeof buff, "\x1b[%dm", ((idx > 7) ? 82 : 30) + idx + !is_fg * 10);
} else {
snprintf(buff, sizeof buff, "\x1b[%d;5;%dm", is_fg ? 38 : 48, idx);
}
Restores harmony to white, brwhite, brblack, black color names.
We don't want "white" to refer to color color #16, but to the
standard color #8. #16 is "brwhite".
Move comments from output.h to output.cpp
Nuke the config.fish set_color hack for linux VTs.
Sync up our various incomplete color lists and fix all color values.
Colors 0-8 are assumed to be brights - e.g. red was FF0000. Perplexing!
Using this table:
<http://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html>
Fixes #3176
2016-07-22 01:55:28 +08:00
|
|
|
if (type == type_rgb) return term16_color_for_rgb(data.color.rgb);
|
2019-11-19 09:08:16 +08:00
|
|
|
return static_cast<unsigned char>(-1); // this is an error
|
2012-02-13 10:05:59 +08:00
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
void rgb_color_t::parse(const wcstring &str) {
|
2012-02-13 10:05:59 +08:00
|
|
|
bool success = false;
|
2016-04-28 06:28:34 +08:00
|
|
|
if (!success) success = try_parse_special(str);
|
|
|
|
if (!success) success = try_parse_named(str);
|
|
|
|
if (!success) success = try_parse_rgb(str);
|
|
|
|
if (!success) {
|
2019-03-13 06:07:07 +08:00
|
|
|
std::memset(&this->data, 0, sizeof this->data);
|
2012-02-13 10:05:59 +08:00
|
|
|
this->type = type_none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
rgb_color_t::rgb_color_t(const wcstring &str) : type(), flags() { this->parse(str); }
|
2012-03-14 05:22:53 +08:00
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
rgb_color_t::rgb_color_t(const std::string &str) : type(), flags() {
|
2012-03-14 05:22:53 +08:00
|
|
|
this->parse(str2wcstring(str));
|
|
|
|
}
|
|
|
|
|
2016-04-28 06:28:34 +08:00
|
|
|
wcstring rgb_color_t::description() const {
|
|
|
|
switch (type) {
|
2016-05-04 07:23:30 +08:00
|
|
|
case type_none: {
|
2012-11-19 16:31:03 +08:00
|
|
|
return L"none";
|
2016-05-04 07:23:30 +08:00
|
|
|
}
|
|
|
|
case type_named: {
|
2019-11-19 09:08:16 +08:00
|
|
|
return format_string(L"named(%d: %ls)", static_cast<int>(data.name_idx),
|
2016-04-28 06:28:34 +08:00
|
|
|
name_for_color_idx(data.name_idx));
|
2016-05-04 07:23:30 +08:00
|
|
|
}
|
|
|
|
case type_rgb: {
|
2016-04-28 06:28:34 +08:00
|
|
|
return format_string(L"rgb(0x%02x%02x%02x)", data.color.rgb[0], data.color.rgb[1],
|
|
|
|
data.color.rgb[2]);
|
2016-05-04 07:23:30 +08:00
|
|
|
}
|
|
|
|
case type_reset: {
|
2012-11-19 16:31:03 +08:00
|
|
|
return L"reset";
|
2016-05-04 07:23:30 +08:00
|
|
|
}
|
|
|
|
case type_normal: {
|
2012-11-19 16:31:03 +08:00
|
|
|
return L"normal";
|
2016-05-04 07:23:30 +08:00
|
|
|
}
|
2019-05-05 18:09:25 +08:00
|
|
|
default: {
|
|
|
|
break;
|
|
|
|
}
|
2012-02-13 10:05:59 +08:00
|
|
|
}
|
2017-05-05 13:42:42 +08:00
|
|
|
DIE("unknown color type");
|
2012-03-11 08:15:56 +08:00
|
|
|
}
|