clap-help prints the --help message of clap based terminal applications.
Note: there's no support for subcommands yet.
The bacon programs uses clap-help with an introduction text, a clearer options table, examples, and a skin consistent with the rest of the application:
How it's done: https://github.com/Canop/bacon/blob/main/src/args.rs.
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
disable_help_flag = true
disabling the standard behaviour of clap regarding help.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
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();
If your program has some kind of graphical identity, you may want to extend it to the help.
You may change colors, preferably with more compatible ansi color codes.
See example in examples/custom
mainly features:
The strategy for those changes is
bold
, italic
, and inline_code
styles to change their foreground color, to remove the background of the code, and to remove the Italic attribute of italic
TEMPLATE_OPTIONS_MERGED_VALUE
template for optionsHere are the relevant parts of the code:
static INTRO: &str = "
Compute `height x width`
More info at *https://dystroy.org*
";
let mut printer = Printer::new(Args::command())
.without("author")
.with("introduction", INTRO)
.with("options", clap_help::TEMPLATE_OPTIONS_MERGED_VALUE);
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));
skin.table_border_chars = termimad::ROUNDED_TABLE_BORDER_CHARS;
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.