Skip to content

Commit

Permalink
feat(mangen): Support flatten_help
Browse files Browse the repository at this point in the history
The `flatten_help` argument combines all subcommands on a single page.
Until now this wasn't supported for `mangen`. With this command the
sections `SYNOPSIS` as well as `SUBCOMMANDS` are changed to imitate the
style of `git stash --help`.

Signed-off-by: Paul Spooren <[email protected]>
  • Loading branch information
aparcar committed Oct 18, 2024
1 parent 89dea44 commit 52a7a4c
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 17 deletions.
6 changes: 5 additions & 1 deletion clap_mangen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
70 changes: 57 additions & 13 deletions clap_mangen/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,45 @@ 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 mut line = usage(cmd, name);
let flatten = cmd.is_flatten_help_set();
let mut ord_v = Vec::new();
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);

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));
first = false;
}
roff.text(line);

if flatten {
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));
}
}

Expand Down Expand Up @@ -226,6 +250,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{}",
Expand Down
10 changes: 7 additions & 3 deletions clap_mangen/tests/snapshots/flatten_help.roff
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
.SH NAME
my\-app
.SH SYNOPSIS
\fBmy\-app\fR [\fB\-c \fR] [\fB\-v \fR] [\fB\-h\fR|\fB\-\-help\fR] [\fIsubcommands\fR]
\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
Expand All @@ -18,9 +22,9 @@ my\-app
Print help
.SH SUBCOMMANDS
.TP
my\-app\-test(1)
\fBtest\fR [\fB\-d \fR]... [\fB\-c \fR] [\fB\-h\fR|\fB\-\-help\fR]
Subcommand
with a second line
.TP
my\-app\-help(1)
\fBhelp\fR
Print this message or the help of the given subcommand(s)
28 changes: 28 additions & 0 deletions clap_mangen/tests/snapshots/flatten_help_subcommand_required.roff
Original file line number Diff line number Diff line change
@@ -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)
22 changes: 22 additions & 0 deletions clap_mangen/tests/testsuite/roff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,25 @@ fn flatten_help_true() {
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);
}

0 comments on commit 52a7a4c

Please sign in to comment.