#[cfg(not(feature = "color"))] use crate::util::termcolor::{Color, ColorChoice}; #[cfg(feature = "color")] use termcolor::{Color, ColorChoice}; use std::{ fmt::{self, Display, Formatter}, io::{self, Write}, }; #[cfg(feature = "color")] fn is_a_tty(stderr: bool) -> bool { debug!("is_a_tty: stderr={:?}", stderr); let stream = if stderr { atty::Stream::Stderr } else { atty::Stream::Stdout }; atty::is(stream) } #[derive(Debug)] pub(crate) struct Colorizer { use_stderr: bool, color_when: ColorChoice, pieces: Vec<(String, Option)>, } impl Colorizer { #[inline] pub(crate) fn new(use_stderr: bool, color_when: ColorChoice) -> Self { Colorizer { use_stderr, color_when, pieces: vec![], } } #[inline] pub(crate) fn good(&mut self, msg: impl Into) { self.pieces.push((msg.into(), Some(Color::Green))); } #[inline] pub(crate) fn warning(&mut self, msg: impl Into) { self.pieces.push((msg.into(), Some(Color::Yellow))); } #[inline] pub(crate) fn error(&mut self, msg: impl Into) { self.pieces.push((msg.into(), Some(Color::Red))); } #[inline] pub(crate) fn none(&mut self, msg: impl Into) { self.pieces.push((msg.into(), None)); } } /// Printing methods. impl Colorizer { #[cfg(feature = "color")] pub(crate) fn print(&self) -> io::Result<()> { use termcolor::{BufferWriter, ColorSpec, WriteColor}; let color_when = if is_a_tty(self.use_stderr) { self.color_when } else { ColorChoice::Never }; let writer = if self.use_stderr { BufferWriter::stderr(color_when) } else { BufferWriter::stdout(color_when) }; let mut buffer = writer.buffer(); for piece in &self.pieces { let mut color = ColorSpec::new(); color.set_fg(piece.1); if piece.1 == Some(Color::Red) { color.set_bold(true); } buffer.set_color(&color)?; buffer.write_all(piece.0.as_bytes())?; buffer.reset()?; } writer.print(&buffer) } #[cfg(not(feature = "color"))] pub(crate) fn print(&self) -> io::Result<()> { // [e]println can't be used here because it panics // if something went wrong. We don't want that. if self.use_stderr { let stderr = std::io::stderr(); let mut stderr = stderr.lock(); write!(stderr, "{}", self) } else { let stdout = std::io::stdout(); let mut stdout = stdout.lock(); write!(stdout, "{}", self) } } } /// Color-unaware printing. Never uses coloring. impl Display for Colorizer { fn fmt(&self, f: &mut Formatter) -> fmt::Result { for piece in &self.pieces { Display::fmt(&piece.0, f)?; } Ok(()) } }