diff --git a/src/build/command.rs b/src/build/command.rs index 312e77b25fe..71fcda65427 100644 --- a/src/build/command.rs +++ b/src/build/command.rs @@ -20,6 +20,7 @@ use crate::build::{arg::ArgProvider, Arg, ArgGroup, ArgPredicate}; use crate::error::ErrorKind; use crate::error::Result as ClapResult; use crate::mkeymap::MKeyMap; +use crate::output::fmt::Stream; use crate::output::{fmt::Colorizer, Help, HelpWriter, Usage}; use crate::parse::{ArgMatcher, ArgMatches, Parser}; use crate::util::ChildGraph; @@ -697,7 +698,7 @@ impl<'help> App<'help> { self._build(); let color = self.get_color(); - let mut c = Colorizer::new(false, color); + let mut c = Colorizer::new(Stream::Stdout, color); let usage = Usage::new(self); Help::new(HelpWriter::Buffer(&mut c), self, &usage, false).write_help()?; c.print() @@ -722,7 +723,7 @@ impl<'help> App<'help> { self._build(); let color = self.get_color(); - let mut c = Colorizer::new(false, color); + let mut c = Colorizer::new(Stream::Stdout, color); let usage = Usage::new(self); Help::new(HelpWriter::Buffer(&mut c), self, &usage, true).write_help()?; c.print() diff --git a/src/error/mod.rs b/src/error/mod.rs index 2b8b8380db9..d4fe8a32de3 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -15,6 +15,7 @@ use std::{ use crate::{ build::Arg, output::fmt::Colorizer, + output::fmt::Stream, parse::features::suggestions, util::{color::ColorChoice, safe_exit, SUCCESS_CODE, USAGE_CODE}, AppSettings, Command, @@ -97,10 +98,14 @@ impl Error { /// Should the message be written to `stdout` or not? #[inline] pub fn use_stderr(&self) -> bool { - !matches!( - self.kind(), - ErrorKind::DisplayHelp | ErrorKind::DisplayVersion - ) + self.stream() == Stream::Stderr + } + + pub(crate) fn stream(&self) -> Stream { + match self.kind() { + ErrorKind::DisplayHelp | ErrorKind::DisplayVersion => Stream::Stdout, + _ => Stream::Stderr, + } } /// Prints the error and exits. @@ -608,7 +613,7 @@ impl Error { if let Some(message) = self.inner.message.as_ref() { message.formatted() } else { - let mut c = Colorizer::new(self.use_stderr(), self.inner.color_when); + let mut c = Colorizer::new(self.stream(), self.inner.color_when); start_error(&mut c); @@ -1090,7 +1095,7 @@ impl Message { fn format(&mut self, cmd: &Command, usage: String) { match self { Message::Raw(s) => { - let mut c = Colorizer::new(true, cmd.get_color()); + let mut c = Colorizer::new(Stream::Stderr, cmd.get_color()); let mut message = String::new(); std::mem::swap(s, &mut message); @@ -1107,7 +1112,7 @@ impl Message { fn formatted(&self) -> Cow { match self { Message::Raw(s) => { - let mut c = Colorizer::new(true, ColorChoice::Never); + let mut c = Colorizer::new(Stream::Stderr, ColorChoice::Never); start_error(&mut c); c.none(s); Cow::Owned(c) diff --git a/src/macros.rs b/src/macros.rs index a9b99537680..f43573b42ef 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -933,7 +933,7 @@ macro_rules! debug { ($($arg:tt)*) => ({ let prefix = format!("[{:>w$}] \t", module_path!(), w = 28); let body = format!($($arg)*); - let mut color = $crate::output::fmt::Colorizer::new(true, $crate::ColorChoice::Auto); + let mut color = $crate::output::fmt::Colorizer::new($crate::output::fmt::Stream::Stderr, $crate::ColorChoice::Auto); color.hint(prefix); color.hint(body); color.none("\n"); diff --git a/src/output/fmt.rs b/src/output/fmt.rs index d524982bf8f..85ba17749ea 100644 --- a/src/output/fmt.rs +++ b/src/output/fmt.rs @@ -5,9 +5,15 @@ use std::{ io::{self, Write}, }; +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) enum Stream { + Stdout, + Stderr, +} + #[derive(Clone, Debug)] pub(crate) struct Colorizer { - use_stderr: bool, + stream: Stream, #[allow(unused)] color_when: ColorChoice, pieces: Vec<(String, Style)>, @@ -15,9 +21,9 @@ pub(crate) struct Colorizer { impl Colorizer { #[inline(never)] - pub(crate) fn new(use_stderr: bool, color_when: ColorChoice) -> Self { + pub(crate) fn new(stream: Stream, color_when: ColorChoice) -> Self { Colorizer { - use_stderr, + stream, color_when, pieces: vec![], } @@ -58,14 +64,13 @@ impl Colorizer { let color_when = match self.color_when { ColorChoice::Always => DepColorChoice::Always, - ColorChoice::Auto if is_a_tty(self.use_stderr) => DepColorChoice::Auto, + ColorChoice::Auto if is_a_tty(self.stream) => DepColorChoice::Auto, _ => DepColorChoice::Never, }; - let writer = if self.use_stderr { - BufferWriter::stderr(color_when) - } else { - BufferWriter::stdout(color_when) + let writer = match self.stream { + Stream::Stdout => BufferWriter::stderr(color_when), + Stream::Stderr => BufferWriter::stdout(color_when), }; let mut buffer = writer.buffer(); @@ -101,14 +106,17 @@ impl Colorizer { 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) + match self.stream { + Stream::Stdout => { + let stdout = std::io::stdout(); + let mut stdout = stdout.lock(); + write!(stdout, "{}", self) + } + Stream::Stderr => { + let stderr = std::io::stderr(); + let mut stderr = stderr.lock(); + write!(stderr, "{}", self) + } } } } @@ -140,11 +148,10 @@ impl Default for Style { } #[cfg(feature = "color")] -fn is_a_tty(stderr: bool) -> bool { - let stream = if stderr { - atty::Stream::Stderr - } else { - atty::Stream::Stdout +fn is_a_tty(stream: Stream) -> bool { + let stream = match stream { + Stream::Stdout => atty::Stream::Stdout, + Stream::Stderr => atty::Stream::Stderr, }; atty::is(stream) diff --git a/src/parse/parser.rs b/src/parse/parser.rs index b344fed216d..d266291431d 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -13,6 +13,7 @@ use crate::build::{Arg, Command}; use crate::error::Error as ClapError; use crate::error::Result as ClapResult; use crate::mkeymap::KeyType; +use crate::output::fmt::Stream; use crate::output::{fmt::Colorizer, Help, HelpWriter, Usage}; use crate::parse::features::suggestions; use crate::parse::{ArgMatcher, SubCommand}; @@ -1509,7 +1510,7 @@ impl<'help, 'cmd> Parser<'help, 'cmd> { pub(crate) fn write_help_err(&self) -> ClapResult { let usage = Usage::new(self.cmd); - let mut c = Colorizer::new(true, self.color_help()); + let mut c = Colorizer::new(Stream::Stderr, self.color_help()); Help::new(HelpWriter::Buffer(&mut c), self.cmd, &usage, false).write_help()?; Ok(c) } @@ -1522,7 +1523,7 @@ impl<'help, 'cmd> Parser<'help, 'cmd> { use_long = use_long && self.cmd.use_long_help(); let usage = Usage::new(self.cmd); - let mut c = Colorizer::new(false, self.color_help()); + let mut c = Colorizer::new(Stream::Stdout, self.color_help()); match Help::new(HelpWriter::Buffer(&mut c), self.cmd, &usage, use_long).write_help() { Err(e) => e.into(), @@ -1534,7 +1535,7 @@ impl<'help, 'cmd> Parser<'help, 'cmd> { debug!("Parser::version_err"); let msg = self.cmd._render_version(use_long); - let mut c = Colorizer::new(false, self.color_help()); + let mut c = Colorizer::new(Stream::Stdout, self.color_help()); c.none(msg); ClapError::display_version(self.cmd, c) }