quill
color.h
1 // Formatting library for C++ - color support
2 //
3 // Copyright (c) 2018 - present, Victor Zverovich and fmt contributors
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7 
8 #ifndef FMTQUILL_COLOR_H_
9 #define FMTQUILL_COLOR_H_
10 
11 #include "format.h"
12 
13 FMTQUILL_BEGIN_NAMESPACE
14 FMTQUILL_BEGIN_EXPORT
15 
16 enum class color : uint32_t {
17  alice_blue = 0xF0F8FF, // rgb(240,248,255)
18  antique_white = 0xFAEBD7, // rgb(250,235,215)
19  aqua = 0x00FFFF, // rgb(0,255,255)
20  aquamarine = 0x7FFFD4, // rgb(127,255,212)
21  azure = 0xF0FFFF, // rgb(240,255,255)
22  beige = 0xF5F5DC, // rgb(245,245,220)
23  bisque = 0xFFE4C4, // rgb(255,228,196)
24  black = 0x000000, // rgb(0,0,0)
25  blanched_almond = 0xFFEBCD, // rgb(255,235,205)
26  blue = 0x0000FF, // rgb(0,0,255)
27  blue_violet = 0x8A2BE2, // rgb(138,43,226)
28  brown = 0xA52A2A, // rgb(165,42,42)
29  burly_wood = 0xDEB887, // rgb(222,184,135)
30  cadet_blue = 0x5F9EA0, // rgb(95,158,160)
31  chartreuse = 0x7FFF00, // rgb(127,255,0)
32  chocolate = 0xD2691E, // rgb(210,105,30)
33  coral = 0xFF7F50, // rgb(255,127,80)
34  cornflower_blue = 0x6495ED, // rgb(100,149,237)
35  cornsilk = 0xFFF8DC, // rgb(255,248,220)
36  crimson = 0xDC143C, // rgb(220,20,60)
37  cyan = 0x00FFFF, // rgb(0,255,255)
38  dark_blue = 0x00008B, // rgb(0,0,139)
39  dark_cyan = 0x008B8B, // rgb(0,139,139)
40  dark_golden_rod = 0xB8860B, // rgb(184,134,11)
41  dark_gray = 0xA9A9A9, // rgb(169,169,169)
42  dark_green = 0x006400, // rgb(0,100,0)
43  dark_khaki = 0xBDB76B, // rgb(189,183,107)
44  dark_magenta = 0x8B008B, // rgb(139,0,139)
45  dark_olive_green = 0x556B2F, // rgb(85,107,47)
46  dark_orange = 0xFF8C00, // rgb(255,140,0)
47  dark_orchid = 0x9932CC, // rgb(153,50,204)
48  dark_red = 0x8B0000, // rgb(139,0,0)
49  dark_salmon = 0xE9967A, // rgb(233,150,122)
50  dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
51  dark_slate_blue = 0x483D8B, // rgb(72,61,139)
52  dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
53  dark_turquoise = 0x00CED1, // rgb(0,206,209)
54  dark_violet = 0x9400D3, // rgb(148,0,211)
55  deep_pink = 0xFF1493, // rgb(255,20,147)
56  deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
57  dim_gray = 0x696969, // rgb(105,105,105)
58  dodger_blue = 0x1E90FF, // rgb(30,144,255)
59  fire_brick = 0xB22222, // rgb(178,34,34)
60  floral_white = 0xFFFAF0, // rgb(255,250,240)
61  forest_green = 0x228B22, // rgb(34,139,34)
62  fuchsia = 0xFF00FF, // rgb(255,0,255)
63  gainsboro = 0xDCDCDC, // rgb(220,220,220)
64  ghost_white = 0xF8F8FF, // rgb(248,248,255)
65  gold = 0xFFD700, // rgb(255,215,0)
66  golden_rod = 0xDAA520, // rgb(218,165,32)
67  gray = 0x808080, // rgb(128,128,128)
68  green = 0x008000, // rgb(0,128,0)
69  green_yellow = 0xADFF2F, // rgb(173,255,47)
70  honey_dew = 0xF0FFF0, // rgb(240,255,240)
71  hot_pink = 0xFF69B4, // rgb(255,105,180)
72  indian_red = 0xCD5C5C, // rgb(205,92,92)
73  indigo = 0x4B0082, // rgb(75,0,130)
74  ivory = 0xFFFFF0, // rgb(255,255,240)
75  khaki = 0xF0E68C, // rgb(240,230,140)
76  lavender = 0xE6E6FA, // rgb(230,230,250)
77  lavender_blush = 0xFFF0F5, // rgb(255,240,245)
78  lawn_green = 0x7CFC00, // rgb(124,252,0)
79  lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
80  light_blue = 0xADD8E6, // rgb(173,216,230)
81  light_coral = 0xF08080, // rgb(240,128,128)
82  light_cyan = 0xE0FFFF, // rgb(224,255,255)
83  light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
84  light_gray = 0xD3D3D3, // rgb(211,211,211)
85  light_green = 0x90EE90, // rgb(144,238,144)
86  light_pink = 0xFFB6C1, // rgb(255,182,193)
87  light_salmon = 0xFFA07A, // rgb(255,160,122)
88  light_sea_green = 0x20B2AA, // rgb(32,178,170)
89  light_sky_blue = 0x87CEFA, // rgb(135,206,250)
90  light_slate_gray = 0x778899, // rgb(119,136,153)
91  light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
92  light_yellow = 0xFFFFE0, // rgb(255,255,224)
93  lime = 0x00FF00, // rgb(0,255,0)
94  lime_green = 0x32CD32, // rgb(50,205,50)
95  linen = 0xFAF0E6, // rgb(250,240,230)
96  magenta = 0xFF00FF, // rgb(255,0,255)
97  maroon = 0x800000, // rgb(128,0,0)
98  medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
99  medium_blue = 0x0000CD, // rgb(0,0,205)
100  medium_orchid = 0xBA55D3, // rgb(186,85,211)
101  medium_purple = 0x9370DB, // rgb(147,112,219)
102  medium_sea_green = 0x3CB371, // rgb(60,179,113)
103  medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
104  medium_spring_green = 0x00FA9A, // rgb(0,250,154)
105  medium_turquoise = 0x48D1CC, // rgb(72,209,204)
106  medium_violet_red = 0xC71585, // rgb(199,21,133)
107  midnight_blue = 0x191970, // rgb(25,25,112)
108  mint_cream = 0xF5FFFA, // rgb(245,255,250)
109  misty_rose = 0xFFE4E1, // rgb(255,228,225)
110  moccasin = 0xFFE4B5, // rgb(255,228,181)
111  navajo_white = 0xFFDEAD, // rgb(255,222,173)
112  navy = 0x000080, // rgb(0,0,128)
113  old_lace = 0xFDF5E6, // rgb(253,245,230)
114  olive = 0x808000, // rgb(128,128,0)
115  olive_drab = 0x6B8E23, // rgb(107,142,35)
116  orange = 0xFFA500, // rgb(255,165,0)
117  orange_red = 0xFF4500, // rgb(255,69,0)
118  orchid = 0xDA70D6, // rgb(218,112,214)
119  pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
120  pale_green = 0x98FB98, // rgb(152,251,152)
121  pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
122  pale_violet_red = 0xDB7093, // rgb(219,112,147)
123  papaya_whip = 0xFFEFD5, // rgb(255,239,213)
124  peach_puff = 0xFFDAB9, // rgb(255,218,185)
125  peru = 0xCD853F, // rgb(205,133,63)
126  pink = 0xFFC0CB, // rgb(255,192,203)
127  plum = 0xDDA0DD, // rgb(221,160,221)
128  powder_blue = 0xB0E0E6, // rgb(176,224,230)
129  purple = 0x800080, // rgb(128,0,128)
130  rebecca_purple = 0x663399, // rgb(102,51,153)
131  red = 0xFF0000, // rgb(255,0,0)
132  rosy_brown = 0xBC8F8F, // rgb(188,143,143)
133  royal_blue = 0x4169E1, // rgb(65,105,225)
134  saddle_brown = 0x8B4513, // rgb(139,69,19)
135  salmon = 0xFA8072, // rgb(250,128,114)
136  sandy_brown = 0xF4A460, // rgb(244,164,96)
137  sea_green = 0x2E8B57, // rgb(46,139,87)
138  sea_shell = 0xFFF5EE, // rgb(255,245,238)
139  sienna = 0xA0522D, // rgb(160,82,45)
140  silver = 0xC0C0C0, // rgb(192,192,192)
141  sky_blue = 0x87CEEB, // rgb(135,206,235)
142  slate_blue = 0x6A5ACD, // rgb(106,90,205)
143  slate_gray = 0x708090, // rgb(112,128,144)
144  snow = 0xFFFAFA, // rgb(255,250,250)
145  spring_green = 0x00FF7F, // rgb(0,255,127)
146  steel_blue = 0x4682B4, // rgb(70,130,180)
147  tan = 0xD2B48C, // rgb(210,180,140)
148  teal = 0x008080, // rgb(0,128,128)
149  thistle = 0xD8BFD8, // rgb(216,191,216)
150  tomato = 0xFF6347, // rgb(255,99,71)
151  turquoise = 0x40E0D0, // rgb(64,224,208)
152  violet = 0xEE82EE, // rgb(238,130,238)
153  wheat = 0xF5DEB3, // rgb(245,222,179)
154  white = 0xFFFFFF, // rgb(255,255,255)
155  white_smoke = 0xF5F5F5, // rgb(245,245,245)
156  yellow = 0xFFFF00, // rgb(255,255,0)
157  yellow_green = 0x9ACD32 // rgb(154,205,50)
158 }; // enum class color
159 
160 enum class terminal_color : uint8_t {
161  black = 30,
162  red,
163  green,
164  yellow,
165  blue,
166  magenta,
167  cyan,
168  white,
169  bright_black = 90,
170  bright_red,
171  bright_green,
172  bright_yellow,
173  bright_blue,
174  bright_magenta,
175  bright_cyan,
176  bright_white
177 };
178 
179 enum class emphasis : uint8_t {
180  bold = 1,
181  faint = 1 << 1,
182  italic = 1 << 2,
183  underline = 1 << 3,
184  blink = 1 << 4,
185  reverse = 1 << 5,
186  conceal = 1 << 6,
187  strikethrough = 1 << 7,
188 };
189 
190 // rgb is a struct for red, green and blue colors.
191 // Using the name "rgb" makes some editors show the color in a tooltip.
192 struct rgb {
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) {}
201  uint8_t r;
202  uint8_t g;
203  uint8_t b;
204 };
205 
206 namespace detail {
207 
208 // A bit-packed variant of an RGB color, a terminal color, or unset color.
209 // see text_style for the bit-packing scheme.
210 struct color_type {
211  constexpr color_type() noexcept = default;
212  constexpr color_type(color rgb_color) noexcept
213  : value_(static_cast<uint32_t>(rgb_color) | (1 << 24)) {}
214  constexpr color_type(rgb rgb_color) noexcept
215  : color_type(static_cast<color>(
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)) {}
220 
221  constexpr auto is_terminal_color() const noexcept -> bool {
222  return (value_ & (1 << 25)) != 0;
223  }
224 
225  constexpr auto value() const noexcept -> uint32_t {
226  return value_ & 0xFFFFFF;
227  }
228 
229  constexpr color_type(uint32_t value) noexcept : value_(value) {}
230 
231  uint32_t value_ = 0;
232 };
233 } // namespace detail
234 
236 class text_style {
237  // The information is packed as follows:
238  // ┌──┐
239  // │ 0│─┐
240  // │..│ ├── foreground color value
241  // │23│─┘
242  // ├──┤
243  // │24│─┬── discriminator for the above value. 00 if unset, 01 if it's
244  // │25│─┘ an RGB color, or 11 if it's a terminal color (10 is unused)
245  // ├──┤
246  // │26│──── overflow bit, always zero (see below)
247  // ├──┤
248  // │27│─┐
249  // │..│ │
250  // │50│ │
251  // ├──┤ │
252  // │51│ ├── background color (same format as the foreground color)
253  // │52│ │
254  // ├──┤ │
255  // │53│─┘
256  // ├──┤
257  // │54│─┐
258  // │..│ ├── emphases
259  // │61│─┘
260  // ├──┤
261  // │62│─┬── unused
262  // │63│─┘
263  // └──┘
264  // The overflow bits are there to make operator|= efficient.
265  // When ORing, we must throw if, for either the foreground or background,
266  // one style specifies a terminal color and the other specifies any color
267  // (terminal or RGB); in other words, if one discriminator is 11 and the
268  // other is 11 or 01.
269  //
270  // We do that check by adding the styles. Consider what adding does to each
271  // possible pair of discriminators:
272  // 00 + 00 = 000
273  // 01 + 00 = 001
274  // 11 + 00 = 011
275  // 01 + 01 = 010
276  // 11 + 01 = 100 (!!)
277  // 11 + 11 = 110 (!!)
278  // In the last two cases, the ones we want to catch, the third bit——the
279  // overflow bit——is set. Bingo.
280  //
281  // We must take into account the possible carry bit from the bits
282  // before the discriminator. The only potentially problematic case is
283  // 11 + 00 = 011 (a carry bit would make it 100, not good!), but a carry
284  // bit is impossible in that case, because 00 (unset color) means the
285  // 24 bits that precede the discriminator are all zero.
286  //
287  // This test can be applied to both colors simultaneously.
288 
289  public:
290  FMTQUILL_CONSTEXPR text_style(emphasis em = emphasis()) noexcept
291  : style_(static_cast<uint64_t>(em) << 54) {}
292 
293  FMTQUILL_CONSTEXPR auto operator|=(text_style rhs) -> text_style& {
294  if (((style_ + rhs.style_) & ((1ULL << 26) | (1ULL << 53))) != 0)
295  report_error("can't OR a terminal color");
296  style_ |= rhs.style_;
297  return *this;
298  }
299 
300  friend FMTQUILL_CONSTEXPR auto operator|(text_style lhs, text_style rhs)
301  -> text_style {
302  return lhs |= rhs;
303  }
304 
305  FMTQUILL_CONSTEXPR auto operator==(text_style rhs) const noexcept -> bool {
306  return style_ == rhs.style_;
307  }
308 
309  FMTQUILL_CONSTEXPR auto operator!=(text_style rhs) const noexcept -> bool {
310  return !(*this == rhs);
311  }
312 
313  FMTQUILL_CONSTEXPR auto has_foreground() const noexcept -> bool {
314  return (style_ & (1 << 24)) != 0;
315  }
316  FMTQUILL_CONSTEXPR auto has_background() const noexcept -> bool {
317  return (style_ & (1ULL << 51)) != 0;
318  }
319  FMTQUILL_CONSTEXPR auto has_emphasis() const noexcept -> bool {
320  return (style_ >> 54) != 0;
321  }
322  FMTQUILL_CONSTEXPR auto get_foreground() const noexcept -> detail::color_type {
323  FMTQUILL_ASSERT(has_foreground(), "no foreground specified for this style");
324  return style_ & 0x3FFFFFF;
325  }
326  FMTQUILL_CONSTEXPR auto get_background() const noexcept -> detail::color_type {
327  FMTQUILL_ASSERT(has_background(), "no background specified for this style");
328  return (style_ >> 27) & 0x3FFFFFF;
329  }
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);
333  }
334 
335  private:
336  FMTQUILL_CONSTEXPR text_style(uint64_t style) noexcept : style_(style) {}
337 
338  friend FMTQUILL_CONSTEXPR auto fg(detail::color_type foreground) noexcept
339  -> text_style;
340 
341  friend FMTQUILL_CONSTEXPR auto bg(detail::color_type background) noexcept
342  -> text_style;
343 
344  uint64_t style_ = 0;
345 };
346 
348 FMTQUILL_CONSTEXPR inline auto fg(detail::color_type foreground) noexcept
349  -> text_style {
350  return foreground.value_;
351 }
352 
354 FMTQUILL_CONSTEXPR inline auto bg(detail::color_type background) noexcept
355  -> text_style {
356  return static_cast<uint64_t>(background.value_) << 27;
357 }
358 
359 FMTQUILL_CONSTEXPR inline auto operator|(emphasis lhs, emphasis rhs) noexcept
360  -> text_style {
361  return text_style(lhs) | rhs;
362 }
363 
364 namespace detail {
365 
366 template <typename Char> struct ansi_color_escape {
367  FMTQUILL_CONSTEXPR ansi_color_escape(color_type text_color,
368  const char* esc) noexcept {
369  // If we have a terminal color, we need to output another escape code
370  // sequence.
371  if (text_color.is_terminal_color()) {
372  bool is_background = esc == string_view("\x1b[48;2;");
373  uint32_t value = text_color.value();
374  // Background ASCII codes are the same as the foreground ones but with
375  // 10 more.
376  if (is_background) value += 10u;
377 
378  size_t index = 0;
379  buffer[index++] = static_cast<Char>('\x1b');
380  buffer[index++] = static_cast<Char>('[');
381 
382  if (value >= 100u) {
383  buffer[index++] = static_cast<Char>('1');
384  value %= 100u;
385  }
386  buffer[index++] = static_cast<Char>('0' + value / 10u);
387  buffer[index++] = static_cast<Char>('0' + value % 10u);
388 
389  buffer[index++] = static_cast<Char>('m');
390  buffer[index++] = static_cast<Char>('\0');
391  return;
392  }
393 
394  for (int i = 0; i < 7; i++) {
395  buffer[i] = static_cast<Char>(esc[i]);
396  }
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);
402  }
403  FMTQUILL_CONSTEXPR ansi_color_escape(emphasis em) noexcept {
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;
413 
414  size_t index = 0;
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');
421  }
422  buffer[index++] = static_cast<Char>(0);
423  }
424  FMTQUILL_CONSTEXPR operator const Char*() const noexcept { return buffer; }
425 
426  FMTQUILL_CONSTEXPR auto begin() const noexcept -> const Char* { return buffer; }
427  FMTQUILL_CONSTEXPR20 auto end() const noexcept -> const Char* {
428  return buffer + basic_string_view<Char>(buffer).size();
429  }
430 
431  private:
432  static constexpr size_t num_emphases = 8;
433  Char buffer[7u + 3u * num_emphases + 1u];
434 
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);
441  }
442  static FMTQUILL_CONSTEXPR auto has_emphasis(emphasis em, emphasis mask) noexcept
443  -> bool {
444  return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
445  }
446 };
447 
448 template <typename Char>
449 FMTQUILL_CONSTEXPR auto make_foreground_color(color_type foreground) noexcept
451  return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
452 }
453 
454 template <typename Char>
455 FMTQUILL_CONSTEXPR auto make_background_color(color_type background) noexcept
457  return ansi_color_escape<Char>(background, "\x1b[48;2;");
458 }
459 
460 template <typename Char>
461 FMTQUILL_CONSTEXPR auto make_emphasis(emphasis em) noexcept
463  return ansi_color_escape<Char>(em);
464 }
465 
466 template <typename Char> inline void reset_color(buffer<Char>& buffer) {
467  auto reset_color = string_view("\x1b[0m");
468  buffer.append(reset_color.begin(), reset_color.end());
469 }
470 
471 template <typename T> struct styled_arg : view {
472  const T& value;
473  text_style style;
474  styled_arg(const T& v, text_style s) : value(v), style(s) {}
475 };
476 
477 template <typename Char>
478 void vformat_to(buffer<Char>& buf, text_style ts, basic_string_view<Char> fmt,
479  basic_format_args<buffered_context<Char>> args) {
480  if (ts.has_emphasis()) {
481  auto emphasis = make_emphasis<Char>(ts.get_emphasis());
482  buf.append(emphasis.begin(), emphasis.end());
483  }
484  if (ts.has_foreground()) {
485  auto foreground = make_foreground_color<Char>(ts.get_foreground());
486  buf.append(foreground.begin(), foreground.end());
487  }
488  if (ts.has_background()) {
489  auto background = make_background_color<Char>(ts.get_background());
490  buf.append(background.begin(), background.end());
491  }
492  vformat_to(buf, fmt, args);
493  if (ts != text_style()) reset_color<Char>(buf);
494 }
495 } // namespace detail
496 
497 inline void vprint(FILE* f, text_style ts, string_view fmt, format_args args) {
498  auto buf = memory_buffer();
499  detail::vformat_to(buf, ts, fmt, args);
500  print(f, FMTQUILL_STRING("{}"), string_view(buf.begin(), buf.size()));
501 }
502 
512 template <typename... T>
513 void print(FILE* f, text_style ts, format_string<T...> fmt, T&&... args) {
514  vprint(f, ts, fmt.str, vargs<T...>{{args...}});
515 }
516 
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)...);
529 }
530 
531 inline auto vformat(text_style ts, string_view fmt, format_args args)
532  -> std::string {
533  auto buf = memory_buffer();
534  detail::vformat_to(buf, ts, fmt, args);
535  return fmtquill::to_string(buf);
536 }
537 
550 template <typename... T>
551 inline auto format(text_style ts, format_string<T...> fmt, T&&... args)
552  -> std::string {
553  return fmtquill::vformat(ts, fmt.str, vargs<T...>{{args...}});
554 }
555 
557 template <typename OutputIt,
559 auto vformat_to(OutputIt out, text_style ts, string_view fmt, format_args args)
560  -> OutputIt {
561  auto&& buf = detail::get_buffer<char>(out);
562  detail::vformat_to(buf, ts, fmt, args);
563  return detail::get_iterator(buf, out);
564 }
565 
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...}});
581 }
582 
583 template <typename T, typename Char>
584 struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
585  template <typename FormatContext>
586  auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const
587  -> decltype(ctx.out()) {
588  const auto& ts = arg.style;
589  auto out = ctx.out();
590 
591  bool has_style = false;
592  if (ts.has_emphasis()) {
593  has_style = true;
594  auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
595  out = detail::copy<Char>(emphasis.begin(), emphasis.end(), out);
596  }
597  if (ts.has_foreground()) {
598  has_style = true;
599  auto foreground =
600  detail::make_foreground_color<Char>(ts.get_foreground());
601  out = detail::copy<Char>(foreground.begin(), foreground.end(), out);
602  }
603  if (ts.has_background()) {
604  has_style = true;
605  auto background =
606  detail::make_background_color<Char>(ts.get_background());
607  out = detail::copy<Char>(background.begin(), background.end(), out);
608  }
609  out = formatter<T, Char>::format(arg.value, ctx);
610  if (has_style) {
611  auto reset_color = string_view("\x1b[0m");
612  out = detail::copy<Char>(reset_color.begin(), reset_color.end(), out);
613  }
614  return out;
615  }
616 };
617 
628 template <typename T>
629 FMTQUILL_CONSTEXPR auto styled(const T& value, text_style ts)
631  return detail::styled_arg<remove_cvref_t<T>>{value, ts};
632 }
633 
634 FMTQUILL_END_EXPORT
635 FMTQUILL_END_NAMESPACE
636 
637 #endif // FMTQUILL_COLOR_H_
Definition: base.h:669
Definition: base.h:1037
Definition: color.h:366
Definition: base.h:2388
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 view of a collection of formatting arguments.
Definition: base.h:661
A text style consisting of foreground and background colors and emphasis.
Definition: color.h:236
Definition: base.h:2303
Definition: base.h:2147
Definition: color.h:210
Definition: color.h:471
A contiguous memory buffer with an optional growing ability.
Definition: base.h:1751
Definition: color.h:192