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}