11 releases (1 stable)
1.0.0 | Sep 2, 2023 |
---|---|
0.7.0 | Aug 20, 2023 |
0.6.2 | Aug 3, 2023 |
0.5.1 | Jul 20, 2023 |
0.1.0 | Jul 15, 2023 |
#180 in Command-line interface
3,361 downloads per month
Used in 5 crates
(4 directly)
580KB
216 lines
clap-help
Purpose and Features
clap-help prints the --help message of clap based terminal applications.
Differences with the vanilla help renderer of the clap crate:
- more readable, thanks to a width aware layout
- more compact: from 2 to 3 times less lines compared to vanilla
- options rendered in a balanced table, optimized for the width of the terminal
- introduction interpreted as Markdown, allowing lists, tables, code blocks, etc.
- doc of options interpreted as Markdown
- skin automatically selected for light or dark terminals
- customizable termimad skin
- you can customize section templates, remove them, reorder them, add sections
clap-help is especially suited to small terminals or big numbers of options.
Note: there's no support for subcommands, create an issue if you need it.
Comparison
This comparison uses the broot program.
With clap-help
With the standard help rendering
(my screen isn't big enough to fit even half the help page)
Usage
Basic usage
Your program needs a clap Command
defined.
Here's for example with clap-derive:
#[derive(Parser, Debug)]
#[command(name="area", author, version, about, disable_help_flag = true)]
struct Args {
/// Print help
#[arg(long)]
help: bool,
/// Height, that is the distance between bottom and top
#[arg(short, long, default_value = "9")]
height: u16,
/// Width, from there, to there, eg `4` or `5`
#[arg(short, long, default_value = "3")]
width: u16,
/// Kill all birds to improve computation
#[arg(short, long)]
kill_birds: bool,
/// Computation strategy
#[arg(long, default_value = "fast")]
strategy: Strategy,
/// Bird separator
#[arg(short, long, value_name = "SEP")]
separator: Option<String>,
/// Root Directory
pub root: Option<std::path::PathBuf>,
}
Notice
- the
disable_help_flag = true
disabling the standard behaviour of clap regarding help. - the explicit
help
argument. Here it's with only#[arg(long)]
because-h
is used for something more important but you would most often have#[arg(short, long)]
.
The help introduction (the part before usage) is defined as a string which will be interpreted as Markdown. It can contain tables, lists, bold, italic, inline code, code blocks, etc.
static INTRO: &str = "
Compute `height x width`
*You can do it either precisely (enough) or fast (I mean not too slow)*.
";
On program launch, you should check the value of the help
flag and, if necessary, print the help:
let args = Args::parse();
if args.help {
Printer::new(Args::command())
.with("introduction", INTRO)
.without("author")
.print_help();
return;
}
Help rendered in a light terminal:
Same help in a dark terminal:
Complete example is in /examples/area
and can be seen with cargo run --example area -- --help
Adding custom sections
Help is usually easier to grasp with a few examples. You can write a few ones in your intro, or you can add them in a later section, after the options.
It's also possible to leverage the template system, which is what is done in the with-examples
example, for this result:
Here's how it's done:
static EXAMPLES_TEMPLATE: &str = "
**Examples:**
${examples
**${example-number})** ${example-title}: `${example-cmd}`
${example-comments}
}
";
let mut printer = clap_help::Printer::new(Args::command())
.with("introduction", INTRO_TEMPLATE)
.without("author");
printer.template_keys_mut().push("examples");
printer.set_template("examples", EXAMPLES_TEMPLATE);
for (i, example) in EXAMPLES.iter().enumerate() {
printer
.expander_mut()
.sub("examples")
.set("example-number", i + 1)
.set("example-title", example.title)
.set("example-cmd", example.cmd)
.set_md("example-comments", example.comments);
}
printer.print_help();
Changing the skin
If your program has some kind of graphical identity, you may want to extend it to the help.
This is the case of bacon which features this kind of saturated pink that kids associate to pigs.
This change was easily done by setting the color of first level headers and bold:
let mut printer = clap_help::Printer::new(Args::command())
.with("introduction", INTRO)
.without("author");
let skin = printer.skin_mut();
skin.headers[0].compound_style.set_fg(ansi(204));
skin.bold.set_fg(ansi(204));
printer.print_help();
Result:
Customizing more: changing both the skin and the templates
The example in examples/custom
mainly features:
- less restreint on the colors
- a removal of the
value
column
The strategy for those changes is
- to redefine the
bold
,italic
, andinline_code
styles to change their foreground color, to remove the background of the code, and to remove the Italic attribute ofitalic
- to change the
"options"
template so that${short}
and${long}
are in italic (i.e. between stars in Markdown) - to modify the template to remove the unwanted column
Here are the relevant parts of the code:
pub static TEMPLATE_OPTIONS: &str = "
**Options:**
|:-:|:-:|:-|
|short|long|what it does|
|:-:|:-|:-|
${option-lines
|*${short}*|*${long}*|${help}${possible_values}${default}|
}
|-
";
let mut printer = Printer::new(Args::command())
.without("author")
.with("introduction", INTRO)
.with("options", TEMPLATE_OPTIONS);
let skin = printer.skin_mut();
skin.headers[0].compound_style.set_fg(ansi(202));
skin.bold.set_fg(ansi(202));
skin.italic = termimad::CompoundStyle::with_fg(ansi(45));
skin.inline_code = termimad::CompoundStyle::with_fg(ansi(223));
printer.print_help();
Complete example is in /examples/custom
and can be seen with cargo run --example custom -- --help
Please note that not every customization is possible or easy. And some may be easy but not obvious. Come to the chat and ask if needed.
Dependencies
~5–15MB
~174K SLoC