@@ -18,10 +18,18 @@ fn default_colors_enabled(out: &Term) -> bool {
18
18
|| & env:: var ( "CLICOLOR_FORCE" ) . unwrap_or_else ( |_| "0" . into ( ) ) != "0"
19
19
}
20
20
21
+ fn default_true_colors_enabled ( out : & Term ) -> bool {
22
+ out. features ( ) . true_colors_supported ( )
23
+ }
24
+
21
25
static STDOUT_COLORS : Lazy < AtomicBool > =
22
26
Lazy :: new ( || AtomicBool :: new ( default_colors_enabled ( & Term :: stdout ( ) ) ) ) ;
27
+ static STDOUT_TRUE_COLORS : Lazy < AtomicBool > =
28
+ Lazy :: new ( || AtomicBool :: new ( default_true_colors_enabled ( & Term :: stdout ( ) ) ) ) ;
23
29
static STDERR_COLORS : Lazy < AtomicBool > =
24
30
Lazy :: new ( || AtomicBool :: new ( default_colors_enabled ( & Term :: stderr ( ) ) ) ) ;
31
+ static STDERR_TRUE_COLORS : Lazy < AtomicBool > =
32
+ Lazy :: new ( || AtomicBool :: new ( default_true_colors_enabled ( & Term :: stderr ( ) ) ) ) ;
25
33
26
34
/// Returns `true` if colors should be enabled for stdout.
27
35
///
@@ -35,6 +43,12 @@ pub fn colors_enabled() -> bool {
35
43
STDOUT_COLORS . load ( Ordering :: Relaxed )
36
44
}
37
45
46
+ /// Returns `true` if true colors should be enabled for stdout.
47
+ #[ inline]
48
+ pub fn true_colors_enabled ( ) -> bool {
49
+ STDERR_TRUE_COLORS . load ( Ordering :: Relaxed )
50
+ }
51
+
38
52
/// Forces colorization on or off for stdout.
39
53
///
40
54
/// This overrides the default for the current process and changes the return value of the
@@ -44,6 +58,15 @@ pub fn set_colors_enabled(val: bool) {
44
58
STDOUT_COLORS . store ( val, Ordering :: Relaxed )
45
59
}
46
60
61
+ /// Forces true colorization on or off for stdout.
62
+ ///
63
+ /// This overrides the default for the current process and changes the return value of the
64
+ /// `true_colors_enabled` function.
65
+ #[ inline]
66
+ pub fn set_true_colors_enabled ( val : bool ) {
67
+ STDOUT_TRUE_COLORS . store ( val, Ordering :: Relaxed )
68
+ }
69
+
47
70
/// Returns `true` if colors should be enabled for stderr.
48
71
///
49
72
/// This honors the [clicolors spec](http://bixense.com/clicolors/).
@@ -56,6 +79,12 @@ pub fn colors_enabled_stderr() -> bool {
56
79
STDERR_COLORS . load ( Ordering :: Relaxed )
57
80
}
58
81
82
+ /// Returns `true` if true colors should be enabled for stderr.
83
+ #[ inline]
84
+ pub fn true_colors_enabled_stderr ( ) -> bool {
85
+ STDERR_TRUE_COLORS . load ( Ordering :: Relaxed )
86
+ }
87
+
59
88
/// Forces colorization on or off for stderr.
60
89
///
61
90
/// This overrides the default for the current process and changes the return value of the
@@ -65,6 +94,15 @@ pub fn set_colors_enabled_stderr(val: bool) {
65
94
STDERR_COLORS . store ( val, Ordering :: Relaxed )
66
95
}
67
96
97
+ /// Forces true colorization on or off for stderr.
98
+ ///
99
+ /// This overrides the default for the current process and changes the return value of the
100
+ /// `true_colors_enabled_stderr` function.
101
+ #[ inline]
102
+ pub fn set_true_colors_enabled_stderr ( val : bool ) {
103
+ STDERR_TRUE_COLORS . store ( val, Ordering :: Relaxed )
104
+ }
105
+
68
106
/// Measure the width of a string in terminal characters.
69
107
pub fn measure_text_width ( s : & str ) -> usize {
70
108
#[ cfg( feature = "ansi-parsing" ) ]
@@ -94,6 +132,7 @@ pub enum Color {
94
132
Cyan ,
95
133
White ,
96
134
Color256 ( u8 ) ,
135
+ TrueColor ( u8 , u8 , u8 ) ,
97
136
}
98
137
99
138
impl Color {
@@ -109,6 +148,7 @@ impl Color {
109
148
Color :: Cyan => 6 ,
110
149
Color :: White => 7 ,
111
150
Color :: Color256 ( x) => x as usize ,
151
+ Color :: TrueColor ( _, _, _) => panic ! ( "RGB colors must be handled separately" ) ,
112
152
}
113
153
}
114
154
@@ -293,6 +333,28 @@ impl Style {
293
333
"reverse" => rv. reverse ( ) ,
294
334
"hidden" => rv. hidden ( ) ,
295
335
"strikethrough" => rv. strikethrough ( ) ,
336
+ on_true_color if on_true_color. starts_with ( "on_#" ) && on_true_color. len ( ) == 10 => {
337
+ if let ( Ok ( r) , Ok ( g) , Ok ( b) ) = (
338
+ u8:: from_str_radix ( & on_true_color[ 4 ..6 ] , 16 ) ,
339
+ u8:: from_str_radix ( & on_true_color[ 6 ..8 ] , 16 ) ,
340
+ u8:: from_str_radix ( & on_true_color[ 8 ..10 ] , 16 ) ,
341
+ ) {
342
+ rv. on_true_color ( r, g, b)
343
+ } else {
344
+ continue ;
345
+ }
346
+ }
347
+ true_color if true_color. starts_with ( '#' ) && true_color. len ( ) == 7 => {
348
+ if let ( Ok ( r) , Ok ( g) , Ok ( b) ) = (
349
+ u8:: from_str_radix ( & true_color[ 1 ..3 ] , 16 ) ,
350
+ u8:: from_str_radix ( & true_color[ 3 ..5 ] , 16 ) ,
351
+ u8:: from_str_radix ( & true_color[ 5 ..7 ] , 16 ) ,
352
+ ) {
353
+ rv. true_color ( r, g, b)
354
+ } else {
355
+ continue ;
356
+ }
357
+ }
296
358
on_c if on_c. starts_with ( "on_" ) => {
297
359
if let Ok ( n) = on_c[ 3 ..] . parse :: < u8 > ( ) {
298
360
rv. on_color256 ( n)
@@ -402,6 +464,10 @@ impl Style {
402
464
pub const fn color256 ( self , color : u8 ) -> Self {
403
465
self . fg ( Color :: Color256 ( color) )
404
466
}
467
+ #[ inline]
468
+ pub const fn true_color ( self , r : u8 , g : u8 , b : u8 ) -> Self {
469
+ self . fg ( Color :: TrueColor ( r, g, b) )
470
+ }
405
471
406
472
#[ inline]
407
473
pub const fn bright ( mut self ) -> Self {
@@ -445,6 +511,10 @@ impl Style {
445
511
pub const fn on_color256 ( self , color : u8 ) -> Self {
446
512
self . bg ( Color :: Color256 ( color) )
447
513
}
514
+ #[ inline]
515
+ pub const fn on_true_color ( self , r : u8 , g : u8 , b : u8 ) -> Self {
516
+ self . bg ( Color :: TrueColor ( r, g, b) )
517
+ }
448
518
449
519
#[ inline]
450
520
pub const fn on_bright ( mut self ) -> Self {
@@ -600,6 +670,10 @@ impl<D> StyledObject<D> {
600
670
pub const fn color256 ( self , color : u8 ) -> StyledObject < D > {
601
671
self . fg ( Color :: Color256 ( color) )
602
672
}
673
+ #[ inline]
674
+ pub const fn true_color ( self , r : u8 , g : u8 , b : u8 ) -> StyledObject < D > {
675
+ self . fg ( Color :: TrueColor ( r, g, b) )
676
+ }
603
677
604
678
#[ inline]
605
679
pub const fn bright ( mut self ) -> StyledObject < D > {
@@ -643,6 +717,10 @@ impl<D> StyledObject<D> {
643
717
pub const fn on_color256 ( self , color : u8 ) -> StyledObject < D > {
644
718
self . bg ( Color :: Color256 ( color) )
645
719
}
720
+ #[ inline]
721
+ pub const fn on_true_color ( self , r : u8 , g : u8 , b : u8 ) -> StyledObject < D > {
722
+ self . bg ( Color :: TrueColor ( r, g, b) )
723
+ }
646
724
647
725
#[ inline]
648
726
pub const fn on_bright ( mut self ) -> StyledObject < D > {
@@ -702,7 +780,9 @@ macro_rules! impl_fmt {
702
780
} )
703
781
{
704
782
if let Some ( fg) = self . style. fg {
705
- if fg. is_color256( ) {
783
+ if let Color :: TrueColor ( r, g, b) = fg {
784
+ write!( f, "\x1b [38;2;{};{};{}m" , r, g, b) ?;
785
+ } else if fg. is_color256( ) {
706
786
write!( f, "\x1b [38;5;{}m" , fg. ansi_num( ) ) ?;
707
787
} else if self . style. fg_bright {
708
788
write!( f, "\x1b [38;5;{}m" , fg. ansi_num( ) + 8 ) ?;
@@ -712,7 +792,9 @@ macro_rules! impl_fmt {
712
792
reset = true ;
713
793
}
714
794
if let Some ( bg) = self . style. bg {
715
- if bg. is_color256( ) {
795
+ if let Color :: TrueColor ( r, g, b) = bg {
796
+ write!( f, "\x1b [48;2;{};{};{}m" , r, g, b) ?;
797
+ } else if bg. is_color256( ) {
716
798
write!( f, "\x1b [48;5;{}m" , bg. ansi_num( ) ) ?;
717
799
} else if self . style. bg_bright {
718
800
write!( f, "\x1b [48;5;{}m" , bg. ansi_num( ) + 8 ) ?;
0 commit comments