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