mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-15 22:44:01 +00:00
Re-implement optimizations to color lookup by name
Hopefully without the null-termination issues this time around. Fixed by simply cloning the str object as-is then transforming it.
This commit is contained in:
parent
7447c8faae
commit
3c90b6c57d
1 changed files with 69 additions and 26 deletions
|
@ -7,6 +7,8 @@
|
|||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cwchar> // IWYU pragma: keep
|
||||
#include <cwctype>
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
#include "fallback.h" // IWYU pragma: keep
|
||||
|
@ -150,29 +152,40 @@ bool rgb_color_t::try_parse_rgb(const wcstring &name) {
|
|||
|
||||
struct named_color_t {
|
||||
const wchar_t *name;
|
||||
unsigned char idx;
|
||||
uint8_t idx;
|
||||
unsigned char rgb[3];
|
||||
bool hidden;
|
||||
};
|
||||
|
||||
static const named_color_t named_colors[] = {
|
||||
{L"black", 0, {0x00, 0x00, 0x00}, false}, {L"red", 1, {0x80, 0x00, 0x00}, false},
|
||||
{L"green", 2, {0x00, 0x80, 0x00}, false}, {L"brown", 3, {0x72, 0x50, 0x00}, true},
|
||||
{L"yellow", 3, {0x80, 0x80, 0x00}, false}, {L"blue", 4, {0x00, 0x00, 0x80}, false},
|
||||
{L"magenta", 5, {0x80, 0x00, 0x80}, false}, {L"purple", 5, {0x80, 0x00, 0x80}, true},
|
||||
{L"cyan", 6, {0x00, 0x80, 0x80}, false}, {L"white", 7, {0xC0, 0xC0, 0xC0}, false},
|
||||
{L"grey", 7, {0xE5, 0xE5, 0xE5}, true}, {L"brblack", 8, {0x80, 0x80, 0x80}, false},
|
||||
{L"brgrey", 8, {0x55, 0x55, 0x55}, true}, {L"brred", 9, {0xFF, 0x00, 0x00}, false},
|
||||
{L"brgreen", 10, {0x00, 0xFF, 0x00}, false}, {L"brbrown", 11, {0xFF, 0xFF, 0x00}, true},
|
||||
{L"bryellow", 11, {0xFF, 0xFF, 0x00}, false}, {L"brblue", 12, {0x00, 0x00, 0xFF}, false},
|
||||
{L"brmagenta", 13, {0xFF, 0x00, 0xFF}, false}, {L"brpurple", 13, {0xFF, 0x00, 0xFF}, true},
|
||||
{L"brcyan", 14, {0x00, 0xFF, 0xFF}, false}, {L"brwhite", 15, {0xFF, 0xFF, 0xFF}, false},
|
||||
// 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},
|
||||
};
|
||||
|
||||
wcstring_list_t rgb_color_t::named_color_names() {
|
||||
const size_t count = sizeof named_colors / sizeof *named_colors;
|
||||
wcstring_list_t result;
|
||||
result.reserve(1 + count);
|
||||
result.reserve(1 + named_colors.size());
|
||||
for (const auto &named_color : named_colors) {
|
||||
if (!named_color.hidden) {
|
||||
result.push_back(named_color.name);
|
||||
|
@ -188,23 +201,53 @@ wcstring_list_t rgb_color_t::named_color_names() {
|
|||
}
|
||||
|
||||
bool rgb_color_t::try_parse_named(const wcstring &str) {
|
||||
static auto named_colors_begin = named_colors.begin();
|
||||
static auto named_colors_end = named_colors.end();
|
||||
std::memset(&data, 0, sizeof data);
|
||||
size_t max = sizeof named_colors / sizeof *named_colors;
|
||||
for (size_t idx = 0; idx < max; idx++) {
|
||||
if (0 == wcscasecmp(str.c_str(), named_colors[idx].name)) {
|
||||
data.name_idx = named_colors[idx].idx;
|
||||
this->type = type_named;
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
// Cannot be a named color
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static const wchar_t *name_for_color_idx(unsigned char idx) {
|
||||
size_t max = sizeof named_colors / sizeof *named_colors;
|
||||
for (size_t i = 0; i < max; i++) {
|
||||
if (named_colors[i].idx == idx) {
|
||||
return named_colors[i].name;
|
||||
if (idx < named_colors.size()) {
|
||||
for (auto &color : named_colors) {
|
||||
if (idx == color.idx) {
|
||||
return color.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return L"unknown";
|
||||
|
|
Loading…
Reference in a new issue