antex/
colors.rs

1//! # Terminal color sequences
2
3use std::io::IsTerminal;
4
5/// Type alias for RGB color.
6pub type RgbColor = (u8, u8, u8);
7
8/// Type representing a color value in several formats.
9#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
10pub enum Color {
11  Black,
12  Red,
13  Green,
14  Yellow,
15  Blue,
16  Magenta,
17  Cyan,
18  White,
19  Long(u8),
20  Rgb(RgbColor),
21}
22
23impl From<u8> for Color {
24  fn from(n: u8) -> Self {
25    match n {
26      0 => Self::Black,
27      1 => Self::Red,
28      2 => Self::Green,
29      3 => Self::Yellow,
30      4 => Self::Blue,
31      5 => Self::Magenta,
32      6 => Self::Cyan,
33      7 => Self::White,
34      _ => Self::Long(n),
35    }
36  }
37}
38
39impl From<RgbColor> for Color {
40  fn from(n: RgbColor) -> Self {
41    Self::Rgb(n)
42  }
43}
44
45/// Color mode to switch terminal colouring `ON` or `OFF`.
46#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
47pub enum ColorMode {
48  /// Switch colouring **on**.
49  On,
50  /// Switch colouring **off**.
51  Off,
52}
53
54impl Default for ColorMode {
55  fn default() -> Self {
56    if std::io::stdout().is_terminal() {
57      Self::On
58    } else {
59      Self::Off
60    }
61  }
62}
63
64impl From<&str> for ColorMode {
65  /// Creates [ColorMode] from str reference.
66  fn from(value: &str) -> Self {
67    Self::new(value)
68  }
69}
70
71impl From<String> for ColorMode {
72  /// Creates [ColorMode] from string.
73  fn from(value: String) -> Self {
74    Self::new(&value)
75  }
76}
77
78impl From<&String> for ColorMode {
79  /// Creates [ColorMode] from string reference.
80  fn from(value: &String) -> Self {
81    Self::new(value)
82  }
83}
84
85impl From<Option<String>> for ColorMode {
86  /// Creates [ColorMode] from optional string.
87  fn from(value: Option<String>) -> Self {
88    value.map_or(Self::default(), |s| Self::new(&s))
89  }
90}
91
92impl From<Option<&String>> for ColorMode {
93  /// Creates [ColorMode] from optional string reference.
94  fn from(value: Option<&String>) -> Self {
95    value.map_or(Self::default(), |s| Self::new(s))
96  }
97}
98
99impl ColorMode {
100  pub fn new(s: &str) -> Self {
101    match s.to_lowercase().trim() {
102      "never" => Self::Off,
103      "always" => Self::On,
104      _ => Self::default(),
105    }
106  }
107
108  pub fn black(&self) -> String {
109    self.color_8(0)
110  }
111
112  pub fn red(&self) -> String {
113    self.color_8(1)
114  }
115
116  pub fn green(&self) -> String {
117    self.color_8(2)
118  }
119
120  pub fn yellow(&self) -> String {
121    self.color_8(3)
122  }
123
124  pub fn blue(&self) -> String {
125    self.color_8(4)
126  }
127
128  pub fn magenta(&self) -> String {
129    self.color_8(5)
130  }
131
132  pub fn cyan(&self) -> String {
133    self.color_8(6)
134  }
135
136  pub fn white(&self) -> String {
137    self.color_8(7)
138  }
139
140  pub fn bg_black(&self) -> String {
141    self.bg_color_8(0)
142  }
143
144  pub fn bg_red(&self) -> String {
145    self.bg_color_8(1)
146  }
147
148  pub fn bg_green(&self) -> String {
149    self.bg_color_8(2)
150  }
151
152  pub fn bg_yellow(&self) -> String {
153    self.bg_color_8(3)
154  }
155
156  pub fn bg_blue(&self) -> String {
157    self.bg_color_8(4)
158  }
159
160  pub fn bg_magenta(&self) -> String {
161    self.bg_color_8(5)
162  }
163
164  pub fn bg_cyan(&self) -> String {
165    self.bg_color_8(6)
166  }
167
168  pub fn bg_white(&self) -> String {
169    self.bg_color_8(7)
170  }
171
172  pub fn color(&self, c: Color) -> String {
173    match c {
174      Color::Black => self.color_8(0),
175      Color::Red => self.color_8(1),
176      Color::Green => self.color_8(2),
177      Color::Yellow => self.color_8(3),
178      Color::Blue => self.color_8(4),
179      Color::Magenta => self.color_8(5),
180      Color::Cyan => self.color_8(6),
181      Color::White => self.color_8(7),
182      Color::Long(value) => self.color_256(value),
183      Color::Rgb(value) => self.color_rgb(value),
184    }
185  }
186
187  pub fn bg_color(&self, c: Color) -> String {
188    match c {
189      Color::Black => self.bg_color_8(0),
190      Color::Red => self.bg_color_8(1),
191      Color::Green => self.bg_color_8(2),
192      Color::Yellow => self.bg_color_8(3),
193      Color::Blue => self.bg_color_8(4),
194      Color::Magenta => self.bg_color_8(5),
195      Color::Cyan => self.bg_color_8(6),
196      Color::White => self.bg_color_8(7),
197      Color::Long(value) => self.bg_color_256(value),
198      Color::Rgb(value) => self.bg_color_rgb(value),
199    }
200  }
201
202  pub fn color_8(&self, c: u8) -> String {
203    match self {
204      ColorMode::On => format!("\u{1b}[{}m", 30 + c.clamp(0, 7)),
205      _ => "".to_string(),
206    }
207  }
208
209  pub fn bg_color_8(&self, c: u8) -> String {
210    match self {
211      ColorMode::On => format!("\u{1b}[{}m", 40 + c.clamp(0, 7)),
212      _ => "".to_string(),
213    }
214  }
215
216  pub fn color_256(&self, c: u8) -> String {
217    match self {
218      ColorMode::On => format!("\u{1b}[38;5;{}m", c),
219      _ => "".to_string(),
220    }
221  }
222
223  pub fn bg_color_256(&self, c: u8) -> String {
224    match self {
225      ColorMode::On => format!("\u{1b}[48;5;{}m", c),
226      _ => "".to_string(),
227    }
228  }
229
230  pub fn color_rgb(&self, c: RgbColor) -> String {
231    match self {
232      ColorMode::On => format!("\u{1b}[38;2;{};{};{}m", c.0, c.1, c.2),
233      _ => "".to_string(),
234    }
235  }
236
237  pub fn bg_color_rgb(&self, c: RgbColor) -> String {
238    match self {
239      ColorMode::On => format!("\u{1b}[48;2;{};{};{}m", c.0, c.1, c.2),
240      _ => "".to_string(),
241    }
242  }
243
244  pub fn bold(&self) -> &str {
245    match self {
246      ColorMode::On => "\u{1b}[1m",
247      _ => "",
248    }
249  }
250
251  pub fn italic(&self) -> &str {
252    match self {
253      ColorMode::On => "\u{1b}[3m",
254      _ => "",
255    }
256  }
257
258  pub fn underline(&self) -> &str {
259    match self {
260      ColorMode::On => "\u{1b}[4m",
261      _ => "",
262    }
263  }
264
265  pub fn clear(&self) -> &str {
266    match self {
267      ColorMode::On => "\u{1b}[0m",
268      _ => "",
269    }
270  }
271}