yansi/color.rs
1use crate::{Style, Attribute, Quirk, Condition};
2
3/// Enum representing a terminal color.
4///
5/// **Note:** The color examples below are purely demonstrative. The actual
6/// color rendered depends entirely on the terminal and its configuration, the
7/// latter of which is entirely arbitrary.
8#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord, Hash)]
9pub enum Color {
10 /// Terminal primary color #9. (foreground code `39`, background code `49`).
11 ///
12 /// This is the terminal's defined "primary" color, that is, the configured
13 /// default foreground and background colors. As such, this color as a
14 /// foreground looks "good" against the terminal's default background color,
15 /// and this color is a "good" background color for the terminal's default
16 /// foreground color.
17 Primary,
18
19 /// A color from 0 to 255, for use in 256-color terminals.
20 Fixed(u8),
21
22 /// A 24-bit
23 /// <span style="background: red; color: white;">R</span>
24 /// <span style="background: green; color: white;">G</span>
25 /// <span style="background: blue; color: white;">B</span>
26 /// "true color", as specified by ISO-8613-3.
27 Rgb(u8, u8, u8),
28
29 /// <span style="background: black; color: white;">Black #0</span>
30 /// (foreground code `30`, background code `40`).
31 Black,
32
33 /// <span style="background: red; color: white;">Red #1</span>
34 /// (foreground code `31`, background code `41`).
35 Red,
36
37 /// <span style="background: green; color: white;">Green: #2</span>
38 /// (foreground code `32`, background code `42`).
39 Green,
40
41 /// <span style="background: gold; color: black;">Yellow: #3</span>
42 /// (foreground code `33`, background code `43`).
43 Yellow,
44
45 /// <span style="background: blue; color: white;">Blue: #4</span>
46 /// (foreground code `34`, background code `44`).
47 Blue,
48
49 /// <span style="background: darkmagenta; color: white;">Magenta: #5</span>
50 /// (foreground code `35`, background code `45`).
51 Magenta,
52
53 /// <span style="background: deepskyblue; color: black;">Cyan: #6</span>
54 /// (foreground code `36`, background code `46`).
55 Cyan,
56
57 /// <span style="background: #eeeeee; color: black;">White: #7</span>
58 /// (foreground code `37`, background code `47`).
59 White,
60
61 /// <span style="background: gray; color: white;">Bright Black #0</span>
62 /// (foreground code `90`, background code `100`).
63 BrightBlack,
64
65 /// <span style="background: hotpink; color: white;">Bright Red #1</span>
66 /// (foreground code `91`, background code `101`).
67 BrightRed,
68
69 /// <span style="background: greenyellow; color: black;">Bright Green: #2</span>
70 /// (foreground code `92`, background code `102`).
71 BrightGreen,
72
73 /// <span style="background: yellow; color: black;">Bright Yellow: #3</span>
74 /// (foreground code `93`, background code `103`).
75 BrightYellow,
76
77 /// <span style="background: dodgerblue; color: white;">Bright Blue: #4</span>
78 /// (foreground code `94`, background code `104`).
79 BrightBlue,
80
81 /// <span style="background: magenta; color: white;">Bright Magenta: #5</span>
82 /// (foreground code `95`, background code `105`).
83 BrightMagenta,
84
85 /// <span style='background: cyan; color: black;'>Bright Cyan: #6</span>
86 /// (foreground code `96`, background code `106`).
87 BrightCyan,
88
89 /// <span style="background: white; color: black;">Bright White: #7</span>
90 /// (foreground code `97`, background code `107`).
91 BrightWhite,
92}
93
94pub(crate) enum Variant { Fg, Bg, }
95
96impl Color {
97 fn fg_base(&self) -> u8 {
98 match self {
99 Color::Black => 30,
100 Color::Red => 31,
101 Color::Green => 32,
102 Color::Yellow => 33,
103 Color::Blue => 34,
104 Color::Magenta => 35,
105 Color::Cyan => 36,
106 Color::White => 37,
107 Color::Fixed(_) | Color::Rgb(..) => 38,
108 Color::Primary => 39,
109 Color::BrightBlack => 30 + 60,
110 Color::BrightRed => 31 + 60,
111 Color::BrightGreen => 32 + 60,
112 Color::BrightYellow => 33 + 60,
113 Color::BrightBlue => 34 + 60,
114 Color::BrightMagenta => 35 + 60,
115 Color::BrightCyan => 36 + 60,
116 Color::BrightWhite => 37 + 60,
117 }
118 }
119
120 pub(crate) const fn to_bright(self) -> Self {
121 match self {
122 Color::Black => Color::BrightBlack,
123 Color::Red => Color::BrightRed,
124 Color::Green => Color::BrightGreen,
125 Color::Yellow => Color::BrightYellow,
126 Color::Blue => Color::BrightBlue,
127 Color::Magenta => Color::BrightMagenta,
128 Color::Cyan => Color::BrightCyan,
129 Color::White => Color::BrightWhite,
130 Color::Fixed(_)
131 | Color::Primary
132 | Color::Rgb(_, _, _)
133 | Color::BrightBlack
134 | Color::BrightRed
135 | Color::BrightGreen
136 | Color::BrightYellow
137 | Color::BrightBlue
138 | Color::BrightMagenta
139 | Color::BrightCyan
140 | Color::BrightWhite => self
141 }
142 }
143
144 pub(crate) fn fmt(&self, f: &mut dyn core::fmt::Write, variant: Variant) -> core::fmt::Result {
145 let base = match variant {
146 Variant::Fg => self.fg_base(),
147 Variant::Bg => self.fg_base() + 10,
148 };
149
150 match *self {
151 Color::Fixed(num) => write!(f, "{};5;{}", base, num),
152 Color::Rgb(r, g, b) => write!(f, "{};2;{};{};{}", base, r, g, b),
153 _ => write!(f, "{}", base)
154 }
155 }
156
157 #[inline(always)]
158 const fn apply(self, a: crate::style::Application) -> Style {
159 Style::new().fg(self).apply(a)
160 }
161
162 /// Returns a `Style` with a foreground color of `self`.
163 ///
164 /// # Example
165 ///
166 /// ```rust
167 /// use yansi::{Style, Color::*};
168 ///
169 /// // A style with a foreground color of "yellow".
170 /// static DEBUG: Style = Yellow.foreground();
171 ///
172 /// // This is equivalent to the above.
173 /// static DEBUG_S: Style = Style::new().fg(Yellow);
174 ///
175 /// // The following two are equivalent. The latter is preferred.
176 /// static DEBUG_A: Style = Yellow.foreground().bold();
177 /// static DEBUG_B: Style = Yellow.bold();
178 /// # use yansi::Paint;
179 /// # assert_eq!("-".paint(DEBUG_A).to_string(), "-".paint(DEBUG_B).to_string());
180 /// ```
181 pub const fn foreground(self) -> Style {
182 Style::new().fg(self)
183 }
184
185 /// Returns a `Style` with a background color of `self`.
186 ///
187 /// # Example
188 ///
189 /// ```rust
190 /// use yansi::{Style, Color::*};
191 ///
192 /// // A style with a background color of "yellow".
193 /// static DEBUG: Style = Yellow.background();
194 ///
195 /// // This is equivalent to the above.
196 /// static DEBUG_S: Style = Style::new().bg(Yellow);
197 ///
198 /// // The following two are equivalent. The latter is preferred.
199 /// static DEBUG_A: Style = Yellow.background().green();
200 /// static DEBUG_B: Style = Green.on_yellow();
201 /// # use yansi::Paint;
202 /// # assert_eq!("-".paint(DEBUG_A).to_string(), "-".paint(DEBUG_B).to_string());
203 /// ```
204 pub const fn background(self) -> Style {
205 Style::new().bg(self)
206 }
207
208 bg!([pub const] constructor(Self) -> Style);
209
210 attr!([pub const] constructor(Self) -> Style);
211
212 quirk!([pub const] constructor(Self) -> Style);
213
214 whenever!([pub const] constructor(Self) -> Style);
215}
216
217impl Default for Color {
218 fn default() -> Self {
219 Color::Primary
220 }
221}
222
223impl From<Color> for Style {
224 fn from(color: Color) -> Self {
225 color.foreground()
226 }
227}