Skip to content

Commit 5435e04

Browse files
committed
[ansi] handle hi-color escapes with colons instead of semi-colons
Related to #1516
1 parent 36c1dea commit 5435e04

2 files changed

Lines changed: 52 additions & 9 deletions

File tree

src/base/ansi_scrubber.cc

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ static const lnav::pcre2pp::code&
4444
ansi_regex()
4545
{
4646
static const auto retval = lnav::pcre2pp::code::from_const(
47-
R"(\x1b\[([\d=;\?]*)([a-zA-Z])|\x1b\](\d+);(.*?)(?:\x07|\x1b\\)|(?:\X\x08\X)+|(\x16+))");
47+
R"(\x1b\[([\d=;:\?]*)([a-zA-Z])|\x1b\](\d+);(.*?)(?:\x07|\x1b\\)|(?:\X\x08\X)+|(\x16+))");
4848

4949
return retval;
5050
}
@@ -122,6 +122,8 @@ scrub_ansi_string(std::string& str, string_attrs_t* sa)
122122
{
123123
thread_local auto md = lnav::pcre2pp::match_data::unitialized();
124124
static constexpr auto semi_pred = string_fragment::tag1{';'};
125+
static constexpr auto colon_pred
126+
= [](char ch) { return ch == ';' || ch == ':'; };
125127

126128
const auto& regex = ansi_regex();
127129
std::optional<std::string> href;
@@ -327,8 +329,8 @@ scrub_ansi_string(std::string& str, string_attrs_t* sa)
327329
}
328330
if (ansi_code == 38 || ansi_code == 48) {
329331
auto color_code_pair
330-
= seq.split_when(semi_pred).second.split_pair(
331-
semi_pred);
332+
= seq.split_when(colon_pred)
333+
.second.split_pair(colon_pred);
332334
if (!color_code_pair) {
333335
break;
334336
}
@@ -338,19 +340,24 @@ scrub_ansi_string(std::string& str, string_attrs_t* sa)
338340
break;
339341
}
340342
if (color_type->value() == 2) {
341-
auto scan_res
342-
= scn::scan<uint8_t, uint8_t, uint8_t>(
343+
auto scan_res = scn::
344+
scan<uint8_t, char, uint8_t, char, uint8_t>(
343345
color_code_pair->second
344346
.to_string_view(),
345-
"{};{};{}");
347+
"{}{}{}{}{}");
346348
if (scan_res) {
347-
auto [r, g, b] = scan_res->values();
348-
attrs.ta_fg_color = rgb_color{r, g, b};
349+
auto [r, sep1, g, sep2, b]
350+
= scan_res->values();
351+
if ((sep1 == ';' && sep2 == ';')
352+
|| (sep1 == ':' && sep2 == ':'))
353+
{
354+
attrs.ta_fg_color = rgb_color{r, g, b};
355+
}
349356
}
350357
} else if (color_type->value() == 5) {
351358
auto color_index_pair
352359
= color_code_pair->second.split_when(
353-
semi_pred);
360+
colon_pred);
354361
auto color_index = scn::scan_value<short>(
355362
color_index_pair.first.to_string_view());
356363
if (!color_index.has_value()

test/test_ansi_scrubber.cc

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,42 @@ main(int argc, char* argv[])
4848
{
4949
printf("BEGIN test\n");
5050

51+
{
52+
auto input = std::string("\x1b[0;1;38:2:1:2:3mHello");
53+
string_attrs_t sa;
54+
55+
scrub_ansi_string(input, &sa);
56+
assert(input == "Hello");
57+
assert(sa.size() == 1);
58+
assert(sa[0].sa_type == &VC_STYLE);
59+
auto ta = sa[0].sa_value.get<text_attrs>();
60+
auto rgb = ta.ta_fg_color.cu_value.get<rgb_color>();
61+
assert(rgb.rc_r == 1);
62+
assert(rgb.rc_g == 2);
63+
assert(rgb.rc_b == 3);
64+
}
65+
66+
{
67+
auto input = std::string("\x1b[0;1;38:5:245mHello");
68+
string_attrs_t sa;
69+
70+
scrub_ansi_string(input, &sa);
71+
assert(input == "Hello");
72+
assert(sa.size() == 1);
73+
assert(sa[0].sa_type == &VC_STYLE);
74+
auto ta = sa[0].sa_value.get<text_attrs>();
75+
assert(ta.ta_fg_color.cu_value.get<palette_color>()
76+
== palette_color{245});
77+
}
78+
79+
{
80+
auto input = std::string("\x1b[0;1;38;5;245mHello");
81+
string_attrs_t sa;
82+
83+
scrub_ansi_string(input, &sa);
84+
assert(input == "Hello");
85+
}
86+
5187
{
5288
auto input = std::string("\x1b[66O\x1b[66O");
5389
string_attrs_t sa;

0 commit comments

Comments
 (0)