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 | |
6 | use std::{borrow::Cow, ops::BitOr}; |
7 | |
8 | use 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)] |
39 | pub struct Color(AnsiColor<'static>); |
40 | |
41 | // todo: Add | operation to combine colors |
42 | |
43 | #[rustfmt::skip] |
44 | impl 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 | |
180 | impl 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 | |
188 | impl From<Color> for AnsiColor<'static> { |
189 | fn from(c: Color) -> Self { |
190 | c.0 |
191 | } |
192 | } |
193 | |
194 | impl From<AnsiColor<'static>> for Color { |
195 | fn from(c: AnsiColor<'static>) -> Self { |
196 | Self(c) |
197 | } |
198 | } |
199 | |
200 | impl 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 | |
209 | impl 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" )] |
233 | impl 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" )] |
242 | impl 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 | |
250 | impl<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 | |
256 | impl<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 | |
262 | impl<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 | |
268 | impl 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)] |
283 | mod 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 | |