mirror of
https://github.com/clap-rs/clap
synced 2024-11-10 14:54:15 +00:00
Merge pull request #3468 from epage/pub2
refactor: Reduce visibility on App members
This commit is contained in:
commit
86864b004b
11 changed files with 283 additions and 189 deletions
|
@ -2,7 +2,7 @@ use clap::AppSettings;
|
||||||
use roff::{bold, italic, roman, Inline, Roff};
|
use roff::{bold, italic, roman, Inline, Roff};
|
||||||
|
|
||||||
pub(crate) fn subcommand_heading(app: &clap::App) -> String {
|
pub(crate) fn subcommand_heading(app: &clap::App) -> String {
|
||||||
match app.get_subommand_help_heading() {
|
match app.get_subcommand_help_heading() {
|
||||||
Some(title) => title.to_string(),
|
Some(title) => title.to_string(),
|
||||||
None => "SUBCOMMANDS".to_string(),
|
None => "SUBCOMMANDS".to_string(),
|
||||||
}
|
}
|
||||||
|
|
138
src/build/app.rs
138
src/build/app.rs
|
@ -3,6 +3,7 @@
|
||||||
// Std
|
// Std
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::ffi::OsStr;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -62,40 +63,40 @@ use crate::build::debug_asserts::assert_app;
|
||||||
/// [`App::get_matches`]: App::get_matches()
|
/// [`App::get_matches`]: App::get_matches()
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct App<'help> {
|
pub struct App<'help> {
|
||||||
pub(crate) id: Id,
|
id: Id,
|
||||||
pub(crate) name: String,
|
name: String,
|
||||||
pub(crate) long_flag: Option<&'help str>,
|
long_flag: Option<&'help str>,
|
||||||
pub(crate) short_flag: Option<char>,
|
short_flag: Option<char>,
|
||||||
pub(crate) bin_name: Option<String>,
|
bin_name: Option<String>,
|
||||||
pub(crate) author: Option<&'help str>,
|
author: Option<&'help str>,
|
||||||
pub(crate) version: Option<&'help str>,
|
version: Option<&'help str>,
|
||||||
pub(crate) long_version: Option<&'help str>,
|
long_version: Option<&'help str>,
|
||||||
pub(crate) about: Option<&'help str>,
|
about: Option<&'help str>,
|
||||||
pub(crate) long_about: Option<&'help str>,
|
long_about: Option<&'help str>,
|
||||||
pub(crate) before_help: Option<&'help str>,
|
before_help: Option<&'help str>,
|
||||||
pub(crate) before_long_help: Option<&'help str>,
|
before_long_help: Option<&'help str>,
|
||||||
pub(crate) after_help: Option<&'help str>,
|
after_help: Option<&'help str>,
|
||||||
pub(crate) after_long_help: Option<&'help str>,
|
after_long_help: Option<&'help str>,
|
||||||
pub(crate) aliases: Vec<(&'help str, bool)>, // (name, visible)
|
aliases: Vec<(&'help str, bool)>, // (name, visible)
|
||||||
pub(crate) short_flag_aliases: Vec<(char, bool)>, // (name, visible)
|
short_flag_aliases: Vec<(char, bool)>, // (name, visible)
|
||||||
pub(crate) long_flag_aliases: Vec<(&'help str, bool)>, // (name, visible)
|
long_flag_aliases: Vec<(&'help str, bool)>, // (name, visible)
|
||||||
pub(crate) usage_str: Option<&'help str>,
|
usage_str: Option<&'help str>,
|
||||||
pub(crate) usage_name: Option<String>,
|
usage_name: Option<String>,
|
||||||
pub(crate) help_str: Option<&'help str>,
|
help_str: Option<&'help str>,
|
||||||
pub(crate) disp_ord: Option<usize>,
|
disp_ord: Option<usize>,
|
||||||
pub(crate) term_w: Option<usize>,
|
term_w: Option<usize>,
|
||||||
pub(crate) max_w: Option<usize>,
|
max_w: Option<usize>,
|
||||||
pub(crate) template: Option<&'help str>,
|
template: Option<&'help str>,
|
||||||
pub(crate) settings: AppFlags,
|
settings: AppFlags,
|
||||||
pub(crate) g_settings: AppFlags,
|
g_settings: AppFlags,
|
||||||
pub(crate) args: MKeyMap<'help>,
|
args: MKeyMap<'help>,
|
||||||
pub(crate) subcommands: Vec<App<'help>>,
|
subcommands: Vec<App<'help>>,
|
||||||
pub(crate) replacers: HashMap<&'help str, &'help [&'help str]>,
|
replacers: HashMap<&'help OsStr, &'help [&'help str]>,
|
||||||
pub(crate) groups: Vec<ArgGroup<'help>>,
|
groups: Vec<ArgGroup<'help>>,
|
||||||
pub(crate) current_help_heading: Option<&'help str>,
|
current_help_heading: Option<&'help str>,
|
||||||
pub(crate) current_disp_ord: Option<usize>,
|
current_disp_ord: Option<usize>,
|
||||||
pub(crate) subcommand_value_name: Option<&'help str>,
|
subcommand_value_name: Option<&'help str>,
|
||||||
pub(crate) subcommand_heading: Option<&'help str>,
|
subcommand_heading: Option<&'help str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Basic API
|
/// Basic API
|
||||||
|
@ -1933,7 +1934,7 @@ impl<'help> App<'help> {
|
||||||
#[cfg(feature = "unstable-replace")]
|
#[cfg(feature = "unstable-replace")]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn replace(mut self, name: &'help str, target: &'help [&'help str]) -> Self {
|
pub fn replace(mut self, name: &'help str, target: &'help [&'help str]) -> Self {
|
||||||
self.replacers.insert(name, target);
|
self.replacers.insert(OsStr::new(name), target);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3151,6 +3152,11 @@ impl<'help> App<'help> {
|
||||||
|
|
||||||
/// Reflection
|
/// Reflection
|
||||||
impl<'help> App<'help> {
|
impl<'help> App<'help> {
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn get_usage_name(&self) -> Option<&str> {
|
||||||
|
self.usage_name.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the name of the binary.
|
/// Get the name of the binary.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_bin_name(&self) -> Option<&str> {
|
pub fn get_bin_name(&self) -> Option<&str> {
|
||||||
|
@ -3324,16 +3330,38 @@ impl<'help> App<'help> {
|
||||||
|
|
||||||
/// Returns the help heading for listing subcommands.
|
/// Returns the help heading for listing subcommands.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_subommand_help_heading(&self) -> Option<&str> {
|
pub fn get_subcommand_help_heading(&self) -> Option<&str> {
|
||||||
self.subcommand_heading
|
self.subcommand_heading
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deprecated, replaced with [`App::get_subcommand_help_heading`]
|
||||||
|
#[inline]
|
||||||
|
#[deprecated(
|
||||||
|
since = "3.1.0",
|
||||||
|
note = "Replaced with `App::get_subcommand_help_heading`"
|
||||||
|
)]
|
||||||
|
pub fn get_subommand_help_heading(&self) -> Option<&str> {
|
||||||
|
self.get_subcommand_help_heading()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the subcommand value name.
|
/// Returns the subcommand value name.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_subcommand_value_name(&self) -> Option<&str> {
|
pub fn get_subcommand_value_name(&self) -> Option<&str> {
|
||||||
self.subcommand_value_name
|
self.subcommand_value_name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the help heading for listing subcommands.
|
||||||
|
#[inline]
|
||||||
|
pub fn get_before_help(&self) -> Option<&str> {
|
||||||
|
self.before_help
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the help heading for listing subcommands.
|
||||||
|
#[inline]
|
||||||
|
pub fn get_before_long_help(&self) -> Option<&str> {
|
||||||
|
self.before_long_help
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the help heading for listing subcommands.
|
/// Returns the help heading for listing subcommands.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_after_help(&self) -> Option<&str> {
|
pub fn get_after_help(&self) -> Option<&str> {
|
||||||
|
@ -3369,6 +3397,12 @@ impl<'help> App<'help> {
|
||||||
self.get_subcommands_mut().find(|s| s.aliases_to(name))
|
self.get_subcommands_mut().find(|s| s.aliases_to(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterate through the set of groups.
|
||||||
|
#[inline]
|
||||||
|
pub fn get_groups(&self) -> impl Iterator<Item = &ArgGroup<'help>> {
|
||||||
|
self.groups.iter()
|
||||||
|
}
|
||||||
|
|
||||||
/// Iterate through the set of arguments.
|
/// Iterate through the set of arguments.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_arguments(&self) -> impl Iterator<Item = &Arg<'help>> {
|
pub fn get_arguments(&self) -> impl Iterator<Item = &Arg<'help>> {
|
||||||
|
@ -3867,6 +3901,38 @@ impl<'help> App<'help> {
|
||||||
|
|
||||||
// Internally used only
|
// Internally used only
|
||||||
impl<'help> App<'help> {
|
impl<'help> App<'help> {
|
||||||
|
pub(crate) fn get_id(&self) -> Id {
|
||||||
|
self.id.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_override_usage(&self) -> Option<&str> {
|
||||||
|
self.usage_str
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_override_help(&self) -> Option<&str> {
|
||||||
|
self.help_str
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_help_template(&self) -> Option<&str> {
|
||||||
|
self.template
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_term_width(&self) -> Option<usize> {
|
||||||
|
self.term_w
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_max_term_width(&self) -> Option<usize> {
|
||||||
|
self.max_w
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_replacement(&self, key: &OsStr) -> Option<&[&str]> {
|
||||||
|
self.replacers.get(key).copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_keymap(&self) -> &MKeyMap<'help> {
|
||||||
|
&self.args
|
||||||
|
}
|
||||||
|
|
||||||
fn get_used_global_args(&self, matches: &ArgMatches, global_arg_vec: &mut Vec<Id>) {
|
fn get_used_global_args(&self, matches: &ArgMatches, global_arg_vec: &mut Vec<Id>) {
|
||||||
global_arg_vec.extend(
|
global_arg_vec.extend(
|
||||||
self.args
|
self.args
|
||||||
|
|
|
@ -7,7 +7,10 @@ fn propagate_version() {
|
||||||
.version("1.1")
|
.version("1.1")
|
||||||
.subcommand(App::new("sub1"));
|
.subcommand(App::new("sub1"));
|
||||||
app._propagate();
|
app._propagate();
|
||||||
assert_eq!(app.subcommands[0].version, Some("1.1"));
|
assert_eq!(
|
||||||
|
app.get_subcommands().next().unwrap().get_version(),
|
||||||
|
Some("1.1")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -17,9 +20,8 @@ fn global_setting() {
|
||||||
.subcommand(App::new("subcmd"));
|
.subcommand(App::new("subcmd"));
|
||||||
app._propagate();
|
app._propagate();
|
||||||
assert!(app
|
assert!(app
|
||||||
.subcommands
|
.get_subcommands()
|
||||||
.iter()
|
.find(|s| s.get_name() == "subcmd")
|
||||||
.find(|s| s.name == "subcmd")
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_disable_version_flag_set());
|
.is_disable_version_flag_set());
|
||||||
}
|
}
|
||||||
|
@ -38,5 +40,9 @@ fn issue_2090() {
|
||||||
.subcommand(App::new("sub"));
|
.subcommand(App::new("sub"));
|
||||||
app._build();
|
app._build();
|
||||||
|
|
||||||
assert!(app.subcommands[0].is_disable_version_flag_set());
|
assert!(app
|
||||||
|
.get_subcommands()
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.is_disable_version_flag_set());
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub(crate) fn assert_app(app: &App) {
|
||||||
let mut long_flags = vec![];
|
let mut long_flags = vec![];
|
||||||
|
|
||||||
// Invalid version flag settings
|
// Invalid version flag settings
|
||||||
if app.version.is_none() && app.long_version.is_none() {
|
if app.get_version().is_none() && app.get_long_version().is_none() {
|
||||||
// PropagateVersion is meaningless if there is no version
|
// PropagateVersion is meaningless if there is no version
|
||||||
assert!(
|
assert!(
|
||||||
!app.is_propagate_version_set(),
|
!app.is_propagate_version_set(),
|
||||||
|
@ -22,37 +22,36 @@ pub(crate) fn assert_app(app: &App) {
|
||||||
|
|
||||||
// Used `App::mut_arg("version", ..) but did not provide any version information to display
|
// Used `App::mut_arg("version", ..) but did not provide any version information to display
|
||||||
let has_mutated_version = app
|
let has_mutated_version = app
|
||||||
.args
|
.get_arguments()
|
||||||
.args()
|
|
||||||
.any(|x| x.id == Id::version_hash() && x.provider == ArgProvider::GeneratedMutated);
|
.any(|x| x.id == Id::version_hash() && x.provider == ArgProvider::GeneratedMutated);
|
||||||
|
|
||||||
if has_mutated_version {
|
if has_mutated_version {
|
||||||
assert!(app.settings.is_set(AppSettings::NoAutoVersion),
|
assert!(app.is_set(AppSettings::NoAutoVersion),
|
||||||
"App {}: Used App::mut_arg(\"version\", ..) without providing App::version, App::long_version or using AppSettings::NoAutoVersion"
|
"App {}: Used App::mut_arg(\"version\", ..) without providing App::version, App::long_version or using AppSettings::NoAutoVersion"
|
||||||
,app.get_name()
|
,app.get_name()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for sc in &app.subcommands {
|
for sc in app.get_subcommands() {
|
||||||
if let Some(s) = sc.short_flag.as_ref() {
|
if let Some(s) = sc.get_short_flag().as_ref() {
|
||||||
short_flags.push(Flag::App(format!("-{}", s), &sc.name));
|
short_flags.push(Flag::App(format!("-{}", s), sc.get_name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (short_alias, _) in &sc.short_flag_aliases {
|
for short_alias in sc.get_all_short_flag_aliases() {
|
||||||
short_flags.push(Flag::App(format!("-{}", short_alias), &sc.name));
|
short_flags.push(Flag::App(format!("-{}", short_alias), sc.get_name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(l) = sc.long_flag.as_ref() {
|
if let Some(l) = sc.get_long_flag().as_ref() {
|
||||||
long_flags.push(Flag::App(format!("--{}", l), &sc.name));
|
long_flags.push(Flag::App(format!("--{}", l), sc.get_name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (long_alias, _) in &sc.long_flag_aliases {
|
for long_alias in sc.get_all_long_flag_aliases() {
|
||||||
long_flags.push(Flag::App(format!("--{}", long_alias), &sc.name));
|
long_flags.push(Flag::App(format!("--{}", long_alias), sc.get_name()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for arg in app.args.args() {
|
for arg in app.get_arguments() {
|
||||||
assert_arg(arg);
|
assert_arg(arg);
|
||||||
|
|
||||||
if let Some(s) = arg.short.as_ref() {
|
if let Some(s) = arg.short.as_ref() {
|
||||||
|
@ -223,10 +222,10 @@ pub(crate) fn assert_app(app: &App) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for group in &app.groups {
|
for group in app.get_groups() {
|
||||||
// Name conflicts
|
// Name conflicts
|
||||||
assert!(
|
assert!(
|
||||||
app.groups.iter().filter(|x| x.id == group.id).count() < 2,
|
app.get_groups().filter(|x| x.id == group.id).count() < 2,
|
||||||
"App {}: Argument group name must be unique\n\n\t'{}' is already in use",
|
"App {}: Argument group name must be unique\n\n\t'{}' is already in use",
|
||||||
app.get_name(),
|
app.get_name(),
|
||||||
group.name,
|
group.name,
|
||||||
|
@ -234,7 +233,7 @@ pub(crate) fn assert_app(app: &App) {
|
||||||
|
|
||||||
// Groups should not have naming conflicts with Args
|
// Groups should not have naming conflicts with Args
|
||||||
assert!(
|
assert!(
|
||||||
!app.args.args().any(|x| x.id == group.id),
|
!app.get_arguments().any(|x| x.id == group.id),
|
||||||
"App {}: Argument group name '{}' must not conflict with argument name",
|
"App {}: Argument group name '{}' must not conflict with argument name",
|
||||||
app.get_name(),
|
app.get_name(),
|
||||||
group.name,
|
group.name,
|
||||||
|
@ -244,8 +243,7 @@ pub(crate) fn assert_app(app: &App) {
|
||||||
if group.required && !group.args.is_empty() {
|
if group.required && !group.args.is_empty() {
|
||||||
assert!(
|
assert!(
|
||||||
group.args.iter().any(|arg| {
|
group.args.iter().any(|arg| {
|
||||||
app.args
|
app.get_arguments()
|
||||||
.args()
|
|
||||||
.any(|x| x.id == *arg && x.default_vals.is_empty())
|
.any(|x| x.id == *arg && x.default_vals.is_empty())
|
||||||
}),
|
}),
|
||||||
"App {}: Argument group '{}' is required but all of it's arguments have a default value.",
|
"App {}: Argument group '{}' is required but all of it's arguments have a default value.",
|
||||||
|
@ -257,7 +255,7 @@ pub(crate) fn assert_app(app: &App) {
|
||||||
for arg in &group.args {
|
for arg in &group.args {
|
||||||
// Args listed inside groups should exist
|
// Args listed inside groups should exist
|
||||||
assert!(
|
assert!(
|
||||||
app.args.args().any(|x| x.id == *arg),
|
app.get_arguments().any(|x| x.id == *arg),
|
||||||
"App {}: Argument group '{}' contains non-existent argument '{:?}'",
|
"App {}: Argument group '{}' contains non-existent argument '{:?}'",
|
||||||
app.get_name(),
|
app.get_name(),
|
||||||
group.name,
|
group.name,
|
||||||
|
@ -276,7 +274,7 @@ pub(crate) fn assert_app(app: &App) {
|
||||||
|
|
||||||
_verify_positionals(app);
|
_verify_positionals(app);
|
||||||
|
|
||||||
if let Some(help_template) = app.template {
|
if let Some(help_template) = app.get_help_template() {
|
||||||
assert!(
|
assert!(
|
||||||
!help_template.contains("{flags}"),
|
!help_template.contains("{flags}"),
|
||||||
"App {}: {}",
|
"App {}: {}",
|
||||||
|
@ -422,7 +420,7 @@ fn _verify_positionals(app: &App) -> bool {
|
||||||
// but no 2)
|
// but no 2)
|
||||||
|
|
||||||
let highest_idx = app
|
let highest_idx = app
|
||||||
.args
|
.get_keymap()
|
||||||
.keys()
|
.keys()
|
||||||
.filter_map(|x| {
|
.filter_map(|x| {
|
||||||
if let KeyType::Position(n) = x {
|
if let KeyType::Position(n) = x {
|
||||||
|
@ -434,7 +432,7 @@ fn _verify_positionals(app: &App) -> bool {
|
||||||
.max()
|
.max()
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
let num_p = app.args.keys().filter(|x| x.is_position()).count();
|
let num_p = app.get_keymap().keys().filter(|x| x.is_position()).count();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
highest_idx == num_p,
|
highest_idx == num_p,
|
||||||
|
@ -455,8 +453,8 @@ fn _verify_positionals(app: &App) -> bool {
|
||||||
|
|
||||||
// We can't pass the closure (it.next()) to the macro directly because each call to
|
// We can't pass the closure (it.next()) to the macro directly because each call to
|
||||||
// find() (iterator, not macro) gets called repeatedly.
|
// find() (iterator, not macro) gets called repeatedly.
|
||||||
let last = &app.args[&KeyType::Position(highest_idx)];
|
let last = &app.get_keymap()[&KeyType::Position(highest_idx)];
|
||||||
let second_to_last = &app.args[&KeyType::Position(highest_idx - 1)];
|
let second_to_last = &app.get_keymap()[&KeyType::Position(highest_idx - 1)];
|
||||||
|
|
||||||
// Either the final positional is required
|
// Either the final positional is required
|
||||||
// Or the second to last has a terminator or .last(true) set
|
// Or the second to last has a terminator or .last(true) set
|
||||||
|
@ -535,7 +533,7 @@ fn _verify_positionals(app: &App) -> bool {
|
||||||
} else {
|
} else {
|
||||||
// Check that if a required positional argument is found, all positions with a lower
|
// Check that if a required positional argument is found, all positions with a lower
|
||||||
// index are also required
|
// index are also required
|
||||||
for p in (1..=num_p).rev().filter_map(|n| app.args.get(&n)) {
|
for p in (1..=num_p).rev().filter_map(|n| app.get_keymap().get(&n)) {
|
||||||
if found {
|
if found {
|
||||||
assert!(
|
assert!(
|
||||||
p.is_required_set(),
|
p.is_required_set(),
|
||||||
|
|
|
@ -182,7 +182,7 @@ impl Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn with_app(self, app: &App) -> Self {
|
pub(crate) fn with_app(self, app: &App) -> Self {
|
||||||
self.set_wait_on_exit(app.settings.is_set(AppSettings::WaitOnError))
|
self.set_wait_on_exit(app.is_set(AppSettings::WaitOnError))
|
||||||
.set_color(app.get_color())
|
.set_color(app.get_color())
|
||||||
.set_help_flag(get_help_flag(app))
|
.set_help_flag(get_help_flag(app))
|
||||||
}
|
}
|
||||||
|
@ -1047,9 +1047,9 @@ fn put_usage(c: &mut Colorizer, usage: impl Into<String>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_help_flag(app: &App) -> Option<&'static str> {
|
fn get_help_flag(app: &App) -> Option<&'static str> {
|
||||||
if !app.settings.is_set(AppSettings::DisableHelpFlag) {
|
if !app.is_disable_help_flag_set() {
|
||||||
Some("--help")
|
Some("--help")
|
||||||
} else if app.has_subcommands() && !app.settings.is_set(AppSettings::DisableHelpSubcommand) {
|
} else if app.has_subcommands() && !app.is_disable_help_subcommand_set() {
|
||||||
Some("help")
|
Some("help")
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -53,12 +53,12 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
use_long: bool,
|
use_long: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug!("Help::new");
|
debug!("Help::new");
|
||||||
let term_w = match app.term_w {
|
let term_w = match app.get_term_width() {
|
||||||
Some(0) => usize::MAX,
|
Some(0) => usize::MAX,
|
||||||
Some(w) => w,
|
Some(w) => w,
|
||||||
None => cmp::min(
|
None => cmp::min(
|
||||||
dimensions().map_or(100, |(w, _)| w),
|
dimensions().map_or(100, |(w, _)| w),
|
||||||
match app.max_w {
|
match app.get_max_term_width() {
|
||||||
None | Some(0) => usize::MAX,
|
None | Some(0) => usize::MAX,
|
||||||
Some(mw) => mw,
|
Some(mw) => mw,
|
||||||
},
|
},
|
||||||
|
@ -80,9 +80,9 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
pub(crate) fn write_help(&mut self) -> io::Result<()> {
|
pub(crate) fn write_help(&mut self) -> io::Result<()> {
|
||||||
debug!("Help::write_help");
|
debug!("Help::write_help");
|
||||||
|
|
||||||
if let Some(h) = self.app.help_str {
|
if let Some(h) = self.app.get_override_help() {
|
||||||
self.none(h)?;
|
self.none(h)?;
|
||||||
} else if let Some(tmpl) = self.app.template {
|
} else if let Some(tmpl) = self.app.get_help_template() {
|
||||||
self.write_templated_help(tmpl)?;
|
self.write_templated_help(tmpl)?;
|
||||||
} else {
|
} else {
|
||||||
let pos = self
|
let pos = self
|
||||||
|
@ -353,9 +353,11 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
fn write_before_help(&mut self) -> io::Result<()> {
|
fn write_before_help(&mut self) -> io::Result<()> {
|
||||||
debug!("Help::write_before_help");
|
debug!("Help::write_before_help");
|
||||||
let before_help = if self.use_long {
|
let before_help = if self.use_long {
|
||||||
self.app.before_long_help.or(self.app.before_help)
|
self.app
|
||||||
|
.get_before_long_help()
|
||||||
|
.or_else(|| self.app.get_before_help())
|
||||||
} else {
|
} else {
|
||||||
self.app.before_help
|
self.app.get_before_help()
|
||||||
};
|
};
|
||||||
if let Some(output) = before_help {
|
if let Some(output) = before_help {
|
||||||
self.none(text_wrapper(&output.replace("{n}", "\n"), self.term_w))?;
|
self.none(text_wrapper(&output.replace("{n}", "\n"), self.term_w))?;
|
||||||
|
@ -367,9 +369,11 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
fn write_after_help(&mut self) -> io::Result<()> {
|
fn write_after_help(&mut self) -> io::Result<()> {
|
||||||
debug!("Help::write_after_help");
|
debug!("Help::write_after_help");
|
||||||
let after_help = if self.use_long {
|
let after_help = if self.use_long {
|
||||||
self.app.after_long_help.or(self.app.after_help)
|
self.app
|
||||||
|
.get_after_long_help()
|
||||||
|
.or_else(|| self.app.get_after_help())
|
||||||
} else {
|
} else {
|
||||||
self.app.after_help
|
self.app.get_after_help()
|
||||||
};
|
};
|
||||||
if let Some(output) = after_help {
|
if let Some(output) = after_help {
|
||||||
self.none("\n\n")?;
|
self.none("\n\n")?;
|
||||||
|
@ -606,9 +610,9 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
|
|
||||||
fn write_about(&mut self, before_new_line: bool, after_new_line: bool) -> io::Result<()> {
|
fn write_about(&mut self, before_new_line: bool, after_new_line: bool) -> io::Result<()> {
|
||||||
let about = if self.use_long {
|
let about = if self.use_long {
|
||||||
self.app.long_about.or(self.app.about)
|
self.app.get_long_about().or_else(|| self.app.get_about())
|
||||||
} else {
|
} else {
|
||||||
self.app.about
|
self.app.get_about()
|
||||||
};
|
};
|
||||||
if let Some(output) = about {
|
if let Some(output) = about {
|
||||||
if before_new_line {
|
if before_new_line {
|
||||||
|
@ -623,7 +627,7 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_author(&mut self, before_new_line: bool, after_new_line: bool) -> io::Result<()> {
|
fn write_author(&mut self, before_new_line: bool, after_new_line: bool) -> io::Result<()> {
|
||||||
if let Some(author) = self.app.author {
|
if let Some(author) = self.app.get_author() {
|
||||||
if before_new_line {
|
if before_new_line {
|
||||||
self.none("\n")?;
|
self.none("\n")?;
|
||||||
}
|
}
|
||||||
|
@ -636,7 +640,10 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_version(&mut self) -> io::Result<()> {
|
fn write_version(&mut self) -> io::Result<()> {
|
||||||
let version = self.app.version.or(self.app.long_version);
|
let version = self
|
||||||
|
.app
|
||||||
|
.get_version()
|
||||||
|
.or_else(|| self.app.get_long_version());
|
||||||
if let Some(output) = version {
|
if let Some(output) = version {
|
||||||
self.none(text_wrapper(output, self.term_w))?;
|
self.none(text_wrapper(output, self.term_w))?;
|
||||||
}
|
}
|
||||||
|
@ -657,20 +664,26 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
|
|
||||||
let spec_vals = &self.sc_spec_vals(app);
|
let spec_vals = &self.sc_spec_vals(app);
|
||||||
|
|
||||||
let about = app.about.or(app.long_about).unwrap_or("");
|
let about = app
|
||||||
|
.get_about()
|
||||||
|
.or_else(|| app.get_long_about())
|
||||||
|
.unwrap_or("");
|
||||||
|
|
||||||
self.subcmd(sc_str, next_line_help, longest)?;
|
self.subcmd(sc_str, next_line_help, longest)?;
|
||||||
self.help(false, about, spec_vals, next_line_help, longest)
|
self.help(false, about, spec_vals, next_line_help, longest)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sc_spec_vals(&self, a: &App) -> String {
|
fn sc_spec_vals(&self, a: &App) -> String {
|
||||||
debug!("Help::sc_spec_vals: a={}", a.name);
|
debug!("Help::sc_spec_vals: a={}", a.get_name());
|
||||||
let mut spec_vals = vec![];
|
let mut spec_vals = vec![];
|
||||||
if !a.aliases.is_empty() || !a.short_flag_aliases.is_empty() {
|
if 0 < a.get_all_aliases().count() || 0 < a.get_all_short_flag_aliases().count() {
|
||||||
debug!("Help::spec_vals: Found aliases...{:?}", a.aliases);
|
debug!(
|
||||||
|
"Help::spec_vals: Found aliases...{:?}",
|
||||||
|
a.get_all_aliases().collect::<Vec<_>>()
|
||||||
|
);
|
||||||
debug!(
|
debug!(
|
||||||
"Help::spec_vals: Found short flag aliases...{:?}",
|
"Help::spec_vals: Found short flag aliases...{:?}",
|
||||||
a.short_flag_aliases
|
a.get_all_short_flag_aliases().collect::<Vec<_>>()
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut short_als = a
|
let mut short_als = a
|
||||||
|
@ -697,7 +710,7 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
// force_next_line
|
// force_next_line
|
||||||
let h = app.about.unwrap_or("");
|
let h = app.get_about().unwrap_or("");
|
||||||
let h_w = display_width(h) + display_width(spec_vals);
|
let h_w = display_width(h) + display_width(spec_vals);
|
||||||
let taken = longest + 12;
|
let taken = longest + 12;
|
||||||
self.term_w >= taken
|
self.term_w >= taken
|
||||||
|
@ -738,8 +751,7 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
|
|
||||||
let custom_headings = self
|
let custom_headings = self
|
||||||
.app
|
.app
|
||||||
.args
|
.get_arguments()
|
||||||
.args()
|
|
||||||
.filter_map(|arg| arg.get_help_heading())
|
.filter_map(|arg| arg.get_help_heading())
|
||||||
.collect::<IndexSet<_>>();
|
.collect::<IndexSet<_>>();
|
||||||
|
|
||||||
|
@ -764,8 +776,7 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
for heading in custom_headings {
|
for heading in custom_headings {
|
||||||
let args = self
|
let args = self
|
||||||
.app
|
.app
|
||||||
.args
|
.get_arguments()
|
||||||
.args()
|
|
||||||
.filter(|a| {
|
.filter(|a| {
|
||||||
if let Some(help_heading) = a.get_help_heading() {
|
if let Some(help_heading) = a.get_help_heading() {
|
||||||
return help_heading == heading;
|
return help_heading == heading;
|
||||||
|
@ -791,7 +802,11 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
self.none("\n\n")?;
|
self.none("\n\n")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.warning(self.app.subcommand_heading.unwrap_or("SUBCOMMANDS"))?;
|
self.warning(
|
||||||
|
self.app
|
||||||
|
.get_subcommand_help_heading()
|
||||||
|
.unwrap_or("SUBCOMMANDS"),
|
||||||
|
)?;
|
||||||
self.warning(":\n")?;
|
self.warning(":\n")?;
|
||||||
|
|
||||||
self.write_subcommands(self.app)?;
|
self.write_subcommands(self.app)?;
|
||||||
|
@ -801,9 +816,16 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Will use next line help on writing subcommands.
|
/// Will use next line help on writing subcommands.
|
||||||
fn will_subcommands_wrap(&self, subcommands: &[App<'help>], longest: usize) -> bool {
|
fn will_subcommands_wrap<'a>(
|
||||||
|
&self,
|
||||||
|
subcommands: impl IntoIterator<Item = &'a App<'help>>,
|
||||||
|
longest: usize,
|
||||||
|
) -> bool
|
||||||
|
where
|
||||||
|
'help: 'a,
|
||||||
|
{
|
||||||
subcommands
|
subcommands
|
||||||
.iter()
|
.into_iter()
|
||||||
.filter(|&subcommand| should_show_subcommand(subcommand))
|
.filter(|&subcommand| should_show_subcommand(subcommand))
|
||||||
.any(|subcommand| {
|
.any(|subcommand| {
|
||||||
let spec_vals = &self.sc_spec_vals(subcommand);
|
let spec_vals = &self.sc_spec_vals(subcommand);
|
||||||
|
@ -818,18 +840,17 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
let mut longest = 2;
|
let mut longest = 2;
|
||||||
let mut ord_v = Vec::new();
|
let mut ord_v = Vec::new();
|
||||||
for subcommand in app
|
for subcommand in app
|
||||||
.subcommands
|
.get_subcommands()
|
||||||
.iter()
|
|
||||||
.filter(|subcommand| should_show_subcommand(subcommand))
|
.filter(|subcommand| should_show_subcommand(subcommand))
|
||||||
{
|
{
|
||||||
let mut sc_str = String::new();
|
let mut sc_str = String::new();
|
||||||
if let Some(short) = subcommand.short_flag {
|
if let Some(short) = subcommand.get_short_flag() {
|
||||||
write!(sc_str, "-{}", short).unwrap();
|
write!(sc_str, "-{}", short).unwrap();
|
||||||
}
|
}
|
||||||
if let Some(long) = subcommand.long_flag {
|
if let Some(long) = subcommand.get_long_flag() {
|
||||||
write!(sc_str, "--{}", long).unwrap();
|
write!(sc_str, "--{}", long).unwrap();
|
||||||
}
|
}
|
||||||
sc_str.push_str(&subcommand.name);
|
sc_str.push_str(subcommand.get_name());
|
||||||
longest = longest.max(display_width(&sc_str));
|
longest = longest.max(display_width(&sc_str));
|
||||||
ord_v.push((subcommand.get_display_order(), sc_str, subcommand));
|
ord_v.push((subcommand.get_display_order(), sc_str, subcommand));
|
||||||
}
|
}
|
||||||
|
@ -837,7 +858,7 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
|
|
||||||
debug!("Help::write_subcommands longest = {}", longest);
|
debug!("Help::write_subcommands longest = {}", longest);
|
||||||
|
|
||||||
let next_line_help = self.will_subcommands_wrap(&app.subcommands, longest);
|
let next_line_help = self.will_subcommands_wrap(app.get_subcommands(), longest);
|
||||||
|
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for (_, sc_str, sc) in &ord_v {
|
for (_, sc_str, sc) in &ord_v {
|
||||||
|
@ -855,15 +876,15 @@ impl<'help, 'app, 'writer> Help<'help, 'app, 'writer> {
|
||||||
fn write_bin_name(&mut self) -> io::Result<()> {
|
fn write_bin_name(&mut self) -> io::Result<()> {
|
||||||
debug!("Help::write_bin_name");
|
debug!("Help::write_bin_name");
|
||||||
|
|
||||||
let bin_name = if let Some(bn) = self.app.bin_name.as_ref() {
|
let bin_name = if let Some(bn) = self.app.get_bin_name() {
|
||||||
if bn.contains(' ') {
|
if bn.contains(' ') {
|
||||||
// In case we're dealing with subcommands i.e. git mv is translated to git-mv
|
// In case we're dealing with subcommands i.e. git mv is translated to git-mv
|
||||||
bn.replace(' ', "-")
|
bn.replace(' ', "-")
|
||||||
} else {
|
} else {
|
||||||
text_wrapper(&self.app.name.replace("{n}", "\n"), self.term_w)
|
text_wrapper(&self.app.get_name().replace("{n}", "\n"), self.term_w)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
text_wrapper(&self.app.name.replace("{n}", "\n"), self.term_w)
|
text_wrapper(&self.app.get_name().replace("{n}", "\n"), self.term_w)
|
||||||
};
|
};
|
||||||
self.good(&bin_name)?;
|
self.good(&bin_name)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -39,7 +39,7 @@ impl<'help, 'app> Usage<'help, 'app> {
|
||||||
// Creates a usage string (*without title*) if one was not provided by the user manually.
|
// Creates a usage string (*without title*) if one was not provided by the user manually.
|
||||||
pub(crate) fn create_usage_no_title(&self, used: &[Id]) -> String {
|
pub(crate) fn create_usage_no_title(&self, used: &[Id]) -> String {
|
||||||
debug!("Usage::create_usage_no_title");
|
debug!("Usage::create_usage_no_title");
|
||||||
if let Some(u) = self.app.usage_str {
|
if let Some(u) = self.app.get_override_usage() {
|
||||||
String::from(&*u)
|
String::from(&*u)
|
||||||
} else if used.is_empty() {
|
} else if used.is_empty() {
|
||||||
self.create_help_usage(true)
|
self.create_help_usage(true)
|
||||||
|
@ -54,11 +54,10 @@ impl<'help, 'app> Usage<'help, 'app> {
|
||||||
let mut usage = String::with_capacity(75);
|
let mut usage = String::with_capacity(75);
|
||||||
let name = self
|
let name = self
|
||||||
.app
|
.app
|
||||||
.usage_name
|
.get_usage_name()
|
||||||
.as_ref()
|
.or_else(|| self.app.get_bin_name())
|
||||||
.or_else(|| self.app.bin_name.as_ref())
|
.unwrap_or_else(|| self.app.get_name());
|
||||||
.unwrap_or(&self.app.name);
|
usage.push_str(name);
|
||||||
usage.push_str(&*name);
|
|
||||||
let req_string = if incl_reqs {
|
let req_string = if incl_reqs {
|
||||||
self.get_required_usage_from(&[], None, false)
|
self.get_required_usage_from(&[], None, false)
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -129,7 +128,7 @@ impl<'help, 'app> Usage<'help, 'app> {
|
||||||
if self.app.has_visible_subcommands() && incl_reqs
|
if self.app.has_visible_subcommands() && incl_reqs
|
||||||
|| self.app.is_allow_external_subcommands_set()
|
|| self.app.is_allow_external_subcommands_set()
|
||||||
{
|
{
|
||||||
let placeholder = self.app.subcommand_value_name.unwrap_or("SUBCOMMAND");
|
let placeholder = self.app.get_subcommand_value_name().unwrap_or("SUBCOMMAND");
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
if self.app.is_subcommand_negates_reqs_set()
|
if self.app.is_subcommand_negates_reqs_set()
|
||||||
|| self.app.is_args_conflicts_with_subcommands_set()
|
|| self.app.is_args_conflicts_with_subcommands_set()
|
||||||
|
@ -172,17 +171,15 @@ impl<'help, 'app> Usage<'help, 'app> {
|
||||||
.fold(String::new(), |acc, s| acc + " " + s);
|
.fold(String::new(), |acc, s| acc + " " + s);
|
||||||
|
|
||||||
usage.push_str(
|
usage.push_str(
|
||||||
&self
|
self.app
|
||||||
.app
|
.get_usage_name()
|
||||||
.usage_name
|
.or_else(|| self.app.get_bin_name())
|
||||||
.as_ref()
|
.unwrap_or_else(|| self.app.get_name()),
|
||||||
.or_else(|| self.app.bin_name.as_ref())
|
|
||||||
.unwrap_or(&self.app.name)[..],
|
|
||||||
);
|
);
|
||||||
usage.push_str(&*r_string);
|
usage.push_str(&*r_string);
|
||||||
if self.app.is_subcommand_required_set() {
|
if self.app.is_subcommand_required_set() {
|
||||||
usage.push_str(" <");
|
usage.push_str(" <");
|
||||||
usage.push_str(self.app.subcommand_value_name.unwrap_or("SUBCOMMAND"));
|
usage.push_str(self.app.get_subcommand_value_name().unwrap_or("SUBCOMMAND"));
|
||||||
usage.push('>');
|
usage.push('>');
|
||||||
}
|
}
|
||||||
usage.shrink_to_fit();
|
usage.shrink_to_fit();
|
||||||
|
@ -204,10 +201,7 @@ impl<'help, 'app> Usage<'help, 'app> {
|
||||||
let required = self.app.groups_for_arg(&pos.id).any(|grp_s| {
|
let required = self.app.groups_for_arg(&pos.id).any(|grp_s| {
|
||||||
debug!("Usage::get_args_tag:iter:{:?}:iter:{:?}", pos.name, grp_s);
|
debug!("Usage::get_args_tag:iter:{:?}:iter:{:?}", pos.name, grp_s);
|
||||||
// if it's part of a required group we don't want to count it
|
// if it's part of a required group we don't want to count it
|
||||||
self.app
|
self.app.get_groups().any(|g| g.required && (g.id == grp_s))
|
||||||
.groups
|
|
||||||
.iter()
|
|
||||||
.any(|g| g.required && (g.id == grp_s))
|
|
||||||
});
|
});
|
||||||
if !required {
|
if !required {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
@ -234,10 +228,7 @@ impl<'help, 'app> Usage<'help, 'app> {
|
||||||
&& !self.app.groups_for_arg(&pos.id).any(|grp_s| {
|
&& !self.app.groups_for_arg(&pos.id).any(|grp_s| {
|
||||||
debug!("Usage::get_args_tag:iter:{:?}:iter:{:?}", pos.name, grp_s);
|
debug!("Usage::get_args_tag:iter:{:?}:iter:{:?}", pos.name, grp_s);
|
||||||
// if it's part of a required group we don't want to count it
|
// if it's part of a required group we don't want to count it
|
||||||
self.app
|
self.app.get_groups().any(|g| g.required && (g.id == grp_s))
|
||||||
.groups
|
|
||||||
.iter()
|
|
||||||
.any(|g| g.required && (g.id == grp_s))
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.expect(INTERNAL_ERROR_MSG);
|
.expect(INTERNAL_ERROR_MSG);
|
||||||
|
@ -319,7 +310,7 @@ impl<'help, 'app> Usage<'help, 'app> {
|
||||||
}
|
}
|
||||||
for grp_s in self.app.groups_for_arg(&f.id) {
|
for grp_s in self.app.groups_for_arg(&f.id) {
|
||||||
debug!("Usage::needs_options_tag:iter:iter: grp_s={:?}", grp_s);
|
debug!("Usage::needs_options_tag:iter:iter: grp_s={:?}", grp_s);
|
||||||
if self.app.groups.iter().any(|g| g.id == grp_s && g.required) {
|
if self.app.get_groups().any(|g| g.id == grp_s && g.required) {
|
||||||
debug!("Usage::needs_options_tag:iter:iter: Group is required");
|
debug!("Usage::needs_options_tag:iter:iter: Group is required");
|
||||||
continue 'outer;
|
continue 'outer;
|
||||||
}
|
}
|
||||||
|
@ -393,8 +384,7 @@ impl<'help, 'app> Usage<'help, 'app> {
|
||||||
|
|
||||||
let args_in_groups = self
|
let args_in_groups = self
|
||||||
.app
|
.app
|
||||||
.groups
|
.get_groups()
|
||||||
.iter()
|
|
||||||
.filter(|gn| required.contains(&gn.id))
|
.filter(|gn| required.contains(&gn.id))
|
||||||
.flat_map(|g| self.app.unroll_args_in_group(&g.id))
|
.flat_map(|g| self.app.unroll_args_in_group(&g.id))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
@ -403,7 +393,7 @@ impl<'help, 'app> Usage<'help, 'app> {
|
||||||
.iter()
|
.iter()
|
||||||
.chain(incls.iter())
|
.chain(incls.iter())
|
||||||
.filter(|name| !self.app.get_positionals().any(|p| &&p.id == name))
|
.filter(|name| !self.app.get_positionals().any(|p| &&p.id == name))
|
||||||
.filter(|name| !self.app.groups.iter().any(|g| &&g.id == name))
|
.filter(|name| !self.app.get_groups().any(|g| &&g.id == name))
|
||||||
.filter(|name| !args_in_groups.contains(name))
|
.filter(|name| !args_in_groups.contains(name))
|
||||||
.filter(|name| !(matcher.is_some() && matcher.as_ref().unwrap().contains(name)))
|
.filter(|name| !(matcher.is_some() && matcher.as_ref().unwrap().contains(name)))
|
||||||
{
|
{
|
||||||
|
@ -414,7 +404,7 @@ impl<'help, 'app> Usage<'help, 'app> {
|
||||||
let mut g_vec: Vec<String> = vec![];
|
let mut g_vec: Vec<String> = vec![];
|
||||||
for g in unrolled_reqs
|
for g in unrolled_reqs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|n| self.app.groups.iter().any(|g| g.id == **n))
|
.filter(|n| self.app.get_groups().any(|g| g.id == **n))
|
||||||
{
|
{
|
||||||
// don't print requirement for required groups that have an arg.
|
// don't print requirement for required groups that have an arg.
|
||||||
if let Some(m) = matcher {
|
if let Some(m) = matcher {
|
||||||
|
|
|
@ -19,12 +19,12 @@ impl ArgMatcher {
|
||||||
ArgMatcher(ArgMatches {
|
ArgMatcher(ArgMatches {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
valid_args: {
|
valid_args: {
|
||||||
let args = _app.args.args().map(|a| a.id.clone());
|
let args = _app.get_arguments().map(|a| a.id.clone());
|
||||||
let groups = _app.groups.iter().map(|g| g.id.clone());
|
let groups = _app.get_groups().map(|g| g.id.clone());
|
||||||
args.chain(groups).collect()
|
args.chain(groups).collect()
|
||||||
},
|
},
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
valid_subcommands: _app.subcommands.iter().map(|sc| sc.id.clone()).collect(),
|
valid_subcommands: _app.get_subcommands().map(|sc| sc.get_id()).collect(),
|
||||||
// HACK: Allow an external subcommand's ArgMatches be a stand-in for any ArgMatches
|
// HACK: Allow an external subcommand's ArgMatches be a stand-in for any ArgMatches
|
||||||
// since users can't detect it and avoid the asserts.
|
// since users can't detect it and avoid the asserts.
|
||||||
//
|
//
|
||||||
|
|
|
@ -33,13 +33,14 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
|
/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
|
||||||
pub(crate) fn did_you_mean_flag<I, T>(
|
pub(crate) fn did_you_mean_flag<'a, 'help, I, T>(
|
||||||
arg: &str,
|
arg: &str,
|
||||||
remaining_args: &[&str],
|
remaining_args: &[&str],
|
||||||
longs: I,
|
longs: I,
|
||||||
subcommands: &mut [App],
|
subcommands: impl IntoIterator<Item = &'a mut App<'help>>,
|
||||||
) -> Option<(String, Option<String>)>
|
) -> Option<(String, Option<String>)>
|
||||||
where
|
where
|
||||||
|
'help: 'a,
|
||||||
T: AsRef<str>,
|
T: AsRef<str>,
|
||||||
I: IntoIterator<Item = T>,
|
I: IntoIterator<Item = T>,
|
||||||
{
|
{
|
||||||
|
@ -48,11 +49,11 @@ where
|
||||||
match did_you_mean(arg, longs).pop() {
|
match did_you_mean(arg, longs).pop() {
|
||||||
Some(candidate) => Some((candidate, None)),
|
Some(candidate) => Some((candidate, None)),
|
||||||
None => subcommands
|
None => subcommands
|
||||||
.iter_mut()
|
.into_iter()
|
||||||
.filter_map(|subcommand| {
|
.filter_map(|subcommand| {
|
||||||
subcommand._build();
|
subcommand._build();
|
||||||
|
|
||||||
let longs = subcommand.args.keys().filter_map(|a| {
|
let longs = subcommand.get_keymap().keys().filter_map(|a| {
|
||||||
if let KeyType::Long(v) = a {
|
if let KeyType::Long(v) = a {
|
||||||
Some(v.to_string_lossy().into_owned())
|
Some(v.to_string_lossy().into_owned())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -79,23 +79,23 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
let mut trailing_values = false;
|
let mut trailing_values = false;
|
||||||
|
|
||||||
// Count of positional args
|
// Count of positional args
|
||||||
let positional_count = self.app.args.keys().filter(|x| x.is_position()).count();
|
let positional_count = self
|
||||||
|
.app
|
||||||
|
.get_keymap()
|
||||||
|
.keys()
|
||||||
|
.filter(|x| x.is_position())
|
||||||
|
.count();
|
||||||
// If any arg sets .last(true)
|
// If any arg sets .last(true)
|
||||||
let contains_last = self.app.args.args().any(|x| x.is_last_set());
|
let contains_last = self.app.get_arguments().any(|x| x.is_last_set());
|
||||||
|
|
||||||
while let Some((arg_os, remaining_args)) = it.next() {
|
while let Some((arg_os, remaining_args)) = it.next() {
|
||||||
// Recover the replaced items if any.
|
// Recover the replaced items if any.
|
||||||
if let Some((_replacer, replaced_items)) = self
|
if let Some(replaced_items) = self.app.get_replacement(arg_os) {
|
||||||
.app
|
|
||||||
.replacers
|
|
||||||
.iter()
|
|
||||||
.find(|(key, _)| OsStr::new(key) == arg_os)
|
|
||||||
{
|
|
||||||
it.insert(replaced_items);
|
|
||||||
debug!(
|
debug!(
|
||||||
"Parser::get_matches_with: found replacer: {:?}, target: {:?}",
|
"Parser::get_matches_with: found replacer: {:?}, target: {:?}",
|
||||||
_replacer, replaced_items
|
arg_os, replaced_items
|
||||||
);
|
);
|
||||||
|
it.insert(replaced_items);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(p) = self.app.args.get(&pos_counter) {
|
if let Some(p) = self.app.get_keymap().get(&pos_counter) {
|
||||||
if p.is_last_set() && !trailing_values {
|
if p.is_last_set() && !trailing_values {
|
||||||
return Err(ClapError::unknown_argument(
|
return Err(ClapError::unknown_argument(
|
||||||
self.app,
|
self.app,
|
||||||
|
@ -464,8 +464,8 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
.app
|
.app
|
||||||
.find_subcommand(pos_sc_name)
|
.find_subcommand(pos_sc_name)
|
||||||
.expect(INTERNAL_ERROR_MSG)
|
.expect(INTERNAL_ERROR_MSG)
|
||||||
.name
|
.get_name()
|
||||||
.clone();
|
.to_owned();
|
||||||
self.parse_subcommand(&sc_name, matcher, it, keep_state)?;
|
self.parse_subcommand(&sc_name, matcher, it, keep_state)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -502,10 +502,9 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
arg_os.to_str_lossy().into_owned(),
|
arg_os.to_str_lossy().into_owned(),
|
||||||
candidates.join(" or "),
|
candidates.join(" or "),
|
||||||
self.app
|
self.app
|
||||||
.bin_name
|
.get_bin_name()
|
||||||
.as_ref()
|
.unwrap_or_else(|| self.app.get_name())
|
||||||
.unwrap_or(&self.app.name)
|
.to_owned(),
|
||||||
.to_string(),
|
|
||||||
Usage::new(self.app).create_usage_with_title(&[]),
|
Usage::new(self.app).create_usage_with_title(&[]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -516,10 +515,9 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
self.app,
|
self.app,
|
||||||
arg_os.to_str_lossy().into_owned(),
|
arg_os.to_str_lossy().into_owned(),
|
||||||
self.app
|
self.app
|
||||||
.bin_name
|
.get_bin_name()
|
||||||
.as_ref()
|
.unwrap_or_else(|| self.app.get_name())
|
||||||
.unwrap_or(&self.app.name)
|
.to_owned(),
|
||||||
.to_string(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ClapError::unknown_argument(
|
ClapError::unknown_argument(
|
||||||
|
@ -552,7 +550,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
// search.
|
// search.
|
||||||
}
|
}
|
||||||
if let Some(sc) = self.app.find_subcommand(arg_os) {
|
if let Some(sc) = self.app.find_subcommand(arg_os) {
|
||||||
return Some(&sc.name);
|
return Some(sc.get_name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
@ -566,7 +564,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
.app
|
.app
|
||||||
.get_subcommands()
|
.get_subcommands()
|
||||||
.fold(Vec::new(), |mut options, sc| {
|
.fold(Vec::new(), |mut options, sc| {
|
||||||
if let Some(long) = sc.long_flag {
|
if let Some(long) = sc.get_long_flag() {
|
||||||
if RawOsStr::from_str(long).starts_with_os(arg_os) {
|
if RawOsStr::from_str(long).starts_with_os(arg_os) {
|
||||||
options.push(long);
|
options.push(long);
|
||||||
}
|
}
|
||||||
|
@ -595,7 +593,11 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
fn parse_help_subcommand(&self, cmds: &[OsString]) -> ClapResult<ParseResult> {
|
fn parse_help_subcommand(&self, cmds: &[OsString]) -> ClapResult<ParseResult> {
|
||||||
debug!("Parser::parse_help_subcommand");
|
debug!("Parser::parse_help_subcommand");
|
||||||
|
|
||||||
let mut bin_name = self.app.bin_name.as_ref().unwrap_or(&self.app.name).clone();
|
let mut bin_name = self
|
||||||
|
.app
|
||||||
|
.get_bin_name()
|
||||||
|
.unwrap_or_else(|| self.app.get_name())
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
let mut sc = {
|
let mut sc = {
|
||||||
let mut sc = self.app.clone();
|
let mut sc = self.app.clone();
|
||||||
|
@ -610,17 +612,16 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
self.app,
|
self.app,
|
||||||
cmd.to_string_lossy().into_owned(),
|
cmd.to_string_lossy().into_owned(),
|
||||||
self.app
|
self.app
|
||||||
.bin_name
|
.get_bin_name()
|
||||||
.as_ref()
|
.unwrap_or_else(|| self.app.get_name())
|
||||||
.unwrap_or(&self.app.name)
|
.to_owned(),
|
||||||
.to_string(),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
sc._build();
|
sc._build();
|
||||||
bin_name.push(' ');
|
bin_name.push(' ');
|
||||||
bin_name.push_str(&sc.name);
|
bin_name.push_str(sc.get_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
sc
|
sc
|
||||||
|
@ -676,7 +677,10 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
if let Some(sc) = self.app._build_subcommand(sc_name) {
|
if let Some(sc) = self.app._build_subcommand(sc_name) {
|
||||||
let mut sc_matcher = ArgMatcher::new(sc);
|
let mut sc_matcher = ArgMatcher::new(sc);
|
||||||
|
|
||||||
debug!("Parser::parse_subcommand: About to parse sc={}", sc.name);
|
debug!(
|
||||||
|
"Parser::parse_subcommand: About to parse sc={}",
|
||||||
|
sc.get_name()
|
||||||
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut p = Parser::new(sc);
|
let mut p = Parser::new(sc);
|
||||||
|
@ -699,8 +703,8 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
matcher.subcommand(SubCommand {
|
matcher.subcommand(SubCommand {
|
||||||
id: sc.id.clone(),
|
id: sc.get_id(),
|
||||||
name: sc.name.clone(),
|
name: sc.get_name().to_owned(),
|
||||||
matches: sc_matcher.into_inner(),
|
matches: sc_matcher.into_inner(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -787,10 +791,10 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
|
|
||||||
// Subcommands aren't checked because we prefer short help for them, deferring to
|
// Subcommands aren't checked because we prefer short help for them, deferring to
|
||||||
// `cmd subcmd --help` for more.
|
// `cmd subcmd --help` for more.
|
||||||
self.app.long_about.is_some()
|
self.app.get_long_about().is_some()
|
||||||
|| self.app.before_long_help.is_some()
|
|| self.app.get_before_long_help().is_some()
|
||||||
|| self.app.after_long_help.is_some()
|
|| self.app.get_after_long_help().is_some()
|
||||||
|| self.app.args.args().any(should_long)
|
|| self.app.get_arguments().any(should_long)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_long_arg(
|
fn parse_long_arg(
|
||||||
|
@ -827,7 +831,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
(long_arg, None)
|
(long_arg, None)
|
||||||
};
|
};
|
||||||
|
|
||||||
let opt = if let Some(opt) = self.app.args.get(&*arg.to_os_str()) {
|
let opt = if let Some(opt) = self.app.get_keymap().get(&*arg.to_os_str()) {
|
||||||
debug!(
|
debug!(
|
||||||
"Parser::parse_long_arg: Found valid opt or flag '{}'",
|
"Parser::parse_long_arg: Found valid opt or flag '{}'",
|
||||||
opt.to_string()
|
opt.to_string()
|
||||||
|
@ -835,7 +839,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
Some(opt)
|
Some(opt)
|
||||||
} else if self.app.is_infer_long_args_set() {
|
} else if self.app.is_infer_long_args_set() {
|
||||||
let arg_str = arg.to_str_lossy();
|
let arg_str = arg.to_str_lossy();
|
||||||
self.app.args.args().find(|a| {
|
self.app.get_arguments().find(|a| {
|
||||||
a.long.map_or(false, |long| long.starts_with(&*arg_str))
|
a.long.map_or(false, |long| long.starts_with(&*arg_str))
|
||||||
|| a.aliases
|
|| a.aliases
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -916,9 +920,14 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
{
|
{
|
||||||
debug!("Parser::parse_short_args: prior arg accepts hyphenated values",);
|
debug!("Parser::parse_short_args: prior arg accepts hyphenated values",);
|
||||||
return ParseResult::MaybeHyphenValue;
|
return ParseResult::MaybeHyphenValue;
|
||||||
} else if self.app.args.get(&pos_counter).map_or(false, |arg| {
|
} else if self
|
||||||
|
.app
|
||||||
|
.get_keymap()
|
||||||
|
.get(&pos_counter)
|
||||||
|
.map_or(false, |arg| {
|
||||||
arg.is_allow_hyphen_values_set() && !arg.is_last_set()
|
arg.is_allow_hyphen_values_set() && !arg.is_last_set()
|
||||||
}) {
|
})
|
||||||
|
{
|
||||||
debug!(
|
debug!(
|
||||||
"Parser::parse_short_args: positional at {} allows hyphens",
|
"Parser::parse_short_args: positional at {} allows hyphens",
|
||||||
pos_counter
|
pos_counter
|
||||||
|
@ -945,7 +954,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
// concatenated value: -oval
|
// concatenated value: -oval
|
||||||
// Option: -o
|
// Option: -o
|
||||||
// Value: val
|
// Value: val
|
||||||
if let Some(opt) = self.app.args.get(&c) {
|
if let Some(opt) = self.app.get_keymap().get(&c) {
|
||||||
debug!(
|
debug!(
|
||||||
"Parser::parse_short_arg:iter:{}: Found valid opt or flag",
|
"Parser::parse_short_arg:iter:{}: Found valid opt or flag",
|
||||||
c
|
c
|
||||||
|
@ -1353,7 +1362,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
) -> ClapResult<()> {
|
) -> ClapResult<()> {
|
||||||
use crate::util::str_to_bool;
|
use crate::util::str_to_bool;
|
||||||
|
|
||||||
self.app.args.args().try_for_each(|a| {
|
self.app.get_arguments().try_for_each(|a| {
|
||||||
// Use env only if the arg was absent among command line args,
|
// Use env only if the arg was absent among command line args,
|
||||||
// early return if this is not the case.
|
// early return if this is not the case.
|
||||||
if matcher
|
if matcher
|
||||||
|
@ -1434,7 +1443,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
// Didn't match a flag or option
|
// Didn't match a flag or option
|
||||||
let longs = self
|
let longs = self
|
||||||
.app
|
.app
|
||||||
.args
|
.get_keymap()
|
||||||
.keys()
|
.keys()
|
||||||
.filter_map(|x| match x {
|
.filter_map(|x| match x {
|
||||||
KeyType::Long(l) => Some(l.to_string_lossy().into_owned()),
|
KeyType::Long(l) => Some(l.to_string_lossy().into_owned()),
|
||||||
|
@ -1447,12 +1456,12 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
arg,
|
arg,
|
||||||
remaining_args,
|
remaining_args,
|
||||||
longs.iter().map(|x| &x[..]),
|
longs.iter().map(|x| &x[..]),
|
||||||
self.app.subcommands.as_mut_slice(),
|
self.app.get_subcommands_mut(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add the arg to the matches to build a proper usage string
|
// Add the arg to the matches to build a proper usage string
|
||||||
if let Some((name, _)) = did_you_mean.as_ref() {
|
if let Some((name, _)) = did_you_mean.as_ref() {
|
||||||
if let Some(opt) = self.app.args.get(&name.as_ref()) {
|
if let Some(opt) = self.app.get_keymap().get(&name.as_ref()) {
|
||||||
self.inc_occurrence_of_arg(matcher, opt);
|
self.inc_occurrence_of_arg(matcher, opt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,11 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> {
|
||||||
}
|
}
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
if !has_subcmd && self.p.app.is_subcommand_required_set() {
|
if !has_subcmd && self.p.app.is_subcommand_required_set() {
|
||||||
let bn = self.p.app.bin_name.as_ref().unwrap_or(&self.p.app.name);
|
let bn = self
|
||||||
|
.p
|
||||||
|
.app
|
||||||
|
.get_bin_name()
|
||||||
|
.unwrap_or_else(|| self.p.app.get_name());
|
||||||
return Err(Error::missing_subcommand(
|
return Err(Error::missing_subcommand(
|
||||||
self.p.app,
|
self.p.app,
|
||||||
bn.to_string(),
|
bn.to_string(),
|
||||||
|
@ -487,7 +491,7 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the conditionally required args
|
// Validate the conditionally required args
|
||||||
for a in self.p.app.args.args() {
|
for a in self.p.app.get_arguments() {
|
||||||
for (other, val) in &a.r_ifs {
|
for (other, val) in &a.r_ifs {
|
||||||
if matcher.check_explicit(other, ArgPredicate::Equals(std::ffi::OsStr::new(*val)))
|
if matcher.check_explicit(other, ArgPredicate::Equals(std::ffi::OsStr::new(*val)))
|
||||||
&& !matcher.contains(&a.id)
|
&& !matcher.contains(&a.id)
|
||||||
|
@ -531,8 +535,7 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> {
|
||||||
let failed_args: Vec<_> = self
|
let failed_args: Vec<_> = self
|
||||||
.p
|
.p
|
||||||
.app
|
.app
|
||||||
.args
|
.get_arguments()
|
||||||
.args()
|
|
||||||
.filter(|&a| {
|
.filter(|&a| {
|
||||||
(!a.r_unless.is_empty() || !a.r_unless_all.is_empty())
|
(!a.r_unless.is_empty() || !a.r_unless_all.is_empty())
|
||||||
&& !matcher.contains(&a.id)
|
&& !matcher.contains(&a.id)
|
||||||
|
|
Loading…
Reference in a new issue