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}