Skip to content

Commit 419244b

Browse files
authored
Merge pull request #6142 from thomas-zahner/respect-display-order
Respect display order
2 parents c7c761f + 24dfa0d commit 419244b

File tree

6 files changed

+224
-18
lines changed

6 files changed

+224
-18
lines changed

clap_mangen/src/render.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ pub(crate) fn synopsis(roff: &mut Roff, cmd: &clap::Command) {
3333
let name = cmd.get_bin_name().unwrap_or_else(|| cmd.get_name());
3434
let mut line = vec![bold(name), roman(" ")];
3535

36-
for opt in cmd.get_arguments().filter(|i| !i.is_hide_set()) {
36+
let mut opts: Vec<_> = cmd.get_arguments().filter(|i| !i.is_hide_set()).collect();
37+
38+
opts.sort_by_key(|opt| option_sort_key(opt));
39+
40+
for opt in opts {
3741
let (lhs, rhs) = option_markers(opt);
3842
match (opt.get_short(), opt.get_long()) {
3943
(Some(short), Some(long)) => {
@@ -89,7 +93,10 @@ pub(crate) fn synopsis(roff: &mut Roff, cmd: &clap::Command) {
8993
}
9094

9195
pub(crate) fn options(roff: &mut Roff, items: &[&Arg]) {
92-
for opt in items.iter().filter(|a| !a.is_positional()) {
96+
let mut sorted_items = items.to_vec();
97+
sorted_items.sort_by_key(|opt| option_sort_key(opt));
98+
99+
for opt in sorted_items.iter().filter(|a| !a.is_positional()) {
93100
let mut header = match (opt.get_short(), opt.get_long()) {
94101
(Some(short), Some(long)) => {
95102
vec![short_option(short), roman(", "), long_option(long)]
@@ -217,7 +224,10 @@ fn possible_options(roff: &mut Roff, arg: &Arg, arg_help_written: bool) {
217224
}
218225

219226
pub(crate) fn subcommands(roff: &mut Roff, cmd: &clap::Command, section: &str) {
220-
for sub in cmd.get_subcommands().filter(|s| !s.is_hide_set()) {
227+
let mut sorted_subcommands: Vec<_> =
228+
cmd.get_subcommands().filter(|s| !s.is_hide_set()).collect();
229+
sorted_subcommands.sort_by_key(|c| subcommand_sort_key(c));
230+
for sub in sorted_subcommands {
221231
roff.control("TP", []);
222232

223233
let name = format!(
@@ -378,3 +388,23 @@ fn format_possible_values(possibles: &Vec<&clap::builder::PossibleValue>) -> (Ve
378388
}
379389
(lines, with_help)
380390
}
391+
392+
fn subcommand_sort_key(command: &clap::Command) -> (usize, &str) {
393+
(command.get_display_order(), command.get_name())
394+
}
395+
396+
/// Note that this function is duplicated from `clap::builder`
397+
fn option_sort_key(arg: &Arg) -> (usize, String) {
398+
let key = if let Some(x) = arg.get_short() {
399+
let mut s = x.to_ascii_lowercase().to_string();
400+
s.push(if x.is_ascii_lowercase() { '0' } else { '1' });
401+
s
402+
} else if let Some(x) = arg.get_long() {
403+
x.to_string()
404+
} else {
405+
let mut s = '{'.to_string();
406+
s.push_str(arg.get_id().as_str());
407+
s
408+
};
409+
(arg.get_display_order(), key)
410+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
.ie \n(.g .ds Aq \(aq
2+
.el .ds Aq '
3+
.TH my-app 1 "my-app "
4+
.SH NAME
5+
my\-app
6+
.SH SYNOPSIS
7+
\fBmy\-app\fR [\fB\-O\fR|\fB\-\-first\fR] [\fB\-P\fR|\fB\-\-second\fR] [\fB\-Q\fR|\fB\-\-third\fR] [\fB\-\-fourth\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fI1st\fR] [\fI2nd\fR] [\fI3rd\fR]
8+
.SH DESCRIPTION
9+
.SH OPTIONS
10+
.TP
11+
\fB\-O\fR, \fB\-\-first\fR
12+
Should be 1st
13+
.TP
14+
\fB\-P\fR, \fB\-\-second\fR
15+
Should be 2nd
16+
.TP
17+
\fB\-Q\fR, \fB\-\-third\fR
18+
Should be 3rd
19+
.TP
20+
\fB\-\-fourth\fR
21+
Should be 4th
22+
.TP
23+
\fB\-h\fR, \fB\-\-help\fR
24+
Print help
25+
.TP
26+
[\fI1st\fR]
27+
1st
28+
.TP
29+
[\fI2nd\fR]
30+
2nd
31+
.TP
32+
[\fI3rd\fR]
33+
3rd
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.ie \n(.g .ds Aq \(aq
2+
.el .ds Aq '
3+
.TH my-app 1 "my-app 1"
4+
.SH NAME
5+
my\-app
6+
.SH SYNOPSIS
7+
\fBmy\-app\fR [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] [\fIsubcommands\fR]
8+
.SH DESCRIPTION
9+
.SH OPTIONS
10+
.TP
11+
\fB\-h\fR, \fB\-\-help\fR
12+
Print help
13+
.TP
14+
\fB\-V\fR, \fB\-\-version\fR
15+
Print version
16+
.SH SUBCOMMANDS
17+
.TP
18+
my\-app\-a1(1)
19+
blah a1
20+
.TP
21+
my\-app\-b1(1)
22+
blah b1
23+
.TP
24+
my\-app\-help(1)
25+
Print this message or the help of the given subcommand(s)
26+
.SH VERSION
27+
v1
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.ie \n(.g .ds Aq \(aq
2+
.el .ds Aq '
3+
.TH my-app 1 "my-app 1"
4+
.SH NAME
5+
my\-app
6+
.SH SYNOPSIS
7+
\fBmy\-app\fR [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] [\fIsubcommands\fR]
8+
.SH DESCRIPTION
9+
.SH OPTIONS
10+
.TP
11+
\fB\-h\fR, \fB\-\-help\fR
12+
Print help
13+
.TP
14+
\fB\-V\fR, \fB\-\-version\fR
15+
Print version
16+
.SH SUBCOMMANDS
17+
.TP
18+
my\-app\-b1(1)
19+
blah b1
20+
.TP
21+
my\-app\-a1(1)
22+
blah a1
23+
.TP
24+
my\-app\-help(1)
25+
Print this message or the help of the given subcommand(s)
26+
.SH VERSION
27+
v1

clap_mangen/tests/testsuite/common.rs

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,40 @@ pub(crate) fn value_name_without_arg(name: &'static str) -> clap::Command {
324324
)
325325
}
326326

327+
pub(crate) fn configured_display_order_args(name: &'static str) -> clap::Command {
328+
clap::Command::new(name)
329+
.arg(clap::Arg::new("1st").help("1st"))
330+
.arg(clap::Arg::new("2nd").help("2nd"))
331+
.arg(clap::Arg::new("3rd").help("3rd").last(true))
332+
.arg(
333+
clap::Arg::new("c")
334+
.long("third")
335+
.short('Q')
336+
.display_order(3)
337+
.help("Should be 3rd"),
338+
)
339+
.arg(
340+
clap::Arg::new("d")
341+
.long("fourth")
342+
.display_order(4)
343+
.help("Should be 4th"),
344+
)
345+
.arg(
346+
clap::Arg::new("a")
347+
.long("first")
348+
.short('O')
349+
.display_order(1)
350+
.help("Should be 1st"),
351+
)
352+
.arg(
353+
clap::Arg::new("b")
354+
.long("second")
355+
.short('P')
356+
.display_order(2)
357+
.help("Should be 2nd"),
358+
)
359+
}
360+
327361
pub(crate) fn help_headings(name: &'static str) -> clap::Command {
328362
clap::Command::new(name)
329363
.arg(
@@ -356,8 +390,7 @@ pub(crate) fn help_headings(name: &'static str) -> clap::Command {
356390
}
357391

358392
pub(crate) fn value_with_required_equals(name: &'static str) -> clap::Command {
359-
clap::Command::new(name)
360-
.arg(
393+
clap::Command::new(name).arg(
361394
clap::Arg::new("config")
362395
.long("config")
363396
.value_name("FILE")
@@ -367,8 +400,7 @@ pub(crate) fn value_with_required_equals(name: &'static str) -> clap::Command {
367400
}
368401

369402
pub(crate) fn optional_value_with_required_equals(name: &'static str) -> clap::Command {
370-
clap::Command::new(name)
371-
.arg(
403+
clap::Command::new(name).arg(
372404
clap::Arg::new("config")
373405
.long("config")
374406
.value_name("FILE")
@@ -379,8 +411,7 @@ pub(crate) fn optional_value_with_required_equals(name: &'static str) -> clap::C
379411
}
380412

381413
pub(crate) fn optional_value(name: &'static str) -> clap::Command {
382-
clap::Command::new(name)
383-
.arg(
414+
clap::Command::new(name).arg(
384415
clap::Arg::new("config")
385416
.long("config")
386417
.value_name("FILE")
@@ -390,8 +421,7 @@ pub(crate) fn optional_value(name: &'static str) -> clap::Command {
390421
}
391422

392423
pub(crate) fn multiple_optional_values(name: &'static str) -> clap::Command {
393-
clap::Command::new(name)
394-
.arg(
424+
clap::Command::new(name).arg(
395425
clap::Arg::new("config")
396426
.long("config")
397427
.value_names(["FILE1", "FILE2"])
@@ -401,13 +431,45 @@ pub(crate) fn multiple_optional_values(name: &'static str) -> clap::Command {
401431
}
402432

403433
pub(crate) fn variadic_values(name: &'static str) -> clap::Command {
404-
clap::Command::new(name)
405-
.arg(
434+
clap::Command::new(name).arg(
406435
clap::Arg::new("config")
407436
.long("config")
408437
.value_names(["FILE1", "FILE2"])
409438
.require_equals(false)
410439
.num_args(3)
411440
.help("Optional config file"),
412441
)
413-
}
442+
}
443+
444+
pub(crate) fn configured_subcmd_order(name: &'static str) -> clap::Command {
445+
clap::Command::new(name)
446+
.version("1")
447+
.next_display_order(None)
448+
.subcommands(vec![
449+
clap::Command::new("b1").about("blah b1").arg(
450+
clap::Arg::new("test")
451+
.short('t')
452+
.action(clap::ArgAction::SetTrue),
453+
),
454+
clap::Command::new("a1").about("blah a1").arg(
455+
clap::Arg::new("roster")
456+
.short('r')
457+
.action(clap::ArgAction::SetTrue),
458+
),
459+
])
460+
}
461+
462+
pub(crate) fn default_subcmd_order(name: &'static str) -> clap::Command {
463+
clap::Command::new(name).version("1").subcommands(vec![
464+
clap::Command::new("b1").about("blah b1").arg(
465+
clap::Arg::new("test")
466+
.short('t')
467+
.action(clap::ArgAction::SetTrue),
468+
),
469+
clap::Command::new("a1").about("blah a1").arg(
470+
clap::Arg::new("roster")
471+
.short('r')
472+
.action(clap::ArgAction::SetTrue),
473+
),
474+
])
475+
}

clap_mangen/tests/testsuite/roff.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,7 @@ fn optional_value_with_required_equals() {
137137
fn optional_value() {
138138
let name = "my-app";
139139
let cmd = common::optional_value(name);
140-
common::assert_matches(
141-
snapbox::file!["../snapshots/optional_value.bash.roff"],
142-
cmd,
143-
);
140+
common::assert_matches(snapbox::file!["../snapshots/optional_value.bash.roff"], cmd);
144141
}
145142

146143
#[test]
@@ -162,3 +159,33 @@ fn variadic_values() {
162159
cmd,
163160
);
164161
}
162+
163+
#[test]
164+
fn configured_display_order_args() {
165+
let name = "my-app";
166+
let cmd = common::configured_display_order_args(name);
167+
common::assert_matches(
168+
snapbox::file!["../snapshots/configured_display_order_args.roff"],
169+
cmd,
170+
);
171+
}
172+
173+
#[test]
174+
fn configured_subcmd_order() {
175+
let name = "my-app";
176+
let cmd = common::configured_subcmd_order(name);
177+
common::assert_matches(
178+
snapbox::file!["../snapshots/configured_subcmd_order.roff"],
179+
cmd,
180+
);
181+
}
182+
183+
#[test]
184+
fn default_subcmd_order() {
185+
let name = "my-app";
186+
let cmd = common::default_subcmd_order(name);
187+
common::assert_matches(
188+
snapbox::file!["../snapshots/default_subcmd_order.roff"],
189+
cmd,
190+
);
191+
}

0 commit comments

Comments
 (0)