owo_colors/
combo.rs

1use crate::{BgColorDisplay, Color, FgColorDisplay};
2use crate::{BgDynColorDisplay, DynColor, FgDynColorDisplay, Style, Styled, colors};
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: ?Sized>(&'a T, PhantomData<(Fg, Bg)>);
12
13/// Wrapper around a type which implements all the formatters the wrapped type does, with the
14/// addition of changing the foreground and background color.
15///
16/// If compile-time coloring is an option, consider using [`ComboColorDisplay`] instead.
17pub struct ComboDynColorDisplay<'a, Fg: DynColor, Bg: DynColor, T: ?Sized>(&'a T, Fg, Bg);
18
19macro_rules! impl_fmt_for_combo {
20    ($($trait:path),* $(,)?) => {
21        $(
22            impl<'a, Fg: Color, Bg: Color, T: ?Sized + $trait> $trait for ComboColorDisplay<'a, Fg, Bg, T> {
23                #[inline(always)]
24                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25                    f.write_str("\x1b[")?;
26                    f.write_str(Fg::RAW_ANSI_FG)?;
27                    f.write_str(";")?;
28                    f.write_str(Bg::RAW_ANSI_BG)?;
29                    f.write_str("m")?;
30                    <T as $trait>::fmt(&self.0, f)?;
31                    f.write_str("\x1b[0m")
32                }
33            }
34        )*
35
36        $(
37            impl<'a, Fg: DynColor, Bg: DynColor, T: ?Sized + $trait> $trait for ComboDynColorDisplay<'a, Fg, Bg, T> {
38                #[inline(always)]
39                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40                    f.write_str("\x1b[")?;
41                    self.1.fmt_raw_ansi_fg(f)?;
42                    f.write_str(";")?;
43                    self.2.fmt_raw_ansi_bg(f)?;
44                    f.write_str("m")?;
45                    <T as $trait>::fmt(&self.0, f)?;
46                    f.write_str("\x1b[0m")
47                }
48            }
49        )*
50    };
51}
52
53impl_fmt_for_combo! {
54    fmt::Display,
55    fmt::Debug,
56    fmt::UpperHex,
57    fmt::LowerHex,
58    fmt::Binary,
59    fmt::UpperExp,
60    fmt::LowerExp,
61    fmt::Octal,
62    fmt::Pointer,
63}
64
65/// implement specialized color methods for FgColorDisplay BgColorDisplay, ComboColorDisplay
66macro_rules! color_methods {
67    ($(
68        #[$fg_meta:meta] #[$bg_meta:meta] $color:ident $fg_method:ident $bg_method:ident
69    ),* $(,)?) => {
70        const _: () = (); // workaround for syntax highlighting bug
71
72        impl<'a, Fg, T: ?Sized> FgColorDisplay<'a, Fg, T>
73        where
74            Fg: Color,
75        {
76            /// Create a new [`FgColorDisplay`], from a reference to a type which implements
77            /// [`Color`].
78            ///
79            /// This is a const function: in non-const contexts, [`OwoColorize::fg`] or one of the
80            /// other methods on it may be more convenient.
81            ///
82            /// # Example
83            ///
84            /// Usage in const contexts:
85            ///
86            /// ```rust
87            /// use owo_colors::{colors::Green, FgColorDisplay};
88            ///
89            /// const GREEN_TEXT: FgColorDisplay<Green, str> = FgColorDisplay::new("green");
90            ///
91            /// println!("{}", GREEN_TEXT);
92            /// # assert_eq!(format!("{}", GREEN_TEXT), "\x1b[32mgreen\x1b[39m");
93            /// ```
94            pub const fn new(thing: &'a T) -> Self {
95                Self(thing, PhantomData)
96            }
97
98            /// Convert self to a generic [`Styled`].
99            ///
100            /// This method erases color-related type parameters, and can be
101            /// used to unify types across branches.
102            ///
103            /// # Example
104            ///
105            /// Typical use:
106            ///
107            /// ```rust
108            /// use owo_colors::OwoColorize;
109            ///
110            /// fn is_blue() -> bool {
111            ///     // ...
112            ///     # true
113            /// }
114            ///
115            /// let styled_str = if is_blue() {
116            ///     "hello".blue().into_styled()
117            /// } else {
118            ///     "hello".green().into_styled()
119            /// };
120            ///
121            /// println!("{}", styled_str);
122            /// # assert_eq!(format!("{}", styled_str), "\x1b[34mhello\x1b[0m");
123            /// ```
124            ///
125            /// Usage in const contexts:
126            ///
127            /// ```rust
128            /// use owo_colors::{colors::{Blue, Green}, FgColorDisplay, Styled};
129            ///
130            /// const fn is_blue() -> bool {
131            ///     // ...
132            ///     # true
133            /// }
134            ///
135            /// const STYLED_STR: Styled<&str> = if is_blue() {
136            ///     FgColorDisplay::<Blue, _>::new("Hello").into_styled()
137            /// } else {
138            ///     FgColorDisplay::<Green, _>::new("Hello").into_styled()
139            /// };
140            ///
141            /// println!("{}", STYLED_STR);
142            /// # assert_eq!(format!("{}", STYLED_STR), "\x1b[34mHello\x1b[0m");
143            /// ```
144            pub const fn into_styled(self) -> Styled<&'a T> {
145                let style = Style::new().fg::<Fg>();
146                Styled { style, target: self.0 }
147            }
148
149            /// Set the foreground color at runtime. Only use if you do not know which color will be used at
150            /// compile-time. If the color is constant, use either [`OwoColorize::fg`] or
151            /// a color-specific method, such as [`OwoColorize::green`],
152            ///
153            /// ```rust
154            /// use owo_colors::{OwoColorize, AnsiColors};
155            ///
156            /// println!("{}", "green".color(AnsiColors::Green));
157            /// ```
158            pub const fn color<NewFg: DynColor>(
159                self,
160                fg: NewFg,
161            ) -> FgDynColorDisplay<'a, NewFg, T> {
162                FgDynColorDisplay(self.0, fg)
163            }
164
165            /// Set the background color at runtime. Only use if you do not know what color to use at
166            /// compile-time. If the color is constant, use either [`OwoColorize::bg`] or
167            /// a color-specific method, such as [`OwoColorize::on_yellow`],
168            ///
169            /// ```rust
170            /// use owo_colors::{OwoColorize, AnsiColors};
171            ///
172            /// println!("{}", "yellow background".on_color(AnsiColors::BrightYellow));
173            /// ```
174            pub const fn on_color<NewBg: DynColor>(
175                self,
176                bg: NewBg,
177            ) -> ComboDynColorDisplay<'a, Fg::DynEquivalent, NewBg, T> {
178                ComboDynColorDisplay(self.0, Fg::DYN_EQUIVALENT, bg)
179            }
180
181            /// Set the foreground color generically
182            ///
183            /// ```rust
184            /// use owo_colors::{OwoColorize, colors::*};
185            ///
186            /// println!("{}", "red foreground".fg::<Red>());
187            /// ```
188            pub const fn fg<C: Color>(self) -> FgColorDisplay<'a, C, T> {
189                FgColorDisplay(self.0, PhantomData)
190            }
191
192            /// Set the background color generically.
193            ///
194            /// ```rust
195            /// use owo_colors::{OwoColorize, colors::*};
196            ///
197            /// println!("{}", "black background".bg::<Black>());
198            /// ```
199            pub const fn bg<C: Color>(self) -> ComboColorDisplay<'a, Fg, C, T> {
200                ComboColorDisplay(self.0, PhantomData)
201            }
202
203            $(
204                #[$fg_meta]
205                #[inline(always)]
206                pub const fn $fg_method(self) -> FgColorDisplay<'a, colors::$color, T> {
207                    FgColorDisplay(self.0, PhantomData)
208                }
209
210                #[$bg_meta]
211                #[inline(always)]
212                pub const fn $bg_method(self) -> ComboColorDisplay<'a, Fg, colors::$color, T> {
213                    ComboColorDisplay(self.0, PhantomData)
214                }
215             )*
216        }
217
218        const _: () = (); // workaround for syntax highlighting bug
219
220        impl<'a, Bg, T: ?Sized> BgColorDisplay<'a, Bg, T>
221        where
222            Bg: Color,
223        {
224            /// Create a new [`BgColorDisplay`], from a reference to a type which implements
225            /// [`Color`].
226            ///
227            /// This is a const function: in non-const contexts, [`OwoColorize::bg`] may be more
228            /// convenient.
229            ///
230            /// # Example
231            ///
232            /// Usage in const contexts:
233            ///
234            /// ```rust
235            /// use owo_colors::{colors::Red, BgColorDisplay};
236            ///
237            /// const RED_BG_TEXT: BgColorDisplay<Red, str> = BgColorDisplay::new("red background");
238            ///
239            /// println!("{}", RED_BG_TEXT);
240            /// # assert_eq!(format!("{}", RED_BG_TEXT), "\x1b[41mred background\x1b[49m");
241            /// ```
242            pub const fn new(thing: &'a T) -> Self {
243                Self(thing, PhantomData)
244            }
245
246            /// Convert self to a generic [`Styled`].
247            ///
248            /// This method erases color-related type parameters, and can be
249            /// used to unify types across branches.
250            ///
251            /// # Example
252            ///
253            /// Typical use:
254            ///
255            /// ```rust
256            /// use owo_colors::OwoColorize;
257            ///
258            /// fn is_red() -> bool {
259            ///     // ...
260            ///     # true
261            /// }
262            ///
263            /// let styled_str = if is_red() {
264            ///     "hello".on_red().into_styled()
265            /// } else {
266            ///     "hello".on_yellow().into_styled()
267            /// };
268            ///
269            /// println!("{}", styled_str);
270            /// # assert_eq!(format!("{}", styled_str), "\x1b[41mhello\x1b[0m");
271            /// ```
272            ///
273            /// Usage in const contexts:
274            ///
275            /// ```rust
276            /// use owo_colors::{colors::{Red, Yellow}, BgColorDisplay, Styled};
277            ///
278            /// const fn is_red() -> bool {
279            ///     // ...
280            ///     # true
281            /// }
282            ///
283            /// const STYLED_STR: Styled<&str> = if is_red() {
284            ///     BgColorDisplay::<Red, _>::new("Hello").into_styled()
285            /// } else {
286            ///     BgColorDisplay::<Yellow, _>::new("Hello").into_styled()
287            /// };
288            ///
289            /// println!("{}", STYLED_STR);
290            /// # assert_eq!(format!("{}", STYLED_STR), "\x1b[41mHello\x1b[0m");
291            /// ```
292            pub const fn into_styled(self) -> Styled<&'a T> {
293                let style = Style::new().bg::<Bg>();
294                Styled { style, target: self.0 }
295            }
296
297            /// Set the foreground color at runtime. Only use if you do not know which color will be used at
298            /// compile-time. If the color is constant, use either [`OwoColorize::fg`] or
299            /// a color-specific method, such as [`OwoColorize::green`],
300            ///
301            /// ```rust
302            /// use owo_colors::{OwoColorize, AnsiColors};
303            ///
304            /// println!("{}", "green".color(AnsiColors::Green));
305            /// ```
306            pub const fn color<NewFg: DynColor>(
307                self,
308                fg: NewFg,
309            ) -> ComboDynColorDisplay<'a, NewFg, Bg::DynEquivalent, T> {
310                ComboDynColorDisplay(self.0, fg, Bg::DYN_EQUIVALENT)
311            }
312
313            /// Set the background color at runtime. Only use if you do not know what color to use at
314            /// compile-time. If the color is constant, use either [`OwoColorize::bg`] or
315            /// a color-specific method, such as [`OwoColorize::on_yellow`],
316            ///
317            /// ```rust
318            /// use owo_colors::{OwoColorize, AnsiColors};
319            ///
320            /// println!("{}", "yellow background".on_color(AnsiColors::BrightYellow));
321            /// ```
322            pub const fn on_color<NewBg: DynColor>(
323                self,
324                bg: NewBg,
325            ) -> BgDynColorDisplay<'a, NewBg, T> {
326                BgDynColorDisplay(self.0, bg)
327            }
328
329            /// Set the foreground color generically
330            ///
331            /// ```rust
332            /// use owo_colors::{OwoColorize, colors::*};
333            ///
334            /// println!("{}", "red foreground".fg::<Red>());
335            /// ```
336            pub const fn fg<C: Color>(self) -> ComboColorDisplay<'a, C, Bg, T> {
337                ComboColorDisplay(self.0, PhantomData)
338            }
339
340            /// Set the background color generically.
341            ///
342            /// ```rust
343            /// use owo_colors::{OwoColorize, colors::*};
344            ///
345            /// println!("{}", "black background".bg::<Black>());
346            /// ```
347            pub const fn bg<C: Color>(self) -> BgColorDisplay<'a, C, T> {
348                BgColorDisplay(self.0, PhantomData)
349            }
350
351            $(
352                #[$bg_meta]
353                #[inline(always)]
354                pub const fn $bg_method(self) -> BgColorDisplay<'a, colors::$color, T> {
355                    BgColorDisplay(self.0, PhantomData)
356                }
357
358                #[$fg_meta]
359                #[inline(always)]
360                pub const fn $fg_method(self) -> ComboColorDisplay<'a, colors::$color, Bg, T> {
361                    ComboColorDisplay(self.0, PhantomData)
362                }
363             )*
364        }
365
366        const _: () = (); // workaround for syntax highlighting bug
367
368        impl<'a, Fg, Bg, T: ?Sized> ComboColorDisplay<'a, Fg, Bg, T>
369        where
370            Fg: Color,
371            Bg: Color,
372        {
373            /// Create a new [`ComboColorDisplay`], from a pair of foreground and background types
374            /// which implement [`Color`].
375            ///
376            /// This is a const function: in non-const contexts, calling the [`OwoColorize`]
377            /// functions may be more convenient.
378            ///
379            /// # Example
380            ///
381            /// Usage in const contexts:
382            ///
383            /// ```rust
384            /// use owo_colors::{colors::{Blue, White}, ComboColorDisplay};
385            ///
386            /// const COMBO_TEXT: ComboColorDisplay<Blue, White, str> =
387            ///    ComboColorDisplay::new("blue text on white background");
388            ///
389            /// println!("{}", COMBO_TEXT);
390            /// # assert_eq!(format!("{}", COMBO_TEXT), "\x1b[34;47mblue text on white background\x1b[0m");
391            /// ```
392            pub const fn new(thing: &'a T) -> Self {
393                Self(thing, PhantomData)
394            }
395
396            /// Convert self to a generic [`Styled`].
397            ///
398            /// This method erases color-related type parameters, and can be
399            /// used to unify types across branches.
400            ///
401            /// # Example
402            ///
403            /// Typical use:
404            ///
405            /// ```rust
406            /// use owo_colors::OwoColorize;
407            ///
408            /// fn is_black_on_white() -> bool {
409            ///     // ...
410            ///     # true
411            /// }
412            ///
413            /// let styled_str = if is_black_on_white() {
414            ///     "hello".black().on_white().into_styled()
415            /// } else {
416            ///     "hello".white().on_black().into_styled()
417            /// };
418            ///
419            /// println!("{}", styled_str);
420            /// # assert_eq!(format!("{}", styled_str), "\x1b[30;47mhello\x1b[0m");
421            /// ```
422            ///
423            /// Usage in const contexts:
424            ///
425            /// ```rust
426            /// use owo_colors::{colors::{Black, White}, ComboColorDisplay, Styled};
427            ///
428            /// const fn is_black_on_white() -> bool {
429            ///     // ...
430            ///     # true
431            /// }
432            ///
433            /// const STYLED_STR: Styled<&str> = if is_black_on_white() {
434            ///     ComboColorDisplay::<Black, White, _>::new("Hello").into_styled()
435            /// } else {
436            ///     ComboColorDisplay::<White, Black, _>::new("Hello").into_styled()
437            /// };
438            ///
439            /// println!("{}", STYLED_STR);
440            /// # assert_eq!(format!("{}", STYLED_STR), "\x1b[30;47mHello\x1b[0m");
441            /// ```
442            pub const fn into_styled(self) -> Styled<&'a T> {
443                let style = Style::new().fg::<Fg>().bg::<Bg>();
444                Styled { style, target: self.0 }
445            }
446
447            /// Set the background color at runtime. Only use if you do not know what color to use at
448            /// compile-time. If the color is constant, use either [`OwoColorize::bg`] or
449            /// a color-specific method, such as [`OwoColorize::on_yellow`],
450            ///
451            /// ```rust
452            /// use owo_colors::{OwoColorize, AnsiColors};
453            ///
454            /// println!("{}", "yellow background".on_color(AnsiColors::BrightYellow));
455            /// ```
456            pub const fn on_color<NewBg: DynColor>(
457                self,
458                bg: NewBg,
459            ) -> ComboDynColorDisplay<'a, Fg::DynEquivalent, NewBg, T> {
460                ComboDynColorDisplay(self.0, Fg::DYN_EQUIVALENT, bg)
461            }
462
463            /// Set the foreground color at runtime. Only use if you do not know which color will be used at
464            /// compile-time. If the color is constant, use either [`OwoColorize::fg`] or
465            /// a color-specific method, such as [`OwoColorize::green`],
466            ///
467            /// ```rust
468            /// use owo_colors::{OwoColorize, AnsiColors};
469            ///
470            /// println!("{}", "green".color(AnsiColors::Green));
471            /// ```
472            pub const fn color<NewFg: DynColor>(
473                self,
474                fg: NewFg,
475            ) -> ComboDynColorDisplay<'a, NewFg, Bg::DynEquivalent, T> {
476                ComboDynColorDisplay(self.0, fg, Bg::DYN_EQUIVALENT)
477            }
478
479            /// Set the foreground color generically
480            ///
481            /// ```rust
482            /// use owo_colors::{OwoColorize, colors::*};
483            ///
484            /// println!("{}", "red foreground".fg::<Red>());
485            /// ```
486            pub const fn fg<C: Color>(self) -> ComboColorDisplay<'a, C, Bg, T> {
487                ComboColorDisplay(self.0, PhantomData)
488            }
489
490            /// Set the background color generically.
491            ///
492            /// ```rust
493            /// use owo_colors::{OwoColorize, colors::*};
494            ///
495            /// println!("{}", "black background".bg::<Black>());
496            /// ```
497            pub const fn bg<C: Color>(self) -> ComboColorDisplay<'a, Fg, C, T> {
498                ComboColorDisplay(self.0, PhantomData)
499            }
500
501            $(
502                #[$bg_meta]
503                #[inline(always)]
504                pub const fn $bg_method(self) -> ComboColorDisplay<'a, Fg, colors::$color, T> {
505                    ComboColorDisplay(self.0, PhantomData)
506                }
507
508                #[$fg_meta]
509                #[inline(always)]
510                pub const fn $fg_method(self) -> ComboColorDisplay<'a, colors::$color, Bg, T> {
511                    ComboColorDisplay(self.0, PhantomData)
512                }
513            )*
514        }
515    };
516}
517
518const _: () = (); // workaround for syntax highlighting bug
519
520color_methods! {
521    /// Change the foreground color to black
522    /// Change the background color to black
523    Black    black    on_black,
524    /// Change the foreground color to red
525    /// Change the background color to red
526    Red      red      on_red,
527    /// Change the foreground color to green
528    /// Change the background color to green
529    Green    green    on_green,
530    /// Change the foreground color to yellow
531    /// Change the background color to yellow
532    Yellow   yellow   on_yellow,
533    /// Change the foreground color to blue
534    /// Change the background color to blue
535    Blue     blue     on_blue,
536    /// Change the foreground color to magenta
537    /// Change the background color to magenta
538    Magenta  magenta  on_magenta,
539    /// Change the foreground color to purple
540    /// Change the background color to purple
541    Magenta  purple   on_purple,
542    /// Change the foreground color to cyan
543    /// Change the background color to cyan
544    Cyan     cyan     on_cyan,
545    /// Change the foreground color to white
546    /// Change the background color to white
547    White    white    on_white,
548
549    /// Change the foreground color to bright black
550    /// Change the background color to bright black
551    BrightBlack    bright_black    on_bright_black,
552    /// Change the foreground color to bright red
553    /// Change the background color to bright red
554    BrightRed      bright_red      on_bright_red,
555    /// Change the foreground color to bright green
556    /// Change the background color to bright green
557    BrightGreen    bright_green    on_bright_green,
558    /// Change the foreground color to bright yellow
559    /// Change the background color to bright yellow
560    BrightYellow   bright_yellow   on_bright_yellow,
561    /// Change the foreground color to bright blue
562    /// Change the background color to bright blue
563    BrightBlue     bright_blue     on_bright_blue,
564    /// Change the foreground color to bright magenta
565    /// Change the background color to bright magenta
566    BrightMagenta  bright_magenta  on_bright_magenta,
567    /// Change the foreground color to bright purple
568    /// Change the background color to bright purple
569    BrightMagenta  bright_purple   on_bright_purple,
570    /// Change the foreground color to bright cyan
571    /// Change the background color to bright cyan
572    BrightCyan     bright_cyan     on_bright_cyan,
573    /// Change the foreground color to bright white
574    /// Change the background color to bright white
575    BrightWhite    bright_white    on_bright_white,
576}
577
578impl<'a, Fg: DynColor + Copy, T: ?Sized> FgDynColorDisplay<'a, Fg, T> {
579    /// Create a new [`FgDynColorDisplay`], from a reference to a type which implements
580    /// [`DynColor`].
581    ///
582    /// This is a const function: in non-const contexts, [`OwoColorize::color`] may be more
583    /// convenient.
584    ///
585    /// # Example
586    ///
587    /// Usage in const contexts:
588    ///
589    /// ```rust
590    /// use owo_colors::{AnsiColors, FgDynColorDisplay};
591    ///
592    /// const DYN_RED_TEXT: FgDynColorDisplay<AnsiColors, str> =
593    ///    FgDynColorDisplay::new("red text (dynamic)", AnsiColors::Red);
594    ///
595    /// println!("{}", DYN_RED_TEXT);
596    /// # assert_eq!(format!("{}", DYN_RED_TEXT), "\x1b[31mred text (dynamic)\x1b[39m");
597    /// ```
598    pub const fn new(thing: &'a T, color: Fg) -> Self {
599        Self(thing, color)
600    }
601
602    /// Convert self to a generic [`Styled`].
603    ///
604    /// This method erases color-related type parameters, and can be
605    /// used to unify types across branches.
606    ///
607    /// # Example
608    ///
609    /// ```rust
610    /// use owo_colors::{AnsiColors, CssColors, OwoColorize};
611    ///
612    /// fn is_blue() -> bool {
613    ///     // ...
614    ///     # true
615    /// }
616    ///
617    /// let styled_str = if is_blue() {
618    ///     "hello".color(AnsiColors::Blue).into_styled()
619    /// } else {
620    ///     "hello".color(CssColors::DarkSeaGreen).into_styled()
621    /// };
622    ///
623    /// println!("{}", styled_str);
624    /// # assert_eq!(format!("{}", styled_str), "\x1b[34mhello\x1b[0m");
625    /// ```
626    pub fn into_styled(self) -> Styled<&'a T> {
627        let Self(target, fg) = self;
628        let style = Style::new().color(fg);
629        Styled { style, target }
630    }
631
632    /// Set the background color at runtime. Only use if you do not know what color to use at
633    /// compile-time. If the color is constant, use either [`OwoColorize::bg`] or
634    /// a color-specific method, such as [`OwoColorize::on_yellow`],
635    ///
636    /// ```rust
637    /// use owo_colors::{OwoColorize, AnsiColors};
638    ///
639    /// println!("{}", "yellow background".on_color(AnsiColors::BrightYellow));
640    /// ```
641    pub const fn on_color<Bg: DynColor>(self, bg: Bg) -> ComboDynColorDisplay<'a, Fg, Bg, T> {
642        let Self(inner, fg) = self;
643        ComboDynColorDisplay(inner, fg, bg)
644    }
645
646    /// Set the foreground color at runtime. Only use if you do not know which color will be used at
647    /// compile-time. If the color is constant, use either [`OwoColorize::fg`] or
648    /// a color-specific method, such as [`OwoColorize::green`],
649    ///
650    /// ```rust
651    /// use owo_colors::{OwoColorize, AnsiColors};
652    ///
653    /// println!("{}", "green".color(AnsiColors::Green));
654    /// ```
655    pub const fn color<NewFg: DynColor>(self, fg: NewFg) -> FgDynColorDisplay<'a, NewFg, T> {
656        let Self(inner, _) = self;
657        FgDynColorDisplay(inner, fg)
658    }
659}
660
661impl<'a, Bg: DynColor + Copy, T: ?Sized> BgDynColorDisplay<'a, Bg, T> {
662    /// Create a new [`BgDynColorDisplay`], from a reference to a type which implements
663    /// [`DynColor`].
664    ///
665    /// This is a const function: in non-const contexts, [`OwoColorize::on_color`] may be more
666    /// convenient.
667    ///
668    /// # Example
669    ///
670    /// Usage in const contexts:
671    ///
672    /// ```rust
673    /// use owo_colors::{AnsiColors, BgDynColorDisplay};
674    ///
675    /// const DYN_GREEN_BG_TEXT: BgDynColorDisplay<AnsiColors, str> =
676    ///    BgDynColorDisplay::new("green background (dynamic)", AnsiColors::Green);
677    ///
678    /// println!("{}", DYN_GREEN_BG_TEXT);
679    /// # assert_eq!(format!("{}", DYN_GREEN_BG_TEXT), "\x1b[42mgreen background (dynamic)\x1b[49m");
680    /// ```
681    pub const fn new(thing: &'a T, color: Bg) -> Self {
682        Self(thing, color)
683    }
684
685    /// Convert self to a generic [`Styled`].
686    ///
687    /// This method erases color-related type parameters, and can be
688    /// used to unify types across branches.
689    ///
690    /// # Example
691    ///
692    /// ```rust
693    /// use owo_colors::{AnsiColors, CssColors, OwoColorize};
694    ///
695    /// fn is_red() -> bool {
696    ///     // ...
697    ///     # true
698    /// }
699    ///
700    /// let styled_str = if is_red() {
701    ///     "hello".on_color(AnsiColors::Red).into_styled()
702    /// } else {
703    ///     "hello".on_color(CssColors::LightGoldenRodYellow).into_styled()
704    /// };
705    ///
706    /// println!("{}", styled_str);
707    /// # assert_eq!(format!("{}", styled_str), "\x1b[41mhello\x1b[0m");
708    /// ```
709    pub fn into_styled(self) -> Styled<&'a T> {
710        let Self(target, bg) = self;
711        let style = Style::new().on_color(bg);
712        Styled { style, target }
713    }
714
715    /// Set the background color at runtime. Only use if you do not know what color to use at
716    /// compile-time. If the color is constant, use either [`OwoColorize::bg`] or
717    /// a color-specific method, such as [`OwoColorize::on_yellow`],
718    ///
719    /// ```rust
720    /// use owo_colors::{OwoColorize, AnsiColors};
721    ///
722    /// println!("{}", "yellow background".on_color(AnsiColors::BrightYellow));
723    /// ```
724    pub const fn on_color<NewBg: DynColor>(self, bg: NewBg) -> BgDynColorDisplay<'a, NewBg, T> {
725        let Self(inner, _) = self;
726        BgDynColorDisplay(inner, bg)
727    }
728
729    /// Set the foreground color at runtime. Only use if you do not know which color will be used at
730    /// compile-time. If the color is constant, use either [`OwoColorize::fg`] or
731    /// a color-specific method, such as [`OwoColorize::green`],
732    ///
733    /// ```rust
734    /// use owo_colors::{OwoColorize, AnsiColors};
735    ///
736    /// println!("{}", "green".color(AnsiColors::Green));
737    /// ```
738    pub const fn color<Fg: DynColor>(self, fg: Fg) -> ComboDynColorDisplay<'a, Fg, Bg, T> {
739        let Self(inner, bg) = self;
740        ComboDynColorDisplay(inner, fg, bg)
741    }
742}
743
744impl<'a, Fg: DynColor + Copy, Bg: DynColor + Copy, T: ?Sized> ComboDynColorDisplay<'a, Fg, Bg, T> {
745    /// Create a new [`ComboDynColorDisplay`], from a pair of types which implement
746    /// [`DynColor`].
747    ///
748    /// This is a const function: in non-const contexts, other functions may be more convenient.
749    ///
750    /// # Example
751    ///
752    /// Usage in const contexts:
753    ///
754    /// ```rust
755    /// use owo_colors::{ComboDynColorDisplay, XtermColors};
756    ///
757    /// const COMBO_DYN_TEXT: ComboDynColorDisplay<XtermColors, XtermColors, str> =
758    ///     ComboDynColorDisplay::new(
759    ///         "blue text on lilac background (dynamic)",
760    ///         XtermColors::BlueRibbon,
761    ///         XtermColors::WistfulLilac,
762    ///     );
763    ///
764    /// println!("{}", COMBO_DYN_TEXT);
765    /// # assert_eq!(format!("{}", COMBO_DYN_TEXT), "\x1b[38;5;27;48;5;146mblue text on lilac background (dynamic)\x1b[0m");
766    /// ```
767    pub const fn new(thing: &'a T, fg: Fg, bg: Bg) -> Self {
768        Self(thing, fg, bg)
769    }
770
771    /// Convert self to a generic [`Styled`].
772    ///
773    /// This method erases color-related type parameters, and can be
774    /// used to unify types across branches.
775    ///
776    /// # Example
777    ///
778    /// Typical use:
779    ///
780    /// ```rust
781    /// use owo_colors::{AnsiColors, CssColors, OwoColorize};
782    ///
783    /// fn is_black_on_white() -> bool {
784    ///     // ...
785    ///     # true
786    /// }
787    ///
788    /// let styled_str = if is_black_on_white() {
789    ///     "hello".color(AnsiColors::Black).on_color(AnsiColors::White).into_styled()
790    /// } else {
791    ///     "hello".color(CssColors::White).on_color(CssColors::Black).into_styled()
792    /// };
793    ///
794    /// println!("{}", styled_str);
795    /// # assert_eq!(format!("{}", styled_str), "\x1b[30;47mhello\x1b[0m");
796    /// ```
797    pub fn into_styled(self) -> Styled<&'a T> {
798        let Self(target, fg, bg) = self;
799        let style = Style::new().color(fg).on_color(bg);
800        Styled { style, target }
801    }
802
803    /// Set the background color at runtime. Only use if you do not know what color to use at
804    /// compile-time. If the color is constant, use either [`OwoColorize::bg`] or
805    /// a color-specific method, such as [`OwoColorize::on_yellow`],
806    ///
807    /// ```rust
808    /// use owo_colors::{OwoColorize, AnsiColors};
809    ///
810    /// println!("{}", "yellow background".on_color(AnsiColors::BrightYellow));
811    /// ```
812    pub const fn on_color<NewBg: DynColor>(
813        self,
814        bg: NewBg,
815    ) -> ComboDynColorDisplay<'a, Fg, NewBg, T> {
816        let Self(inner, fg, _) = self;
817        ComboDynColorDisplay(inner, fg, bg)
818    }
819
820    /// Set the foreground color at runtime. Only use if you do not know which color will be used at
821    /// compile-time. If the color is constant, use either [`OwoColorize::fg`] or
822    /// a color-specific method, such as [`OwoColorize::green`],
823    ///
824    /// ```rust
825    /// use owo_colors::{OwoColorize, AnsiColors};
826    ///
827    /// println!("{}", "green".color(AnsiColors::Green));
828    /// ```
829    pub const fn color<NewFg: DynColor>(self, fg: NewFg) -> ComboDynColorDisplay<'a, NewFg, Bg, T> {
830        // TODO: Make this const after https://github.com/rust-lang/rust/issues/73255 is stabilized.
831        let Self(inner, _, bg) = self;
832        ComboDynColorDisplay(inner, fg, bg)
833    }
834}
835
836#[cfg(test)]
837mod tests {
838    use crate::{AnsiColors, OwoColorize, colors::*};
839
840    #[test]
841    fn fg_bg_combo() {
842        let test = "test".red().on_blue();
843        assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
844    }
845
846    #[test]
847    fn bg_fg_combo() {
848        let test = "test".on_blue().red();
849        assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
850    }
851
852    #[test]
853    fn fg_bg_dyn_combo() {
854        let test = "test".color(AnsiColors::Red).on_color(AnsiColors::Blue);
855        assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
856    }
857
858    #[test]
859    fn bg_fg_dyn_combo() {
860        let test = "test".on_color(AnsiColors::Blue).color(AnsiColors::Red);
861        assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
862    }
863
864    #[test]
865    fn fg_override() {
866        let test = "test".green().yellow().red().on_blue();
867        assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
868    }
869
870    #[test]
871    fn bg_override() {
872        let test = "test".on_green().on_yellow().on_blue().red();
873        assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
874    }
875
876    #[test]
877    fn multiple_override() {
878        let test = "test"
879            .on_green()
880            .on_yellow()
881            .on_red()
882            .green()
883            .on_blue()
884            .red();
885        assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
886
887        let test = "test"
888            .color(AnsiColors::Blue)
889            .color(AnsiColors::White)
890            .on_color(AnsiColors::Black)
891            .color(AnsiColors::Red)
892            .on_color(AnsiColors::Blue);
893        assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
894
895        let test = "test"
896            .on_yellow()
897            .on_red()
898            .on_color(AnsiColors::Black)
899            .color(AnsiColors::Red)
900            .on_color(AnsiColors::Blue);
901        assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
902
903        let test = "test"
904            .yellow()
905            .red()
906            .color(AnsiColors::Red)
907            .on_color(AnsiColors::Black)
908            .on_color(AnsiColors::Blue);
909        assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
910
911        let test = "test"
912            .yellow()
913            .red()
914            .on_color(AnsiColors::Black)
915            .color(AnsiColors::Red)
916            .on_color(AnsiColors::Blue);
917        assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
918    }
919
920    #[test]
921    fn generic_multiple_override() {
922        use crate::colors::*;
923
924        let test = "test"
925            .bg::<Green>()
926            .bg::<Yellow>()
927            .bg::<Red>()
928            .fg::<Green>()
929            .bg::<Blue>()
930            .fg::<Red>();
931        assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
932    }
933
934    #[test]
935    fn fg_bg_combo_generic() {
936        let test = "test".fg::<Red>().bg::<Blue>();
937        assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
938    }
939
940    #[test]
941    fn bg_fg_combo_generic() {
942        let test = "test".bg::<Blue>().fg::<Red>();
943        assert_eq!(test.to_string(), "\x1b[31;44mtest\x1b[0m");
944    }
945}