diff --git a/clap_mangen/src/lib.rs b/clap_mangen/src/lib.rs index 7b8d8af7900..b9fbdb76d1a 100644 --- a/clap_mangen/src/lib.rs +++ b/clap_mangen/src/lib.rs @@ -258,7 +258,11 @@ impl Man { fn _render_subcommands_section(&self, roff: &mut Roff) { let heading = subcommand_heading(&self.cmd); roff.control("SH", [heading]); - render::subcommands(roff, &self.cmd, &self.section); + if self.cmd.is_flatten_help_set() { + render::flat_subcommands(roff, &self.cmd); + } else { + render::subcommands(roff, &self.cmd, &self.section); + } } /// Render the EXTRA section into the writer. diff --git a/clap_mangen/src/render.rs b/clap_mangen/src/render.rs index 81d4e8c6b1c..2bf0d0ceeae 100644 --- a/clap_mangen/src/render.rs +++ b/clap_mangen/src/render.rs @@ -30,9 +30,46 @@ pub(crate) fn description(roff: &mut Roff, cmd: &clap::Command) { } pub(crate) fn synopsis(roff: &mut Roff, cmd: &clap::Command) { - let name = cmd.get_bin_name().unwrap_or_else(|| cmd.get_name()); - let mut line = vec![bold(name), roman(" ")]; + let flatten = cmd.is_flatten_help_set(); + let mut first = true; + if !cmd.is_subcommand_required_set() || cmd.is_args_conflicts_with_subcommands_set() { + let mut line = usage(cmd, cmd.get_bin_name().unwrap_or_else(|| cmd.get_name())); + if cmd.has_subcommands() && !flatten { + let (lhs, rhs) = subcommand_markers(cmd); + line.push(roman(lhs)); + line.push(italic( + cmd.get_subcommand_value_name() + .unwrap_or_else(|| subcommand_heading(cmd)) + .to_lowercase(), + )); + line.push(roman(rhs)); + } + roff.text(line); + first = false; + } + if flatten { + let mut ord_v = Vec::new(); + for subcommand in cmd.get_subcommands() { + ord_v.push(( + subcommand.get_display_order(), + subcommand.get_bin_name().unwrap_or_else(|| cmd.get_name()), + subcommand, + )); + } + ord_v.sort_by(|a, b| (a.0, &a.1).cmp(&(b.0, &b.1))); + for (_, name, cmd) in ord_v { + if !first { + roff.control("br", []); + } else { + first = false; + } + roff.text(usage(cmd, name)); + } + } +} +fn usage(cmd: &clap::Command, name: &str) -> Vec { + let mut line = vec![bold(name), roman(" ")]; for opt in cmd.get_arguments().filter(|i| !i.is_hide_set()) { let (lhs, rhs) = option_markers(opt); match (opt.get_short(), opt.get_long()) { @@ -74,18 +111,7 @@ pub(crate) fn synopsis(roff: &mut Roff, cmd: &clap::Command) { line.push(roman(" ")); } - if cmd.has_subcommands() { - let (lhs, rhs) = subcommand_markers(cmd); - line.push(roman(lhs)); - line.push(italic( - cmd.get_subcommand_value_name() - .unwrap_or_else(|| subcommand_heading(cmd)) - .to_lowercase(), - )); - line.push(roman(rhs)); - } - - roff.text(line); + line } pub(crate) fn options(roff: &mut Roff, cmd: &clap::Command) { @@ -220,6 +246,26 @@ pub(crate) fn subcommands(roff: &mut Roff, cmd: &clap::Command, section: &str) { } } +pub(crate) fn flat_subcommands(roff: &mut Roff, cmd: &clap::Command) { + for sub in cmd.get_subcommands().filter(|s| !s.is_hide_set()) { + roff.control("TP", []); + + let mut line = usage(sub, sub.get_name()); + + if let Some(about) = sub.get_long_about().or_else(|| sub.get_about()) { + line.push(roman("\n")); + line.push(roman(about.to_string())); + } + + if let Some(after_help) = sub.get_after_help() { + line.push(roman("\n")); + line.push(roman(after_help.to_string())); + } + + roff.text(line); + } +} + pub(crate) fn version(cmd: &clap::Command) -> String { format!( "v{}", diff --git a/clap_mangen/tests/snapshots/flatten_arg_required.roff b/clap_mangen/tests/snapshots/flatten_arg_required.roff new file mode 100644 index 00000000000..4e3016bba1c --- /dev/null +++ b/clap_mangen/tests/snapshots/flatten_arg_required.roff @@ -0,0 +1,27 @@ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.TH parent 1 "parent " +.SH NAME +parent \- parent command +.SH SYNOPSIS +\fBparent\fR <\fB\-\-parent\fR> [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent test\fR <\fB\-\-child\fR> [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent help\fR +.SH DESCRIPTION +parent command +.SH OPTIONS +.TP +\fB\-\-parent\fR + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help +.SH SUBCOMMANDS +.TP +\fBtest\fR <\fB\-\-child\fR> [\fB\-h\fR|\fB\-\-help\fR] +test command +.TP +\fBhelp\fR +Print this message or the help of the given subcommand(s) diff --git a/clap_mangen/tests/snapshots/flatten_basic.roff b/clap_mangen/tests/snapshots/flatten_basic.roff new file mode 100644 index 00000000000..be64adbdd50 --- /dev/null +++ b/clap_mangen/tests/snapshots/flatten_basic.roff @@ -0,0 +1,27 @@ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.TH parent 1 "parent " +.SH NAME +parent \- parent command +.SH SYNOPSIS +\fBparent\fR [\fB\-\-parent\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent test\fR [\fB\-\-child\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent help\fR +.SH DESCRIPTION +parent command +.SH OPTIONS +.TP +\fB\-\-parent\fR + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help +.SH SUBCOMMANDS +.TP +\fBtest\fR [\fB\-\-child\fR] [\fB\-h\fR|\fB\-\-help\fR] +test command +.TP +\fBhelp\fR +Print this message or the help of the given subcommand(s) diff --git a/clap_mangen/tests/snapshots/flatten_help.roff b/clap_mangen/tests/snapshots/flatten_help.roff new file mode 100644 index 00000000000..8ed198d8e03 --- /dev/null +++ b/clap_mangen/tests/snapshots/flatten_help.roff @@ -0,0 +1,30 @@ +.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\-c \fR] [\fB\-v \fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBmy\-app test\fR [\fB\-d \fR]... [\fB\-c \fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBmy\-app help\fR +.SH DESCRIPTION +.SH OPTIONS +.TP +\fB\-c\fR + +.TP +\fB\-v\fR + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help +.SH SUBCOMMANDS +.TP +\fBtest\fR [\fB\-d \fR]... [\fB\-c \fR] [\fB\-h\fR|\fB\-\-help\fR] +Subcommand +with a second line +.TP +\fBhelp\fR +Print this message or the help of the given subcommand(s) diff --git a/clap_mangen/tests/snapshots/flatten_help_cmd.roff b/clap_mangen/tests/snapshots/flatten_help_cmd.roff new file mode 100644 index 00000000000..23028212879 --- /dev/null +++ b/clap_mangen/tests/snapshots/flatten_help_cmd.roff @@ -0,0 +1,27 @@ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.TH parent 1 "parent " +.SH NAME +parent \- parent command +.SH SYNOPSIS +\fBparent\fR [\fB\-\-parent\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent test\fR [\fB\-\-child\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent help\fR +.SH DESCRIPTION +parent command +.SH OPTIONS +.TP +\fB\-\-parent\fR +bar +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help (see a summary with \*(Aq\-h\*(Aq) +.SH SUBCOMMANDS +.TP +\fBtest\fR [\fB\-\-child\fR] [\fB\-h\fR|\fB\-\-help\fR] +long some +.TP +\fBhelp\fR +Print this message or the help of the given subcommand(s) diff --git a/clap_mangen/tests/snapshots/flatten_help_subcommand_required.roff b/clap_mangen/tests/snapshots/flatten_help_subcommand_required.roff new file mode 100644 index 00000000000..e2dd9cc9a9f --- /dev/null +++ b/clap_mangen/tests/snapshots/flatten_help_subcommand_required.roff @@ -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 test\fR [\fB\-d \fR]... [\fB\-c \fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBmy\-app help\fR +.SH DESCRIPTION +.SH OPTIONS +.TP +\fB\-c\fR + +.TP +\fB\-v\fR + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help +.SH SUBCOMMANDS +.TP +\fBtest\fR [\fB\-d \fR]... [\fB\-c \fR] [\fB\-h\fR|\fB\-\-help\fR] +Subcommand +with a second line +.TP +\fBhelp\fR +Print this message or the help of the given subcommand(s) diff --git a/clap_mangen/tests/snapshots/flatten_hidden_command.roff b/clap_mangen/tests/snapshots/flatten_hidden_command.roff new file mode 100644 index 00000000000..21ef1ab791f --- /dev/null +++ b/clap_mangen/tests/snapshots/flatten_hidden_command.roff @@ -0,0 +1,34 @@ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.TH parent 1 "parent " +.SH NAME +parent \- parent command +.SH SYNOPSIS +\fBparent\fR [\fB\-\-parent\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent child1\fR [\fB\-\-child1\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent child2\fR [\fB\-\-child2\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent child3\fR [\fB\-\-child3\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent help\fR +.SH DESCRIPTION +parent command +.SH OPTIONS +.TP +\fB\-\-parent\fR + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help +.SH SUBCOMMANDS +.TP +\fBchild1\fR [\fB\-\-child1\fR] [\fB\-h\fR|\fB\-\-help\fR] +child1 command +.TP +\fBchild2\fR [\fB\-\-child2\fR] [\fB\-h\fR|\fB\-\-help\fR] +child2 command +.TP +\fBhelp\fR +Print this message or the help of the given subcommand(s) diff --git a/clap_mangen/tests/snapshots/flatten_not_recursive.roff b/clap_mangen/tests/snapshots/flatten_not_recursive.roff new file mode 100644 index 00000000000..c72e34138bb --- /dev/null +++ b/clap_mangen/tests/snapshots/flatten_not_recursive.roff @@ -0,0 +1,37 @@ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.TH parent 1 "parent " +.SH NAME +parent \- parent command +.SH SYNOPSIS +\fBparent\fR [\fB\-\-parent\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent child1\fR [\fB\-\-child1\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent child2\fR [\fB\-\-child2\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent child3\fR [\fB\-\-child3\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent help\fR +.SH DESCRIPTION +parent command +.SH OPTIONS +.TP +\fB\-\-parent\fR + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help +.SH SUBCOMMANDS +.TP +\fBchild1\fR [\fB\-\-child1\fR] [\fB\-h\fR|\fB\-\-help\fR] +child1 command +.TP +\fBchild2\fR [\fB\-\-child2\fR] [\fB\-h\fR|\fB\-\-help\fR] +child2 command +.TP +\fBchild3\fR [\fB\-\-child3\fR] [\fB\-h\fR|\fB\-\-help\fR] +child3 command +.TP +\fBhelp\fR +Print this message or the help of the given subcommand(s) diff --git a/clap_mangen/tests/snapshots/flatten_recursive.roff b/clap_mangen/tests/snapshots/flatten_recursive.roff new file mode 100644 index 00000000000..21ef1ab791f --- /dev/null +++ b/clap_mangen/tests/snapshots/flatten_recursive.roff @@ -0,0 +1,34 @@ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.TH parent 1 "parent " +.SH NAME +parent \- parent command +.SH SYNOPSIS +\fBparent\fR [\fB\-\-parent\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent child1\fR [\fB\-\-child1\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent child2\fR [\fB\-\-child2\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent child3\fR [\fB\-\-child3\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent help\fR +.SH DESCRIPTION +parent command +.SH OPTIONS +.TP +\fB\-\-parent\fR + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help +.SH SUBCOMMANDS +.TP +\fBchild1\fR [\fB\-\-child1\fR] [\fB\-h\fR|\fB\-\-help\fR] +child1 command +.TP +\fBchild2\fR [\fB\-\-child2\fR] [\fB\-h\fR|\fB\-\-help\fR] +child2 command +.TP +\fBhelp\fR +Print this message or the help of the given subcommand(s) diff --git a/clap_mangen/tests/snapshots/flatten_single_hidden_command.roff b/clap_mangen/tests/snapshots/flatten_single_hidden_command.roff new file mode 100644 index 00000000000..aef2e4c39c3 --- /dev/null +++ b/clap_mangen/tests/snapshots/flatten_single_hidden_command.roff @@ -0,0 +1,24 @@ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.TH parent 1 "parent " +.SH NAME +parent \- parent command +.SH SYNOPSIS +\fBparent\fR [\fB\-\-parent\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent child1\fR [\fB\-\-child1\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent help\fR +.SH DESCRIPTION +parent command +.SH OPTIONS +.TP +\fB\-\-parent\fR + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help +.SH SUBCOMMANDS +.TP +\fBhelp\fR +Print this message or the help of the given subcommand(s) diff --git a/clap_mangen/tests/snapshots/flatten_with_args_conflicts_with_subcommands.roff b/clap_mangen/tests/snapshots/flatten_with_args_conflicts_with_subcommands.roff new file mode 100644 index 00000000000..be64adbdd50 --- /dev/null +++ b/clap_mangen/tests/snapshots/flatten_with_args_conflicts_with_subcommands.roff @@ -0,0 +1,27 @@ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.TH parent 1 "parent " +.SH NAME +parent \- parent command +.SH SYNOPSIS +\fBparent\fR [\fB\-\-parent\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent test\fR [\fB\-\-child\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent help\fR +.SH DESCRIPTION +parent command +.SH OPTIONS +.TP +\fB\-\-parent\fR + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help +.SH SUBCOMMANDS +.TP +\fBtest\fR [\fB\-\-child\fR] [\fB\-h\fR|\fB\-\-help\fR] +test command +.TP +\fBhelp\fR +Print this message or the help of the given subcommand(s) diff --git a/clap_mangen/tests/snapshots/flatten_with_external_subcommand.roff b/clap_mangen/tests/snapshots/flatten_with_external_subcommand.roff new file mode 100644 index 00000000000..be64adbdd50 --- /dev/null +++ b/clap_mangen/tests/snapshots/flatten_with_external_subcommand.roff @@ -0,0 +1,27 @@ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.TH parent 1 "parent " +.SH NAME +parent \- parent command +.SH SYNOPSIS +\fBparent\fR [\fB\-\-parent\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent test\fR [\fB\-\-child\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent help\fR +.SH DESCRIPTION +parent command +.SH OPTIONS +.TP +\fB\-\-parent\fR + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help +.SH SUBCOMMANDS +.TP +\fBtest\fR [\fB\-\-child\fR] [\fB\-h\fR|\fB\-\-help\fR] +test command +.TP +\fBhelp\fR +Print this message or the help of the given subcommand(s) diff --git a/clap_mangen/tests/snapshots/flatten_with_global.roff b/clap_mangen/tests/snapshots/flatten_with_global.roff new file mode 100644 index 00000000000..e9e273518f2 --- /dev/null +++ b/clap_mangen/tests/snapshots/flatten_with_global.roff @@ -0,0 +1,27 @@ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.TH parent 1 "parent " +.SH NAME +parent \- parent command +.SH SYNOPSIS +\fBparent\fR [\fB\-\-parent\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent test\fR [\fB\-\-child\fR] [\fB\-\-parent\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent help\fR +.SH DESCRIPTION +parent command +.SH OPTIONS +.TP +\fB\-\-parent\fR + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help +.SH SUBCOMMANDS +.TP +\fBtest\fR [\fB\-\-child\fR] [\fB\-\-parent\fR] [\fB\-h\fR|\fB\-\-help\fR] +test command +.TP +\fBhelp\fR +Print this message or the help of the given subcommand(s) diff --git a/clap_mangen/tests/snapshots/flatten_with_subcommand_required.roff b/clap_mangen/tests/snapshots/flatten_with_subcommand_required.roff new file mode 100644 index 00000000000..c6802089606 --- /dev/null +++ b/clap_mangen/tests/snapshots/flatten_with_subcommand_required.roff @@ -0,0 +1,25 @@ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.TH parent 1 "parent " +.SH NAME +parent \- parent command +.SH SYNOPSIS +\fBparent test\fR [\fB\-\-child\fR] [\fB\-h\fR|\fB\-\-help\fR] +.br +\fBparent help\fR +.SH DESCRIPTION +parent command +.SH OPTIONS +.TP +\fB\-\-parent\fR + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help +.SH SUBCOMMANDS +.TP +\fBtest\fR [\fB\-\-child\fR] [\fB\-h\fR|\fB\-\-help\fR] +test command +.TP +\fBhelp\fR +Print this message or the help of the given subcommand(s) diff --git a/clap_mangen/tests/snapshots/flatten_without_subcommands.roff b/clap_mangen/tests/snapshots/flatten_without_subcommands.roff new file mode 100644 index 00000000000..d2855bfb428 --- /dev/null +++ b/clap_mangen/tests/snapshots/flatten_without_subcommands.roff @@ -0,0 +1,16 @@ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.TH parent 1 "parent " +.SH NAME +parent \- parent command +.SH SYNOPSIS +\fBparent\fR [\fB\-\-parent\fR] [\fB\-h\fR|\fB\-\-help\fR] +.SH DESCRIPTION +parent command +.SH OPTIONS +.TP +\fB\-\-parent\fR + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help diff --git a/clap_mangen/tests/testsuite/roff.rs b/clap_mangen/tests/testsuite/roff.rs index 9f3f4ee660e..d7e65fe5943 100644 --- a/clap_mangen/tests/testsuite/roff.rs +++ b/clap_mangen/tests/testsuite/roff.rs @@ -1,4 +1,5 @@ use crate::common; +use clap::{Arg, Command}; #[test] fn basic() { @@ -105,3 +106,359 @@ fn value_name_without_arg() { cmd, ); } + +#[test] +fn flatten_help_false() { + let name = "my-app"; + let cmd = common::basic_command(name).flatten_help(false); + common::assert_matches(snapbox::file!["../snapshots/basic.bash.roff"], cmd); +} + +#[test] +fn flatten_help_true() { + let name = "my-app"; + let cmd = common::basic_command(name).flatten_help(true); + common::assert_matches(snapbox::file!["../snapshots/flatten_help.roff"], cmd); +} + +#[test] +fn flatten_help_true_subcommand_required_true() { + let name = "my-app"; + let cmd = common::basic_command(name) + .flatten_help(true) + .subcommand_required(true); + common::assert_matches( + snapbox::file!["../snapshots/flatten_help_subcommand_required.roff"], + cmd, + ); +} + +#[test] +fn flatten_help_true_subcommand_args_conflicts_with_subcommands() { + let name = "my-app"; + let cmd = common::basic_command(name) + .flatten_help(true) + .subcommand_required(false) + .args_conflicts_with_subcommands(false); + common::assert_matches(snapbox::file!["../snapshots/flatten_help.roff"], cmd); +} + +#[test] +fn flatten_basic() { + let cmd = Command::new("parent") + .flatten_help(true) + .about("parent command") + .arg(Arg::new("parent").long("parent")) + .subcommand( + Command::new("test") + .about("test command") + .arg(Arg::new("child").long("child")), + ); + + common::assert_matches(snapbox::file!["../snapshots/flatten_basic.roff"], cmd); +} + +#[test] +fn flatten_help_cmd() { + let cmd = Command::new("parent") + .flatten_help(true) + .about("parent command") + .arg( + Arg::new("parent") + .long("parent") + .help("foo") + .long_help("bar"), + ) + .subcommand( + Command::new("test") + .about("test command") + .long_about("long some") + .arg(Arg::new("child").long("child").help("foo").long_help("bar")), + ); + + common::assert_matches(snapbox::file!["../snapshots/flatten_help_cmd.roff"], cmd); +} + +#[test] +fn flatten_with_global() { + let cmd = Command::new("parent") + .flatten_help(true) + .about("parent command") + .arg(Arg::new("parent").long("parent").global(true)) + .subcommand( + Command::new("test") + .about("test command") + .arg(Arg::new("child").long("child")), + ); + + common::assert_matches(snapbox::file!["../snapshots/flatten_with_global.roff"], cmd); +} + +#[test] +fn flatten_arg_required() { + let cmd = Command::new("parent") + .flatten_help(true) + .about("parent command") + .arg(Arg::new("parent").long("parent").required(true)) + .subcommand( + Command::new("test") + .about("test command") + .arg(Arg::new("child").long("child").required(true)), + ); + + common::assert_matches( + snapbox::file!["../snapshots/flatten_arg_required.roff"], + cmd, + ); +} + +#[test] +fn flatten_with_external_subcommand() { + let cmd = Command::new("parent") + .flatten_help(true) + .about("parent command") + .allow_external_subcommands(true) + .arg(Arg::new("parent").long("parent")) + .subcommand( + Command::new("test") + .about("test command") + .arg(Arg::new("child").long("child")), + ); + + common::assert_matches( + snapbox::file!["../snapshots/flatten_with_external_subcommand.roff"], + cmd, + ); +} + +#[test] +fn flatten_without_subcommands() { + let cmd = Command::new("parent") + .flatten_help(true) + .about("parent command") + .arg(Arg::new("parent").long("parent")); + + common::assert_matches( + snapbox::file!["../snapshots/flatten_without_subcommands.roff"], + cmd, + ); +} + +#[test] +fn flatten_with_subcommand_required() { + let cmd = Command::new("parent") + .flatten_help(true) + .about("parent command") + .subcommand_required(true) + .arg(Arg::new("parent").long("parent")) + .subcommand( + Command::new("test") + .about("test command") + .arg(Arg::new("child").long("child")), + ); + + common::assert_matches( + snapbox::file!["../snapshots/flatten_with_subcommand_required.roff"], + cmd, + ); +} + +#[test] +fn flatten_with_args_conflicts_with_subcommands() { + let cmd = Command::new("parent") + .flatten_help(true) + .about("parent command") + .subcommand_required(true) + .args_conflicts_with_subcommands(true) + .arg(Arg::new("parent").long("parent")) + .subcommand( + Command::new("test") + .about("test command") + .arg(Arg::new("child").long("child")), + ); + + common::assert_matches( + snapbox::file!["../snapshots/flatten_with_args_conflicts_with_subcommands.roff"], + cmd, + ); +} + +#[test] +fn flatten_single_hidden_command() { + let cmd = Command::new("parent") + .flatten_help(true) + .about("parent command") + .arg(Arg::new("parent").long("parent")) + .subcommand( + Command::new("child1") + .hide(true) + .about("child1 command") + .arg(Arg::new("child").long("child1")), + ); + + common::assert_matches( + snapbox::file!["../snapshots/flatten_single_hidden_command.roff"], + cmd, + ); +} + +#[test] +fn flatten_hidden_command() { + let cmd = Command::new("parent") + .flatten_help(true) + .about("parent command") + .arg(Arg::new("parent").long("parent")) + .subcommand( + Command::new("child1") + .about("child1 command") + .arg(Arg::new("child").long("child1")), + ) + .subcommand( + Command::new("child2") + .about("child2 command") + .arg(Arg::new("child").long("child2")), + ) + .subcommand( + Command::new("child3") + .hide(true) + .about("child3 command") + .arg(Arg::new("child").long("child3")), + ); + + common::assert_matches( + snapbox::file!["../snapshots/flatten_hidden_command.roff"], + cmd, + ); +} + +#[test] +fn flatten_recursive() { + let cmd = Command::new("parent") + .flatten_help(true) + .about("parent command") + .arg(Arg::new("parent").long("parent")) + .subcommand( + Command::new("child1") + .flatten_help(true) + .about("child1 command") + .arg(Arg::new("child").long("child1")) + .subcommand( + Command::new("grandchild1") + .flatten_help(true) + .about("grandchild1 command") + .arg(Arg::new("grandchild").long("grandchild1")) + .subcommand( + Command::new("greatgrandchild1") + .about("greatgrandchild1 command") + .arg(Arg::new("greatgrandchild").long("greatgrandchild1")), + ) + .subcommand( + Command::new("greatgrandchild2") + .about("greatgrandchild2 command") + .arg(Arg::new("greatgrandchild").long("greatgrandchild2")), + ) + .subcommand( + Command::new("greatgrandchild3") + .about("greatgrandchild3 command") + .arg(Arg::new("greatgrandchild").long("greatgrandchild3")), + ), + ) + .subcommand( + Command::new("grandchild2") + .about("grandchild2 command") + .arg(Arg::new("grandchild").long("grandchild2")), + ) + .subcommand( + Command::new("grandchild3") + .about("grandchild3 command") + .arg(Arg::new("grandchild").long("grandchild3")), + ), + ) + .subcommand( + Command::new("child2") + .about("child2 command") + .arg(Arg::new("child").long("child2")), + ) + .subcommand( + Command::new("child3") + .hide(true) + .about("child3 command") + .arg(Arg::new("child").long("child3")) + .subcommand( + Command::new("grandchild1") + .flatten_help(true) + .about("grandchild1 command") + .arg(Arg::new("grandchild").long("grandchild1")) + .subcommand( + Command::new("greatgrandchild1") + .about("greatgrandchild1 command") + .arg(Arg::new("greatgrandchild").long("greatgrandchild1")), + ) + .subcommand( + Command::new("greatgrandchild2") + .about("greatgrandchild2 command") + .arg(Arg::new("greatgrandchild").long("greatgrandchild2")), + ) + .subcommand( + Command::new("greatgrandchild3") + .about("greatgrandchild3 command") + .arg(Arg::new("greatgrandchild").long("greatgrandchild3")), + ), + ) + .subcommand( + Command::new("grandchild2") + .about("grandchild2 command") + .arg(Arg::new("grandchild").long("grandchild2")), + ) + .subcommand( + Command::new("grandchild3") + .about("grandchild3 command") + .arg(Arg::new("grandchild").long("grandchild3")), + ), + ); + + common::assert_matches(snapbox::file!["../snapshots/flatten_recursive.roff"], cmd); +} + +#[test] +fn flatten_not_recursive() { + let cmd = Command::new("parent") + .flatten_help(true) + .about("parent command") + .arg(Arg::new("parent").long("parent")) + .subcommand( + Command::new("child1") + .about("child1 command") + .arg(Arg::new("child").long("child1")) + .subcommand( + Command::new("grandchild1") + .about("grandchild1 command") + .arg(Arg::new("grandchild").long("grandchild1")), + ) + .subcommand( + Command::new("grandchild2") + .about("grandchild2 command") + .arg(Arg::new("grandchild").long("grandchild2")), + ) + .subcommand( + Command::new("grandchild3") + .about("grandchild3 command") + .arg(Arg::new("grandchild").long("grandchild3")), + ), + ) + .subcommand( + Command::new("child2") + .about("child2 command") + .arg(Arg::new("child").long("child2")), + ) + .subcommand( + Command::new("child3") + .about("child3 command") + .arg(Arg::new("child").long("child3")), + ); + + common::assert_matches( + snapbox::file!["../snapshots/flatten_not_recursive.roff"], + cmd, + ); +}