use std::io::{self, IsTerminal}; use termcolor::HyperlinkSpec; /// A writer that supports coloring with either line or block buffering. #[derive(Debug)] pub struct StandardStream(StandardStreamKind); /// Returns a possibly buffered writer to stdout for the given color choice. /// /// The writer returned is either line buffered or block buffered. The decision /// between these two is made automatically based on whether a tty is attached /// to stdout or not. If a tty is attached, then line buffering is used. /// Otherwise, block buffering is used. In general, block buffering is more /// efficient, but may increase the time it takes for the end user to see the /// first bits of output. /// /// If you need more fine grained control over the buffering mode, then use one /// of `stdout_buffered_line` or `stdout_buffered_block`. /// /// The color choice given is passed along to the underlying writer. To /// completely disable colors in all cases, use `ColorChoice::Never`. pub fn stdout(color_choice: termcolor::ColorChoice) -> StandardStream { if std::io::stdout().is_terminal() { stdout_buffered_line(color_choice) } else { stdout_buffered_block(color_choice) } } /// Returns a line buffered writer to stdout for the given color choice. /// /// This writer is useful when printing results directly to a tty such that /// users see output as soon as it's written. The downside of this approach /// is that it can be slower, especially when there is a lot of output. /// /// You might consider using [`stdout`] instead, which chooses the buffering /// strategy automatically based on whether stdout is connected to a tty. pub fn stdout_buffered_line( color_choice: termcolor::ColorChoice, ) -> StandardStream { let out = termcolor::StandardStream::stdout(color_choice); StandardStream(StandardStreamKind::LineBuffered(out)) } /// Returns a block buffered writer to stdout for the given color choice. /// /// This writer is useful when printing results to a file since it amortizes /// the cost of writing data. The downside of this approach is that it can /// increase the latency of display output when writing to a tty. /// /// You might consider using [`stdout`] instead, which chooses the buffering /// strategy automatically based on whether stdout is connected to a tty. pub fn stdout_buffered_block( color_choice: termcolor::ColorChoice, ) -> StandardStream { let out = termcolor::BufferedStandardStream::stdout(color_choice); StandardStream(StandardStreamKind::BlockBuffered(out)) } #[derive(Debug)] enum StandardStreamKind { LineBuffered(termcolor::StandardStream), BlockBuffered(termcolor::BufferedStandardStream), } impl io::Write for StandardStream { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { use self::StandardStreamKind::*; match self.0 { LineBuffered(ref mut w) => w.write(buf), BlockBuffered(ref mut w) => w.write(buf), } } #[inline] fn flush(&mut self) -> io::Result<()> { use self::StandardStreamKind::*; match self.0 { LineBuffered(ref mut w) => w.flush(), BlockBuffered(ref mut w) => w.flush(), } } } impl termcolor::WriteColor for StandardStream { #[inline] fn supports_color(&self) -> bool { use self::StandardStreamKind::*; match self.0 { LineBuffered(ref w) => w.supports_color(), BlockBuffered(ref w) => w.supports_color(), } } #[inline] fn supports_hyperlinks(&self) -> bool { use self::StandardStreamKind::*; match self.0 { LineBuffered(ref w) => w.supports_hyperlinks(), BlockBuffered(ref w) => w.supports_hyperlinks(), } } #[inline] fn set_color(&mut self, spec: &termcolor::ColorSpec) -> io::Result<()> { use self::StandardStreamKind::*; match self.0 { LineBuffered(ref mut w) => w.set_color(spec), BlockBuffered(ref mut w) => w.set_color(spec), } } #[inline] fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> { use self::StandardStreamKind::*; match self.0 { LineBuffered(ref mut w) => w.set_hyperlink(link), BlockBuffered(ref mut w) => w.set_hyperlink(link), } } #[inline] fn reset(&mut self) -> io::Result<()> { use self::StandardStreamKind::*; match self.0 { LineBuffered(ref mut w) => w.reset(), BlockBuffered(ref mut w) => w.reset(), } } #[inline] fn is_synchronous(&self) -> bool { use self::StandardStreamKind::*; match self.0 { LineBuffered(ref w) => w.is_synchronous(), BlockBuffered(ref w) => w.is_synchronous(), } } }