Skip to main content

owo_colors/
supports_colors.rs

1use core::fmt;
2
3#[cfg(feature = "supports-colors")]
4/// A display wrapper which applies a transformation based on if the given stream supports
5/// colored terminal output
6pub struct SupportsColorsDisplay<'a, InVal, Out, ApplyFn>(
7    pub(crate) &'a InVal,
8    pub(crate) ApplyFn,
9    pub(crate) Stream,
10)
11where
12    InVal: ?Sized,
13    ApplyFn: Fn(&'a InVal) -> Out;
14
15/// A possible stream source.
16#[derive(Clone, Copy, Debug)]
17pub enum Stream {
18    /// Standard output.
19    Stdout,
20
21    /// Standard error.
22    Stderr,
23}
24
25use crate::OVERRIDE;
26
27impl From<supports_color::Stream> for Stream {
28    fn from(stream: supports_color::Stream) -> Self {
29        match stream {
30            supports_color::Stream::Stdout => Self::Stdout,
31            supports_color::Stream::Stderr => Self::Stderr,
32        }
33    }
34}
35
36impl From<supports_color_2::Stream> for Stream {
37    fn from(stream: supports_color_2::Stream) -> Self {
38        match stream {
39            supports_color_2::Stream::Stdout => Self::Stdout,
40            supports_color_2::Stream::Stderr => Self::Stderr,
41        }
42    }
43}
44
45macro_rules! impl_fmt_for {
46    ($($trait:path),* $(,)?) => {
47        $(
48            impl<'a, In, Out, F> $trait for SupportsColorsDisplay<'a, In, Out, F>
49                where In: $trait,
50                      Out: $trait,
51                      F: Fn(&'a In) -> Out,
52            {
53                #[inline(always)]
54                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55                    let (force_enabled, force_disabled) = OVERRIDE.is_force_enabled_or_disabled();
56                    if force_enabled || (on_cached(self.2) && !force_disabled) {
57                        <Out as $trait>::fmt(&self.1(self.0), f)
58                    } else {
59                        <In as $trait>::fmt(self.0, f)
60                    }
61                }
62            }
63        )*
64    };
65}
66
67fn on_cached(stream: Stream) -> bool {
68    let stream = match stream {
69        Stream::Stdout => supports_color::Stream::Stdout,
70        Stream::Stderr => supports_color::Stream::Stderr,
71    };
72    supports_color::on_cached(stream)
73        .map(|level| level.has_basic)
74        .unwrap_or(false)
75}
76
77impl_fmt_for! {
78    fmt::Display,
79    fmt::Debug,
80    fmt::UpperHex,
81    fmt::LowerHex,
82    fmt::Binary,
83    fmt::UpperExp,
84    fmt::LowerExp,
85    fmt::Octal,
86    fmt::Pointer,
87}
88
89#[cfg(test)]
90mod test {
91    use crate::OwoColorize;
92
93    #[test]
94    fn test_supports_color_versions() {
95        println!(
96            "{}",
97            "This might be green"
98                .if_supports_color(supports_color_2::Stream::Stdout, |x| x.green())
99        );
100
101        println!(
102            "{}",
103            "This might be red".if_supports_color(supports_color::Stream::Stdout, |x| x.red())
104        );
105    }
106}