Skip to content

Commit

Permalink
Merge pull request #4117 from epage/styled-help
Browse files Browse the repository at this point in the history
fix(help): Use a more neutral palette
  • Loading branch information
epage committed Aug 26, 2022
2 parents a6cb2e6 + 6079a87 commit c2ce1dd
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 57 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -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)
Expand Down
27 changes: 13 additions & 14 deletions src/builder/arg.rs
Expand Up @@ -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
Expand All @@ -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
Expand Down
25 changes: 25 additions & 0 deletions src/builder/styled_str.rs
Expand Up @@ -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());
}
Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -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,
Expand Down
32 changes: 16 additions & 16 deletions src/output/help.rs
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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) {
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
}
Expand All @@ -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
}
Expand All @@ -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);
}
Expand Down Expand Up @@ -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)
}
Expand All @@ -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));
}
}

Expand Down Expand Up @@ -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");

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
55 changes: 28 additions & 27 deletions src/output/usage.rs
Expand Up @@ -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
}
Expand All @@ -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();
Expand All @@ -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
Expand All @@ -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(']');
}
}
}
Expand All @@ -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();
Expand All @@ -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())
Expand All @@ -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
}
Expand Down

0 comments on commit c2ce1dd

Please sign in to comment.