| mod atty; |
| mod termcolor; |
| |
| use self::atty::{is_stderr, is_stdout}; |
| use self::termcolor::BufferWriter; |
| use std::{fmt, io}; |
| |
| pub(in crate::fmt) mod glob { |
| pub use super::termcolor::glob::*; |
| pub use super::*; |
| } |
| |
| pub(in crate::fmt) use self::termcolor::Buffer; |
| |
| /// Log target, either `stdout` or `stderr`. |
| #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] |
| pub enum Target { |
| /// Logs will be sent to standard output. |
| Stdout, |
| /// Logs will be sent to standard error. |
| Stderr, |
| } |
| |
| impl Default for Target { |
| fn default() -> Self { |
| Target::Stderr |
| } |
| } |
| |
| /// Whether or not to print styles to the target. |
| #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] |
| pub enum WriteStyle { |
| /// Try to print styles, but don't force the issue. |
| Auto, |
| /// Try very hard to print styles. |
| Always, |
| /// Never print styles. |
| Never, |
| } |
| |
| impl Default for WriteStyle { |
| fn default() -> Self { |
| WriteStyle::Auto |
| } |
| } |
| |
| /// A terminal target with color awareness. |
| pub(crate) struct Writer { |
| inner: BufferWriter, |
| write_style: WriteStyle, |
| } |
| |
| impl Writer { |
| pub fn write_style(&self) -> WriteStyle { |
| self.write_style |
| } |
| |
| pub(in crate::fmt) fn buffer(&self) -> Buffer { |
| self.inner.buffer() |
| } |
| |
| pub(in crate::fmt) fn print(&self, buf: &Buffer) -> io::Result<()> { |
| self.inner.print(buf) |
| } |
| } |
| |
| /// A builder for a terminal writer. |
| /// |
| /// The target and style choice can be configured before building. |
| pub(crate) struct Builder { |
| target: Target, |
| write_style: WriteStyle, |
| is_test: bool, |
| built: bool, |
| } |
| |
| impl Builder { |
| /// Initialize the writer builder with defaults. |
| pub(crate) fn new() -> Self { |
| Builder { |
| target: Default::default(), |
| write_style: Default::default(), |
| is_test: false, |
| built: false, |
| } |
| } |
| |
| /// Set the target to write to. |
| pub(crate) fn target(&mut self, target: Target) -> &mut Self { |
| self.target = target; |
| self |
| } |
| |
| /// Parses a style choice string. |
| /// |
| /// See the [Disabling colors] section for more details. |
| /// |
| /// [Disabling colors]: ../index.html#disabling-colors |
| pub(crate) fn parse_write_style(&mut self, write_style: &str) -> &mut Self { |
| self.write_style(parse_write_style(write_style)) |
| } |
| |
| /// Whether or not to print style characters when writing. |
| pub(crate) fn write_style(&mut self, write_style: WriteStyle) -> &mut Self { |
| self.write_style = write_style; |
| self |
| } |
| |
| /// Whether or not to capture logs for `cargo test`. |
| pub(crate) fn is_test(&mut self, is_test: bool) -> &mut Self { |
| self.is_test = is_test; |
| self |
| } |
| |
| /// Build a terminal writer. |
| pub(crate) fn build(&mut self) -> Writer { |
| assert!(!self.built, "attempt to re-use consumed builder"); |
| self.built = true; |
| |
| let color_choice = match self.write_style { |
| WriteStyle::Auto => { |
| if match self.target { |
| Target::Stderr => is_stderr(), |
| Target::Stdout => is_stdout(), |
| } { |
| WriteStyle::Auto |
| } else { |
| WriteStyle::Never |
| } |
| } |
| color_choice => color_choice, |
| }; |
| |
| let writer = match self.target { |
| Target::Stderr => BufferWriter::stderr(self.is_test, color_choice), |
| Target::Stdout => BufferWriter::stdout(self.is_test, color_choice), |
| }; |
| |
| Writer { |
| inner: writer, |
| write_style: self.write_style, |
| } |
| } |
| } |
| |
| impl Default for Builder { |
| fn default() -> Self { |
| Builder::new() |
| } |
| } |
| |
| impl fmt::Debug for Builder { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| f.debug_struct("Logger") |
| .field("target", &self.target) |
| .field("write_style", &self.write_style) |
| .finish() |
| } |
| } |
| |
| impl fmt::Debug for Writer { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| f.debug_struct("Writer").finish() |
| } |
| } |
| |
| fn parse_write_style(spec: &str) -> WriteStyle { |
| match spec { |
| "auto" => WriteStyle::Auto, |
| "always" => WriteStyle::Always, |
| "never" => WriteStyle::Never, |
| _ => Default::default(), |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| |
| #[test] |
| fn parse_write_style_valid() { |
| let inputs = vec![ |
| ("auto", WriteStyle::Auto), |
| ("always", WriteStyle::Always), |
| ("never", WriteStyle::Never), |
| ]; |
| |
| for (input, expected) in inputs { |
| assert_eq!(expected, parse_write_style(input)); |
| } |
| } |
| |
| #[test] |
| fn parse_write_style_invalid() { |
| let inputs = vec!["", "true", "false", "NEVER!!"]; |
| |
| for input in inputs { |
| assert_eq!(WriteStyle::Auto, parse_write_style(input)); |
| } |
| } |
| } |