mirror of
https://github.com/clap-rs/clap
synced 2025-01-21 00:53:52 +00:00
fix: Use roff bullet lists for possible_values
This commit is contained in:
parent
ec518e4819
commit
069098cfcb
5 changed files with 106 additions and 40 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
use std::vec;
|
||||||
|
|
||||||
use roff::{bold, italic, roman, Inline, Roff};
|
use roff::{bold, italic, roman, Inline, Roff};
|
||||||
|
|
||||||
pub(crate) fn subcommand_heading(cmd: &clap::Command) -> &str {
|
pub(crate) fn subcommand_heading(cmd: &clap::Command) -> &str {
|
||||||
|
@ -113,21 +115,48 @@ pub(crate) fn options(roff: &mut Roff, cmd: &clap::Command) {
|
||||||
body.push(roman(help));
|
body.push(roman(help));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
roff.control("TP", []);
|
||||||
|
roff.text(header);
|
||||||
|
roff.text(body);
|
||||||
|
|
||||||
let possibles = &opt.get_possible_values();
|
let possibles = &opt.get_possible_values();
|
||||||
|
let possibles: Vec<&clap::builder::PossibleValue> =
|
||||||
|
possibles.iter().filter(|pos| !pos.is_hide_set()).collect();
|
||||||
|
|
||||||
if !(possibles.is_empty() || opt.is_hide_possible_values_set()) {
|
if !(possibles.is_empty() || opt.is_hide_possible_values_set()) {
|
||||||
if help_written {
|
if help_written {
|
||||||
// It looks nice to have a separation between the help and the values
|
// It looks nice to have a separation between the help and the values
|
||||||
body.push(Inline::LineBreak);
|
roff.text([Inline::LineBreak]);
|
||||||
|
}
|
||||||
|
// with help for each possible value
|
||||||
|
|
||||||
|
if possibles.iter().any(|p| p.get_help().is_some()) {
|
||||||
|
roff.text([Inline::LineBreak, italic("Possible values:")]);
|
||||||
|
|
||||||
|
// Need to indent twice to get it to look right,
|
||||||
|
// because .TP heading indents, but that indent doesn't
|
||||||
|
// Carry over to the .IP for the bullets.
|
||||||
|
// The standard shift size is 7 for terminal devices
|
||||||
|
roff.control("RS", ["14"]);
|
||||||
|
for line in format_possible_values(&possibles) {
|
||||||
|
roff.control("IP", ["\\(bu", "2"]);
|
||||||
|
roff.text([roman(line)]);
|
||||||
|
}
|
||||||
|
roff.control("RE", []);
|
||||||
}
|
}
|
||||||
|
|
||||||
let possible_vals = possibles.iter().filter(|pos| !pos.is_hide_set()).collect();
|
// without help for each possible value
|
||||||
body.append(&mut format_possible_values(possible_vals));
|
else {
|
||||||
|
let possible_list = format_possible_values(&possibles);
|
||||||
|
let possible_value_text: Vec<Inline> = vec![
|
||||||
|
Inline::LineBreak,
|
||||||
|
italic("[possible values: "),
|
||||||
|
roman(possible_list.join(", ")),
|
||||||
|
roman("]"),
|
||||||
|
];
|
||||||
|
roff.text(possible_value_text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
roff.control("TP", []);
|
|
||||||
roff.text(header);
|
|
||||||
roff.text(body);
|
|
||||||
|
|
||||||
if let Some(env) = option_environment(opt) {
|
if let Some(env) = option_environment(opt) {
|
||||||
roff.control("RS", []);
|
roff.control("RS", []);
|
||||||
|
@ -253,40 +282,18 @@ fn option_default_values(opt: &clap::Arg) -> Option<String> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a Vector of Inline Commands to push to the roff
|
fn format_possible_values(possibles: &Vec<&clap::builder::PossibleValue>) -> Vec<String> {
|
||||||
/// to properly format possible values that an option can take.
|
let mut lines = vec![];
|
||||||
fn format_possible_values(values: Vec<&clap::builder::PossibleValue>) -> Vec<Inline> {
|
if possibles.iter().any(|p| p.get_help().is_some()) {
|
||||||
let mut formats: Vec<Inline> = vec![];
|
for value in possibles {
|
||||||
// With Help
|
let val_name = value.get_name();
|
||||||
if values.iter().any(|p| p.get_help().is_some()) {
|
|
||||||
formats.push(Inline::LineBreak);
|
|
||||||
formats.push(roman("Possible values:"));
|
|
||||||
formats.push(Inline::LineBreak);
|
|
||||||
for value in values {
|
|
||||||
formats.push(roman(" - "));
|
|
||||||
formats.push(roman(value.get_name().as_str()));
|
|
||||||
match value.get_help() {
|
match value.get_help() {
|
||||||
Some(help) => {
|
Some(help) => lines.push(format!("{}: {}", val_name, help)),
|
||||||
formats.push(roman(": "));
|
None => lines.push(val_name.to_string()),
|
||||||
formats.push(roman(help.as_str()));
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
formats.push(Inline::LineBreak);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Without help
|
} else {
|
||||||
else {
|
lines.append(&mut possibles.iter().map(|p| p.get_name().to_string()).collect());
|
||||||
formats.push(Inline::LineBreak);
|
|
||||||
formats.push(roman("[possible values: "));
|
|
||||||
formats.push(italic(
|
|
||||||
values
|
|
||||||
.iter()
|
|
||||||
.map(|p| p.get_name().as_str())
|
|
||||||
.collect::<Vec<&str>>()
|
|
||||||
.join(", "),
|
|
||||||
));
|
|
||||||
formats.push(roman("]"));
|
|
||||||
}
|
}
|
||||||
formats
|
lines
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use clap::builder::PossibleValue;
|
||||||
|
|
||||||
pub fn basic_command(name: &'static str) -> clap::Command {
|
pub fn basic_command(name: &'static str) -> clap::Command {
|
||||||
clap::Command::new(name)
|
clap::Command::new(name)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -278,3 +280,24 @@ pub fn assert_matches_path(expected_path: impl AsRef<std::path::Path>, cmd: clap
|
||||||
.action_env("SNAPSHOTS")
|
.action_env("SNAPSHOTS")
|
||||||
.matches_path(expected_path, buf);
|
.matches_path(expected_path, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn possible_values_command(name: &'static str) -> clap::Command<'static> {
|
||||||
|
clap::Command::new(name)
|
||||||
|
.trailing_var_arg(true)
|
||||||
|
.arg(
|
||||||
|
clap::Arg::new("choice")
|
||||||
|
.long("choice")
|
||||||
|
.action(clap::ArgAction::Set)
|
||||||
|
.value_parser(["bash", "fish", "zsh"]),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
clap::Arg::new("method")
|
||||||
|
.long("method")
|
||||||
|
.action(clap::ArgAction::Set)
|
||||||
|
.value_parser([
|
||||||
|
PossibleValue::new("fast").help("use the Fast method"),
|
||||||
|
PossibleValue::new("slow").help("use the slow method"),
|
||||||
|
PossibleValue::new("normal").help("use normal mode").hide(true)
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -62,3 +62,10 @@ fn value_env() {
|
||||||
let cmd = common::env_value_command(name);
|
let cmd = common::env_value_command(name);
|
||||||
common::assert_matches_path("tests/snapshots/value_env.bash.roff", cmd);
|
common::assert_matches_path("tests/snapshots/value_env.bash.roff", cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn possible_values() {
|
||||||
|
let name = "my-app";
|
||||||
|
let cmd = common::possible_values_command(name);
|
||||||
|
common::assert_matches_path("tests/snapshots/possible_values.bash.roff", cmd);
|
||||||
|
}
|
||||||
|
|
28
clap_mangen/tests/snapshots/possible_values.bash.roff
Normal file
28
clap_mangen/tests/snapshots/possible_values.bash.roff
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
.ie /n(.g .ds Aq /(aq
|
||||||
|
.el .ds Aq '
|
||||||
|
.TH my-app 1 "my-app "
|
||||||
|
.SH NAME
|
||||||
|
my/-app
|
||||||
|
.SH SYNOPSIS
|
||||||
|
/fBmy/-app/fR [/fB/-/-choice/fR] [/fB/-/-method/fR] [/fB/-h/fR|/fB/-/-help/fR]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
/fB/-/-choice/fR
|
||||||
|
|
||||||
|
.br
|
||||||
|
/fI[possible values: /fRbash, fish, zsh]
|
||||||
|
.TP
|
||||||
|
/fB/-/-method/fR
|
||||||
|
|
||||||
|
.br
|
||||||
|
/fIPossible values:/fR
|
||||||
|
.RS 14
|
||||||
|
.IP /(bu 2
|
||||||
|
fast: use the Fast method
|
||||||
|
.IP /(bu 2
|
||||||
|
slow: use the slow method
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
/fB/-h/fR, /fB/-/-help/fR
|
||||||
|
Print help information
|
|
@ -9,8 +9,9 @@ my/-app
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
/fB/-/-choice/fR
|
/fB/-/-choice/fR
|
||||||
|
|
||||||
.br
|
.br
|
||||||
[possible values: /fIbash, fish, zsh/fR]
|
/fI[possible values: /fRbash, fish, zsh]
|
||||||
.TP
|
.TP
|
||||||
/fB/-/-unknown/fR
|
/fB/-/-unknown/fR
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue