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
22enum class PredefinedColor : std::uint8_t {
23 none,
24 black,
25 red,
26 green,
27 yellow,
28 blue,
29 magenta,
30 cyan,
31 white
32};
33
41struct RgbColor {
42 std::uint8_t r;
43 std::uint8_t g;
44 std::uint8_t b;
45};
46
66class Style {
67 public:
68 // Formatting constants
69 static const Style none;
70 static const Style bold;
71 static const Style faint;
72 static const Style italic;
73 static const Style underline;
74 static const Style blink;
75
76 // Foreground color constants
77 static const Style black;
78 static const Style red;
79 static const Style green;
80 static const Style yellow;
81 static const Style blue;
82 static const Style magenta;
83 static const Style cyan;
84 static const Style white;
85
86 // Background color constants
87 static const Style bg_black;
88 static const Style bg_red;
89 static const Style bg_green;
90 static const Style bg_yellow;
91 static const Style bg_blue;
92 static const Style bg_magenta;
93 static const Style bg_cyan;
94 static const Style bg_white;
95
99 constexpr Style() = default;
100
113 [[nodiscard]] constexpr Style operator|(const Style &other) const
114 {
115 Style result{};
116
117 // Combine format flags with bitwise OR
118 result.format_flags_ = format_flags_ | other.format_flags_;
119
120 // Foreground color: right-hand side wins if both have foreground colors
121 if (other.has_fg_color()) {
122 result.fg_predefined_ = other.fg_predefined_;
123 result.fg_rgb_ = other.fg_rgb_;
124 result.has_fg_rgb_ = other.has_fg_rgb_;
125 }
126 else if (has_fg_color()) {
127 result.fg_predefined_ = fg_predefined_;
128 result.fg_rgb_ = fg_rgb_;
129 result.has_fg_rgb_ = has_fg_rgb_;
130 }
131
132 // Background color: right-hand side wins if both have background colors
133 if (other.has_bg_color()) {
134 result.bg_predefined_ = other.bg_predefined_;
135 result.bg_rgb_ = other.bg_rgb_;
136 result.has_bg_rgb_ = other.has_bg_rgb_;
137 }
138 else if (has_bg_color()) {
139 result.bg_predefined_ = bg_predefined_;
140 result.bg_rgb_ = bg_rgb_;
141 result.has_bg_rgb_ = has_bg_rgb_;
142 }
143
144 return result;
145 }
146
152 [[nodiscard]] constexpr bool has_bold() const
153 {
154 return (format_flags_ & bold_flag) != 0;
155 }
156
162 [[nodiscard]] constexpr bool has_faint() const
163 {
164 return (format_flags_ & faint_flag) != 0;
165 }
166
172 [[nodiscard]] constexpr bool has_italic() const
173 {
174 return (format_flags_ & italic_flag) != 0;
175 }
176
182 [[nodiscard]] constexpr bool has_underline() const
183 {
184 return (format_flags_ & underline_flag) != 0;
185 }
186
192 [[nodiscard]] constexpr bool has_blink() const
193 {
194 return (format_flags_ & blink_flag) != 0;
195 }
196
202 [[nodiscard]] constexpr bool has_fg_color() const
203 {
204 return has_fg_rgb_ || fg_predefined_ != PredefinedColor::none;
205 }
206
212 [[nodiscard]] constexpr bool has_bg_color() const
213 {
214 return has_bg_rgb_ || bg_predefined_ != PredefinedColor::none;
215 }
216
222 [[nodiscard]] constexpr bool is_fg_rgb() const
223 {
224 return has_fg_rgb_;
225 }
226
232 [[nodiscard]] constexpr bool is_bg_rgb() const
233 {
234 return has_bg_rgb_;
235 }
236
243 [[nodiscard]] constexpr RgbColor fg_rgb() const
244 {
245 return fg_rgb_;
246 }
247
254 [[nodiscard]] constexpr RgbColor bg_rgb() const
255 {
256 return bg_rgb_;
257 }
258
265 [[nodiscard]] constexpr PredefinedColor fg_predefined() const
266 {
267 return fg_predefined_;
268 }
269
276 [[nodiscard]] constexpr PredefinedColor bg_predefined() const
277 {
278 return bg_predefined_;
279 }
280
281 private:
282 static constexpr std::uint8_t bold_flag = 1 << 0;
283 static constexpr std::uint8_t faint_flag = 1 << 1;
284 static constexpr std::uint8_t italic_flag = 1 << 2;
285 static constexpr std::uint8_t underline_flag = 1 << 3;
286 static constexpr std::uint8_t blink_flag = 1 << 4;
287
288 std::uint8_t format_flags_{0};
291 RgbColor fg_rgb_{0, 0, 0};
292 RgbColor bg_rgb_{0, 0, 0};
293 bool has_fg_rgb_{false};
294 bool has_bg_rgb_{false};
295
296 // Private constructors for creating specific style types
297 enum class FormatFlagTag { bold, faint, italic, underline, blink };
298 enum class FgColorTag { predefined, rgb };
299 enum class BgColorTag { predefined, rgb };
300
301 constexpr explicit Style(FormatFlagTag tag)
302 {
303 switch (tag) {
304 case FormatFlagTag::bold:
305 format_flags_ = bold_flag;
306 break;
307 case FormatFlagTag::faint:
308 format_flags_ = faint_flag;
309 break;
310 case FormatFlagTag::italic:
311 format_flags_ = italic_flag;
312 break;
313 case FormatFlagTag::underline:
314 format_flags_ = underline_flag;
315 break;
316 case FormatFlagTag::blink:
317 format_flags_ = blink_flag;
318 break;
319 default:
320 panic("unhandled FormatFlagTag value");
321 }
322 }
323
324 constexpr explicit Style(FgColorTag, PredefinedColor color) : fg_predefined_{color} {}
325
326 constexpr explicit Style(BgColorTag, PredefinedColor color) : bg_predefined_{color} {}
327
328 constexpr explicit Style(FgColorTag, std::uint8_t r, std::uint8_t g, std::uint8_t b)
329 : fg_rgb_{r, g, b}, has_fg_rgb_{true}
330 {
331 }
332
333 constexpr explicit Style(BgColorTag, std::uint8_t r, std::uint8_t g, std::uint8_t b)
334 : bg_rgb_{r, g, b}, has_bg_rgb_{true}
335 {
336 }
337
338 // Friend functions for creating RGB styles
339 friend constexpr Style rgb_fg_style(std::uint8_t r, std::uint8_t g, std::uint8_t b);
340 friend constexpr Style rgb_bg_style(std::uint8_t r, std::uint8_t g, std::uint8_t b);
341};
342
359[[nodiscard]] constexpr Style rgb_fg_style(std::uint8_t r, std::uint8_t g, std::uint8_t b)
360{
361 return Style{Style::FgColorTag::rgb, r, g, b};
362}
363
380[[nodiscard]] constexpr Style rgb_bg_style(std::uint8_t r, std::uint8_t g, std::uint8_t b)
381{
382 return Style{Style::BgColorTag::rgb, r, g, b};
383}
384
397[[nodiscard]] constexpr Style rgb_style(std::uint8_t r, std::uint8_t g, std::uint8_t b)
398{
399 return rgb_fg_style(r, g, b);
400}
401
418 public:
427 FormatParam(std::string text) : text_{std::move(text)}, styles_{Style::none} {}
428
438 explicit FormatParam(std::string text, Style styles) : text_{std::move(text)}, styles_{styles} {}
439
451 template <typename T>
452 requires(
453 !std::is_same_v<std::decay_t<T>, std::string> && !std::is_same_v<std::decay_t<T>, FormatParam> &&
454 std::formattable<std::decay_t<T>, char>)
455 FormatParam(T &&value) : FormatParam(resolve_string(std::forward<T>(value)))
456 {
457 }
458
470 template <typename T>
471 requires(
472 !std::is_same_v<std::decay_t<T>, std::string> && !std::is_same_v<std::decay_t<T>, FormatParam> &&
473 std::formattable<std::decay_t<T>, char>)
474 explicit FormatParam(T &&value, Style styles) : FormatParam(resolve_string(std::forward<T>(value)), styles)
475 {
476 }
477
478 [[nodiscard]] const std::string &text() const
479 {
480 return text_;
481 }
482
483 [[nodiscard]] Style styles() const
484 {
485 return styles_;
486 }
487
488 private:
489 std::string text_;
490 Style styles_;
491
503 template <typename T>
504 static std::string resolve_string(T &&value)
505 {
506 return std::format("{}", std::forward<T>(value));
507 }
508};
509
530 public:
531 virtual ~TextFormatter() = default;
532
545 [[nodiscard]] virtual std::string style(const std::string &text, Style styles) const = 0;
546
564 [[nodiscard]] virtual std::string
565 format(const std::string &format_str, const std::vector<FormatParam> &params) const;
566
590 template <typename FirstParam, typename... RestParams>
591 requires(
592 !std::is_same_v<std::decay_t<FirstParam>, std::vector<FormatParam>> &&
593 std::is_constructible_v<FormatParam, FirstParam> &&
594 (std::is_constructible_v<FormatParam, RestParams> && ...))
595 [[nodiscard]] std::string format(const std::string &format_str, FirstParam &&first, RestParams &&...rest) const
596 {
597 std::vector<FormatParam> param_vector;
598 param_vector.reserve(1 + sizeof...(RestParams));
599 param_vector.emplace_back(std::forward<FirstParam>(first));
600 (param_vector.emplace_back(std::forward<RestParams>(rest)), ...);
601 return this->format(format_str, param_vector);
602 }
603};
604
623using FormattedMessageBuilder = std::function<std::vector<std::string>(const TextFormatter &)>;
624
625} // 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)