Skip to content

Commit

Permalink
Merge pull request clap-rs#4116 from epage/usage
Browse files Browse the repository at this point in the history
feat: Allow stylized usage
  • Loading branch information
epage authored Aug 26, 2022
2 parents f2e5b06 + d6d838e commit a6cb2e6
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 113 deletions.
22 changes: 15 additions & 7 deletions src/builder/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3975,6 +3975,20 @@ impl Arg {
}
}

pub(crate) fn stylized(&self) -> StyledStr {
let mut styled = StyledStr::new();
// Write the name such --long or -l
if let Some(l) = self.get_long() {
styled.none("--");
styled.none(l);
} else if let Some(s) = self.get_short() {
styled.none("-");
styled.none(s);
}
styled.extend(self.stylize_arg_suffix().into_iter());
styled
}

pub(crate) fn stylize_arg_suffix(&self) -> StyledStr {
let mut styled = StyledStr::new();

Expand Down Expand Up @@ -4090,13 +4104,7 @@ impl Eq for Arg {}

impl Display for Arg {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
// Write the name such --long or -l
if let Some(l) = self.get_long() {
write!(f, "--{}", l)?;
} else if let Some(s) = self.get_short() {
write!(f, "-{}", s)?;
}
self.stylize_arg_suffix().fmt(f)
self.stylized().fmt(f)
}
}

