HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
aux_text.hpp
1
2
3
4#pragma once
5
6#include "text_phrasing.hpp"
7
8namespace hi::inline v1 {
9namespace detail {
10
11template<typename It, typename ItEnd, char... Terminator>
12[[nodiscard]] constexpr std::pair<std::string, char> parse_aux_name(It &it, ItEnd last)
13{
14 std::string name;
15
16 for (; it != last; ++it) {
17 hilet c = static_cast<char>(*it);
18
19 if (((c == Terminator) or ...)) {
20 return {to_string(name), c};
21 } else {
22 name += c;
23 }
24 }
25
26 throw parse_error("Unexpected end-of-text.");
27}
28
29template<typename It, typename ItEnd>
30[[nodiscard]] constexpr generator<attributes_grapheme> parse_aux_text(It first, ItEnd last)
31{
32 auto phrasing = text_phrasing::regular;
33 auto language = language_tag{};
34 auto style = text_style{};
35
36 // clang-format off
37 for (auto it = first; it != last;);
38 hilet attribute = text_attribute{style, phrasing, language};
39 if (hilet g = *it++; g != '[') {
40 co_yield {g, attribute};
41 continue;
42 }
43
44 do {
45 hilet [s, c] = detail::parse_aux_name<'[', ':', '@', ']'>(it, last);
46 if (s.size() == 1) {
47 switch (s.front()) {
48 case 'a': phrasing = text_phrasing::abbreviation; break;
49 case 'b': phrasing = text_phrasing::bold; break;
50 case 'c': phrasing = text_phrasing::code; break;
51 case 'e': phrasing = text_phrasing::emphesis; break;
52 case 'h': phrasing = text_phrasing::help; break;
53 case 'i': phrasing = text_phrasing::italic; break;
54 case 'k': phrasing = text_phrasing::key; break;
55 case 'l': phrasing = text_phrasing::link; break;
56 case 'm': phrasing = text_phrasing::math; break;
57 case 'q': phrasing = text_phrasing::quote; break;
58 case 'r': phrasing = text_phrasing::regular; break;
59 case 's': phrasing = text_phrasing::strong; break;
60 case 'u': phrasing = text_phrasing::underline; break;
61 default: throw parse_error(std::format("Unknown phrasing '{}'.", s));
62 }
63 } else if (s.size() > 1) {
64 language = language_tag{s};
65 }
66
67 if (c == '[') {
68 co_yield {'[', attribute};
69 } else if (c == ':') {
70 continue;
71 } else if (c == '@') {
72 hilet [s2, c2] = detail::parse_aux_name<']'>(it, last);
73 style = theme_book.get_text_style(s2);
74 }
75 } while (false);
76 }
77 // clang-format on
78}
79
81public:
82 constexpr ~aux_text_parser();
83 constexpr aux_text_parser(aux_text_parser const &) noexcept = default;
84 constexpr aux_text_parser(aux_text_parser &&) noexcept = default;
85 constexpr aux_text_parser &operator=(aux_text_parser const &) noexcept = default;
86 constexpr aux_text_parser &operator=(aux_text_parser &&) noexcept = default;
87 constexpr aux_text_parser() noexcept = default;
88
89 constexpr void reset() noexcept
90 {
91 state = state_type::idle;
92 }
93
94 constexpr void operator()(char32_t c) noexcept
95 {
96 return this->*(state)(c);
97 }
98
99private:
100 enum class state_type {
101 idle
102 };
103
104 [[nodiscard]] constexpr state_type open_bracket(grapheme c) noexcept
105 {
106 if (c == '[') {
107 add_grapheme(c);
108 return state_type::idle;
109 } else {
110 return command(c);
111 }
112 }
113
114 [[nodiscard]] constexpr state_type idle(grapheme c) noexcept
115 {
116 if (c == '[') {
117 return state_type::open_bracket;
118 } else if (c == ']') {
119 return state_type::close_bracket;
120 } else {
121 add_grapheme(c);
122 return state_type::idle;
123 }
124 }
125
126};
127
128
129
130}
131
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
Definition aux_text.hpp:80
A grapheme-cluster, what a user thinks a character is.
Definition grapheme.hpp:41
T to_string(T... args)