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