From c0e3931729ba06ca496cc494c09414751b5fbe12 Mon Sep 17 00:00:00 2001 From: Tim Stack Date: Fri, 5 Jan 2024 21:31:00 -0800 Subject: [PATCH] [ansi] add support for 256/rgb colors --- src/base/CMakeLists.txt | 3 + src/base/Makefile.am | 3 + src/base/ansi_scrubber.cc | 100 ++++++++++++++--------- src/base/color_spaces.cc | 165 ++++++++++++++++++++++++++++++++++++++ src/base/color_spaces.hh | 94 ++++++++++++++++++++++ src/base/from_trait.hh | 40 +++++++++ src/styling.cc | 50 +----------- src/styling.hh | 64 +-------------- src/view_curses.cc | 126 +++++------------------------ test/lnav_doctests.cc | 5 +- 10 files changed, 398 insertions(+), 252 deletions(-) create mode 100644 src/base/color_spaces.cc create mode 100644 src/base/color_spaces.hh create mode 100644 src/base/from_trait.hh diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index b9a21660..77b23a64 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -6,6 +6,7 @@ add_library( attr_line.builder.cc auto_fd.cc auto_pid.cc + color_spaces.cc date_time_scanner.cc fs_util.cc humanize.cc @@ -34,9 +35,11 @@ add_library( auto_mem.hh auto_pid.hh bus.hh + color_spaces.hh date_time_scanner.cfg.hh date_time_scanner.hh enum_util.hh + from_trait.hh fs_util.hh func_util.hh future_util.hh diff --git a/src/base/Makefile.am b/src/base/Makefile.am index 6ee19154..787ab769 100644 --- a/src/base/Makefile.am +++ b/src/base/Makefile.am @@ -30,10 +30,12 @@ noinst_HEADERS = \ auto_mem.hh \ auto_pid.hh \ bus.hh \ + color_spaces.hh \ date_time_scanner.cfg.hh \ date_time_scanner.hh \ enum_util.hh \ file_range.hh \ + from_trait.hh \ fs_util.hh \ func_util.hh \ future_util.hh \ @@ -74,6 +76,7 @@ libbase_a_SOURCES = \ attr_line.builder.cc \ auto_fd.cc \ auto_pid.cc \ + color_spaces.cc \ date_time_scanner.cc \ fs_util.cc \ humanize.cc \ diff --git a/src/base/ansi_scrubber.cc b/src/base/ansi_scrubber.cc index 63fd5ad6..7fe4099d 100644 --- a/src/base/ansi_scrubber.cc +++ b/src/base/ansi_scrubber.cc @@ -122,6 +122,8 @@ void scrub_ansi_string(std::string& str, string_attrs_t* sa) { static thread_local auto md = lnav::pcre2pp::match_data::unitialized(); + static const auto semi_pred = string_fragment::tag1{';'}; + const auto& regex = ansi_regex(); int64_t origin_offset = 0; int last_origin_offset_end = 0; @@ -253,8 +255,7 @@ scrub_ansi_string(std::string& str, string_attrs_t* sa) if (osc_id) { switch (osc_id.value()) { case 8: - auto split_res - = md[4]->split_pair(string_fragment::tag1{';'}); + auto split_res = md[4]->split_pair(semi_pred); if (split_res) { // auto params = split_res->first; auto uri = split_res->second; @@ -282,46 +283,73 @@ scrub_ansi_string(std::string& str, string_attrs_t* sa) switch (terminator[0]) { case 'm': - for (auto lpc = seq.sf_begin; - lpc != std::string::npos && lpc < (size_t) seq.sf_end;) - { - auto ansi_code_res = scn::scan_value( - scn::string_view{&str[lpc], &str[seq.sf_end]}); - - if (ansi_code_res) { - auto ansi_code = ansi_code_res.value(); - if (90 <= ansi_code && ansi_code <= 97) { - ansi_code -= 60; - attrs.ta_attrs |= A_STANDOUT; - } - if (30 <= ansi_code && ansi_code <= 37) { - attrs.ta_fg_color = ansi_code - 30; + while (!seq.empty()) { + auto ansi_code_res + = scn::scan_value(seq.to_string_view()); + + if (!ansi_code_res) { + break; + } + auto ansi_code = ansi_code_res.value(); + if (90 <= ansi_code && ansi_code <= 97) { + ansi_code -= 60; + attrs.ta_attrs |= A_STANDOUT; + } + if (30 <= ansi_code && ansi_code <= 37) { + attrs.ta_fg_color = ansi_code - 30; + } + if (40 <= ansi_code && ansi_code <= 47) { + attrs.ta_bg_color = ansi_code - 40; + } + if (ansi_code == 38 || ansi_code == 48) { + auto color_code_pair + = seq.split_when(semi_pred).second.split_pair( + semi_pred); + if (!color_code_pair) { + break; } - if (40 <= ansi_code && ansi_code <= 47) { - attrs.ta_bg_color = ansi_code - 40; + auto color_type = scn::scan_value( + color_code_pair->first.to_string_view()); + if (!color_type.has_value()) { + break; } - switch (ansi_code) { - case 1: - attrs.ta_attrs |= A_BOLD; - break; - - case 2: - attrs.ta_attrs |= A_DIM; - break; - - case 4: - attrs.ta_attrs |= A_UNDERLINE; - break; - - case 7: - attrs.ta_attrs |= A_REVERSE; + if (color_type.value() == 2) { + } else if (color_type.value() == 5) { + auto color_index_pair + = color_code_pair->second.split_when( + semi_pred); + auto color_index = scn::scan_value( + color_index_pair.first.to_string_view()); + if (!color_index.has_value()) { break; + } + if (ansi_code == 38) { + attrs.ta_fg_color = color_index.value(); + } else { + attrs.ta_bg_color = color_index.value(); + } + seq = color_index_pair.second; } } - lpc = str.find(';', lpc); - if (lpc != std::string::npos) { - lpc += 1; + switch (ansi_code) { + case 1: + attrs.ta_attrs |= A_BOLD; + break; + + case 2: + attrs.ta_attrs |= A_DIM; + break; + + case 4: + attrs.ta_attrs |= A_UNDERLINE; + break; + + case 7: + attrs.ta_attrs |= A_REVERSE; + break; } + auto split_pair = seq.split_when(semi_pred); + seq = split_pair.second; } has_attrs = true; break; diff --git a/src/base/color_spaces.cc b/src/base/color_spaces.cc new file mode 100644 index 00000000..8fc5b726 --- /dev/null +++ b/src/base/color_spaces.cc @@ -0,0 +1,165 @@ +/** + * Copyright (c) 2024, Timothy Stack + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Timothy Stack nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "color_spaces.hh" + +#include "config.h" + +bool +rgb_color::operator<(const rgb_color& rhs) const +{ + if (rc_r < rhs.rc_r) + return true; + if (rhs.rc_r < rc_r) + return false; + if (rc_g < rhs.rc_g) + return true; + if (rhs.rc_g < rc_g) + return false; + return rc_b < rhs.rc_b; +} + +bool +rgb_color::operator>(const rgb_color& rhs) const +{ + return rhs < *this; +} + +bool +rgb_color::operator<=(const rgb_color& rhs) const +{ + return !(rhs < *this); +} + +bool +rgb_color::operator>=(const rgb_color& rhs) const +{ + return !(*this < rhs); +} + +bool +rgb_color::operator==(const rgb_color& rhs) const +{ + return rc_r == rhs.rc_r && rc_g == rhs.rc_g && rc_b == rhs.rc_b; +} + +bool +rgb_color::operator!=(const rgb_color& rhs) const +{ + return !(rhs == *this); +} + +lab_color::lab_color(const rgb_color& rgb) +{ + double r = rgb.rc_r / 255.0, g = rgb.rc_g / 255.0, b = rgb.rc_b / 255.0, x, + y, z; + + r = (r > 0.04045) ? pow((r + 0.055) / 1.055, 2.4) : r / 12.92; + g = (g > 0.04045) ? pow((g + 0.055) / 1.055, 2.4) : g / 12.92; + b = (b > 0.04045) ? pow((b + 0.055) / 1.055, 2.4) : b / 12.92; + + x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047; + y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000; + z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883; + + x = (x > 0.008856) ? pow(x, 1.0 / 3.0) : (7.787 * x) + 16.0 / 116.0; + y = (y > 0.008856) ? pow(y, 1.0 / 3.0) : (7.787 * y) + 16.0 / 116.0; + z = (z > 0.008856) ? pow(z, 1.0 / 3.0) : (7.787 * z) + 16.0 / 116.0; + + this->lc_l = (116.0 * y) - 16; + this->lc_a = 500.0 * (x - y); + this->lc_b = 200.0 * (y - z); +} + +double +lab_color::deltaE(const lab_color& other) const +{ + double deltaL = this->lc_l - other.lc_l; + double deltaA = this->lc_a - other.lc_a; + double deltaB = this->lc_b - other.lc_b; + double c1 = sqrt(this->lc_a * this->lc_a + this->lc_b * this->lc_b); + double c2 = sqrt(other.lc_a * other.lc_a + other.lc_b * other.lc_b); + double deltaC = c1 - c2; + double deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC; + deltaH = deltaH < 0.0 ? 0.0 : sqrt(deltaH); + double sc = 1.0 + 0.045 * c1; + double sh = 1.0 + 0.015 * c1; + double deltaLKlsl = deltaL / (1.0); + double deltaCkcsc = deltaC / (sc); + double deltaHkhsh = deltaH / (sh); + double i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + + deltaHkhsh * deltaHkhsh; + return i < 0.0 ? 0.0 : sqrt(i); +} + +bool +lab_color::operator<(const lab_color& rhs) const +{ + if (lc_l < rhs.lc_l) + return true; + if (rhs.lc_l < lc_l) + return false; + if (lc_a < rhs.lc_a) + return true; + if (rhs.lc_a < lc_a) + return false; + return lc_b < rhs.lc_b; +} + +bool +lab_color::operator>(const lab_color& rhs) const +{ + return rhs < *this; +} + +bool +lab_color::operator<=(const lab_color& rhs) const +{ + return !(rhs < *this); +} + +bool +lab_color::operator>=(const lab_color& rhs) const +{ + return !(*this < rhs); +} + +bool +lab_color::operator==(const lab_color& rhs) const +{ + return lc_l == rhs.lc_l && lc_a == rhs.lc_a && lc_b == rhs.lc_b; +} + +bool +lab_color::operator!=(const lab_color& rhs) const +{ + return !(rhs == *this); +} diff --git a/src/base/color_spaces.hh b/src/base/color_spaces.hh new file mode 100644 index 00000000..9e1f0a9d --- /dev/null +++ b/src/base/color_spaces.hh @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2024, Timothy Stack + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Timothy Stack nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef color_spaces_hh +#define color_spaces_hh + +struct rgb_color { + explicit rgb_color(short r = -1, short g = -1, short b = -1) + : rc_r(r), rc_g(g), rc_b(b) + { + } + + bool empty() const + { + return this->rc_r == -1 && this->rc_g == -1 && this->rc_b == -1; + } + + bool operator==(const rgb_color& rhs) const; + + bool operator!=(const rgb_color& rhs) const; + + bool operator<(const rgb_color& rhs) const; + + bool operator>(const rgb_color& rhs) const; + + bool operator<=(const rgb_color& rhs) const; + + bool operator>=(const rgb_color& rhs) const; + + short rc_r; + short rc_g; + short rc_b; +}; + +struct lab_color { + lab_color() : lc_l(0), lc_a(0), lc_b(0) {} + + explicit lab_color(const rgb_color& rgb); + + double deltaE(const lab_color& other) const; + + lab_color& operator=(const lab_color& other) + { + this->lc_l = other.lc_l; + this->lc_a = other.lc_a; + this->lc_b = other.lc_b; + + return *this; + } + + bool operator==(const lab_color& rhs) const; + + bool operator!=(const lab_color& rhs) const; + + bool operator<(const lab_color& rhs) const; + + bool operator>(const lab_color& rhs) const; + + bool operator<=(const lab_color& rhs) const; + + bool operator>=(const lab_color& rhs) const; + + double lc_l; + double lc_a; + double lc_b; +}; + +#endif diff --git a/src/base/from_trait.hh b/src/base/from_trait.hh new file mode 100644 index 00000000..05c426ec --- /dev/null +++ b/src/base/from_trait.hh @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2024, Timothy Stack + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Timothy Stack nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef from_trait_hh +#define from_trait_hh + +#include + +#include "result.h" + +template +Result from(S v); + +#endif diff --git a/src/styling.cc b/src/styling.cc index ecd09a10..7520ec0d 100644 --- a/src/styling.cc +++ b/src/styling.cc @@ -32,6 +32,7 @@ #include "styling.hh" #include "ansi-palette-json.h" +#include "base/from_trait.hh" #include "config.h" #include "css-color-names-json.h" #include "fmt/format.h" @@ -109,8 +110,9 @@ ansi_colors() return &retval; } +template<> Result -rgb_color::from_str(string_fragment sf) +from(string_fragment sf) { if (sf.empty()) { return Ok(rgb_color()); @@ -173,50 +175,6 @@ rgb_color::from_str(string_fragment sf) sf)); } -bool -rgb_color::operator<(const rgb_color& rhs) const -{ - if (rc_r < rhs.rc_r) - return true; - if (rhs.rc_r < rc_r) - return false; - if (rc_g < rhs.rc_g) - return true; - if (rhs.rc_g < rc_g) - return false; - return rc_b < rhs.rc_b; -} - -bool -rgb_color::operator>(const rgb_color& rhs) const -{ - return rhs < *this; -} - -bool -rgb_color::operator<=(const rgb_color& rhs) const -{ - return !(rhs < *this); -} - -bool -rgb_color::operator>=(const rgb_color& rhs) const -{ - return !(*this < rhs); -} - -bool -rgb_color::operator==(const rgb_color& rhs) const -{ - return rc_r == rhs.rc_r && rc_g == rhs.rc_g && rc_b == rhs.rc_b; -} - -bool -rgb_color::operator!=(const rgb_color& rhs) const -{ - return !(rhs == *this); -} - term_color_palette::term_color_palette(const char* name, const string_fragment& json) { @@ -271,7 +229,7 @@ color_unit::from_str(const string_fragment& sf) return Ok(color_unit{semantic{}}); } - auto retval = TRY(rgb_color::from_str(sf)); + auto retval = TRY(from(sf)); return Ok(color_unit{retval}); } diff --git a/src/styling.hh b/src/styling.hh index da42dde9..d17a8fd8 100644 --- a/src/styling.hh +++ b/src/styling.hh @@ -35,6 +35,7 @@ #include #include +#include "base/color_spaces.hh" #include "base/intern_string.hh" #include "base/result.h" #include "log_level.hh" @@ -42,69 +43,6 @@ #include "yajlpp/yajlpp.hh" #include "yajlpp/yajlpp_def.hh" -struct rgb_color { - static Result from_str(string_fragment sf); - - explicit rgb_color(short r = -1, short g = -1, short b = -1) - : rc_r(r), rc_g(g), rc_b(b) - { - } - - bool empty() const - { - return this->rc_r == -1 && this->rc_g == -1 && this->rc_b == -1; - } - - bool operator==(const rgb_color& rhs) const; - - bool operator!=(const rgb_color& rhs) const; - - bool operator<(const rgb_color& rhs) const; - - bool operator>(const rgb_color& rhs) const; - - bool operator<=(const rgb_color& rhs) const; - - bool operator>=(const rgb_color& rhs) const; - - short rc_r; - short rc_g; - short rc_b; -}; - -struct lab_color { - lab_color() : lc_l(0), lc_a(0), lc_b(0) {} - - explicit lab_color(const rgb_color& rgb); - - double deltaE(const lab_color& other) const; - - lab_color& operator=(const lab_color& other) - { - this->lc_l = other.lc_l; - this->lc_a = other.lc_a; - this->lc_b = other.lc_b; - - return *this; - } - - bool operator==(const lab_color& rhs) const; - - bool operator!=(const lab_color& rhs) const; - - bool operator<(const lab_color& rhs) const; - - bool operator>(const lab_color& rhs) const; - - bool operator<=(const lab_color& rhs) const; - - bool operator>=(const lab_color& rhs) const; - - double lc_l; - double lc_a; - double lc_b; -}; - struct term_color { short xc_id; std::string xc_name; diff --git a/src/view_curses.cc b/src/view_curses.cc index 69b1d13f..60c895dc 100644 --- a/src/view_curses.cc +++ b/src/view_curses.cc @@ -39,6 +39,7 @@ #include "base/ansi_scrubber.hh" #include "base/attr_line.hh" +#include "base/from_trait.hh" #include "base/itertools.hh" #include "base/lnav_log.hh" #include "config.h" @@ -705,24 +706,26 @@ view_colors::init_roles(const lnav_theme& lt, auto fg_str = fg_iter == lt.lt_vars.end() ? "" : fg_iter->second; auto bg_str = bg_iter == lt.lt_vars.end() ? "" : bg_iter->second; - auto rgb_fg = rgb_color::from_str(fg_str).unwrapOrElse( - [&](const auto& msg) { - reporter(&fg_str, - lnav::console::user_message::error( - attr_line_t("invalid color -- ") - .append_quoted(fg_str)) - .with_reason(msg)); - return rgb_color{}; - }); - auto rgb_bg = rgb_color::from_str(bg_str).unwrapOrElse( - [&](const auto& msg) { - reporter(&bg_str, - lnav::console::user_message::error( - attr_line_t("invalid background color -- ") - .append_quoted(bg_str)) - .with_reason(msg)); - return rgb_color{}; - }); + auto rgb_fg = from(string_fragment::from_str(fg_str)) + .unwrapOrElse([&](const auto& msg) { + reporter(&fg_str, + lnav::console::user_message::error( + attr_line_t("invalid color -- ") + .append_quoted(fg_str)) + .with_reason(msg)); + return rgb_color{}; + }); + auto rgb_bg + = from(string_fragment::from_str(bg_str)) + .unwrapOrElse([&](const auto& msg) { + reporter( + &bg_str, + lnav::console::user_message::error( + attr_line_t("invalid background color -- ") + .append_quoted(bg_str)) + .with_reason(msg)); + return rgb_color{}; + }); short fg = vc_active_palette->match_color(lab_color(rgb_fg)); short bg = vc_active_palette->match_color(lab_color(rgb_bg)); @@ -1179,93 +1182,6 @@ view_colors::attrs_for_ident(const char* str, size_t len) const return retval; } -lab_color::lab_color(const rgb_color& rgb) -{ - double r = rgb.rc_r / 255.0, g = rgb.rc_g / 255.0, b = rgb.rc_b / 255.0, x, - y, z; - - r = (r > 0.04045) ? pow((r + 0.055) / 1.055, 2.4) : r / 12.92; - g = (g > 0.04045) ? pow((g + 0.055) / 1.055, 2.4) : g / 12.92; - b = (b > 0.04045) ? pow((b + 0.055) / 1.055, 2.4) : b / 12.92; - - x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047; - y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000; - z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883; - - x = (x > 0.008856) ? pow(x, 1.0 / 3.0) : (7.787 * x) + 16.0 / 116.0; - y = (y > 0.008856) ? pow(y, 1.0 / 3.0) : (7.787 * y) + 16.0 / 116.0; - z = (z > 0.008856) ? pow(z, 1.0 / 3.0) : (7.787 * z) + 16.0 / 116.0; - - this->lc_l = (116.0 * y) - 16; - this->lc_a = 500.0 * (x - y); - this->lc_b = 200.0 * (y - z); -} - -double -lab_color::deltaE(const lab_color& other) const -{ - double deltaL = this->lc_l - other.lc_l; - double deltaA = this->lc_a - other.lc_a; - double deltaB = this->lc_b - other.lc_b; - double c1 = sqrt(this->lc_a * this->lc_a + this->lc_b * this->lc_b); - double c2 = sqrt(other.lc_a * other.lc_a + other.lc_b * other.lc_b); - double deltaC = c1 - c2; - double deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC; - deltaH = deltaH < 0.0 ? 0.0 : sqrt(deltaH); - double sc = 1.0 + 0.045 * c1; - double sh = 1.0 + 0.015 * c1; - double deltaLKlsl = deltaL / (1.0); - double deltaCkcsc = deltaC / (sc); - double deltaHkhsh = deltaH / (sh); - double i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc - + deltaHkhsh * deltaHkhsh; - return i < 0.0 ? 0.0 : sqrt(i); -} - -bool -lab_color::operator<(const lab_color& rhs) const -{ - if (lc_l < rhs.lc_l) - return true; - if (rhs.lc_l < lc_l) - return false; - if (lc_a < rhs.lc_a) - return true; - if (rhs.lc_a < lc_a) - return false; - return lc_b < rhs.lc_b; -} - -bool -lab_color::operator>(const lab_color& rhs) const -{ - return rhs < *this; -} - -bool -lab_color::operator<=(const lab_color& rhs) const -{ - return !(rhs < *this); -} - -bool -lab_color::operator>=(const lab_color& rhs) const -{ - return !(*this < rhs); -} - -bool -lab_color::operator==(const lab_color& rhs) const -{ - return lc_l == rhs.lc_l && lc_a == rhs.lc_a && lc_b == rhs.lc_b; -} - -bool -lab_color::operator!=(const lab_color& rhs) const -{ - return !(rhs == *this); -} - Result screen_curses::create() { diff --git a/test/lnav_doctests.cc b/test/lnav_doctests.cc index caaa6f9c..78acf8d2 100644 --- a/test/lnav_doctests.cc +++ b/test/lnav_doctests.cc @@ -30,6 +30,7 @@ #include "config.h" #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "base/from_trait.hh" #include "byte_array.hh" #include "data_scanner.hh" #include "doctest/doctest.h" @@ -164,8 +165,8 @@ TEST_CASE("ptime_fmt") TEST_CASE("rgb_color from string") { - string name = "SkyBlue1"; - auto color = rgb_color::from_str(name).unwrap(); + const auto name = string_fragment::from_const("SkyBlue1"); + auto color = from(name).unwrap(); CHECK(color.rc_r == 135); CHECK(color.rc_g == 215); CHECK(color.rc_b == 255);