1//! This module contains a configuration of a [`Border`] or a [`Table`] to set its borders color via [`Color`].
2//!
3//! [`Border`]: crate::settings::Border
4//! [`Table`]: crate::Table
5
6use std::{borrow::Cow, ops::BitOr};
7
8use crate::{
9 grid::{
10 color::{AnsiColor, StaticColor},
11 config::{ColoredConfig, Entity},
12 },
13 settings::{CellOption, TableOption},
14};
15
16/// Color represents a color which can be set to things like [`Border`], [`Padding`] and [`Margin`].
17///
18/// # Example
19///
20/// ```
21/// use tabled::{settings::Color, Table};
22///
23/// let data = [
24/// (0u8, "Hello"),
25/// (1u8, "World"),
26/// ];
27///
28/// let table = Table::new(data)
29/// .with(Color::BG_BLUE)
30/// .to_string();
31///
32/// println!("{}", table);
33/// ```
34///
35/// [`Padding`]: crate::settings::Padding
36/// [`Margin`]: crate::settings::Margin
37/// [`Border`]: crate::settings::Border
38#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
39pub struct Color(AnsiColor<'static>);
40
41// todo: Add | operation to combine colors
42
43#[rustfmt::skip]
44impl Color {
45 /// A color representation.
46 ///
47 /// Notice that the colors are constants so you can't combine them.
48 pub const FG_BLACK: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[30m"), Cow::Borrowed("\u{1b}[39m")));
49 /// A color representation.
50 ///
51 /// Notice that the colors are constants so you can't combine them.
52 pub const FG_BLUE: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[34m"), Cow::Borrowed("\u{1b}[39m")));
53 /// A color representation.
54 ///
55 /// Notice that the colors are constants so you can't combine them.
56 pub const FG_BRIGHT_BLACK: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[90m"), Cow::Borrowed("\u{1b}[39m")));
57 /// A color representation.
58 ///
59 /// Notice that the colors are constants so you can't combine them.
60 pub const FG_BRIGHT_BLUE: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[94m"), Cow::Borrowed("\u{1b}[39m")));
61 /// A color representation.
62 ///
63 /// Notice that the colors are constants so you can't combine them.
64 pub const FG_BRIGHT_CYAN: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[96m"), Cow::Borrowed("\u{1b}[39m")));
65 /// A color representation.
66 ///
67 /// Notice that the colors are constants so you can't combine them.
68 pub const FG_BRIGHT_GREEN: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[92m"), Cow::Borrowed("\u{1b}[39m")));
69 /// A color representation.
70 ///
71 /// Notice that the colors are constants so you can't combine them.
72 pub const FG_BRIGHT_MAGENTA: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[95m"), Cow::Borrowed("\u{1b}[39m")));
73 /// A color representation.
74 ///
75 /// Notice that the colors are constants so you can't combine them.
76 pub const FG_BRIGHT_RED: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[91m"), Cow::Borrowed("\u{1b}[39m")));
77 /// A color representation.
78 ///
79 /// Notice that the colors are constants so you can't combine them.
80 pub const FG_BRIGHT_WHITE: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[97m"), Cow::Borrowed("\u{1b}[39m")));
81 /// A color representation.
82 ///
83 /// Notice that the colors are constants so you can't combine them.
84 pub const FG_BRIGHT_YELLOW: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[93m"), Cow::Borrowed("\u{1b}[39m")));
85 /// A color representation.
86 ///
87 /// Notice that the colors are constants so you can't combine them.
88 pub const FG_CYAN: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[36m"), Cow::Borrowed("\u{1b}[39m")));
89 /// A color representation.
90 ///
91 /// Notice that the colors are constants so you can't combine them.
92 pub const FG_GREEN: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[32m"), Cow::Borrowed("\u{1b}[39m")));
93 /// A color representation.
94 ///
95 /// Notice that the colors are constants so you can't combine them.
96 pub const FG_MAGENTA: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[35m"), Cow::Borrowed("\u{1b}[39m")));
97 /// A color representation.
98 ///
99 /// Notice that the colors are constants so you can't combine them.
100 pub const FG_RED: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[31m"), Cow::Borrowed("\u{1b}[39m")));
101 /// A color representation.
102 ///
103 /// Notice that the colors are constants so you can't combine them.
104 pub const FG_WHITE: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[37m"), Cow::Borrowed("\u{1b}[39m")));
105 /// A color representation.
106 ///
107 /// Notice that the colors are constants so you can't combine them.
108 pub const FG_YELLOW: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[33m"), Cow::Borrowed("\u{1b}[39m")));
109 /// A color representation.
110 ///
111 /// Notice that the colors are constants so you can't combine them.
112
113 pub const BG_BLACK: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[40m"), Cow::Borrowed("\u{1b}[49m")));
114 /// A color representation.
115 ///
116 /// Notice that the colors are constants so you can't combine them.
117 pub const BG_BLUE: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[44m"), Cow::Borrowed("\u{1b}[49m")));
118 /// A color representation.
119 ///
120 /// Notice that the colors are constants so you can't combine them.
121 pub const BG_BRIGHT_BLACK: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[100m"), Cow::Borrowed("\u{1b}[49m")));
122 /// A color representation.
123 ///
124 /// Notice that the colors are constants so you can't combine them.
125 pub const BG_BRIGHT_BLUE: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[104m"), Cow::Borrowed("\u{1b}[49m")));
126 /// A color representation.
127 ///
128 /// Notice that the colors are constants so you can't combine them.
129 pub const BG_BRIGHT_CYAN: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[106m"), Cow::Borrowed("\u{1b}[49m")));
130 /// A color representation.
131 ///
132 /// Notice that the colors are constants so you can't combine them.
133 pub const BG_BRIGHT_GREEN: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[102m"), Cow::Borrowed("\u{1b}[49m")));
134 /// A color representation.
135 ///
136 /// Notice that the colors are constants so you can't combine them.
137 pub const BG_BRIGHT_MAGENTA: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[105m"), Cow::Borrowed("\u{1b}[49m")));
138 /// A color representation.
139 ///
140 /// Notice that the colors are constants so you can't combine them.
141 pub const BG_BRIGHT_RED: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[101m"), Cow::Borrowed("\u{1b}[49m")));
142 /// A color representation.
143 ///
144 /// Notice that the colors are constants so you can't combine them.
145 pub const BG_BRIGHT_WHITE: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[107m"), Cow::Borrowed("\u{1b}[49m")));
146 /// A color representation.
147 ///
148 /// Notice that the colors are constants so you can't combine them.
149 pub const BG_BRIGHT_YELLOW: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[103m"), Cow::Borrowed("\u{1b}[49m")));
150 /// A color representation.
151 ///
152 /// Notice that the colors are constants so you can't combine them.
153 pub const BG_CYAN: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[46m"), Cow::Borrowed("\u{1b}[49m")));
154 /// A color representation.
155 ///
156 /// Notice that the colors are constants so you can't combine them.
157 pub const BG_GREEN: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[42m"), Cow::Borrowed("\u{1b}[49m")));
158 /// A color representation.
159 ///
160 /// Notice that the colors are constants so you can't combine them.
161 pub const BG_MAGENTA: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[45m"), Cow::Borrowed("\u{1b}[49m")));
162 /// A color representation.
163 ///
164 /// Notice that the colors are constants so you can't combine them.
165 pub const BG_RED: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[41m"), Cow::Borrowed("\u{1b}[49m")));
166 /// A color representation.
167 ///
168 /// Notice that the colors are constants so you can't combine them.
169 pub const BG_WHITE: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[47m"), Cow::Borrowed("\u{1b}[49m")));
170 /// A color representation.
171 ///
172 /// Notice that the colors are constants so you can't combine them.
173 pub const BG_YELLOW: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[43m"), Cow::Borrowed("\u{1b}[49m")));
174 /// A color representation.
175 ///
176 /// Notice that the colors are constants so you can't combine them.
177 pub const BOLD: Self = Self(AnsiColor::new(Cow::Borrowed("\u{1b}[1m"), Cow::Borrowed("\u{1b}[22m")));
178}
179
180impl Color {
181 /// Creates a new [`Color`]` instance, with ANSI prefix and ANSI suffix.
182 /// You can use [`TryFrom`] to construct it from [`String`].
183 pub fn new(prefix: String, suffix: String) -> Self {
184 Self(AnsiColor::new(prefix:prefix.into(), suffix:suffix.into()))
185 }
186}
187
188impl From<Color> for AnsiColor<'static> {
189 fn from(c: Color) -> Self {
190 c.0
191 }
192}
193
194impl From<AnsiColor<'static>> for Color {
195 fn from(c: AnsiColor<'static>) -> Self {
196 Self(c)
197 }
198}
199
200impl From<StaticColor> for Color {
201 fn from(c: StaticColor) -> Self {
202 Self(AnsiColor::new(
203 prefix:Cow::Borrowed(c.get_prefix()),
204 suffix:Cow::Borrowed(c.get_suffix()),
205 ))
206 }
207}
208
209impl BitOr for Color {
210 type Output = Color;
211
212 fn bitor(self, rhs: Self) -> Self::Output {
213 let l_prefix: &str = self.0.get_prefix();
214 let l_suffix: &str = self.0.get_suffix();
215 let r_prefix: &str = rhs.0.get_prefix();
216 let r_suffix: &str = rhs.0.get_suffix();
217
218 let mut prefix: String = l_prefix.to_string();
219 if l_prefix != r_prefix {
220 prefix.push_str(string:r_prefix);
221 }
222
223 let mut suffix: String = l_suffix.to_string();
224 if l_suffix != r_suffix {
225 suffix.push_str(string:r_suffix);
226 }
227
228 Self::new(prefix, suffix)
229 }
230}
231
232#[cfg(feature = "color")]
233impl std::convert::TryFrom<&str> for Color {
234 type Error = ();
235
236 fn try_from(value: &str) -> Result<Self, Self::Error> {
237 AnsiColor::try_from(value).map(Color)
238 }
239}
240
241#[cfg(feature = "color")]
242impl std::convert::TryFrom<String> for Color {
243 type Error = ();
244
245 fn try_from(value: String) -> Result<Self, Self::Error> {
246 AnsiColor::try_from(value).map(Color)
247 }
248}
249
250impl<R, D> TableOption<R, D, ColoredConfig> for Color {
251 fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
252 let _ = cfg.set_color(pos:Entity::Global, self.0.clone());
253 }
254}
255
256impl<R> CellOption<R, ColoredConfig> for Color {
257 fn change(self, _: &mut R, cfg: &mut ColoredConfig, entity: Entity) {
258 let _ = cfg.set_color(pos:entity, self.0.clone());
259 }
260}
261
262impl<R> CellOption<R, ColoredConfig> for &Color {
263 fn change(self, _: &mut R, cfg: &mut ColoredConfig, entity: Entity) {
264 let _ = cfg.set_color(pos:entity, self.0.clone());
265 }
266}
267
268impl crate::grid::color::Color for Color {
269 fn fmt_prefix<W: std::fmt::Write>(&self, f: &mut W) -> std::fmt::Result {
270 self.0.fmt_prefix(f)
271 }
272
273 fn fmt_suffix<W: std::fmt::Write>(&self, f: &mut W) -> std::fmt::Result {
274 self.0.fmt_suffix(f)
275 }
276
277 fn colorize<W: std::fmt::Write>(&self, f: &mut W, text: &str) -> std::fmt::Result {
278 self.0.colorize(f, text)
279 }
280}
281
282#[cfg(test)]
283mod tests {
284 use super::*;
285
286 #[cfg(feature = "color")]
287 use ::{owo_colors::OwoColorize, std::convert::TryFrom};
288
289 #[test]
290 fn test_xor_operation() {
291 assert_eq!(
292 Color::FG_BLACK | Color::FG_BLUE,
293 Color::new(
294 String::from("\u{1b}[30m\u{1b}[34m"),
295 String::from("\u{1b}[39m")
296 )
297 );
298 assert_eq!(
299 Color::FG_BRIGHT_GREEN | Color::BG_BLUE,
300 Color::new(
301 String::from("\u{1b}[92m\u{1b}[44m"),
302 String::from("\u{1b}[39m\u{1b}[49m")
303 )
304 );
305 assert_eq!(
306 Color::new(String::from("..."), String::from("!!!"))
307 | Color::new(String::from("@@@"), String::from("###")),
308 Color::new(String::from("...@@@"), String::from("!!!###"))
309 );
310 assert_eq!(
311 Color::new(String::from("..."), String::from("!!!"))
312 | Color::new(String::from("@@@"), String::from("###"))
313 | Color::new(String::from("$$$"), String::from("%%%")),
314 Color::new(String::from("...@@@$$$"), String::from("!!!###%%%"))
315 );
316 }
317
318 #[cfg(feature = "color")]
319 #[test]
320 fn test_try_from() {
321 assert_eq!(Color::try_from(""), Err(()));
322 assert_eq!(Color::try_from("".red().on_green().to_string()), Err(()));
323 assert_eq!(
324 Color::try_from("."),
325 Ok(Color::new(String::new(), String::new()))
326 );
327 assert_eq!(
328 Color::try_from("...."),
329 Ok(Color::new(String::new(), String::new()))
330 );
331 assert_eq!(
332 Color::try_from(".".red().on_green().to_string()),
333 Ok(Color::new(
334 String::from("\u{1b}[31m\u{1b}[42m"),
335 String::from("\u{1b}[39m\u{1b}[49m")
336 ))
337 );
338 assert_eq!(
339 Color::try_from("....".red().on_green().to_string()),
340 Ok(Color::new(
341 String::from("\u{1b}[31m\u{1b}[42m"),
342 String::from("\u{1b}[39m\u{1b}[49m")
343 ))
344 );
345 }
346}
347