1#include "terminalpp/ansi/charset.hpp"
2#include "terminalpp/character_set.hpp"
6namespace terminalpp::detail {
24 fg_greyscale_colour_0,
25 fg_greyscale_colour_1,
36 bg_greyscale_colour_0,
37 bg_greyscale_colour_1,
53 parser_state state{parser_state::idle};
62constexpr byte digit10_to_byte(
char const ch)
64 return static_cast<byte>(ch -
'0');
67constexpr byte digit16_to_byte(
char const ch)
69 return (ch >=
'0' && ch <=
'9') ?
static_cast<byte>(ch -
'0')
70 : (ch >=
'a' && ch <=
'f') ? static_cast<byte>((ch -
'a') + 10)
71 : (ch >=
'A' && ch <=
'F') ? static_cast<byte>((ch -
'A') + 10)
72 : static_cast<byte>(0);
75constexpr void parse_utf8_3(
char const ch, parser_info &info, element &elem)
77 constexpr std::uint64_t
const maxima[] = {
78 0x00007F, 0x0007FF, 0x00FFFF, 0x10FFFF};
81 uint16_t
const value = (info.utf8 * 16) + digit16_to_byte(ch);
88 if (value <= maxima[0])
90 text[0] = byte(value & 0x7F);
94 else if (value <= maxima[1])
96 text[0] = byte(0b11000000 | (value >> 6));
97 text[1] = byte(0b10000000 | (value & 0b00111111));
100 else if (value <= maxima[2])
102 text[0] = byte(0b11100000 | (value >> 12));
103 text[1] = byte(0b10000000 | ((value >> 6) & 0b00111111));
104 text[2] = byte(0b10000000 | (value & 0b00111111));
114 info.state = parser_state::done;
117constexpr void parse_utf8_2(
char const ch, parser_info &info, element &elem)
120 info.utf8 += digit16_to_byte(ch);
121 info.state = parser_state::utf8_3;
124constexpr void parse_utf8_1(
char const ch, parser_info &info, element &elem)
127 info.utf8 += digit16_to_byte(ch);
128 info.state = parser_state::utf8_2;
131constexpr void parse_utf8_0(
char const ch, parser_info &info, element &elem)
133 info.utf8 = digit16_to_byte(ch);
134 info.state = parser_state::utf8_1;
137constexpr void parse_bg_true_colour_5(
138 char const ch, parser_info &info, element &elem)
140 info.blue |= digit16_to_byte(ch);
142 elem.attribute_.background_colour_ =
143 true_colour{info.red, info.green, info.blue};
145 info.state = parser_state::idle;
148constexpr void parse_bg_true_colour_4(
149 char const ch, parser_info &info, element &elem)
151 info.blue = digit16_to_byte(ch) << 4;
152 info.state = parser_state::bg_true_colour_5;
155constexpr void parse_bg_true_colour_3(
156 char const ch, parser_info &info, element &elem)
158 info.green |= digit16_to_byte(ch);
159 info.state = parser_state::bg_true_colour_4;
162constexpr void parse_bg_true_colour_2(
163 char const ch, parser_info &info, element &elem)
165 info.green = digit16_to_byte(ch) << 4;
166 info.state = parser_state::bg_true_colour_3;
169constexpr void parse_bg_true_colour_1(
170 char const ch, parser_info &info, element &elem)
172 info.red |= digit16_to_byte(ch);
173 info.state = parser_state::bg_true_colour_2;
176constexpr void parse_bg_true_colour_0(
177 char const ch, parser_info &info, element &elem)
179 info.red = digit16_to_byte(ch) << 4;
180 info.state = parser_state::bg_true_colour_1;
183constexpr void parse_bg_greyscale_1(
184 char const ch, parser_info &info, element &elem)
186 byte const col = (info.greyscale * 10) + digit10_to_byte(ch);
187 elem.attribute_.background_colour_ = greyscale_colour(col);
188 info.state = parser_state::idle;
191constexpr void parse_bg_greyscale_0(
192 char const ch, parser_info &info, element &elem)
194 info.greyscale = digit10_to_byte(ch);
195 info.state = parser_state::bg_greyscale_colour_1;
198constexpr void parse_bg_high_colour_2(
199 char const ch, parser_info &info, element &elem)
201 auto const blue = digit10_to_byte(ch);
202 elem.attribute_.background_colour_ =
203 high_colour(info.red, info.green, blue);
204 info.state = parser_state::idle;
207constexpr void parse_bg_high_colour_1(
208 char const ch, parser_info &info, element &elem)
210 info.green = digit10_to_byte(ch);
211 info.state = parser_state::bg_high_colour_2;
214constexpr void parse_bg_high_colour_0(
215 char const ch, parser_info &info, element &elem)
217 info.red = digit10_to_byte(ch);
218 info.state = parser_state::bg_high_colour_1;
221constexpr void parse_bg_low_colour(
222 char const ch, parser_info &info, element &elem)
224 auto const col_code = digit10_to_byte(ch);
225 auto const col =
static_cast<terminalpp::graphics::colour
>(col_code);
227 elem.attribute_.background_colour_ = low_colour(col);
228 info.state = parser_state::idle;
231constexpr void parse_fg_greyscale_1(
232 char const ch, parser_info &info, element &elem)
234 byte const col = (info.greyscale * 10) + digit10_to_byte(ch);
235 elem.attribute_.foreground_colour_ = greyscale_colour(col);
236 info.state = parser_state::idle;
239constexpr void parse_fg_greyscale_0(
240 char const ch, parser_info &info, element &elem)
242 info.greyscale = digit10_to_byte(ch);
243 info.state = parser_state::fg_greyscale_colour_1;
246constexpr void parse_fg_true_colour_5(
247 char const ch, parser_info &info, element &elem)
249 info.blue |= digit16_to_byte(ch);
251 elem.attribute_.foreground_colour_ =
252 true_colour{info.red, info.green, info.blue};
254 info.state = parser_state::idle;
257constexpr void parse_fg_true_colour_4(
258 char const ch, parser_info &info, element &elem)
260 info.blue = digit16_to_byte(ch) << 4;
261 info.state = parser_state::fg_true_colour_5;
264constexpr void parse_fg_true_colour_3(
265 char const ch, parser_info &info, element &elem)
267 info.green |= digit16_to_byte(ch);
268 info.state = parser_state::fg_true_colour_4;
271constexpr void parse_fg_true_colour_2(
272 char const ch, parser_info &info, element &elem)
274 info.green = digit16_to_byte(ch) << 4;
275 info.state = parser_state::fg_true_colour_3;
278constexpr void parse_fg_true_colour_1(
279 char const ch, parser_info &info, element &elem)
281 info.red |= digit16_to_byte(ch);
282 info.state = parser_state::fg_true_colour_2;
285constexpr void parse_fg_true_colour_0(
286 char const ch, parser_info &info, element &elem)
288 info.red = digit16_to_byte(ch) << 4;
289 info.state = parser_state::fg_true_colour_1;
292constexpr void parse_fg_high_colour_2(
293 char const ch, parser_info &info, element &elem)
295 auto const blue = digit10_to_byte(ch);
296 elem.attribute_.foreground_colour_ =
297 high_colour(info.red, info.green, blue);
298 info.state = parser_state::idle;
301constexpr void parse_fg_high_colour_1(
302 char const ch, parser_info &info, element &elem)
304 info.green = digit10_to_byte(ch);
305 info.state = parser_state::fg_high_colour_2;
308constexpr void parse_fg_high_colour_0(
309 char const ch, parser_info &info, element &elem)
311 info.red = digit10_to_byte(ch);
312 info.state = parser_state::fg_high_colour_1;
315constexpr void parse_fg_low_colour(
316 char const ch, parser_info &info, element &elem)
318 auto const col_code = digit10_to_byte(ch);
319 auto const col =
static_cast<terminalpp::graphics::colour
>(col_code);
321 elem.attribute_.foreground_colour_ = low_colour(col);
322 info.state = parser_state::idle;
325constexpr void parse_underlining(
326 char const ch, parser_info &info, element &elem)
331 elem.attribute_.underlining_ = graphics::underlining::underlined;
335 elem.attribute_.underlining_ =
336 graphics::underlining::not_underlined;
340 elem.attribute_.underlining_ =
341 graphics::underlining::not_underlined;
345 info.state = parser_state::idle;
348constexpr void parse_polarity(
char const ch, parser_info &info, element &elem)
353 elem.attribute_.polarity_ = graphics::polarity::positive;
357 elem.attribute_.polarity_ = graphics::polarity::negative;
361 elem.attribute_.polarity_ = graphics::polarity::positive;
365 info.state = parser_state::idle;
368constexpr void parse_intensity(
char const ch, parser_info &info, element &elem)
373 elem.attribute_.intensity_ = graphics::intensity::bold;
377 elem.attribute_.intensity_ = graphics::intensity::faint;
381 elem.attribute_.intensity_ = graphics::intensity::normal;
385 info.state = parser_state::idle;
388constexpr void parse_charset_ext(
389 char const ch, parser_info &info, element &elem)
391 byte const charset_code[] = {ansi::charset_extender,
static_cast<byte>(ch)};
392 auto const charset = lookup_character_set(charset_code);
393 elem.glyph_.charset_ = charset ? *charset : elem.glyph_.charset_;
394 info.state = parser_state::idle;
397constexpr void parse_charset(
char const ch, parser_info &info, element &elem)
402 info.state = parser_state::charset_ext;
407 byte const charset_code[] = {
static_cast<byte>(ch)};
408 auto const charset = lookup_character_set(charset_code);
409 elem.glyph_.charset_ = charset ? *charset : elem.glyph_.charset_;
410 info.state = parser_state::idle;
415constexpr void parse_charcode_2(
char const ch, parser_info &info, element &elem)
418 info.charcode += digit10_to_byte(ch);
419 elem.glyph_.character_ = info.charcode;
420 info.state = parser_state::done;
423constexpr void parse_charcode_1(
char const ch, parser_info &info, element &elem)
426 info.charcode += digit10_to_byte(ch);
427 info.state = parser_state::charcode_2;
430constexpr void parse_charcode_0(
char const ch, parser_info &info, element &elem)
432 info.charcode = digit10_to_byte(ch);
433 info.state = parser_state::charcode_1;
436constexpr void parse_escape(
char const ch, parser_info &info, element &elem)
441 info.state = parser_state::charcode_0;
445 info.state = parser_state::charset;
449 info.state = parser_state::intensity;
453 info.state = parser_state::polarity;
457 info.state = parser_state::underlining;
461 info.state = parser_state::fg_low_colour;
465 info.state = parser_state::fg_high_colour_0;
469 info.state = parser_state::fg_greyscale_colour_0;
473 info.state = parser_state::fg_true_colour_0;
477 info.state = parser_state::bg_low_colour;
481 info.state = parser_state::bg_high_colour_0;
485 info.state = parser_state::bg_greyscale_colour_0;
489 info.state = parser_state::bg_true_colour_0;
493 info.state = parser_state::utf8_0;
497 elem.attribute_ = {};
498 info.state = parser_state::idle;
502 elem.glyph_.character_ =
static_cast<byte>(ch);
503 info.state = parser_state::done;
508constexpr void parse_idle(
char const ch, parser_info &info, element &elem)
513 info.state = parser_state::escape;
517 elem.glyph_.character_ =
static_cast<byte>(ch);
518 info.state = parser_state::done;
523constexpr element element_with_base(element
const &elem_base)
525 element result = elem_base;
526 result.glyph_.charset_ = result.glyph_.charset_ == charset::utf8
528 : result.glyph_.charset_;
529 result.glyph_.character_ =
' ';
534constexpr element parse_element(
535 std::span<char const> &text, element
const &elem_base)
537 auto info = parser_info{};
538 auto elem = element_with_base(elem_base);
540 using handler = void (*)(char, parser_info &, element &);
541 handler
const handlers[] = {
553 parse_fg_high_colour_0,
554 parse_fg_high_colour_1,
555 parse_fg_high_colour_2,
556 parse_fg_greyscale_0,
557 parse_fg_greyscale_1,
558 parse_fg_true_colour_0,
559 parse_fg_true_colour_1,
560 parse_fg_true_colour_2,
561 parse_fg_true_colour_3,
562 parse_fg_true_colour_4,
563 parse_fg_true_colour_5,
565 parse_bg_high_colour_0,
566 parse_bg_high_colour_1,
567 parse_bg_high_colour_2,
568 parse_bg_greyscale_0,
569 parse_bg_greyscale_1,
570 parse_bg_true_colour_0,
571 parse_bg_true_colour_1,
572 parse_bg_true_colour_2,
573 parse_bg_true_colour_3,
574 parse_bg_true_colour_4,
575 parse_bg_true_colour_5,
582 while (!text.empty() && info.state != parser_state::done)
584 handlers[
static_cast<int>(info.state)](text[0], info, elem);
585 text = text.subspan(1);
A structure that carries around the character attributes of an ANSI element.
Definition glyph.hpp:19