8 #ifndef FMTQUILL_COLOR_H_ 9 #define FMTQUILL_COLOR_H_ 13 FMTQUILL_BEGIN_NAMESPACE
16 enum class color : uint32_t {
17 alice_blue = 0xF0F8FF,
18 antique_white = 0xFAEBD7,
20 aquamarine = 0x7FFFD4,
25 blanched_almond = 0xFFEBCD,
27 blue_violet = 0x8A2BE2,
29 burly_wood = 0xDEB887,
30 cadet_blue = 0x5F9EA0,
31 chartreuse = 0x7FFF00,
34 cornflower_blue = 0x6495ED,
40 dark_golden_rod = 0xB8860B,
42 dark_green = 0x006400,
43 dark_khaki = 0xBDB76B,
44 dark_magenta = 0x8B008B,
45 dark_olive_green = 0x556B2F,
46 dark_orange = 0xFF8C00,
47 dark_orchid = 0x9932CC,
49 dark_salmon = 0xE9967A,
50 dark_sea_green = 0x8FBC8F,
51 dark_slate_blue = 0x483D8B,
52 dark_slate_gray = 0x2F4F4F,
53 dark_turquoise = 0x00CED1,
54 dark_violet = 0x9400D3,
56 deep_sky_blue = 0x00BFFF,
58 dodger_blue = 0x1E90FF,
59 fire_brick = 0xB22222,
60 floral_white = 0xFFFAF0,
61 forest_green = 0x228B22,
64 ghost_white = 0xF8F8FF,
66 golden_rod = 0xDAA520,
69 green_yellow = 0xADFF2F,
72 indian_red = 0xCD5C5C,
77 lavender_blush = 0xFFF0F5,
78 lawn_green = 0x7CFC00,
79 lemon_chiffon = 0xFFFACD,
80 light_blue = 0xADD8E6,
81 light_coral = 0xF08080,
82 light_cyan = 0xE0FFFF,
83 light_golden_rod_yellow = 0xFAFAD2,
84 light_gray = 0xD3D3D3,
85 light_green = 0x90EE90,
86 light_pink = 0xFFB6C1,
87 light_salmon = 0xFFA07A,
88 light_sea_green = 0x20B2AA,
89 light_sky_blue = 0x87CEFA,
90 light_slate_gray = 0x778899,
91 light_steel_blue = 0xB0C4DE,
92 light_yellow = 0xFFFFE0,
94 lime_green = 0x32CD32,
98 medium_aquamarine = 0x66CDAA,
99 medium_blue = 0x0000CD,
100 medium_orchid = 0xBA55D3,
101 medium_purple = 0x9370DB,
102 medium_sea_green = 0x3CB371,
103 medium_slate_blue = 0x7B68EE,
104 medium_spring_green = 0x00FA9A,
105 medium_turquoise = 0x48D1CC,
106 medium_violet_red = 0xC71585,
107 midnight_blue = 0x191970,
108 mint_cream = 0xF5FFFA,
109 misty_rose = 0xFFE4E1,
111 navajo_white = 0xFFDEAD,
115 olive_drab = 0x6B8E23,
117 orange_red = 0xFF4500,
119 pale_golden_rod = 0xEEE8AA,
120 pale_green = 0x98FB98,
121 pale_turquoise = 0xAFEEEE,
122 pale_violet_red = 0xDB7093,
123 papaya_whip = 0xFFEFD5,
124 peach_puff = 0xFFDAB9,
128 powder_blue = 0xB0E0E6,
130 rebecca_purple = 0x663399,
132 rosy_brown = 0xBC8F8F,
133 royal_blue = 0x4169E1,
134 saddle_brown = 0x8B4513,
136 sandy_brown = 0xF4A460,
137 sea_green = 0x2E8B57,
138 sea_shell = 0xFFF5EE,
142 slate_blue = 0x6A5ACD,
143 slate_gray = 0x708090,
145 spring_green = 0x00FF7F,
146 steel_blue = 0x4682B4,
151 turquoise = 0x40E0D0,
155 white_smoke = 0xF5F5F5,
157 yellow_green = 0x9ACD32
160 enum class terminal_color : uint8_t {
179 enum class emphasis : uint8_t {
187 strikethrough = 1 << 7,
193 constexpr
rgb() : r(0), g(0), b(0) {}
194 constexpr rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {}
195 constexpr rgb(uint32_t hex)
196 : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {}
197 constexpr rgb(color hex)
198 : r((uint32_t(hex) >> 16) & 0xFF),
199 g((uint32_t(hex) >> 8) & 0xFF),
200 b(uint32_t(hex) & 0xFF) {}
212 constexpr
color_type(color rgb_color) noexcept
213 : value_(static_cast<uint32_t>(rgb_color) | (1 << 24)) {}
216 (static_cast<uint32_t>(rgb_color.r) << 16) |
217 (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b)) {}
218 constexpr
color_type(terminal_color term_color) noexcept
219 : value_(static_cast<uint32_t>(term_color) | (3 << 24)) {}
221 constexpr
auto is_terminal_color()
const noexcept ->
bool {
222 return (value_ & (1 << 25)) != 0;
225 constexpr
auto value()
const noexcept -> uint32_t {
226 return value_ & 0xFFFFFF;
290 FMTQUILL_CONSTEXPR
text_style(emphasis em = emphasis()) noexcept
291 : style_(static_cast<uint64_t>(em) << 54) {}
294 if (((style_ + rhs.style_) & ((1ULL << 26) | (1ULL << 53))) != 0)
295 report_error(
"can't OR a terminal color");
296 style_ |= rhs.style_;
305 FMTQUILL_CONSTEXPR
auto operator==(
text_style rhs)
const noexcept ->
bool {
306 return style_ == rhs.style_;
309 FMTQUILL_CONSTEXPR
auto operator!=(
text_style rhs)
const noexcept ->
bool {
310 return !(*
this == rhs);
313 FMTQUILL_CONSTEXPR
auto has_foreground()
const noexcept ->
bool {
314 return (style_ & (1 << 24)) != 0;
316 FMTQUILL_CONSTEXPR
auto has_background()
const noexcept ->
bool {
317 return (style_ & (1ULL << 51)) != 0;
319 FMTQUILL_CONSTEXPR
auto has_emphasis()
const noexcept ->
bool {
320 return (style_ >> 54) != 0;
323 FMTQUILL_ASSERT(has_foreground(),
"no foreground specified for this style");
324 return style_ & 0x3FFFFFF;
327 FMTQUILL_ASSERT(has_background(),
"no background specified for this style");
328 return (style_ >> 27) & 0x3FFFFFF;
330 FMTQUILL_CONSTEXPR
auto get_emphasis()
const noexcept -> emphasis {
331 FMTQUILL_ASSERT(has_emphasis(),
"no emphasis specified for this style");
332 return static_cast<emphasis
>(style_ >> 54);
336 FMTQUILL_CONSTEXPR
text_style(uint64_t style) noexcept : style_(style) {}
350 return foreground.value_;
356 return static_cast<uint64_t
>(background.value_) << 27;
359 FMTQUILL_CONSTEXPR
inline auto operator|(emphasis lhs, emphasis rhs) noexcept
368 const char* esc) noexcept {
371 if (text_color.is_terminal_color()) {
372 bool is_background = esc ==
string_view(
"\x1b[48;2;");
373 uint32_t
value = text_color.value();
376 if (is_background) value += 10u;
379 buffer[index++] =
static_cast<Char
>(
'\x1b');
380 buffer[index++] =
static_cast<Char
>(
'[');
383 buffer[index++] =
static_cast<Char
>(
'1');
386 buffer[index++] =
static_cast<Char
>(
'0' + value / 10u);
387 buffer[index++] =
static_cast<Char
>(
'0' + value % 10u);
389 buffer[index++] =
static_cast<Char
>(
'm');
390 buffer[index++] =
static_cast<Char
>(
'\0');
394 for (
int i = 0; i < 7; i++) {
395 buffer[i] =
static_cast<Char
>(esc[i]);
397 rgb color(text_color.value());
398 to_esc(color.r,
buffer + 7,
';');
399 to_esc(color.g,
buffer + 11,
';');
400 to_esc(color.b,
buffer + 15,
'm');
401 buffer[19] =
static_cast<Char
>(0);
404 uint8_t em_codes[num_emphases] = {};
405 if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
406 if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
407 if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3;
408 if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4;
409 if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5;
410 if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7;
411 if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8;
412 if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9;
415 for (
size_t i = 0; i < num_emphases; ++i) {
416 if (!em_codes[i])
continue;
417 buffer[index++] =
static_cast<Char
>(
'\x1b');
418 buffer[index++] =
static_cast<Char
>(
'[');
419 buffer[index++] =
static_cast<Char
>(
'0' + em_codes[i]);
420 buffer[index++] =
static_cast<Char
>(
'm');
422 buffer[index++] =
static_cast<Char
>(0);
424 FMTQUILL_CONSTEXPR
operator const Char*()
const noexcept {
return buffer; }
426 FMTQUILL_CONSTEXPR
auto begin()
const noexcept ->
const Char* {
return buffer; }
427 FMTQUILL_CONSTEXPR20
auto end()
const noexcept ->
const Char* {
432 static constexpr
size_t num_emphases = 8;
433 Char
buffer[7u + 3u * num_emphases + 1u];
435 static FMTQUILL_CONSTEXPR
void to_esc(uint8_t c, Char* out,
436 char delimiter) noexcept {
437 out[0] =
static_cast<Char
>(
'0' + c / 100);
438 out[1] =
static_cast<Char
>(
'0' + c / 10 % 10);
439 out[2] =
static_cast<Char
>(
'0' + c % 10);
440 out[3] =
static_cast<Char
>(delimiter);
442 static FMTQUILL_CONSTEXPR
auto has_emphasis(emphasis em, emphasis mask) noexcept
444 return static_cast<uint8_t
>(em) & static_cast<uint8_t>(mask);
448 template <
typename Char>
449 FMTQUILL_CONSTEXPR
auto make_foreground_color(
color_type foreground) noexcept
454 template <
typename Char>
455 FMTQUILL_CONSTEXPR
auto make_background_color(
color_type background) noexcept
460 template <
typename Char>
461 FMTQUILL_CONSTEXPR
auto make_emphasis(emphasis em) noexcept
468 buffer.
append(reset_color.begin(), reset_color.end());
477 template <
typename Char>
480 if (ts.has_emphasis()) {
481 auto emphasis = make_emphasis<Char>(ts.get_emphasis());
482 buf.
append(emphasis.begin(), emphasis.end());
484 if (ts.has_foreground()) {
485 auto foreground = make_foreground_color<Char>(ts.get_foreground());
486 buf.
append(foreground.begin(), foreground.end());
488 if (ts.has_background()) {
489 auto background = make_background_color<Char>(ts.get_background());
490 buf.
append(background.begin(), background.end());
492 vformat_to(buf, fmt, args);
493 if (ts !=
text_style()) reset_color<Char>(buf);
499 detail::vformat_to(buf, ts, fmt, args);
500 print(f, FMTQUILL_STRING(
"{}"),
string_view(buf.begin(), buf.size()));
512 template <
typename... T>
513 void print(FILE* f,
text_style ts, format_string<T...> fmt, T&&... args) {
526 template <
typename... T>
527 void print(
text_style ts, format_string<T...> fmt, T&&... args) {
528 return print(stdout, ts, fmt, std::forward<T>(args)...);
534 detail::vformat_to(buf, ts, fmt, args);
535 return fmtquill::to_string(buf);
550 template <
typename... T>
551 inline auto format(
text_style ts, format_string<T...> fmt, T&&... args)
553 return fmtquill::vformat(ts, fmt.str,
vargs<T...>{{args...}});
557 template <
typename OutputIt,
561 auto&& buf = detail::get_buffer<char>(out);
562 detail::vformat_to(buf, ts, fmt, args);
563 return detail::get_iterator(buf, out);
576 template <
typename OutputIt,
typename... T,
578 inline auto format_to(OutputIt out,
text_style ts, format_string<T...> fmt,
579 T&&... args) -> OutputIt {
580 return vformat_to(out, ts, fmt.str,
vargs<T...>{{args...}});
583 template <
typename T,
typename Char>
585 template <
typename FormatContext>
587 -> decltype(ctx.out()) {
588 const auto& ts = arg.style;
589 auto out = ctx.out();
591 bool has_style =
false;
592 if (ts.has_emphasis()) {
594 auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
595 out = detail::copy<Char>(emphasis.begin(), emphasis.end(), out);
597 if (ts.has_foreground()) {
600 detail::make_foreground_color<Char>(ts.get_foreground());
601 out = detail::copy<Char>(foreground.begin(), foreground.end(), out);
603 if (ts.has_background()) {
606 detail::make_background_color<Char>(ts.get_background());
607 out = detail::copy<Char>(background.begin(), background.end(), out);
612 out = detail::copy<Char>(reset_color.begin(), reset_color.end(), out);
628 template <
typename T>
629 FMTQUILL_CONSTEXPR
auto styled(
const T& value,
text_style ts)
635 FMTQUILL_END_NAMESPACE
637 #endif // FMTQUILL_COLOR_H_
FMTQUILL_CONSTEXPR20 void append(const U *begin, const U *end)
Appends data to the end of the buffer.
Definition: base.h:1833
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:24
A text style consisting of foreground and background colors and emphasis.
Definition: color.h:236
A contiguous memory buffer with an optional growing ability.
Definition: base.h:1751