1
1
"""
2
2
Utility functions for handling terminal colors
3
3
"""
4
- import colorsys
5
4
import os
6
- from typing import Iterable , List , Mapping , NamedTuple , Tuple
5
+ from typing import Iterable , List , Mapping , NamedTuple , Tuple , no_type_check
6
+
7
+ import colorama
7
8
8
9
from .consts import ANSI_COLORS , ANSI_RGB
9
10
@@ -17,6 +18,15 @@ class Style(NamedTuple):
17
18
_Hsv = Tuple [float , float , float ]
18
19
19
20
21
+ def support_truecolor () -> bool :
22
+ return os .name != "nt" or (
23
+ os .getenv ("ANSICON" ) is not None
24
+ or os .getenv ("WT_SESSION" ) is not None
25
+ or "ON" == os .getenv ("ConEmuANSI" )
26
+ or "xterm" == os .getenv ("Term" )
27
+ )
28
+
29
+
20
30
def hex_to_rgb (hex_string : str ) -> _Rgb :
21
31
"""Return a tuple of red, green and blue components for the color
22
32
given as #rrggbb.
@@ -33,12 +43,56 @@ def rgb_to_hex(rgb: _Rgb) -> str:
33
43
return "#" + "" .join ("%02x" % c for c in rgb )
34
44
35
45
46
+ @no_type_check
36
47
def rgb_to_hsv (rgb : _Rgb ) -> _Hsv :
37
- return colorsys .rgb_to_hsv (* rgb )
48
+ r , g , b = rgb
49
+ r /= 255
50
+ g /= 255
51
+ b /= 255
52
+
53
+ max_value = max (r , g , b )
54
+ min_value = min (r , g , b )
55
+ diff = max_value - min_value
56
+
57
+ h , s , v = 0 , diff / max_value if max_value > 0 else 0 , max_value
58
+
59
+ if max_value == min_value :
60
+ h = 0
61
+ elif max_value == r :
62
+ h = 60 * (g - b ) / diff
63
+ if g < b :
64
+ h += 360
65
+ elif max_value == g :
66
+ h = 60 * (b - r ) / diff + 120
67
+ else :
68
+ h = 60 * (r - g ) / diff + 240
69
+
70
+ return h , (s * 100 ), (v * 100 )
38
71
39
72
40
73
def hsv_to_rgb (hsv : _Hsv ) -> _Rgb :
41
- return tuple (int (c ) for c in colorsys .hsv_to_rgb (* hsv )) # type: ignore
74
+ h , s , v = hsv
75
+ h /= 60
76
+ s /= 100
77
+ v /= 100
78
+ hi = int (h ) % 6
79
+
80
+ f = h - int (h )
81
+ p = 255 * v * (1 - s )
82
+ q = 255 * v * (1 - (s * f ))
83
+ t = 255 * v * (1 - (s * (1 - f )))
84
+ v *= 255
85
+
86
+ result = {
87
+ 0 : (v , t , p ),
88
+ 1 : (q , v , p ),
89
+ 2 : (p , v , t ),
90
+ 3 : (p , q , v ),
91
+ 4 : (t , p , v ),
92
+ 5 : (v , p , q ),
93
+ }[hi ]
94
+ r , g , b = result
95
+ return int (r ), int (g ), int (b )
42
96
43
97
44
98
def _color_distance (left : _Hsv , right : _Hsv ) -> float :
@@ -147,10 +201,11 @@ def rgb_style(self, color: _Rgb, background: bool) -> Style:
147
201
return Style ("\x1b [{};2;{};{};{}m" .format (open_bit , r , g , b ), close )
148
202
149
203
150
- if (os .getenv ("DISABLE_TRUECOLOR" ) or os . name == "nt" ) and not os .getenv (
204
+ if (os .getenv ("DISABLE_TRUECOLOR" ) or not support_truecolor () ) and not os .getenv (
151
205
"ENABLE_TRUECOLOR"
152
206
):
153
207
# Disable truecolor for windows
154
208
pen = AnsiPen ()
209
+ colorama .init ()
155
210
else :
156
211
pen = TrueColorPen ()
0 commit comments