Skip to content

Commit

Permalink
Merge pull request #4082 from Calder-Ty/bugfix/3861
Browse files Browse the repository at this point in the history
fix: Show possible values in generated man file
  • Loading branch information
epage authored Aug 24, 2022
2 parents d4ec9ca + a55db43 commit 79bdeb2
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 1 deletion.
90 changes: 90 additions & 0 deletions clap_mangen/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,45 @@ 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));
}

roff.control("TP", []);
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<Inline> = 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);
Expand All @@ -138,8 +169,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", []);
Expand All @@ -151,6 +184,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<Inline> = vec![
Inline::LineBreak,
roman("["),
italic("possible values: "),
roman(possible_values_text.join(", ")),
roman("]"),
];
roff.text(possible_value_text);
}
}
}
}

Expand Down Expand Up @@ -238,3 +300,31 @@ fn option_default_values(opt: &clap::Arg) -> Option<String> {

None
}

fn get_possible_values(arg: &clap::Arg) -> Option<(Vec<String>, bool)> {
let possibles = &arg.get_possible_values();
let possibles: Vec<&clap::builder::PossibleValue> =
possibles.iter().filter(|pos| !pos.is_hide_set()).collect();

if !(possibles.is_empty() || arg.is_hide_possible_values_set()) {
return Some(format_possible_values(&possibles));
}
None
}

fn format_possible_values(possibles: &Vec<&clap::builder::PossibleValue>) -> (Vec<String>, 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)
}
35 changes: 35 additions & 0 deletions clap_mangen/tests/common.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use clap::builder::PossibleValue;

pub fn basic_command(name: &'static str) -> clap::Command {
clap::Command::new(name)
.arg(
Expand Down Expand Up @@ -278,3 +280,36 @@ pub fn assert_matches_path(expected_path: impl AsRef<std::path::Path>, 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),
]),
)
}
7 changes: 7 additions & 0 deletions clap_mangen/tests/roff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
2 changes: 2 additions & 0 deletions clap_mangen/tests/snapshots/feature_sample.bash.roff
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ some input file
.TP
[/fIchoice/fR]

.br
[/fIpossible values: /fRfirst, second]
.SH SUBCOMMANDS
.TP
my/-app/-test(1)
Expand Down
41 changes: 41 additions & 0 deletions clap_mangen/tests/snapshots/possible_values.bash.roff
Original file line number Diff line number Diff line change
@@ -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/-/-choice/fR] [/fB/-/-method/fR] [/fB/-h/fR|/fB/-/-help/fR] [/fIpositional_choice/fR]
.SH DESCRIPTION
.SH OPTIONS
.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
/fB/-h/fR, /fB/-/-help/fR
Print help information
.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
2 changes: 2 additions & 0 deletions clap_mangen/tests/snapshots/special_commands.bash.roff
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ some input file
.TP
[/fIchoice/fR]

.br
[/fIpossible values: /fRfirst, second]
.SH SUBCOMMANDS
.TP
my/-app/-test(1)
Expand Down
2 changes: 2 additions & 0 deletions clap_mangen/tests/snapshots/sub_subcommands.bash.roff
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ some input file
.TP
[/fIchoice/fR]

.br
[/fIpossible values: /fRfirst, second]
.SH SUBCOMMANDS
.TP
my/-app/-test(1)
Expand Down
2 changes: 2 additions & 0 deletions clap_mangen/tests/snapshots/value_hint.bash.roff
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ my/-app
.TP
/fB/-/-choice/fR

.br
[/fIpossible values: /fRbash, fish, zsh]
.TP
/fB/-/-unknown/fR

Expand Down
4 changes: 3 additions & 1 deletion src/builder/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3656,7 +3656,9 @@ impl Arg {
Some(longs)
}

pub(crate) fn get_possible_values(&self) -> Vec<PossibleValue> {
/// Get the names of possible values for this argument. Only useful for user
/// facing applications, such as building help messages or man files
pub fn get_possible_values(&self) -> Vec<PossibleValue> {
if !self.is_takes_value_set() {
vec![]
} else {
Expand Down

0 comments on commit 79bdeb2

Please sign in to comment.