Skip to content

Commit

Permalink
feat: Allow disabling derive display order
Browse files Browse the repository at this point in the history
In clap 4.0, we will make `DeriveDisplayOrder` the default and this is
how you'll disable it.

This is part of clap-rs#2808
  • Loading branch information
epage committed Feb 8, 2022
1 parent 5290f82 commit 6ad52f4
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 8 deletions.
59 changes: 51 additions & 8 deletions src/build/app/mod.rs
Expand Up @@ -62,7 +62,7 @@ use crate::{Error, INTERNAL_ERROR_MSG};
/// // Your program logic starts here...
/// ```
/// [`App::get_matches`]: App::get_matches()
#[derive(Default, Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct App<'help> {
pub(crate) id: Id,
pub(crate) name: String,
Expand Down Expand Up @@ -95,7 +95,7 @@ pub struct App<'help> {
pub(crate) replacers: HashMap<&'help str, &'help [&'help str]>,
pub(crate) groups: Vec<ArgGroup<'help>>,
pub(crate) current_help_heading: Option<&'help str>,
pub(crate) current_disp_ord: usize,
pub(crate) current_disp_ord: Option<usize>,
pub(crate) subcommand_value_name: Option<&'help str>,
pub(crate) subcommand_heading: Option<&'help str>,
}
Expand Down Expand Up @@ -170,10 +170,12 @@ impl<'help> App<'help> {
#[must_use]
pub fn arg<A: Into<Arg<'help>>>(mut self, a: A) -> Self {
let mut arg = a.into();
if !arg.is_positional() && arg.provider != ArgProvider::Generated {
let current = self.current_disp_ord;
arg.disp_ord.set_implicit(current);
self.current_disp_ord = current + 1;
if let Some(current_disp_ord) = self.current_disp_ord.as_mut() {
if !arg.is_positional() && arg.provider != ArgProvider::Generated {
let current = *current_disp_ord;
arg.disp_ord.set_implicit(current);
*current_disp_ord = current + 1;
}
}

arg.help_heading.get_or_insert(self.current_help_heading);
Expand Down Expand Up @@ -1374,8 +1376,8 @@ impl<'help> App<'help> {
/// This will be used for any arg that hasn't had [`Arg::display_order`] called.
#[inline]
#[must_use]
pub fn next_display_order(mut self, disp_ord: usize) -> Self {
self.current_disp_ord = disp_ord;
pub fn next_display_order(mut self, disp_ord: impl Into<Option<usize>>) -> Self {
self.current_disp_ord = disp_ord.into();
self
}

Expand Down Expand Up @@ -3355,6 +3357,47 @@ impl<'help> App<'help> {
}
}

impl<'help> Default for App<'help> {
fn default() -> Self {
Self {
id: Default::default(),
name: Default::default(),
long_flag: Default::default(),
short_flag: Default::default(),
bin_name: Default::default(),
author: Default::default(),
version: Default::default(),
long_version: Default::default(),
about: Default::default(),
long_about: Default::default(),
before_help: Default::default(),
before_long_help: Default::default(),
after_help: Default::default(),
after_long_help: Default::default(),
aliases: Default::default(),
short_flag_aliases: Default::default(),
long_flag_aliases: Default::default(),
usage_str: Default::default(),
usage: Default::default(),
help_str: Default::default(),
disp_ord: Default::default(),
term_w: Default::default(),
max_w: Default::default(),
template: Default::default(),
settings: Default::default(),
g_settings: Default::default(),
args: Default::default(),
subcommands: Default::default(),
replacers: Default::default(),
groups: Default::default(),
current_help_heading: Default::default(),
current_disp_ord: Some(0),
subcommand_value_name: Default::default(),
subcommand_heading: Default::default(),
}
}
}

impl<'help> Index<&'_ Id> for App<'help> {
type Output = Arg<'help>;

Expand Down
38 changes: 38 additions & 0 deletions tests/builder/derive_order.rs
Expand Up @@ -172,6 +172,44 @@ OPTIONS:
assert!(utils::compare_output(app, "test --help", HELP, false));
}

#[test]
fn derive_order_no_next_order() {
static HELP: &str = "test 1.2
USAGE:
test [OPTIONS]
OPTIONS:
--flag_a first flag
--flag_b second flag
-h, --help Print help information
--option_a <option_a> first option
--option_b <option_b> second option
-V, --version Print version information
";

let app = App::new("test")
.setting(AppSettings::DeriveDisplayOrder)
.version("1.2")
.next_display_order(None)
.arg(Arg::new("flag_a").long("flag_a").help("first flag"))
.arg(
Arg::new("option_a")
.long("option_a")
.takes_value(true)
.help("first option"),
)
.arg(Arg::new("flag_b").long("flag_b").help("second flag"))
.arg(
Arg::new("option_b")
.long("option_b")
.takes_value(true)
.help("second option"),
);

assert!(utils::compare_output(app, "test --help", HELP, false));
}

#[test]
fn derive_order_subcommand_propagate() {
let app = App::new("test")
Expand Down
56 changes: 56 additions & 0 deletions tests/derive/help.rs
Expand Up @@ -342,3 +342,59 @@ OPTIONS:
let help = String::from_utf8(buffer).unwrap();
assert_eq!(help, HELP);
}

#[test]
fn derive_order_no_next_order() {
static HELP: &str = "test 1.2
USAGE:
test [OPTIONS]
OPTIONS:
--flag-a first flag
--flag-b second flag
-h, --help Print help information
--option-a <OPTION_A> first option
--option-b <OPTION_B> second option
-V, --version Print version information
";

#[derive(Parser, Debug)]
#[clap(name = "test", version = "1.2")]
#[clap(setting = AppSettings::DeriveDisplayOrder)]
#[clap(next_display_order = None)]
struct Args {
#[clap(flatten)]
a: A,
#[clap(flatten)]
b: B,
}

#[derive(Args, Debug)]
struct A {
/// first flag
#[clap(long)]
flag_a: bool,
/// first option
#[clap(long)]
option_a: Option<String>,
}

#[derive(Args, Debug)]
struct B {
/// second flag
#[clap(long)]
flag_b: bool,
/// second option
#[clap(long)]
option_b: Option<String>,
}

use clap::IntoApp;
let mut app = Args::into_app();

let mut buffer: Vec<u8> = Default::default();
app.write_help(&mut buffer).unwrap();
let help = String::from_utf8(buffer).unwrap();
assert_eq!(help, HELP);
}

0 comments on commit 6ad52f4

Please sign in to comment.