[ansi] add support for 256/rgb colors

pull/1235/head
Tim Stack 4 months ago
parent 96e6950884
commit c0e3931729

@ -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

@ -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 \

@ -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<int>(
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<int>(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<int>(
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<short>(
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;

@ -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 <cmath>
#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);
}

@ -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

@ -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 <string>
#include "result.h"
template<typename R, typename S>
Result<R, std::string> from(S v);
#endif

@ -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, std::string>
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<rgb_color>(sf));
return Ok(color_unit{retval});
}

@ -35,6 +35,7 @@
#include <utility>
#include <vector>
#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<rgb_color, std::string> 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;

@ -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<rgb_color>(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<rgb_color>(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, std::string>
screen_curses::create()
{

@ -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<rgb_color>(name).unwrap();
CHECK(color.rc_r == 135);
CHECK(color.rc_g == 215);
CHECK(color.rc_b == 255);

Loading…
Cancel
Save