mirror of
https://github.com/clap-rs/clap
synced 2024-12-15 07:12:32 +00:00
Lazy subcommand propagation, avoid redundant _build() function call
rustfmt and clippy Indepth cleaning Apply suggestions
This commit is contained in:
parent
5b73699825
commit
2f9846d048
6 changed files with 55 additions and 91 deletions
|
@ -117,7 +117,7 @@ pub trait Generator {
|
||||||
|
|
||||||
/// Gets all the short options, their visible aliases and flags of a [`clap::App`](../clap/struct.App.html).
|
/// Gets all the short options, their visible aliases and flags of a [`clap::App`](../clap/struct.App.html).
|
||||||
/// Includes `h` and `V` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html).
|
/// Includes `h` and `V` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html).
|
||||||
fn shorts_and_visible_aliases<'help>(p: &App<'help>) -> Vec<char> {
|
fn shorts_and_visible_aliases(p: &App) -> Vec<char> {
|
||||||
debug!("shorts: name={}", p.get_name());
|
debug!("shorts: name={}", p.get_name());
|
||||||
|
|
||||||
let mut shorts_and_visible_aliases: Vec<char> = p
|
let mut shorts_and_visible_aliases: Vec<char> = p
|
||||||
|
@ -155,7 +155,7 @@ pub trait Generator {
|
||||||
|
|
||||||
/// Gets all the long options and flags of a [`clap::App`](../clap/struct.App.html).
|
/// Gets all the long options and flags of a [`clap::App`](../clap/struct.App.html).
|
||||||
/// Includes `help` and `version` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html).
|
/// Includes `help` and `version` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html).
|
||||||
fn longs<'help>(p: &App<'help>) -> Vec<String> {
|
fn longs(p: &App) -> Vec<String> {
|
||||||
debug!("longs: name={}", p.get_name());
|
debug!("longs: name={}", p.get_name());
|
||||||
|
|
||||||
let mut longs: Vec<String> = p
|
let mut longs: Vec<String> = p
|
||||||
|
|
|
@ -181,10 +181,8 @@ where
|
||||||
{
|
{
|
||||||
app.set_bin_name(bin_name);
|
app.set_bin_name(bin_name);
|
||||||
|
|
||||||
if !app.is_set(clap::AppSettings::Built) {
|
|
||||||
app._build();
|
app._build();
|
||||||
app._build_bin_names();
|
app._build_bin_names();
|
||||||
}
|
|
||||||
|
|
||||||
G::generate(app, buf)
|
G::generate(app, buf)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,17 +31,6 @@ use crate::{
|
||||||
Result as ClapResult, INTERNAL_ERROR_MSG,
|
Result as ClapResult, INTERNAL_ERROR_MSG,
|
||||||
};
|
};
|
||||||
|
|
||||||
// @TODO FIXME (@CreepySkeleton): some of these variants (None) are never constructed
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub(crate) enum Propagation {
|
|
||||||
To(Id),
|
|
||||||
Full,
|
|
||||||
#[cfg_attr(not(test), allow(unused))]
|
|
||||||
NextLevel,
|
|
||||||
#[allow(unused)]
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents a command line interface which is made up of all possible
|
/// Represents a command line interface which is made up of all possible
|
||||||
/// command line arguments and subcommands. Interface arguments and settings are
|
/// command line arguments and subcommands. Interface arguments and settings are
|
||||||
/// configured using the "builder pattern." Once all configuration is complete,
|
/// configured using the "builder pattern." Once all configuration is complete,
|
||||||
|
@ -1958,9 +1947,7 @@ impl<'help> App<'help> {
|
||||||
pub fn generate_usage(&mut self) -> String {
|
pub fn generate_usage(&mut self) -> String {
|
||||||
// If there are global arguments, or settings we need to propagate them down to subcommands
|
// If there are global arguments, or settings we need to propagate them down to subcommands
|
||||||
// before parsing incase we run into a subcommand
|
// before parsing incase we run into a subcommand
|
||||||
if !self.settings.is_set(AppSettings::Built) {
|
|
||||||
self._build();
|
self._build();
|
||||||
}
|
|
||||||
|
|
||||||
let mut parser = Parser::new(self);
|
let mut parser = Parser::new(self);
|
||||||
parser._build();
|
parser._build();
|
||||||
|
@ -2267,9 +2254,7 @@ impl<'help> App<'help> {
|
||||||
|
|
||||||
// If there are global arguments, or settings we need to propagate them down to subcommands
|
// If there are global arguments, or settings we need to propagate them down to subcommands
|
||||||
// before parsing in case we run into a subcommand
|
// before parsing in case we run into a subcommand
|
||||||
if !self.settings.is_set(AppSettings::Built) {
|
|
||||||
self._build();
|
self._build();
|
||||||
}
|
|
||||||
|
|
||||||
// do the real parsing
|
// do the real parsing
|
||||||
let mut parser = Parser::new(self);
|
let mut parser = Parser::new(self);
|
||||||
|
@ -2292,11 +2277,11 @@ impl<'help> App<'help> {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn _build(&mut self) {
|
pub fn _build(&mut self) {
|
||||||
debug!("App::_build");
|
debug!("App::_build");
|
||||||
|
if !self.settings.is_set(AppSettings::Built) {
|
||||||
// Make sure all the globally set flags apply to us as well
|
// Make sure all the globally set flags apply to us as well
|
||||||
self.settings = self.settings | self.g_settings;
|
self.settings = self.settings | self.g_settings;
|
||||||
|
|
||||||
self._propagate(Propagation::Full);
|
self._propagate();
|
||||||
|
|
||||||
self._derive_display_order();
|
self._derive_display_order();
|
||||||
self._create_help_and_version();
|
self._create_help_and_version();
|
||||||
|
@ -2329,10 +2314,13 @@ impl<'help> App<'help> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.args._build();
|
self.args._build();
|
||||||
self.settings.set(AppSettings::Built);
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
self::debug_asserts::assert_app(self);
|
self::debug_asserts::assert_app(self);
|
||||||
|
self.settings.set(AppSettings::Built);
|
||||||
|
} else {
|
||||||
|
debug!("App::_build: already built");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _panic_on_missing_help(&self, help_required_globally: bool) {
|
fn _panic_on_missing_help(&self, help_required_globally: bool) {
|
||||||
|
@ -2376,7 +2364,8 @@ impl<'help> App<'help> {
|
||||||
two_elements_of(self.groups.iter().filter(|a| condition(a)))
|
two_elements_of(self.groups.iter().filter(|a| condition(a)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn _propagate(&mut self, prop: Propagation) {
|
/// Propagate one and only one level.
|
||||||
|
pub(crate) fn _propagate(&mut self) {
|
||||||
macro_rules! propagate_subcmd {
|
macro_rules! propagate_subcmd {
|
||||||
($_self:expr, $sc:expr) => {{
|
($_self:expr, $sc:expr) => {{
|
||||||
// We have to create a new scope in order to tell rustc the borrow of `sc` is
|
// We have to create a new scope in order to tell rustc the borrow of `sc` is
|
||||||
|
@ -2418,24 +2407,8 @@ impl<'help> App<'help> {
|
||||||
|
|
||||||
debug!("App::_propagate:{}", self.name);
|
debug!("App::_propagate:{}", self.name);
|
||||||
|
|
||||||
match prop {
|
|
||||||
Propagation::NextLevel | Propagation::Full => {
|
|
||||||
for sc in &mut self.subcommands {
|
for sc in &mut self.subcommands {
|
||||||
propagate_subcmd!(self, sc);
|
propagate_subcmd!(self, sc);
|
||||||
if prop == Propagation::Full {
|
|
||||||
sc._propagate(prop.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Propagation::To(id) => {
|
|
||||||
let mut sc = self
|
|
||||||
.subcommands
|
|
||||||
.iter_mut()
|
|
||||||
.find(|sc| sc.id == id)
|
|
||||||
.expect(INTERNAL_ERROR_MSG);
|
|
||||||
propagate_subcmd!(self, sc);
|
|
||||||
}
|
|
||||||
Propagation::None => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{build::app::Propagation, App, AppSettings};
|
use crate::{App, AppSettings};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn global_version() {
|
fn global_version() {
|
||||||
|
@ -6,7 +6,7 @@ fn global_version() {
|
||||||
.setting(AppSettings::GlobalVersion)
|
.setting(AppSettings::GlobalVersion)
|
||||||
.version("1.1")
|
.version("1.1")
|
||||||
.subcommand(App::new("sub1"));
|
.subcommand(App::new("sub1"));
|
||||||
app._propagate(Propagation::NextLevel);
|
app._propagate();
|
||||||
assert_eq!(app.subcommands[0].version, Some("1.1"));
|
assert_eq!(app.subcommands[0].version, Some("1.1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ fn global_setting() {
|
||||||
let mut app = App::new("test")
|
let mut app = App::new("test")
|
||||||
.global_setting(AppSettings::ColoredHelp)
|
.global_setting(AppSettings::ColoredHelp)
|
||||||
.subcommand(App::new("subcmd"));
|
.subcommand(App::new("subcmd"));
|
||||||
app._propagate(Propagation::NextLevel);
|
app._propagate();
|
||||||
assert!(app
|
assert!(app
|
||||||
.subcommands
|
.subcommands
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -30,7 +30,7 @@ fn global_settings() {
|
||||||
.global_setting(AppSettings::ColoredHelp)
|
.global_setting(AppSettings::ColoredHelp)
|
||||||
.global_setting(AppSettings::TrailingVarArg)
|
.global_setting(AppSettings::TrailingVarArg)
|
||||||
.subcommand(App::new("subcmd"));
|
.subcommand(App::new("subcmd"));
|
||||||
app._propagate(Propagation::NextLevel);
|
app._propagate();
|
||||||
assert!(app
|
assert!(app
|
||||||
.subcommands
|
.subcommands
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -44,9 +44,11 @@ impl<'help> UsageParser<'help> {
|
||||||
|
|
||||||
pub(crate) fn parse(mut self) -> Arg<'help> {
|
pub(crate) fn parse(mut self) -> Arg<'help> {
|
||||||
debug!("UsageParser::parse");
|
debug!("UsageParser::parse");
|
||||||
let mut arg = Arg::default();
|
let mut arg = Arg {
|
||||||
arg.disp_ord = 999;
|
disp_ord: 999,
|
||||||
arg.unified_ord = 999;
|
unified_ord: 999,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
loop {
|
loop {
|
||||||
debug!("UsageParser::parse:iter: pos={}", self.pos);
|
debug!("UsageParser::parse:iter: pos={}", self.pos);
|
||||||
self.stop_at(token);
|
self.stop_at(token);
|
||||||
|
|
|
@ -6,7 +6,6 @@ use std::{
|
||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
use crate::{
|
use crate::{
|
||||||
build::app::Propagation,
|
|
||||||
build::AppSettings as AS,
|
build::AppSettings as AS,
|
||||||
build::{App, Arg, ArgSettings},
|
build::{App, Arg, ArgSettings},
|
||||||
mkeymap::KeyType,
|
mkeymap::KeyType,
|
||||||
|
@ -865,9 +864,6 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
help_help = true;
|
help_help = true;
|
||||||
break; // Maybe?
|
break; // Maybe?
|
||||||
}
|
}
|
||||||
if let Some(id) = sc.find_subcommand(cmd).map(|x| x.id.clone()) {
|
|
||||||
sc._propagate(Propagation::To(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(mut c) = sc.find_subcommand(cmd).cloned() {
|
if let Some(mut c) = sc.find_subcommand(cmd).cloned() {
|
||||||
c._build();
|
c._build();
|
||||||
|
@ -975,11 +971,6 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(x) = self.app.find_subcommand(sc_name) {
|
|
||||||
let id = x.id.clone();
|
|
||||||
self.app._propagate(Propagation::To(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(sc) = self.app.subcommands.iter_mut().find(|s| s.name == sc_name) {
|
if let Some(sc) = self.app.subcommands.iter_mut().find(|s| s.name == sc_name) {
|
||||||
let mut sc_matcher = ArgMatcher::default();
|
let mut sc_matcher = ArgMatcher::default();
|
||||||
// Display subcommand name, short and long in usage
|
// Display subcommand name, short and long in usage
|
||||||
|
|
Loading…
Reference in a new issue