xref: /third_party/rust/crates/clap/src/output/fmt.rs (revision 19625d8c)
1use crate::builder::StyledStr;
2use crate::util::color::ColorChoice;
3
4#[derive(Copy, Clone, Debug, PartialEq, Eq)]
5pub(crate) enum Stream {
6    Stdout,
7    Stderr,
8}
9
10#[derive(Clone, Debug)]
11pub(crate) struct Colorizer {
12    stream: Stream,
13    #[allow(unused)]
14    color_when: ColorChoice,
15    content: StyledStr,
16}
17
18impl Colorizer {
19    pub(crate) fn new(stream: Stream, color_when: ColorChoice) -> Self {
20        Colorizer {
21            stream,
22            color_when,
23            content: Default::default(),
24        }
25    }
26
27    pub(crate) fn with_content(mut self, content: StyledStr) -> Self {
28        self.content = content;
29        self
30    }
31}
32
33/// Printing methods.
34impl Colorizer {
35    #[cfg(feature = "color")]
36    pub(crate) fn print(&self) -> std::io::Result<()> {
37        use termcolor::{BufferWriter, ColorChoice as DepColorChoice};
38
39        let color_when = match self.color_when {
40            ColorChoice::Always => DepColorChoice::Always,
41            ColorChoice::Auto if is_a_tty(self.stream) => DepColorChoice::Auto,
42            _ => DepColorChoice::Never,
43        };
44
45        let writer = match self.stream {
46            Stream::Stderr => BufferWriter::stderr(color_when),
47            Stream::Stdout => BufferWriter::stdout(color_when),
48        };
49
50        let mut buffer = writer.buffer();
51        ok!(self.content.write_colored(&mut buffer));
52        writer.print(&buffer)
53    }
54
55    #[cfg(not(feature = "color"))]
56    pub(crate) fn print(&self) -> std::io::Result<()> {
57        use std::io::Write;
58
59        // [e]println can't be used here because it panics
60        // if something went wrong. We don't want that.
61        match self.stream {
62            Stream::Stdout => {
63                let stdout = std::io::stdout();
64                let mut stdout = stdout.lock();
65                write!(stdout, "{}", self)
66            }
67            Stream::Stderr => {
68                let stderr = std::io::stderr();
69                let mut stderr = stderr.lock();
70                write!(stderr, "{}", self)
71            }
72        }
73    }
74}
75
76/// Color-unaware printing. Never uses coloring.
77impl std::fmt::Display for Colorizer {
78    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
79        self.content.fmt(f)
80    }
81}
82
83#[cfg(feature = "color")]
84fn is_a_tty(stream: Stream) -> bool {
85    use is_terminal::IsTerminal;
86    match stream {
87        Stream::Stdout => std::io::stdout().is_terminal(),
88        Stream::Stderr => std::io::stderr().is_terminal(),
89    }
90}
91