1 #[cfg(not(feature = "color"))]
2 use crate::util::termcolor::{Color, ColorChoice};
3 #[cfg(feature = "color")]
4 use termcolor::{Color, ColorChoice};
5 
6 use std::{
7     fmt::{self, Display, Formatter},
8     io::{self, Write},
9 };
10 
11 #[cfg(feature = "color")]
is_a_tty(stderr: bool) -> bool12 fn is_a_tty(stderr: bool) -> bool {
13     debug!("is_a_tty: stderr={:?}", stderr);
14 
15     let stream = if stderr {
16         atty::Stream::Stderr
17     } else {
18         atty::Stream::Stdout
19     };
20 
21     atty::is(stream)
22 }
23 
24 #[derive(Debug)]
25 pub(crate) struct Colorizer {
26     use_stderr: bool,
27     color_when: ColorChoice,
28     pieces: Vec<(String, Option<Color>)>,
29 }
30 
31 impl Colorizer {
32     #[inline]
new(use_stderr: bool, color_when: ColorChoice) -> Self33     pub(crate) fn new(use_stderr: bool, color_when: ColorChoice) -> Self {
34         Colorizer {
35             use_stderr,
36             color_when,
37             pieces: vec![],
38         }
39     }
40 
41     #[inline]
good(&mut self, msg: impl Into<String>)42     pub(crate) fn good(&mut self, msg: impl Into<String>) {
43         self.pieces.push((msg.into(), Some(Color::Green)));
44     }
45 
46     #[inline]
warning(&mut self, msg: impl Into<String>)47     pub(crate) fn warning(&mut self, msg: impl Into<String>) {
48         self.pieces.push((msg.into(), Some(Color::Yellow)));
49     }
50 
51     #[inline]
error(&mut self, msg: impl Into<String>)52     pub(crate) fn error(&mut self, msg: impl Into<String>) {
53         self.pieces.push((msg.into(), Some(Color::Red)));
54     }
55 
56     #[inline]
none(&mut self, msg: impl Into<String>)57     pub(crate) fn none(&mut self, msg: impl Into<String>) {
58         self.pieces.push((msg.into(), None));
59     }
60 }
61 
62 /// Printing methods.
63 impl Colorizer {
64     #[cfg(feature = "color")]
print(&self) -> io::Result<()>65     pub(crate) fn print(&self) -> io::Result<()> {
66         use termcolor::{BufferWriter, ColorSpec, WriteColor};
67 
68         let color_when = if is_a_tty(self.use_stderr) {
69             self.color_when
70         } else {
71             ColorChoice::Never
72         };
73 
74         let writer = if self.use_stderr {
75             BufferWriter::stderr(color_when)
76         } else {
77             BufferWriter::stdout(color_when)
78         };
79 
80         let mut buffer = writer.buffer();
81 
82         for piece in &self.pieces {
83             let mut color = ColorSpec::new();
84             color.set_fg(piece.1);
85             if piece.1 == Some(Color::Red) {
86                 color.set_bold(true);
87             }
88 
89             buffer.set_color(&color)?;
90             buffer.write_all(piece.0.as_bytes())?;
91             buffer.reset()?;
92         }
93 
94         writer.print(&buffer)
95     }
96 
97     #[cfg(not(feature = "color"))]
print(&self) -> io::Result<()>98     pub(crate) fn print(&self) -> io::Result<()> {
99         // [e]println can't be used here because it panics
100         // if something went wrong. We don't want that.
101         if self.use_stderr {
102             let stderr = std::io::stderr();
103             let mut stderr = stderr.lock();
104             write!(stderr, "{}", self)
105         } else {
106             let stdout = std::io::stdout();
107             let mut stdout = stdout.lock();
108             write!(stdout, "{}", self)
109         }
110     }
111 }
112 
113 /// Color-unaware printing. Never uses coloring.
114 impl Display for Colorizer {
fmt(&self, f: &mut Formatter) -> fmt::Result115     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
116         for piece in &self.pieces {
117             Display::fmt(&piece.0, f)?;
118         }
119 
120         Ok(())
121     }
122 }
123