From 6079a871a0f453d1f7634be881028a285e44e56c Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 25 Aug 2022 14:33:03 -0500 Subject: [PATCH] fix(help): Use a more neutral palette Fixes #2963 --- CHANGELOG.md | 1 + src/builder/arg.rs | 27 +++++++++---------- src/builder/styled_str.rs | 25 ++++++++++++++++++ src/output/help.rs | 32 +++++++++++------------ src/output/usage.rs | 55 ++++++++++++++++++++------------------- 5 files changed, 83 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42b5410335e..25891b8d0dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,7 @@ MSRV is now 1.60.0 - *(assert)* Ensure subcommand names are not duplicated - *(help)* Use `Command::display_name` in the help title rather than `Command::bin_name` - *(help)* Show when a flag is `ArgAction::Count` by adding an `...` +- *(help)* Use a more neutral palette for coloring - *(version)* Use `Command::display_name` rather than `Command::bin_name` - *(parser)* Assert on unknown args when using external subcommands (#3703) - *(parser)* Always fill in `""` argument for external subcommands (#3263) diff --git a/src/builder/arg.rs b/src/builder/arg.rs index f01b7c61e5e..ee97a5779b3 100644 --- a/src/builder/arg.rs +++ b/src/builder/arg.rs @@ -3979,11 +3979,11 @@ impl Arg { let mut styled = StyledStr::new(); // Write the name such --long or -l if let Some(l) = self.get_long() { - styled.none("--"); - styled.none(l); + styled.literal("--"); + styled.literal(l); } else if let Some(s) = self.get_short() { - styled.none("-"); - styled.none(s); + styled.literal("-"); + styled.literal(s); } styled.extend(self.stylize_arg_suffix().into_iter()); styled @@ -3995,29 +3995,28 @@ impl Arg { let mut need_closing_bracket = false; if self.is_takes_value_set() && !self.is_positional() { let is_optional_val = self.get_min_vals() == 0; - let sep = if self.is_require_equals_set() { + if self.is_require_equals_set() { if is_optional_val { need_closing_bracket = true; - "[=" + styled.placeholder("[="); } else { - "=" + styled.literal("="); } } else if is_optional_val { need_closing_bracket = true; - " [" + styled.placeholder(" ["); } else { - " " - }; - styled.good(sep); + styled.placeholder(" "); + } } if self.is_takes_value_set() || self.is_positional() { let arg_val = self.render_arg_val(); - styled.good(arg_val); + styled.placeholder(arg_val); } else if matches!(*self.get_action(), ArgAction::Count) { - styled.good("..."); + styled.placeholder("..."); } if need_closing_bracket { - styled.none("]"); + styled.placeholder("]"); } styled diff --git a/src/builder/styled_str.rs b/src/builder/styled_str.rs index 1cae9022d7b..68057f9f7f2 100644 --- a/src/builder/styled_str.rs +++ b/src/builder/styled_str.rs @@ -13,6 +13,18 @@ impl StyledStr { Self { pieces: Vec::new() } } + pub(crate) fn header(&mut self, msg: impl Into) { + self.stylize_(Some(Style::Header), msg.into()); + } + + pub(crate) fn literal(&mut self, msg: impl Into) { + self.stylize_(Some(Style::Literal), msg.into()); + } + + pub(crate) fn placeholder(&mut self, msg: impl Into) { + self.stylize_(Some(Style::Placeholder), msg.into()); + } + pub(crate) fn good(&mut self, msg: impl Into) { self.stylize_(Some(Style::Good), msg.into()); } @@ -137,6 +149,16 @@ impl StyledStr { for (style, content) in &self.pieces { let mut color = termcolor::ColorSpec::new(); match style { + Some(Style::Header) => { + color.set_bold(true); + color.set_underline(true); + } + Some(Style::Literal) => { + color.set_bold(true); + } + Some(Style::Placeholder) => { + color.set_dimmed(true); + } Some(Style::Good) => { color.set_fg(Some(termcolor::Color::Green)); } @@ -212,6 +234,9 @@ impl std::fmt::Display for StyledStr { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum Style { + Header, + Literal, + Placeholder, Good, Warning, Error, diff --git a/src/output/help.rs b/src/output/help.rs index 890fd7f878a..786db8db6ac 100644 --- a/src/output/help.rs +++ b/src/output/help.rs @@ -155,7 +155,7 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> { self.write_about(true, true); } "usage-heading" => { - self.warning("USAGE:"); + self.header("USAGE:"); } "usage" => { self.writer @@ -215,7 +215,7 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> { .replace("{n}", "\n"), self.term_w, ); - self.good(&display_name); + self.none(&display_name); } /// Writes binary name of a Parser Object to the wrapped stream. @@ -232,7 +232,7 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> { } else { wrap(&self.cmd.get_name().replace("{n}", "\n"), self.term_w) }; - self.good(&bin_name); + self.none(&bin_name); } fn write_version(&mut self) { @@ -340,7 +340,7 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> { let mut first = if !pos.is_empty() { // Write positional args if any - self.warning("ARGS:\n"); + self.header("ARGS:\n"); self.write_args(&pos, "ARGS", positional_sort_key); false } else { @@ -351,7 +351,7 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> { if !first { self.none("\n\n"); } - self.warning("OPTIONS:\n"); + self.header("OPTIONS:\n"); self.write_args(&non_pos, "OPTIONS", option_sort_key); first = false; } @@ -373,7 +373,7 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> { if !first { self.none("\n\n"); } - self.warning(format!("{}:\n", heading)); + self.header(format!("{}:\n", heading)); self.write_args(&args, heading, option_sort_key); first = false } @@ -386,12 +386,12 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> { } let default_help_heading = Str::from("SUBCOMMANDS"); - self.warning( + self.header( self.cmd .get_subcommand_help_heading() .unwrap_or(&default_help_heading), ); - self.warning(":\n"); + self.header(":\n"); self.write_subcommands(self.cmd); } @@ -465,7 +465,7 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> { debug!("Help::short"); if let Some(s) = arg.get_short() { - self.good(format!("-{}", s)); + self.literal(format!("-{}", s)); } else if arg.get_long().is_some() { self.none(TAB) } @@ -478,7 +478,7 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> { if arg.short.is_some() { self.none(", "); } - self.good(format!("--{}", long)); + self.literal(format!("--{}", long)); } } @@ -622,7 +622,7 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> { self.none("\n"); self.spaces(spaces); self.none("- "); - self.good(pv.get_name()); + self.literal(pv.get_name()); if let Some(help) = pv.get_help() { debug!("Help::help: Possible Value help"); @@ -775,12 +775,12 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> { self.writer.extend(msg.iter()); } - fn good>(&mut self, msg: T) { - self.writer.good(msg); + fn header>(&mut self, msg: T) { + self.writer.header(msg); } - fn warning>(&mut self, msg: T) { - self.writer.warning(msg); + fn literal>(&mut self, msg: T) { + self.writer.literal(msg); } fn none>(&mut self, msg: T) { @@ -915,7 +915,7 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> { /// Writes subcommand to the wrapped stream. fn subcmd(&mut self, sc_str: &str, next_line_help: bool, longest: usize) { self.none(TAB); - self.good(sc_str); + self.literal(sc_str); if !next_line_help { let width = display_width(sc_str); self.spaces(width.max(longest + 4) - width); diff --git a/src/output/usage.rs b/src/output/usage.rs index 9545af5dc69..eb37bce41c3 100644 --- a/src/output/usage.rs +++ b/src/output/usage.rs @@ -32,7 +32,7 @@ impl<'cmd> Usage<'cmd> { pub(crate) fn create_usage_with_title(&self, used: &[Id]) -> StyledStr { debug!("Usage::create_usage_with_title"); let mut styled = StyledStr::new(); - styled.none("USAGE:\n "); + styled.header("USAGE:\n "); styled.extend(self.create_usage_no_title(used).into_iter()); styled } @@ -58,10 +58,10 @@ impl<'cmd> Usage<'cmd> { .get_usage_name() .or_else(|| self.cmd.get_bin_name()) .unwrap_or_else(|| self.cmd.get_name()); - styled.none(name); + styled.literal(name); if self.needs_options_tag() { - styled.none(" [OPTIONS]"); + styled.placeholder(" [OPTIONS]"); } let allow_missing_positional = self.cmd.is_allow_missing_positional_set(); @@ -80,15 +80,15 @@ impl<'cmd> Usage<'cmd> { && !(self.cmd.has_visible_subcommands() || self.cmd.is_allow_external_subcommands_set()) && !has_last { - styled.none(" [--]"); + styled.placeholder(" [--]"); } let not_req_or_hidden = |p: &Arg| (!p.is_required_set() || p.is_last_set()) && !p.is_hide_set(); if self.cmd.get_positionals().any(not_req_or_hidden) { if let Some(args_tag) = self.get_args_tag(incl_reqs) { - styled.none(&*args_tag); + styled.placeholder(&*args_tag); } else { - styled.none(" [ARGS]"); + styled.placeholder(" [ARGS]"); } if has_last && incl_reqs { let pos = self @@ -102,17 +102,18 @@ impl<'cmd> Usage<'cmd> { ); let req = pos.is_required_set(); if req && self.cmd.get_positionals().any(|p| !p.is_required_set()) { - styled.none(" -- <"); + styled.literal(" -- "); + styled.placeholder("<"); } else if req { - styled.none(" [--] <"); + styled.placeholder(" [--] <"); } else { - styled.none(" [-- <"); + styled.placeholder(" [-- <"); } - styled.none(&*pos.name_no_brackets()); - styled.none('>'); - styled.none(pos.multiple_str()); + styled.placeholder(&*pos.name_no_brackets()); + styled.placeholder('>'); + styled.placeholder(pos.multiple_str()); if !req { - styled.none(']'); + styled.placeholder(']'); } } } @@ -136,19 +137,19 @@ impl<'cmd> Usage<'cmd> { if !self.cmd.is_args_conflicts_with_subcommands_set() { styled.extend(self.create_help_usage(false).into_iter()); } else { - styled.none(name); + styled.literal(name); } - styled.none(" <"); - styled.none(placeholder); - styled.none(">"); + styled.placeholder(" <"); + styled.placeholder(placeholder); + styled.placeholder(">"); } else if self.cmd.is_subcommand_required_set() { - styled.none(" <"); - styled.none(placeholder); - styled.none(">"); + styled.placeholder(" <"); + styled.placeholder(placeholder); + styled.placeholder(">"); } else { - styled.none(" ["); - styled.none(placeholder); - styled.none("]"); + styled.placeholder(" ["); + styled.placeholder(placeholder); + styled.placeholder("]"); } } styled.trim(); @@ -162,7 +163,7 @@ impl<'cmd> Usage<'cmd> { debug!("Usage::create_smart_usage"); let mut styled = StyledStr::new(); - styled.none( + styled.literal( self.cmd .get_usage_name() .or_else(|| self.cmd.get_bin_name()) @@ -172,13 +173,13 @@ impl<'cmd> Usage<'cmd> { self.write_required_usage_from(used, None, true, &mut styled); if self.cmd.is_subcommand_required_set() { - styled.none(" <"); - styled.none( + styled.placeholder(" <"); + styled.placeholder( self.cmd .get_subcommand_value_name() .unwrap_or(DEFAULT_SUB_VALUE_NAME), ); - styled.none(">"); + styled.placeholder(">"); } styled }