    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90

    use crate::builder::StyledStr;
    use crate::util::color::ColorChoice;

    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
    pub(crate) enum Stream {
        Stdout,
        Stderr,
    }

    #[derive(Clone, Debug)]
    pub(crate) struct Colorizer {
        stream: Stream,
        #[allow(unused)]
        color_when: ColorChoice,
        content: StyledStr,
    }

    impl Colorizer {
        pub(crate) fn new(stream: Stream, color_when: ColorChoice) -> Self {
            Colorizer {
                stream,
                color_when,
                content: Default::default(),
            }
        }

        pub(crate) fn with_content(mut self, content: StyledStr) -> Self {
            self.content = content;
            self
        }
    }

    /// Printing methods.
    impl Colorizer {
        #[cfg(feature = "color")]
        pub(crate) fn print(&self) -> std::io::Result<()> {
            use termcolor::{BufferWriter, ColorChoice as DepColorChoice};

            let color_when = match self.color_when {
                ColorChoice::Always => DepColorChoice::Always,
                ColorChoice::Auto if is_a_tty(self.stream) => DepColorChoice::Auto,
                _ => DepColorChoice::Never,
            };

            let writer = match self.stream {
                Stream::Stderr => BufferWriter::stderr(color_when),
                Stream::Stdout => BufferWriter::stdout(color_when),
            };

            let mut buffer = writer.buffer();
            ok!(self.content.write_colored(&mut buffer));
            writer.print(&buffer)
        }

        #[cfg(not(feature = "color"))]
        pub(crate) fn print(&self) -> std::io::Result<()> {
            use std::io::Write;

            // [e]println can't be used here because it panics
            // if something went wrong. We don't want that.
            match self.stream {
                Stream::Stdout => {
                    let stdout = std::io::stdout();
                    let mut stdout = stdout.lock();
                    write!(stdout, "{}", self)
                }
                Stream::Stderr => {
                    let stderr = std::io::stderr();
                    let mut stderr = stderr.lock();
                    write!(stderr, "{}", self)
                }
            }
        }
    }

    /// Color-unaware printing. Never uses coloring.
    impl std::fmt::Display for Colorizer {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            self.content.fmt(f)
        }
    }

    #[cfg(feature = "color")]
    fn is_a_tty(stream: Stream) -> bool {
        use is_terminal::IsTerminal;
        match stream {
            Stream::Stdout => std::io::stdout().is_terminal(),
            Stream::Stderr => std::io::stderr().is_terminal(),
        }
    }