fix(help): Use a more neutral palette

Fixes #2963
This commit is contained in:
Ed Page 2022-08-25 14:33:03 -05:00
parent a6cb2e65bc
commit 6079a871a0
5 changed files with 83 additions and 57 deletions

View file

@ -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)

View file

@ -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

View file

@ -13,6 +13,18 @@ impl StyledStr {
Self { pieces: Vec::new() }
}
pub(crate) fn header(&mut self, msg: impl Into<String>) {
self.stylize_(Some(Style::Header), msg.into());
}
pub(crate) fn literal(&mut self, msg: impl Into<String>) {
self.stylize_(Some(Style::Literal), msg.into());
}
pub(crate) fn placeholder(&mut self, msg: impl Into<String>) {
self.stylize_(Some(Style::Placeholder), msg.into());
}
pub(crate) fn good(&mut self, msg: impl Into<String>) {
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,

View file

@ -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<T: Into<String>>(&mut self, msg: T) {
self.writer.good(msg);
fn header<T: Into<String>>(&mut self, msg: T) {
self.writer.header(msg);
}
fn warning<T: Into<String>>(&mut self, msg: T) {
self.writer.warning(msg);
fn literal<T: Into<String>>(&mut self, msg: T) {
self.writer.literal(msg);
}
fn none<T: Into<String>>(&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);

View file

@ -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
}