owo_colors/
combo.rs

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}