Skip to content

Commit

Permalink
feat: implemented more cli help for args/flags/subcommands
Browse files Browse the repository at this point in the history
  • Loading branch information
jdx committed Oct 14, 2024
1 parent 7c49fcb commit 669f44e
Show file tree
Hide file tree
Showing 12 changed files with 315 additions and 95 deletions.
17 changes: 13 additions & 4 deletions cli/src/cli/bash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ pub struct Bash {
#[clap(allow_hyphen_values = true)]
args: Vec<String>,

#[clap(short, long)]
/// show help
#[clap(short)]
h: bool,

/// show help
#[clap(long)]
help: bool,
}

Expand All @@ -26,8 +31,11 @@ impl Bash {
let mut args = self.args.clone();
args.insert(0, spec.bin.clone());

if self.h {
return self.help(&spec, &args, false);
}
if self.help {
return self.help(&spec, &args);
return self.help(&spec, &args, true);
}

let parsed = usage::parse::parse(&spec, &args)?;
Expand All @@ -54,8 +62,9 @@ impl Bash {
Ok(())
}

pub fn help(&self, spec: &Spec, _args: &[String]) -> miette::Result<()> {
println!("{}", usage::docs::cli::render_help(spec));
pub fn help(&self, spec: &Spec, args: &[String], long: bool) -> miette::Result<()> {
let parsed = usage::parse::parse_partial(spec, args)?;
println!("{}", usage::docs::cli::render_help(spec, &parsed.cmd, long));
Ok(())
}
}
20 changes: 12 additions & 8 deletions lib/src/docs/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
use crate::Spec;
use crate::{Spec, SpecCommand};
use once_cell::sync::Lazy;
use tera::Tera;

pub fn render_help(spec: &Spec) -> String {
pub fn render_help(spec: &Spec, cmd: &SpecCommand, long: bool) -> String {
let mut ctx = tera::Context::new();
ctx.insert("spec", spec);
TERA.render("spec_template.md.tera", &ctx)
.unwrap()
.trim()
.to_string()
+ "\n"
ctx.insert("cmd", cmd);
ctx.insert("long", &long);
let template = if long {
"spec_template_long.tera"
} else {
"spec_template_short.tera"
};
TERA.render(template, &ctx).unwrap().trim().to_string() + "\n"
}

static TERA: Lazy<Tera> = Lazy::new(|| {
let mut tera = Tera::default();

#[rustfmt::skip]
tera.add_raw_templates([
("spec_template.md.tera", include_str!("templates/spec_template.tera")),
("spec_template_short.tera", include_str!("templates/spec_template_short.tera")),
("spec_template_long.tera", include_str!("templates/spec_template_long.tera")),
]).unwrap();

// tera.register_filter(
Expand Down
2 changes: 0 additions & 2 deletions lib/src/docs/cli/templates/spec_no_args_template.tera

This file was deleted.

31 changes: 0 additions & 31 deletions lib/src/docs/cli/templates/spec_template.tera

This file was deleted.

52 changes: 52 additions & 0 deletions lib/src/docs/cli/templates/spec_template_long.tera
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{%- if spec.about_long %}{{ spec.about_long }}

{% elif spec.about %}{{ spec.about }}

{% endif %}
Usage: {{ spec.bin ~ " " ~ cmd.usage | trim }}

{%- if cmd.subcommands %}

Commands:
{%- for name, cmd in cmd.subcommands %}
{{ cmd.usage | trim }}
{%- if cmd.aliases %} [aliases: {{ cmd.aliases | join(sep=", ") }}]{% endif %}
{%- set help = cmd.help_long | default(value=cmd.help) %}
{%- if help %}
{{ help | indent(width=4) }}
{%- endif %}
{% endfor %}
help
Print this message or the help of the given subcommand(s)
{%- endif %}

{%- if cmd.args %}

Arguments:
{%- for arg in cmd.args %}
{{ arg.usage | trim }}
{%- set help = arg.help_long | default(value=arg.help) %}
{%- if help %}
{{ help | indent(width=2) }}
{%- endif %}
{%- if arg.choices %}
[possible values: {{ arg.choices.choices | join(sep=", ") }}]
{%- endif %}
{%- endfor %}
{%- endif %}

{%- if cmd.flags %}

Flags:
{%- for flag in cmd.flags %}
{{ flag.usage | trim }}
{%- if flag.aliases %} [aliases: {{ flag.aliases | join(sep=", ") }}]{% endif %}
{%- set help = flag.help_long | default(value=flag.help) %}
{%- if help %}
{{ help | indent(width=2) }}
{%- endif %}
{%- if flag.arg.choices %}
[possible values: {{ flag.arg.choices.choices | join(sep=", ") }}]
{%- endif %}
{%- endfor %}
{%- endif -%}
36 changes: 36 additions & 0 deletions lib/src/docs/cli/templates/spec_template_short.tera
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{% if spec.about %}{{ spec.about }}

{% endif %}
Usage: {{ spec.bin ~ " " ~ cmd.usage | trim }}

{%- if cmd.subcommands %}

Commands:
{%- for name, cmd in cmd.subcommands %}
{{ cmd.usage | trim }}
{%- if cmd.aliases %} [aliases: {{ cmd.aliases | join(sep=", ") }}]{% endif %}
{%- if cmd.help %} {{ cmd.help }}{%- endif %}
{%- endfor %}
help Print this message or the help of the given subcommand(s)
{%- endif %}

{%- if cmd.args %}

Arguments:
{%- for arg in cmd.args %}
{{ arg.usage | trim }}
{%- if arg.help %} {{ arg.help }}{%- endif %}
{%- if arg.choices %} [{{ arg.choices.choices | join(sep=", ") }}]{%- endif %}
{%- endfor %}
{%- endif %}

{%- if cmd.flags %}

Flags:
{%- for flag in cmd.flags %}
{{ flag.usage | trim }}
{%- if flag.aliases %} [aliases: {{ flag.aliases | join(sep=", ") }}]{% endif %}
{%- if flag.help %} {{ flag.help }}{%- endif %}
{%- if flag.arg.choices %} [{{ flag.arg.choices.choices | join(sep=", ") }}]{%- endif %}
{%- endfor %}
{%- endif -%}
20 changes: 18 additions & 2 deletions lib/src/docs/markdown/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ mod tests {
#[test]
fn test_render_markdown_cmd() {
let ctx = MarkdownRenderer::new(&SPEC_KITCHEN_SINK).with_multi(true);
assert_snapshot!(ctx.render_cmd(&SPEC_KITCHEN_SINK.cmd).unwrap(), @r####"
assert_snapshot!(ctx.render_cmd(&SPEC_KITCHEN_SINK.cmd).unwrap(), @r#####"
# `mycli`
**Usage**: `mycli [FLAGS] <ARGS>… <SUBCOMMAND>`
Expand All @@ -34,6 +34,16 @@ mod tests {
arg2 description
#### Choices
- `choice1`
- `choice2`
- `choice3`
#### Default
`default value`
### `<arg3>`
arg3 long description
Expand All @@ -56,9 +66,15 @@ mod tests {
### `--shell <shell>`
#### Choices
- `bash`
- `zsh`
- `fish`
## Subcommands
* [`mycli plugin <SUBCOMMAND>`](/plugin.md)
"####);
"#####);
}
}
16 changes: 16 additions & 0 deletions lib/src/docs/markdown/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ mod tests {
arg2 description
#### Choices
- `choice1`
- `choice2`
- `choice3`
#### Default
`default value`
### `<arg3>`
arg3 long description
Expand All @@ -62,6 +72,12 @@ mod tests {
### `--shell <shell>`
#### Choices
- `bash`
- `zsh`
- `fish`
## `mycli plugin`
**Usage**: `mycli plugin <SUBCOMMAND>`
Expand Down
19 changes: 19 additions & 0 deletions lib/src/docs/markdown/templates/arg_template.md.tera
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,23 @@
{%- if help %}

{{ help | escape_md }}
{%- endif %}
{%- if arg.choices %}

{{ "#" | repeat(count=header_level) }}### Choices
{% for choice in arg.choices.choices %}
- `{{ choice }}`
{%- endfor %}
{%- endif %}
{%- if arg.default %}

{{ "#" | repeat(count=header_level) }}### Default

`{{ arg.default }}`
{%- endif %}
{%- if arg.env %}

{{ "#" | repeat(count=header_level) }}### Environment Variable

`{{ arg.env }}`
{%- endif -%}
19 changes: 19 additions & 0 deletions lib/src/docs/markdown/templates/flag_template.md.tera
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,23 @@
{%- if help %}

{{ help | escape_md }}
{%- endif %}
{%- if flag.arg.choices %}

{{ "#" | repeat(count=header_level) }}### Choices
{% for choice in flag.arg.choices.choices %}
- `{{ choice }}`
{%- endfor %}
{%- endif %}
{%- if flag.default %}

{{ "#" | repeat(count=header_level) }}### Default

`{{ flag.default }}`
{%- endif %}
{%- if flag.env %}

{{ "#" | repeat(count=header_level) }}### Environment Variable

`{{ flag.env }}`
{%- endif -%}
10 changes: 7 additions & 3 deletions lib/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,9 @@ pub fn parse_partial(spec: &Spec, input: &[String]) -> Result<ParseOutput, miett
if !choices.choices.contains(&w) {
if is_help_arg(spec, &w) {
// TODO: render based on current args
let long = w.len() > 2;
out.errors
.push(UsageErr::Help(docs::cli::render_help(spec)));
.push(UsageErr::Help(docs::cli::render_help(spec, &out.cmd, long)));
continue;
}
bail!(
Expand Down Expand Up @@ -197,8 +198,9 @@ pub fn parse_partial(spec: &Spec, input: &[String]) -> Result<ParseOutput, miett
if !choices.choices.contains(&w) {
if is_help_arg(spec, &w) {
// TODO: render based on current args
let long = w.len() > 2;
out.errors
.push(UsageErr::Help(docs::cli::render_help(spec)));
.push(UsageErr::Help(docs::cli::render_help(spec, &out.cmd, long)));
continue;
}
bail!(
Expand All @@ -215,8 +217,10 @@ pub fn parse_partial(spec: &Spec, input: &[String]) -> Result<ParseOutput, miett
}
if is_help_arg(spec, &w) {
// TODO: render based on current args
dbg!(&out.cmd);
let long = w.len() > 2;
out.errors
.push(UsageErr::Help(docs::cli::render_help(spec)));
.push(UsageErr::Help(docs::cli::render_help(spec, &out.cmd, long)));
continue;
}
bail!("unexpected word: {w}");
Expand Down
Loading

0 comments on commit 669f44e

Please sign in to comment.