diff --git a/clap_mangen/src/render.rs b/clap_mangen/src/render.rs index b17f3bb849e..60775fa9dc3 100644 --- a/clap_mangen/src/render.rs +++ b/clap_mangen/src/render.rs @@ -1,4 +1,5 @@ use clap::AppSettings; + use roff::{bold, italic, roman, Inline, Roff}; pub(crate) fn subcommand_heading(cmd: &clap::Command) -> String { @@ -108,7 +109,9 @@ pub(crate) fn options(roff: &mut Roff, cmd: &clap::Command) { } let mut body = vec![]; + let mut arg_help_written = false; if let Some(help) = opt.get_long_help().or_else(|| opt.get_help()) { + arg_help_written = true; body.push(roman(help)); } @@ -116,6 +119,35 @@ pub(crate) fn options(roff: &mut Roff, cmd: &clap::Command) { roff.text(header); roff.text(body); + if let Some((possible_values_text, with_help)) = get_possible_values(opt) { + if arg_help_written { + // It looks nice to have a separation between the help and the values + roff.text([Inline::LineBreak]); + } + if with_help { + 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 possible_values_text { + roff.control("IP", ["\\(bu", "2"]); + roff.text([roman(line)]); + } + roff.control("RE", []); + } else { + let possible_value_text: Vec = vec![ + Inline::LineBreak, + roman("["), + italic("possible values: "), + roman(possible_values_text.join(", ")), + roman("]"), + ]; + roff.text(possible_value_text); + } + } + if let Some(env) = option_environment(opt) { roff.control("RS", []); roff.text(env); @@ -139,8 +171,10 @@ pub(crate) fn options(roff: &mut Roff, cmd: &clap::Command) { } let mut body = vec![]; + let mut arg_help_written = false; if let Some(help) = pos.get_long_help().or_else(|| pos.get_help()) { body.push(roman(&help.to_string())); + arg_help_written = true; } roff.control("TP", []); @@ -152,6 +186,35 @@ pub(crate) fn options(roff: &mut Roff, cmd: &clap::Command) { roff.text(env); roff.control("RE", []); } + // If possible options are available + if let Some((possible_values_text, with_help)) = get_possible_values(pos) { + if arg_help_written { + // It looks nice to have a separation between the help and the values + roff.text([Inline::LineBreak]); + } + if with_help { + 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 possible_values_text { + roff.control("IP", ["\\(bu", "2"]); + roff.text([roman(line)]); + } + roff.control("RE", []); + } else { + let possible_value_text: Vec = vec![ + Inline::LineBreak, + roman("["), + italic("possible values: "), + roman(possible_values_text.join(", ")), + roman("]"), + ]; + roff.text(possible_value_text); + } + } } } @@ -240,3 +303,35 @@ fn option_default_values(opt: &clap::Arg) -> Option { None } + +fn get_possible_values(arg: &clap::Arg) -> Option<(Vec, bool)> { + let possibles = arg.get_value_parser().possible_values(); + + if let Some(possible_vals) = possibles { + let possibles: Vec<_> = possible_vals.collect(); + let shown_possibles: Vec<_> = possibles.iter().filter(|pos| !pos.is_hide_set()).collect(); + + if !(shown_possibles.is_empty() || arg.is_hide_possible_values_set()) { + return Some(format_possible_values(&shown_possibles)); + } + return None; + } + None +} + +fn format_possible_values(possibles: &[&clap::builder::PossibleValue]) -> (Vec, bool) { + let mut lines = vec![]; + let with_help = possibles.iter().any(|p| p.get_help().is_some()); + if with_help { + for value in possibles { + let val_name = value.get_name(); + match value.get_help() { + Some(help) => lines.push(format!("{}: {}", val_name, help)), + None => lines.push(val_name.to_string()), + } + } + } else { + lines.append(&mut possibles.iter().map(|p| p.get_name().to_string()).collect()); + } + (lines, with_help) +} diff --git a/clap_mangen/tests/common.rs b/clap_mangen/tests/common.rs index 3b8bcdc3cfb..836f9c5a69e 100644 --- a/clap_mangen/tests/common.rs +++ b/clap_mangen/tests/common.rs @@ -1,3 +1,5 @@ +use clap::builder::PossibleValue; + pub fn basic_command(name: &'static str) -> clap::Command<'static> { clap::Command::new(name) .arg(clap::Arg::new("config").short('c').global(true)) @@ -252,3 +254,36 @@ pub fn assert_matches_path(expected_path: impl AsRef, cmd: clap .action_env("SNAPSHOTS") .matches_path(expected_path, buf); } + +pub fn possible_values_command(name: &'static str) -> clap::Command { + 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), + ]), + ) + .arg( + clap::Arg::new("positional_choice") + .action(clap::ArgAction::Set) + .help("Pick the Position you want the command to run in") + .value_parser([ + PossibleValue::new("left").help("run left adjusted"), + PossibleValue::new("right"), + PossibleValue::new("center").hide(true), + ]), + ) +} diff --git a/clap_mangen/tests/roff.rs b/clap_mangen/tests/roff.rs index 946b8e764e5..0c6d99dbf33 100644 --- a/clap_mangen/tests/roff.rs +++ b/clap_mangen/tests/roff.rs @@ -62,3 +62,10 @@ fn value_env() { let cmd = common::env_value_command(name); 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); +} diff --git a/clap_mangen/tests/snapshots/feature_sample.bash.roff b/clap_mangen/tests/snapshots/feature_sample.bash.roff index ae9be971f3a..4c43af3f5a5 100644 --- a/clap_mangen/tests/snapshots/feature_sample.bash.roff +++ b/clap_mangen/tests/snapshots/feature_sample.bash.roff @@ -23,6 +23,8 @@ some input file .TP [/fIchoice/fR] +.br +[/fIpossible values: /fRfirst, second] .SH SUBCOMMANDS .TP my/-app/-test(1) diff --git a/clap_mangen/tests/snapshots/possible_values.bash.roff b/clap_mangen/tests/snapshots/possible_values.bash.roff new file mode 100644 index 00000000000..b150a540f34 --- /dev/null +++ b/clap_mangen/tests/snapshots/possible_values.bash.roff @@ -0,0 +1,41 @@ +.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/-h/fR|/fB/-/-help/fR] [/fB/-/-choice/fR] [/fB/-/-method/fR] [/fIpositional_choice/fR] +.SH DESCRIPTION +.SH OPTIONS +.TP +/fB/-h/fR, /fB/-/-help/fR +Print help information +.TP +/fB/-/-choice/fR + +.br +[/fIpossible 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 +[/fIpositional_choice/fR] +Pick the Position you want the command to run in +.br + +.br +/fIPossible values:/fR +.RS 14 +.IP /(bu 2 +left: run left adjusted +.IP /(bu 2 +right +.RE diff --git a/clap_mangen/tests/snapshots/special_commands.bash.roff b/clap_mangen/tests/snapshots/special_commands.bash.roff index 08d364d8bc3..47c1c473b43 100644 --- a/clap_mangen/tests/snapshots/special_commands.bash.roff +++ b/clap_mangen/tests/snapshots/special_commands.bash.roff @@ -23,6 +23,8 @@ some input file .TP [/fIchoice/fR] +.br +[/fIpossible values: /fRfirst, second] .SH SUBCOMMANDS .TP my/-app/-test(1) diff --git a/clap_mangen/tests/snapshots/sub_subcommands.bash.roff b/clap_mangen/tests/snapshots/sub_subcommands.bash.roff index e364240fe71..f23a250285d 100644 --- a/clap_mangen/tests/snapshots/sub_subcommands.bash.roff +++ b/clap_mangen/tests/snapshots/sub_subcommands.bash.roff @@ -23,6 +23,8 @@ some input file .TP [/fIchoice/fR] +.br +[/fIpossible values: /fRfirst, second] .SH SUBCOMMANDS .TP my/-app/-test(1) diff --git a/clap_mangen/tests/snapshots/value_hint.bash.roff b/clap_mangen/tests/snapshots/value_hint.bash.roff index cb02d3ca96f..3ff1f76e1a7 100644 --- a/clap_mangen/tests/snapshots/value_hint.bash.roff +++ b/clap_mangen/tests/snapshots/value_hint.bash.roff @@ -13,6 +13,8 @@ Print help information .TP /fB/-/-choice/fR +.br +[/fIpossible values: /fRbash, fish, zsh] .TP /fB/-/-unknown/fR