Porytiles
Loading...
Searching...
No Matches
text_formatter.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <format>
5#include <functional>
6#include <string>
7#include <type_traits>
8#include <utility>
9#include <vector>
10
12
13namespace porytiles {
14
20enum class PredefinedColor : std::uint8_t {
21 none,
22 black,
23 red,
24 green,
25 yellow,
26 blue,
27 magenta,
28 cyan,
29 white
30};
31
37struct RgbColor {
38 std::uint8_t r;
39 std::uint8_t g;
40 std::uint8_t b;
41};
42
60class Style {
61 public:
62 // Formatting constants
63 static const Style none;
64 static const Style bold;
65 static const Style faint;
66 static const Style italic;
67 static const Style underline;
68 static const Style blink;
69
70 // Foreground color constants
71 static const Style black;
72 static const Style red;
73 static const Style green;
74 static const Style yellow;
75 static const Style blue;
76 static const Style magenta;
77 static const Style cyan;
78 static const Style white;
79
80 // Background color constants
81 static const Style bg_black;
82 static const Style bg_red;
83 static const Style bg_green;
84 static const Style bg_yellow;
85 static const Style bg_blue;
86 static const Style bg_magenta;
87 static const Style bg_cyan;
88 static const Style bg_white;
89
91 constexpr Style() = default;
92
103 [[nodiscard]] constexpr Style operator|(const Style &other) const
104 {
105 Style result{};
106
107 // Combine format flags with bitwise OR
108 result.format_flags_ = format_flags_ | other.format_flags_;
109
110 // Foreground color: right-hand side wins if both have foreground colors
111 if (other.has_fg_color()) {
112 result.fg_predefined_ = other.fg_predefined_;
113 result.fg_rgb_ = other.fg_rgb_;
114 result.has_fg_rgb_ = other.has_fg_rgb_;
115 }
116 else if (has_fg_color()) {
117 result.fg_predefined_ = fg_predefined_;
118 result.fg_rgb_ = fg_rgb_;
119 result.has_fg_rgb_ = has_fg_rgb_;
120 }
121
122 // Background color: right-hand side wins if both have background colors
123 if (other.has_bg_color()) {
124 result.bg_predefined_ = other.bg_predefined_;
125 result.bg_rgb_ = other.bg_rgb_;
126 result.has_bg_rgb_ = other.has_bg_rgb_;
127 }
128 else if (has_bg_color()) {
129 result.bg_predefined_ = bg_predefined_;
130 result.bg_rgb_ = bg_rgb_;
131 result.has_bg_rgb_ = has_bg_rgb_;
132 }
133
134 return result;
135 }
136
140 [[nodiscard]] constexpr bool has_bold() const
141 {
142 return (format_flags_ & bold_flag) != 0;
143 }
144
148 [[nodiscard]] constexpr bool has_faint() const
149 {
150 return (format_flags_ & faint_flag) != 0;
151 }
152
156 [[nodiscard]] constexpr bool has_italic() const
157 {
158 return (format_flags_ & italic_flag) != 0;
159 }
160
164 [[nodiscard]] constexpr bool has_underline() const
165 {
166 return (format_flags_ & underline_flag) != 0;
167 }
168
172 [[nodiscard]] constexpr bool has_blink() const
173 {
174 return (format_flags_ & blink_flag) != 0;
175 }
176
180 [[nodiscard]] constexpr bool has_fg_color() const
181 {
182 return has_fg_rgb_ || fg_predefined_ != PredefinedColor::none;
183 }
184
188 [[nodiscard]] constexpr bool has_bg_color() const
189 {
190 return has_bg_rgb_ || bg_predefined_ != PredefinedColor::none;
191 }
192
196 [[nodiscard]] constexpr bool is_fg_rgb() const
197 {
198 return has_fg_rgb_;
199 }
200
204 [[nodiscard]] constexpr bool is_bg_rgb() const
205 {
206 return has_bg_rgb_;
207 }
208
213 [[nodiscard]] constexpr RgbColor fg_rgb() const
214 {
215 return fg_rgb_;
216 }
217
222 [[nodiscard]] constexpr RgbColor bg_rgb() const
223 {
224 return bg_rgb_;
225 }
226
231 [[nodiscard]] constexpr PredefinedColor fg_predefined() const
232 {
233 return fg_predefined_;
234 }
235
240 [[nodiscard]] constexpr PredefinedColor bg_predefined() const
241 {
242 return bg_predefined_;
243 }
244
245 private:
246 static constexpr std::uint8_t bold_flag = 1 << 0;
247 static constexpr std::uint8_t faint_flag = 1 << 1;
248 static constexpr std::uint8_t italic_flag = 1 << 2;
249 static constexpr std::uint8_t underline_flag = 1 << 3;
250 static constexpr std::uint8_t blink_flag = 1 << 4;
251
252 std::uint8_t format_flags_{0};
255 RgbColor fg_rgb_{0, 0, 0};
256 RgbColor bg_rgb_{0, 0, 0};
257 bool has_fg_rgb_{false};
258 bool has_bg_rgb_{false};
259
260 // Private constructors for creating specific style types
261 enum class FormatFlagTag { bold, faint, italic, underline, blink };
262 enum class FgColorTag { predefined, rgb };
263 enum class BgColorTag { predefined, rgb };
264
265 constexpr explicit Style(FormatFlagTag tag)
266 {
267 switch (tag) {
268 case FormatFlagTag::bold:
269 format_flags_ = bold_flag;
270 break;
271 case FormatFlagTag::faint:
272 format_flags_ = faint_flag;
273 break;
274 case FormatFlagTag::italic:
275 format_flags_ = italic_flag;
276 break;
277 case FormatFlagTag::underline:
278 format_flags_ = underline_flag;
279 break;
280 case FormatFlagTag::blink:
281 format_flags_ = blink_flag;
282 break;
283 default:
284 panic("unhandled FormatFlagTag value");
285 }
286 }
287
288 constexpr explicit Style(FgColorTag, PredefinedColor color) : fg_predefined_{color} {}
289
290 constexpr explicit Style(BgColorTag, PredefinedColor color) : bg_predefined_{color} {}
291
292 constexpr explicit Style(FgColorTag, std::uint8_t r, std::uint8_t g, std::uint8_t b)
293 : fg_rgb_{r, g, b}, has_fg_rgb_{true}
294 {
295 }
296
297 constexpr explicit Style(BgColorTag, std::uint8_t r, std::uint8_t g, std::uint8_t b)
298 : bg_rgb_{r, g, b}, has_bg_rgb_{true}
299 {
300 }
301
302 // Friend functions for creating RGB styles
303 friend constexpr Style rgb_fg_style(std::uint8_t r, std::uint8_t g, std::uint8_t b);
304 friend constexpr Style rgb_bg_style(std::uint8_t r, std::uint8_t g, std::uint8_t b);
305};
306
321[[nodiscard]] constexpr Style rgb_fg_style(std::uint8_t r, std::uint8_t g, std::uint8_t b)
322{
323 return Style{Style::FgColorTag::rgb, r, g, b};
324}
325
340[[nodiscard]] constexpr Style rgb_bg_style(std::uint8_t r, std::uint8_t g, std::uint8_t b)
341{
342 return Style{Style::BgColorTag::rgb, r, g, b};
343}
344
355[[nodiscard]] constexpr Style rgb_style(std::uint8_t r, std::uint8_t g, std::uint8_t b)
356{
357 return rgb_fg_style(r, g, b);
358}
359
374 public:
381 FormatParam(std::string text) : text_{std::move(text)}, styles_{Style::none} {}
382
390 explicit FormatParam(std::string text, Style styles) : text_{std::move(text)}, styles_{styles} {}
391
401 template <typename T>
402 requires(
403 !std::is_same_v<std::decay_t<T>, std::string> && !std::is_same_v<std::decay_t<T>, FormatParam> &&
404 std::formattable<std::decay_t<T>, char>)
405 FormatParam(T &&value) : FormatParam(resolve_string(std::forward<T>(value)))
406 {
407 }
408
418 template <typename T>
419 requires(
420 !std::is_same_v<std::decay_t<T>, std::string> && !std::is_same_v<std::decay_t<T>, FormatParam> &&
421 std::formattable<std::decay_t<T>, char>)
422 explicit FormatParam(T &&value, Style styles) : FormatParam(resolve_string(std::forward<T>(value)), styles)
423 {
424 }
425
426 [[nodiscard]] const std::string &text() const
427 {
428 return text_;
429 }
430
431 [[nodiscard]] Style styles() const
432 {
433 return styles_;
434 }
435
436 private:
437 std::string text_;
438 Style styles_;
439
449 template <typename T>
450 static std::string resolve_string(T &&value)
451 {
452 return std::format("{}", std::forward<T>(value));
453 }
454};
455
470 public:
471 virtual ~TextFormatter() = default;
472
483 [[nodiscard]] virtual std::string style(const std::string &text, Style styles) const = 0;
484
500 [[nodiscard]] virtual std::string
501 format(const std::string &format_str, const std::vector<FormatParam> &params) const;
502
524 template <typename FirstParam, typename... RestParams>
525 requires(
526 !std::is_same_v<std::decay_t<FirstParam>, std::vector<FormatParam>> &&
527 std::is_constructible_v<FormatParam, FirstParam> &&
528 (std::is_constructible_v<FormatParam, RestParams> && ...))
529 [[nodiscard]] std::string format(const std::string &format_str, FirstParam &&first, RestParams &&...rest) const
530 {
531 std::vector<FormatParam> param_vector;
532 param_vector.reserve(1 + sizeof...(RestParams));
533 param_vector.emplace_back(std::forward<FirstParam>(first));
534 (param_vector.emplace_back(std::forward<RestParams>(rest)), ...);
535 return this->format(format_str, param_vector);
536 }
537};
538
555using FormattedMessageBuilder = std::function<std::vector<std::string>(const TextFormatter &)>;
556
557} // namespace porytiles
A text parameter with associated styling for formatted output.
FormatParam(std::string text)
Constructs a FormatParam with unstyled text.
FormatParam(T &&value, Style styles)
Constructs a FormatParam by converting a value to styled string.
const std::string & text() const
FormatParam(T &&value)
Constructs a FormatParam by converting a value to string.
FormatParam(std::string text, Style styles)
Constructs a FormatParam with styled text.
Text styling class supporting formatting, foreground colors, and background colors.
constexpr bool is_bg_rgb() const
Checks if the background color is in RGB mode.
friend constexpr Style rgb_bg_style(std::uint8_t r, std::uint8_t g, std::uint8_t b)
Creates a Style value with a custom RGB background color.
constexpr bool has_faint() const
Checks if this Style has faint formatting.
static const Style bg_green
Green background color.
static const Style white
White foreground color.
static const Style bg_blue
Blue background color.
static const Style faint
Faint text formatting.
static const Style underline
Underline text formatting.
static const Style bg_yellow
Yellow background color.
static const Style italic
Italic text formatting.
static const Style none
No styling applied.
constexpr Style operator|(const Style &other) const
Combines two Style values using the | operator.
static const Style black
Black foreground color.
static const Style bg_black
Black background color.
constexpr bool has_fg_color() const
Checks if this Style has a foreground color set.
constexpr bool has_blink() const
Checks if this Style has blink formatting.
constexpr RgbColor fg_rgb() const
Returns the foreground RGB color.
constexpr bool has_underline() const
Checks if this Style has underline formatting.
constexpr bool has_italic() const
Checks if this Style has italic formatting.
static const Style yellow
Yellow foreground color.
constexpr PredefinedColor bg_predefined() const
Returns the predefined background color.
static const Style bg_white
White background color.
static const Style bg_magenta
Magenta background color.
constexpr PredefinedColor fg_predefined() const
Returns the predefined foreground color.
static const Style magenta
Magenta foreground color.
static const Style bg_cyan
Cyan background color.
constexpr bool has_bold() const
Checks if this Style has bold formatting.
static const Style red
Red foreground color.
static const Style cyan
Cyan foreground color.
static const Style blue
Blue foreground color.
constexpr RgbColor bg_rgb() const
Returns the background RGB color.
static const Style bold
Bold text formatting.
friend constexpr Style rgb_fg_style(std::uint8_t r, std::uint8_t g, std::uint8_t b)
Creates a Style value with a custom RGB foreground color.
constexpr bool is_fg_rgb() const
Checks if the foreground color is in RGB mode.
constexpr bool has_bg_color() const
Checks if this Style has a background color set.
static const Style bg_red
Red background color.
constexpr Style()=default
Default constructor creating a style with no attributes.
static const Style green
Green foreground color.
static const Style blink
Blink text formatting.
Abstract base class for applying text styling with context-aware formatting.
virtual std::string style(const std::string &text, Style styles) const =0
Applies styling to a text string.
virtual ~TextFormatter()=default
virtual std::string format(const std::string &format_str, const std::vector< FormatParam > &params) const
Formats a string with styled parameters using fmtlib syntax.
std::string format(const std::string &format_str, FirstParam &&first, RestParams &&...rest) const
Formats a string with styled parameters using variadic template syntax.
void panic(const StringViewSourceLoc &s)
Unconditionally terminates the program with a panic message.
Definition panic.cpp:43
constexpr Style rgb_fg_style(std::uint8_t r, std::uint8_t g, std::uint8_t b)
Creates a Style value with a custom RGB foreground color.
constexpr Style rgb_bg_style(std::uint8_t r, std::uint8_t g, std::uint8_t b)
Creates a Style value with a custom RGB background color.
PredefinedColor
Predefined color options for text styling.
std::function< std::vector< std::string >(const TextFormatter &)> FormattedMessageBuilder
Function type for building formatted messages with TextFormatter access.
constexpr Style rgb_style(std::uint8_t r, std::uint8_t g, std::uint8_t b)
Creates a Style value with a custom RGB foreground color (backward compatibility alias).
RGB color representation for extracting color components from Style values.
std::uint8_t b
Blue channel (0-255)
std::uint8_t r
Red channel (0-255)
std::uint8_t g
Green channel (0-255)