1use crate::{colors, BgDynColorDisplay, DynColor, FgDynColorDisplay};
2use crate::{BgColorDisplay, Color, FgColorDisplay};
3
4use core::fmt;
5use core::marker::PhantomData;
6
7#[cfg(doc)]
8use crate::OwoColorize;
9
10/// A wrapper type which applies both a foreground and background color
11pub struct ComboColorDisplay<'a, Fg: Color, Bg: Color, T>(&'a T, PhantomData<(Fg, Bg)>);
12
13/// Wrapper around a type which implements all the formatters the wrapped type does,
14/// with the addition of changing the foreground and background color. Is not recommended
15/// unless compile-time coloring is not an option.
16pub struct ComboDynColorDisplay<'a, Fg: DynColor, Bg: DynColor, T>(&'a T, Fg, Bg);
17
18macro_rules! impl_fmt_for_combo {
19 ($($trait:path),* $(,)?) => {
20 $(
21 impl<'a, Fg: Color, Bg: Color, T: $trait> $trait for ComboColorDisplay<'a, Fg, Bg, T> {
22 #[inline(always)]
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 f.write_str("\x1b[")?;
25 f.write_str(Fg::RAW_ANSI_FG)?;
26 f.write_str(";")?;
27 f.write_str(Bg::RAW_ANSI_BG)?;
28 f.write_str("m")?;
29 <T as $trait>::fmt(&self.0, f)?;
30 f.write_str("\x1b[0m")
31 }
32 }
33 )*
34
35 $(
36 impl<'a, Fg: DynColor, Bg: DynColor, T: $trait> $trait for ComboDynColorDisplay<'a, Fg, Bg, T> {
37 #[inline(always)]
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 f.write_str("\x1b[")?;
40 self.1.fmt_raw_ansi_fg(f)?;
41 f.write_str(";")?;
42 self.2.fmt_raw_ansi_bg(f)?;
43 f.write_str("m")?;
44 <T as $trait>::fmt(&self.0, f)?;
45 f.write_str("\x1b[0m")
46 }
47 }
48 )*
49 };
50}
51
52impl_fmt_for_combo! {
53 fmt::Display,
54 fmt::Debug,
55 fmt::UpperHex,
56 fmt::LowerHex,
57 fmt::Binary,
58 fmt::UpperExp,
59 fmt::LowerExp,
60 fmt::Octal,
61 fmt::Pointer,
62}
63
64/// implement specialized color methods for FgColorDisplay BgColorDisplay, ComboColorDisplay
65macro_rules! color_methods {
66 ($(
67 #[$fg_meta:meta] #[$bg_meta:meta] $color:ident $fg_method:ident $bg_method:ident
68 ),* $(,)?) => {
69 const _: () = (); // workaround for syntax highlighting bug
70
71 impl<'a, Fg, T> FgColorDisplay<'a, Fg, T>
72 where
73 Fg: Color,
74 {
75 /// Set the foreground color at runtime. Only use if you do not know which color will be used at
76 /// compile-time. If the color is constant, use either [`OwoColorize::fg`](OwoColorize::fg) or
77 /// a color-specific method, such as [`OwoColorize::green`](OwoColorize::green),
78 ///
79 /// ```rust
80 /// use owo_colors::{OwoColorize, AnsiColors};
81 ///
82 /// println!("{}", "green".color(AnsiColors::Green));
83 /// ```
84 pub fn color<NewFg: DynColor>(
85 self,
86 fg: NewFg,
87 ) -> FgDynColorDisplay<'a, NewFg, T> {
88 FgDynColorDisplay(self.0, fg)
89 }
90
91 /// Set the background color at runtime. Only use if you do not know what color to use at
92 /// compile-time. If the color is constant, use either [`OwoColorize::bg`](OwoColorize::bg) or
93 /// a color-specific method, such as [`OwoColorize::on_yellow`](OwoColorize::on_yellow),
94 ///
95 /// ```rust
96 /// use owo_colors::{OwoColorize, AnsiColors};
97 ///
98 /// println!("{}", "yellow background".on_color(AnsiColors::BrightYellow));
99 /// ```
100 pub fn on_color<NewBg: DynColor>(
101 self,
102 bg: NewBg,
103 ) -> ComboDynColorDisplay<'a, Fg::DynEquivelant, NewBg, T> {
104 ComboDynColorDisplay(self.0, Fg::DYN_EQUIVELANT, bg)
105 }
106
107 /// Set the foreground color generically
108 ///
109 /// ```rust
110 /// use owo_colors::{OwoColorize, colors::*};
111 ///
112 /// println!("{}", "red foreground".fg::<Red>());
113 /// ```
114 pub fn fg<C: Color>(self) -> FgColorDisplay<'a, C, T> {
115 FgColorDisplay(self.0, PhantomData)
116 }
117
118 /// Set the background color generically.
119 ///
120 /// ```rust
121 /// use owo_colors::{OwoColorize, colors::*};
122 ///
123 /// println!("{}", "black background".bg::<Black>());
124 /// ```
125 pub fn bg<C: Color>(self) -> ComboColorDisplay<'a, Fg, C, T> {
126 ComboColorDisplay(self.0, PhantomData)
127 }
128
129 $(
130 #[$fg_meta]
131 #[inline(always)]
132 pub fn $fg_method(self) -> FgColorDisplay<'a, colors::$color, T> {
133 FgColorDisplay(self.0, PhantomData)
134 }
135
136 #[$bg_meta]
137 #[inline(always)]
138 pub fn $bg_method(self) -> ComboColorDisplay<'a, Fg, colors::$color, T> {
139 ComboColorDisplay(self.0, PhantomData)
140 }
141 )*
142 }
143
144 const _: () = (); // workaround for syntax highlighting bug
145
146 impl<'a, Bg, T> BgColorDisplay<'a, Bg, T>
147 where
148 Bg: Color,
149 {
150 /// Set the foreground color at runtime. Only use if you do not know which color will be used at
151 /// compile-time. If the color is constant, use either [`OwoColorize::fg`](OwoColorize::fg) or
152 /// a color-specific method, such as [`OwoColorize::green`](OwoColorize::green),
153 ///
154 /// ```rust
155 /// use owo_colors::{OwoColorize, AnsiColors};
156 ///
157 /// println!("{}", "green".color(AnsiColors::Green));
158 /// ```
159 pub fn color<NewFg: DynColor>(
160 self,
161 fg: NewFg,
162 ) -> ComboDynColorDisplay<'a, NewFg, Bg::DynEquivelant, T> {
163 ComboDynColorDisplay(self.0, fg, Bg::DYN_EQUIVELANT)
164 }
165
166 /// Set the background color at runtime. Only use if you do not know what color to use at
167 /// compile-time. If the color is constant, use either [`OwoColorize::bg`](OwoColorize::bg) or
168 /// a color-specific method, such as [`OwoColorize::on_yellow`](OwoColorize::on_yellow),
169 ///
170 /// ```rust
171 /// use owo_colors::{OwoColorize, AnsiColors};
172 ///
173 /// println!("{}", "yellow background".on_color(AnsiColors::BrightYellow));
174 /// ```
175 pub fn on_color<NewBg: DynColor>(
176 self,
177 bg: NewBg,
178 ) -> BgDynColorDisplay<'a, NewBg, T> {
179 BgDynColorDisplay(self.0, bg)
180 }
181
182 /// Set the foreground color generically
183 ///
184 /// ```rust
185 /// use owo_colors::{OwoColorize, colors::*};
186 ///
187 /// println!("{}", "red foreground".fg::<Red>());
188 /// ```
189 pub fn fg<C: Color>(self) -> ComboColorDisplay<'a, C, Bg, T> {
190 ComboColorDisplay(self.0, PhantomData)
191 }
192
193 /// Set the background color generically.
194 ///
195 /// ```rust
196 /// use owo_colors::{OwoColorize, colors::*};
197 ///
198 /// println!("{}", "black background".bg::<Black>());
199 /// ```
200 pub fn bg<C: Color>(self) -> BgColorDisplay<'a, C, T> {
201 BgColorDisplay(self.0, PhantomData)
202 }
203
204 $(
205 #[$bg_meta]
206 #[inline(always)]
207 pub fn $bg_method(self) -> BgColorDisplay<'a, colors::$color, T> {
208 BgColorDisplay(self.0, PhantomData)
209 }
210
211 #[$fg_meta]
212 #[inline(always)]
213 pub fn $fg_method(self) -> ComboColorDisplay<'a, colors::$color, Bg, T> {
214 ComboColorDisplay(self.0, PhantomData)
215 }
216 )*
217 }
218
219 const _: () = (); // workaround for syntax highlighting bug
220
221 impl<'a, Fg, Bg, T> ComboColorDisplay<'a, Fg, Bg, T>
222 where
223 Fg: Color,
224 Bg: Color,
225 {
226 /// Set the background color at runtime. Only use if you do not know what color to use at
227 /// compile-time. If the color is constant, use either [`OwoColorize::bg`](OwoColorize::bg) or
228 /// a color-specific method, such as [`OwoColorize::on_yellow`](OwoColorize::on_yellow),
229 ///
230 /// ```rust
231 /// use owo_colors::{OwoColorize, AnsiColors};
232 ///
233 /// println!("{}", "yellow background".on_color(AnsiColors::BrightYellow));
234 /// ```
235 pub fn on_color<NewBg: DynColor>(
236 self,
237 bg: NewBg,
238 ) -> ComboDynColorDisplay<'a, Fg::DynEquivelant, NewBg, T> {
239 ComboDynColorDisplay(self.0, Fg::DYN_EQUIVELANT, bg)
240 }
241
242 /// Set the foreground color at runtime. Only use if you do not know which color will be used at
243 /// compile-time. If the color is constant, use either [`OwoColorize::fg`](OwoColorize::fg) or
244 /// a color-specific method, such as [`OwoColorize::green`](OwoColorize::green),
245 ///
246 /// ```rust
247 /// use owo_colors::{OwoColorize, AnsiColors};
248 ///
249 /// println!("{}", "green".color(AnsiColors::Green));
250 /// ```
251 pub fn color<NewFg: DynColor>(
252 self,
253 fg: NewFg,
254 ) -> ComboDynColorDisplay<'a, NewFg, Bg::DynEquivelant, T> {
255 ComboDynColorDisplay(self.0, fg, Bg::DYN_EQUIVELANT)
256 }
257
258 /// Set the foreground color generically
259 ///
260 /// ```rust
261 /// use owo_colors::{OwoColorize, colors::*};
262 ///
263 /// println!("{}", "red foreground".fg::<Red>());
264 /// ```
265 pub fn fg<C: Color>(self) -> ComboColorDisplay<'a, C, Bg, T> {
266 ComboColorDisplay(self.0, PhantomData)
267 }
268
269 /// Set the background color generically.
270 ///
271 /// ```rust
272 /// use owo_colors::{OwoColorize, colors::*};
273 ///
274 /// println!("{}", "black background".bg::<Black>());
275 /// ```
276 pub fn bg<C: Color>(self) -> ComboColorDisplay<'a, Fg, C, T> {
277 ComboColorDisplay(self.0, PhantomData)
278 }
279
280 $(
281 #[$bg_meta]
282 #[inline(always)]
283 pub fn $bg_method(self) -> ComboColorDisplay<'a, Fg, colors::$color, T> {
284 ComboColorDisplay(self.0, PhantomData)
285 }
286
287 #[$fg_meta]
288 #[inline(always)]
289 pub fn $fg_method(self) -> ComboColorDisplay<'a, colors::$color, Bg, T> {
290 ComboColorDisplay(self.0, PhantomData)
291 }
292 )*
293 }
294 };
295}
296
297const _: () = (); // workaround for syntax highlighting bug
298
299color_methods! {
300 /// Change the foreground color to black
301 /// Change the background color to black
302 Black black on_black,
303 /// Change the foreground color to red
304 /// Change the background color to red
305 Red red on_red,
306 /// Change the foreground color to green
307 /// Change the background color to green
308 Green green on_green,
309 /// Change the foreground color to yellow
310 /// Change the background color to yellow
311 Yellow yellow on_yellow,
312 /// Change the foreground color to blue
313 /// Change the background color to blue
314 Blue blue on_blue,
315 /// Change the foreground color to magenta
316 /// Change the background color to magenta
317 Magenta magenta on_magenta,
318 /// Change the foreground color to purple
319 /// Change the background color to purple
320 Magenta purple on_purple,
321 /// Change the foreground color to cyan
322 /// Change the background color to cyan
323 Cyan cyan on_cyan,
324 /// Change the foreground color to white
325 /// Change the background color to white
326 White white on_white,
327
328 /// Change the foreground color to bright black
329 /// Change the background color to bright black
330 BrightBlack bright_black on_bright_black,
331 /// Change the foreground color to bright red
332 /// Change the background color to bright red
333 BrightRed bright_red on_bright_red,
334 /// Change the foreground color to bright green
335 /// Change the background color to bright green
336 BrightGreen bright_green on_bright_green,
337 /// Change the foreground color to bright yellow
338 /// Change the background color to bright yellow
339 BrightYellow bright_yellow on_bright_yellow,
340 /// Change the foreground color to bright blue
341 /// Change the background color to bright blue
342 BrightBlue bright_blue on_bright_blue,
343 /// Change the foreground color to bright magenta
344 /// Change the background color to bright magenta
345 BrightMagenta bright_magenta on_bright_magenta,
346 /// Change the foreground color to bright purple
347 /// Change the background color to bright purple
348 BrightMagenta bright_purple on_bright_purple,
349 /// Change the foreground color to bright cyan
350 /// Change the background color to bright cyan
351 BrightCyan bright_cyan on_bright_cyan,
352 /// Change the foreground color to bright white
353 /// Change the background color to bright white
354 BrightWhite bright_white on_bright_white,
355}
356
357impl<'a, Fg: DynColor, T> FgDynColorDisplay<'a, Fg, T> {
358 /// Set the background color at runtime. Only use if you do not know what color to use at
359 /// compile-time. If the color is constant, use either [`OwoColorize::bg`](OwoColorize::bg) or
360 /// a color-specific method, such as [`OwoColorize::on_yellow`](OwoColorize::on_yellow),
361 ///
362 /// ```rust
363 /// use owo_colors::{OwoColorize, AnsiColors};
364 ///
365 /// println!("{}", "yellow background".on_color(AnsiColors::BrightYellow));
366 /// ```
367 pub fn on_color<Bg: DynColor>(self, bg: Bg) -> ComboDynColorDisplay<'a, Fg, Bg, T> {
368 let Self(inner, fg) = self;
369 ComboDynColorDisplay(inner, fg, bg)
370 }
371
372 /// Set the foreground color at runtime. Only use if you do not know which color will be used at
373 /// compile-time. If the color is constant, use either [`OwoColorize::fg`](OwoColorize::fg) or
374 /// a color-specific method, such as [`OwoColorize::green`](OwoColorize::green),
375 ///
376 /// ```rust
377 /// use owo_colors::{OwoColorize, AnsiColors};
378 ///
379 /// println!("{}", "green".color(AnsiColors::Green));
380 /// ```
381 pub fn color<NewFg: DynColor>(self, fg: NewFg) -> FgDynColorDisplay<'a, NewFg, T> {
382 let Self(inner, _) = self;
383 FgDynColorDisplay(inner, fg)
384 }
385}
386
387impl<'a, Bg: DynColor, T> BgDynColorDisplay<'a, Bg, T> {
388 /// Set the background color at runtime. Only use if you do not know what color to use at
389 /// compile-time. If the color is constant, use either [`OwoColorize::bg`](OwoColorize::bg) or
390 /// a color-specific method, such as [`OwoColorize::on_yellow`](OwoColorize::on_yellow),
391 ///
392 /// ```rust
393 /// use owo_colors::{OwoColorize, AnsiColors};
394 ///
395 /// println!("{}", "yellow background".on_color(AnsiColors::BrightYellow));
396 /// ```
397 pub fn on_color<NewBg: DynColor>(self, bg: NewBg) -> BgDynColorDisplay<'a, NewBg, T> {
398 let Self(inner, _) = self;
399 BgDynColorDisplay(inner, bg)
400 }
401
402 /// Set the foreground color at runtime. Only use if you do not know which color will be used at
403 /// compile-time. If the color is constant, use either [`OwoColorize::fg`](OwoColorize::fg) or
404 /// a color-specific method, such as [`OwoColorize::green`](OwoColorize::green),
405 ///
406 /// ```rust
407 /// use owo_colors::{OwoColorize, AnsiColors};
408 ///
409 /// println!("{}", "green".color(AnsiColors::Green));
410 /// ```
411 pub fn color<Fg: DynColor>(self, fg: Fg) -> ComboDynColorDisplay<'a, Fg, Bg, T> {
412 let Self(inner, bg) = self;
413 ComboDynColorDisplay(inner, fg, bg)
414 }
415}
416
417impl<'a, Fg: DynColor, Bg: DynColor, T> ComboDynColorDisplay<'a, Fg, Bg, T> {
418 /// Set the background color at runtime. Only use if you do not know what color to use at
419 /// compile-time. If the color is constant, use either [`OwoColorize::bg`](OwoColorize::bg) or
420 /// a color-specific method, such as [`OwoColorize::on_yellow`](OwoColorize::on_yellow),
421 ///
422 /// ```rust
423 /// use owo_colors::{OwoColorize, AnsiColors};
424 ///
425 /// println!("{}", "yellow background".on_color(AnsiColors::BrightYellow));
426 /// ```
427 pub fn on_color<NewBg: DynColor>(self, bg: NewBg) -> ComboDynColorDisplay<'a, Fg, NewBg, T> {
428 let Self(inner, fg, _) = self;
429 ComboDynColorDisplay(inner, fg, bg)
430 }
431
432 /// Set the foreground color at runtime. Only use if you do not know which color will be used at
433 /// compile-time. If the color is constant, use either [`OwoColorize::fg`](OwoColorize::fg) or
434 /// a color-specific method, such as [`OwoColorize::green`](OwoColorize::green),
435 ///
436 /// ```rust
437 /// use owo_colors::{OwoColorize, AnsiColors};
438 ///
439 /// println!("{}", "green".color(AnsiColors::Green));
440 /// ```
441 pub fn color<NewFg: DynColor>(self, fg: NewFg) -> ComboDynColorDisplay<'a, NewFg, Bg, T> {
442 let Self(inner, _, bg) = self;
443 ComboDynColorDisplay(inner, fg, bg)
444 }
445}
446
447#[cfg(test)]
448mod tests {
449 use crate::{colors::*, AnsiColors, OwoColorize};
450
451 #[test]
452 fn fg_bg_combo() {
453 let test = "test".red().on_blue();
454 assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
455 }
456
457 #[test]
458 fn bg_fg_combo() {
459 let test = "test".on_blue().red();
460 assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
461 }
462
463 #[test]
464 fn fg_bg_dyn_combo() {
465 let test = "test".color(AnsiColors::Red).on_color(AnsiColors::Blue);
466 assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
467 }
468
469 #[test]
470 fn bg_fg_dyn_combo() {
471 let test = "test".on_color(AnsiColors::Blue).color(AnsiColors::Red);
472 assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
473 }
474
475 #[test]
476 fn fg_overide() {
477 let test = "test".green().yellow().red().on_blue();
478 assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
479 }
480
481 #[test]
482 fn bg_overide() {
483 let test = "test".on_green().on_yellow().on_blue().red();
484 assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
485 }
486
487 #[test]
488 fn multiple_overide() {
489 let test = "test"
490 .on_green()
491 .on_yellow()
492 .on_red()
493 .green()
494 .on_blue()
495 .red();
496 assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
497
498 let test = "test"
499 .color(AnsiColors::Blue)
500 .color(AnsiColors::White)
501 .on_color(AnsiColors::Black)
502 .color(AnsiColors::Red)
503 .on_color(AnsiColors::Blue);
504 assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
505
506 let test = "test"
507 .on_yellow()
508 .on_red()
509 .on_color(AnsiColors::Black)
510 .color(AnsiColors::Red)
511 .on_color(AnsiColors::Blue);
512 assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
513
514 let test = "test"
515 .yellow()
516 .red()
517 .color(AnsiColors::Red)
518 .on_color(AnsiColors::Black)
519 .on_color(AnsiColors::Blue);
520 assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
521
522 let test = "test"
523 .yellow()
524 .red()
525 .on_color(AnsiColors::Black)
526 .color(AnsiColors::Red)
527 .on_color(AnsiColors::Blue);
528 assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
529 }
530
531 #[test]
532 fn generic_multiple_override() {
533 use crate::colors::*;
534
535 let test = "test"
536 .bg::<Green>()
537 .bg::<Yellow>()
538 .bg::<Red>()
539 .fg::<Green>()
540 .bg::<Blue>()
541 .fg::<Red>();
542 assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
543 }
544
545 #[test]
546 fn fg_bg_combo_generic() {
547 let test = "test".fg::<Red>().bg::<Blue>();
548 assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
549 }
550
551 #[test]
552 fn bg_fg_combo_generic() {
553 let test = "test".bg::<Blue>().fg::<Red>();
554 assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
555 }
556}
557