Expand Down
16 changes: 12 additions & 4 deletions src/builder/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,10 @@ impl Command {
/// println!("{}", cmd.render_usage());
/// ```
pub fn render_usage(&mut self) -> String {
self.render_usage_().to_string()
}

pub(crate) fn render_usage_(&mut self) -> StyledStr {
// If there are global arguments, or settings we need to propagate them down to subcommands
// before parsing incase we run into a subcommand
self._build_self();
Expand Down Expand Up @@ -3832,7 +3836,7 @@ impl Command {
let reqs = Usage::new(self).get_required_usage_from(&[], None, true); // maybe Some(m)

for s in &reqs {
mid_string.push_str(s);
mid_string.push_str(&s.to_string());
mid_string.push(' ');
}
}
Expand Down Expand Up @@ -3916,7 +3920,7 @@ impl Command {
let reqs = Usage::new(self).get_required_usage_from(&[], None, true); // maybe Some(m)

for s in &reqs {
mid_string.push_str(s);
mid_string.push_str(&s.to_string());
mid_string.push(' ');
}
}
Expand Down Expand Up @@ -4182,7 +4186,7 @@ impl Command {
format!("{} {}\n", display_name, ver)
}

pub(crate) fn format_group(&self, g: &Id) -> String {
pub(crate) fn format_group(&self, g: &Id) -> StyledStr {
let g_string = self
.unroll_args_in_group(g)
.iter()
Expand All @@ -4198,7 +4202,11 @@ impl Command {
})
.collect::<Vec<_>>()
.join("|");
format!("<{}>", &*g_string)
let mut styled = StyledStr::new();
styled.none("<");
styled.none(g_string);
styled.none(">");
styled
}
}

Expand Down
17 changes: 17 additions & 0 deletions src/builder/styled_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,23 @@ impl StyledStr {
self.stylize_(style.into(), msg.into());
}

pub(crate) fn trim(&mut self) {
self.trim_start();
self.trim_end();
}

pub(crate) fn trim_start(&mut self) {
if let Some((_, item)) = self.pieces.first_mut() {
*item = item.trim_start().to_owned();
}
}

pub(crate) fn trim_end(&mut self) {
if let Some((_, item)) = self.pieces.last_mut() {
*item = item.trim_end().to_owned();
}
}

pub(crate) fn replace_newline(&mut self) {
for (_, content) in &mut self.pieces {
*content = content.replace("{n}", "\n");
Expand Down
3 changes: 3 additions & 0 deletions src/error/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ pub enum ContextValue {
/// Many values
Strings(Vec<String>),
/// A single value
StyledStr(crate::builder::StyledStr),
/// A single value
Number(isize),
}

Expand All @@ -86,6 +88,7 @@ impl std::fmt::Display for ContextValue {
Self::Bool(v) => v.fmt(f),
Self::String(v) => v.fmt(f),
Self::Strings(v) => v.join(", ").fmt(f),
Self::StyledStr(v) => v.fmt(f),
Self::Number(v) => v.fmt(f),
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/error/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ impl ErrorFormatter for RichFormatter {
}

let usage = error.get(ContextKind::Usage);
if let Some(ContextValue::String(usage)) = usage {
put_usage(&mut styled, usage);
if let Some(ContextValue::StyledStr(usage)) = usage {
put_usage(&mut styled, usage.clone());
}

try_help(&mut styled, error.inner.help_flag);
Expand Down Expand Up @@ -385,7 +385,7 @@ fn write_dynamic_context(error: &crate::Error, styled: &mut StyledStr) -> bool {
pub(crate) fn format_error_message(
message: &str,
cmd: Option<&Command>,
usage: Option<String>,
usage: Option<StyledStr>,
) -> StyledStr {
let mut styled = StyledStr::new();
start_error(&mut styled);
Expand All @@ -408,9 +408,9 @@ fn singular_or_plural(n: usize) -> &'static str {
}
}

fn put_usage(styled: &mut StyledStr, usage: impl Into<String>) {
fn put_usage(styled: &mut StyledStr, usage: StyledStr) {
styled.none("\n\n");
styled.none(usage);
styled.extend(usage.into_iter());
}

pub(crate) fn get_help_flag(cmd: &Command) -> Option<&'static str> {
Expand Down
57 changes: 31 additions & 26 deletions src/error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ impl<F: ErrorFormatter> Error<F> {
#[must_use]
pub fn format(mut self, cmd: &mut Command) -> Self {
cmd._build_self();
let usage = cmd.render_usage();
let usage = cmd.render_usage_();
if let Some(message) = self.inner.message.as_mut() {
message.format(cmd, usage);
}
Expand Down Expand Up @@ -270,7 +270,7 @@ impl<F: ErrorFormatter> Error<F> {
cmd: &Command,
arg: String,
mut others: Vec<String>,
usage: String,
usage: StyledStr,
) -> Self {
let others = match others.len() {
0 => ContextValue::None,
Expand All @@ -282,20 +282,20 @@ impl<F: ErrorFormatter> Error<F> {
.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::String(arg)),
(ContextKind::PriorArg, others),
(ContextKind::Usage, ContextValue::String(usage)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
}

pub(crate) fn empty_value(cmd: &Command, good_vals: &[String], arg: String) -> Self {
Self::invalid_value(cmd, "".to_owned(), good_vals, arg)
}

pub(crate) fn no_equals(cmd: &Command, arg: String, usage: String) -> Self {
pub(crate) fn no_equals(cmd: &Command, arg: String, usage: StyledStr) -> Self {
Self::new(ErrorKind::NoEquals)
.with_cmd(cmd)
.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::String(arg)),
(ContextKind::Usage, ContextValue::String(usage)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
}

Expand Down Expand Up @@ -330,7 +330,7 @@ impl<F: ErrorFormatter> Error<F> {
subcmd: String,
did_you_mean: String,
name: String,
usage: String,
usage: StyledStr,
) -> Self {
let suggestion = format!("{} -- {}", name, subcmd);
Self::new(ErrorKind::InvalidSubcommand)
Expand All @@ -345,54 +345,59 @@ impl<F: ErrorFormatter> Error<F> {
ContextKind::SuggestedCommand,
ContextValue::String(suggestion),
),
(ContextKind::Usage, ContextValue::String(usage)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
}

pub(crate) fn unrecognized_subcommand(cmd: &Command, subcmd: String, usage: String) -> Self {
pub(crate) fn unrecognized_subcommand(cmd: &Command, subcmd: String, usage: StyledStr) -> Self {
Self::new(ErrorKind::InvalidSubcommand)
.with_cmd(cmd)
.extend_context_unchecked([
(ContextKind::InvalidSubcommand, ContextValue::String(subcmd)),
(ContextKind::Usage, ContextValue::String(usage)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
}

pub(crate) fn missing_required_argument(
cmd: &Command,
required: Vec<String>,
usage: String,
usage: StyledStr,
) -> Self {
Self::new(ErrorKind::MissingRequiredArgument)
.with_cmd(cmd)
.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::Strings(required)),
(ContextKind::Usage, ContextValue::String(usage)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
}

pub(crate) fn missing_subcommand(cmd: &Command, name: String, usage: String) -> Self {
pub(crate) fn missing_subcommand(cmd: &Command, name: String, usage: StyledStr) -> Self {
Self::new(ErrorKind::MissingSubcommand)
.with_cmd(cmd)
.extend_context_unchecked([
(ContextKind::InvalidSubcommand, ContextValue::String(name)),
(ContextKind::Usage, ContextValue::String(usage)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
}

pub(crate) fn invalid_utf8(cmd: &Command, usage: String) -> Self {
pub(crate) fn invalid_utf8(cmd: &Command, usage: StyledStr) -> Self {
Self::new(ErrorKind::InvalidUtf8)
.with_cmd(cmd)
.extend_context_unchecked([(ContextKind::Usage, ContextValue::String(usage))])
.extend_context_unchecked([(ContextKind::Usage, ContextValue::StyledStr(usage))])
}

pub(crate) fn too_many_values(cmd: &Command, val: String, arg: String, usage: String) -> Self {
pub(crate) fn too_many_values(
cmd: &Command,
val: String,
arg: String,
usage: StyledStr,
) -> Self {
Self::new(ErrorKind::TooManyValues)
.with_cmd(cmd)
.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::String(arg)),
(ContextKind::InvalidValue, ContextValue::String(val)),
(ContextKind::Usage, ContextValue::String(usage)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
}

Expand All @@ -401,7 +406,7 @@ impl<F: ErrorFormatter> Error<F> {
arg: String,
min_vals: usize,
curr_vals: usize,
usage: String,
usage: StyledStr,
) -> Self {
Self::new(ErrorKind::TooFewValues)
.with_cmd(cmd)
Expand All @@ -415,7 +420,7 @@ impl<F: ErrorFormatter> Error<F> {
ContextKind::ActualNumValues,
ContextValue::Number(curr_vals as isize),
),
(ContextKind::Usage, ContextValue::String(usage)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
}

Expand All @@ -437,7 +442,7 @@ impl<F: ErrorFormatter> Error<F> {
arg: String,
num_vals: usize,
curr_vals: usize,
usage: String,
usage: StyledStr,
) -> Self {
Self::new(ErrorKind::WrongNumberOfValues)
.with_cmd(cmd)
Expand All @@ -451,21 +456,21 @@ impl<F: ErrorFormatter> Error<F> {
ContextKind::ActualNumValues,
ContextValue::Number(curr_vals as isize),
),
(ContextKind::Usage, ContextValue::String(usage)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
}

pub(crate) fn unknown_argument(
cmd: &Command,
arg: String,
did_you_mean: Option<(String, Option<String>)>,
usage: String,
usage: StyledStr,
) -> Self {
let mut err = Self::new(ErrorKind::UnknownArgument)
.with_cmd(cmd)
.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::String(arg)),
(ContextKind::Usage, ContextValue::String(usage)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
]);
if let Some((flag, sub)) = did_you_mean {
err = err.insert_context_unchecked(
Expand All @@ -482,13 +487,13 @@ impl<F: ErrorFormatter> Error<F> {
err
}

pub(crate) fn unnecessary_double_dash(cmd: &Command, arg: String, usage: String) -> Self {
pub(crate) fn unnecessary_double_dash(cmd: &Command, arg: String, usage: StyledStr) -> Self {
Self::new(ErrorKind::UnknownArgument)
.with_cmd(cmd)
.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::String(arg)),
(ContextKind::TrailingArg, ContextValue::Bool(true)),
(ContextKind::Usage, ContextValue::String(usage)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
}

Expand Down Expand Up @@ -547,7 +552,7 @@ pub(crate) enum Message {
}

impl Message {
fn format(&mut self, cmd: &Command, usage: String) {
fn format(&mut self, cmd: &Command, usage: StyledStr) {
match self {
Message::Raw(s) => {
let mut message = String::new();
Expand Down
3 changes: 2 additions & 1 deletion src/output/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> {
self.warning("USAGE:");
}
"usage" => {
self.none(self.usage.create_usage_no_title(&[]));
self.writer
.extend(self.usage.create_usage_no_title(&[]).into_iter());
}
"all-args" => {
self.write_all_args();
Expand Down
Loading

0 comments on commit a6cb2e6

Please sign in to comment.