@@ -191,6 +191,25 @@ enum class color : uint32_t {
191
191
yellow_green = 0x9ACD32 // rgb(154,205,50)
192
192
}; // enum class color
193
193
194
+ enum class terminal_color : uint8_t {
195
+ black = 30 ,
196
+ red,
197
+ green,
198
+ yellow,
199
+ blue,
200
+ magenta,
201
+ cyan,
202
+ white,
203
+ bright_black = 90 ,
204
+ bright_red,
205
+ bright_green,
206
+ bright_yellow,
207
+ bright_blue,
208
+ bright_magenta,
209
+ bright_cyan,
210
+ bright_white
211
+ }; // enum class terminal_color
212
+
194
213
enum class emphasis : uint8_t {
195
214
bold = 1 ,
196
215
italic = 1 << 1 ,
@@ -215,6 +234,32 @@ struct rgb {
215
234
uint8_t b;
216
235
};
217
236
237
+ namespace internal {
238
+
239
+ // color is a struct of either a rgb color or a terminal color.
240
+ struct color_type {
241
+ FMT_CONSTEXPR color_type () FMT_NOEXCEPT
242
+ : is_rgb(), value{} {}
243
+ FMT_CONSTEXPR color_type (color rgb_color) FMT_NOEXCEPT
244
+ : is_rgb(true ), value{} {
245
+ value.rgb_color = static_cast <uint32_t >(rgb_color);
246
+ }
247
+ FMT_CONSTEXPR color_type (rgb rgb_color) FMT_NOEXCEPT
248
+ : is_rgb(true ), value{} {
249
+ value.rgb_color = (rgb_color.r << 16 ) + (rgb_color.g << 8 ) + rgb_color.b ;
250
+ }
251
+ FMT_CONSTEXPR color_type (terminal_color term_color) FMT_NOEXCEPT
252
+ : is_rgb(), value{} {
253
+ value.term_color = static_cast <uint8_t >(term_color);
254
+ }
255
+ bool is_rgb;
256
+ union color_union {
257
+ uint8_t term_color;
258
+ uint32_t rgb_color;
259
+ } value;
260
+ };
261
+ } // namespace internal
262
+
218
263
// Experimental text formatting support.
219
264
class text_style {
220
265
public:
@@ -227,18 +272,18 @@ class text_style {
227
272
set_foreground_color = rhs.set_foreground_color ;
228
273
foreground_color = rhs.foreground_color ;
229
274
} else if (rhs.set_foreground_color ) {
230
- foreground_color.r |= rhs.foreground_color .r ;
231
- foreground_color. g |= rhs. foreground_color . g ;
232
- foreground_color.b |= rhs.foreground_color .b ;
275
+ if (! foreground_color.is_rgb || ! rhs.foreground_color .is_rgb )
276
+ throw format_error ( " can't OR a terminal color " ) ;
277
+ foreground_color.value . rgb_color |= rhs.foreground_color .value . rgb_color ;
233
278
}
234
279
235
280
if (!set_background_color) {
236
281
set_background_color = rhs.set_background_color ;
237
282
background_color = rhs.background_color ;
238
283
} else if (rhs.set_background_color ) {
239
- background_color.r |= rhs.background_color .r ;
240
- background_color. g |= rhs. background_color . g ;
241
- background_color.b |= rhs.background_color .b ;
284
+ if (! background_color.is_rgb || ! rhs.background_color .is_rgb )
285
+ throw format_error ( " can't OR a terminal color " ) ;
286
+ background_color.value . rgb_color |= rhs.background_color .value . rgb_color ;
242
287
}
243
288
244
289
ems = static_cast <emphasis>(static_cast <uint8_t >(ems) |
@@ -256,18 +301,18 @@ class text_style {
256
301
set_foreground_color = rhs.set_foreground_color ;
257
302
foreground_color = rhs.foreground_color ;
258
303
} else if (rhs.set_foreground_color ) {
259
- foreground_color.r &= rhs.foreground_color .r ;
260
- foreground_color. g &= rhs. foreground_color . g ;
261
- foreground_color.b &= rhs.foreground_color .b ;
304
+ if (! foreground_color.is_rgb || ! rhs.foreground_color .is_rgb )
305
+ throw format_error ( " can't AND a terminal color " ) ;
306
+ foreground_color.value . rgb_color &= rhs.foreground_color .value . rgb_color ;
262
307
}
263
308
264
309
if (!set_background_color) {
265
310
set_background_color = rhs.set_background_color ;
266
311
background_color = rhs.background_color ;
267
312
} else if (rhs.set_background_color ) {
268
- background_color.r &= rhs.background_color .r ;
269
- background_color. g &= rhs. background_color . g ;
270
- background_color.b &= rhs.background_color .b ;
313
+ if (! background_color.is_rgb || ! rhs.background_color .is_rgb )
314
+ throw format_error ( " can't AND a terminal color " ) ;
315
+ background_color.value . rgb_color &= rhs.background_color .value . rgb_color ;
271
316
}
272
317
273
318
ems = static_cast <emphasis>(static_cast <uint8_t >(ems) &
@@ -289,11 +334,11 @@ class text_style {
289
334
FMT_CONSTEXPR bool has_emphasis () const FMT_NOEXCEPT {
290
335
return static_cast <uint8_t >(ems) != 0 ;
291
336
}
292
- FMT_CONSTEXPR rgb get_foreground () const FMT_NOEXCEPT {
337
+ FMT_CONSTEXPR internal::color_type get_foreground () const FMT_NOEXCEPT {
293
338
assert (has_foreground () && " no foreground specified for this style" );
294
339
return foreground_color;
295
340
}
296
- FMT_CONSTEXPR rgb get_background () const FMT_NOEXCEPT {
341
+ FMT_CONSTEXPR internal::color_type get_background () const FMT_NOEXCEPT {
297
342
assert (has_background () && " no background specified for this style" );
298
343
return background_color;
299
344
}
@@ -303,32 +348,37 @@ class text_style {
303
348
}
304
349
305
350
private:
306
- FMT_CONSTEXPR text_style (bool is_foreground, rgb text_color) FMT_NOEXCEPT
307
- : set_foreground_color(), set_background_color(), ems() {
308
- if (is_foreground) {
309
- foreground_color = text_color;
310
- set_foreground_color = true ;
311
- } else {
312
- background_color = text_color;
313
- set_background_color = true ;
314
- }
315
- }
316
-
317
- friend FMT_CONSTEXPR_DECL text_style fg (rgb foreground) FMT_NOEXCEPT;
318
- friend FMT_CONSTEXPR_DECL text_style bg (rgb background) FMT_NOEXCEPT;
319
-
320
- rgb foreground_color;
321
- rgb background_color;
351
+ FMT_CONSTEXPR text_style (bool is_foreground,
352
+ internal::color_type text_color) FMT_NOEXCEPT
353
+ : set_foreground_color(),
354
+ set_background_color(),
355
+ ems() {
356
+ if (is_foreground) {
357
+ foreground_color = text_color;
358
+ set_foreground_color = true ;
359
+ } else {
360
+ background_color = text_color;
361
+ set_background_color = true ;
362
+ }
363
+ }
364
+
365
+ friend FMT_CONSTEXPR_DECL text_style fg (internal::color_type foreground)
366
+ FMT_NOEXCEPT;
367
+ friend FMT_CONSTEXPR_DECL text_style bg (internal::color_type background)
368
+ FMT_NOEXCEPT;
369
+
370
+ internal::color_type foreground_color;
371
+ internal::color_type background_color;
322
372
bool set_foreground_color;
323
373
bool set_background_color;
324
374
emphasis ems;
325
375
};
326
376
327
- FMT_CONSTEXPR text_style fg (rgb foreground) FMT_NOEXCEPT {
377
+ FMT_CONSTEXPR text_style fg (internal::color_type foreground) FMT_NOEXCEPT {
328
378
return text_style (/* is_foreground=*/ true , foreground);
329
379
}
330
380
331
- FMT_CONSTEXPR text_style bg (rgb background) FMT_NOEXCEPT {
381
+ FMT_CONSTEXPR text_style bg (internal::color_type background) FMT_NOEXCEPT {
332
382
return text_style (/* is_foreground=*/ false , background);
333
383
}
334
384
@@ -340,10 +390,37 @@ namespace internal {
340
390
341
391
template <typename Char>
342
392
struct ansi_color_escape {
343
- FMT_CONSTEXPR ansi_color_escape (rgb color, const char * esc) FMT_NOEXCEPT {
393
+ FMT_CONSTEXPR ansi_color_escape (internal::color_type text_color, const char * esc) FMT_NOEXCEPT {
394
+ // If we have a terminal color, we need to output another escape code
395
+ // sequence.
396
+ if (!text_color.is_rgb ) {
397
+ bool is_background = esc == internal::data::BACKGROUND_COLOR;
398
+ uint8_t value = text_color.value .term_color ;
399
+ // Background ASCII codes are the same as the foreground ones but with
400
+ // 10 more.
401
+ if (is_background)
402
+ value += 10 ;
403
+
404
+ std::size_t index = 0 ;
405
+ buffer[index++] = static_cast <Char>(' \x1b ' );
406
+ buffer[index++] = static_cast <Char>(' [' );
407
+
408
+ if (value >= 100 ) {
409
+ buffer[index++] = static_cast <Char>(' 1' );
410
+ value %= 100 ;
411
+ }
412
+ buffer[index++] = static_cast <Char>(' 0' + value / 10 );
413
+ buffer[index++] = static_cast <Char>(' 0' + value % 10 );
414
+
415
+ buffer[index++] = static_cast <Char>(' m' );
416
+ buffer[index++] = static_cast <Char>(' \0 ' );
417
+ return ;
418
+ }
419
+
344
420
for (int i = 0 ; i < 7 ; i++) {
345
421
buffer[i] = static_cast <Char>(esc[i]);
346
422
}
423
+ rgb color (text_color.value .rgb_color );
347
424
to_esc (color.r , buffer + 7 , ' ;' );
348
425
to_esc (color.g , buffer + 11 , ' ;' );
349
426
to_esc (color.b , buffer + 15 , ' m' );
@@ -388,14 +465,14 @@ struct ansi_color_escape {
388
465
389
466
template <typename Char>
390
467
FMT_CONSTEXPR ansi_color_escape<Char>
391
- make_foreground_color (rgb color ) FMT_NOEXCEPT {
392
- return ansi_color_escape<Char>(color , internal::data::FOREGROUND_COLOR);
468
+ make_foreground_color (internal::color_type foreground ) FMT_NOEXCEPT {
469
+ return ansi_color_escape<Char>(foreground , internal::data::FOREGROUND_COLOR);
393
470
}
394
471
395
472
template <typename Char>
396
473
FMT_CONSTEXPR ansi_color_escape<Char>
397
- make_background_color (rgb color ) FMT_NOEXCEPT {
398
- return ansi_color_escape<Char>(color , internal::data::BACKGROUND_COLOR);
474
+ make_background_color (internal::color_type background ) FMT_NOEXCEPT {
475
+ return ansi_color_escape<Char>(background , internal::data::BACKGROUND_COLOR);
399
476
}
400
477
401
478
template <typename Char>
0 commit comments