mirror of
https://github.com/clap-rs/clap
synced 2024-12-12 22:02:35 +00:00
Auto merge of #923 - kbknapp:issues-869,900,919,922, r=kbknapp
Issues 869,900,919,922 <!-- Reviewable:start --> This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/kbknapp/clap-rs/923) <!-- Reviewable:end -->
This commit is contained in:
commit
5b669ec520
17 changed files with 571 additions and 219 deletions
31
CHANGELOG.md
31
CHANGELOG.md
|
@ -1,3 +1,34 @@
|
|||
<a name="v2.23.0"></a>
|
||||
## v2.23.0 (2017-04-05)
|
||||
|
||||
|
||||
#### API Additions
|
||||
|
||||
* `App::long_about`
|
||||
* `App::long_version`
|
||||
* `App::print_long_help`
|
||||
* `App::write_long_help`
|
||||
* `App::print_long_version`
|
||||
* `App::write_long_version`
|
||||
* `Arg::long_help`
|
||||
|
||||
#### Features
|
||||
|
||||
* allows distinguishing between short and long version messages (-V/short or --version/long) ([59272b06](https://github.com/kbknapp/clap-rs/commit/59272b06cc213289dc604dbc694cb95d383a5d68))
|
||||
* allows distinguishing between short and long help with subcommands in the same manner as args ([6b371891](https://github.com/kbknapp/clap-rs/commit/6b371891a1702173a849d1e95f9fecb168bf6fc4))
|
||||
* allows specifying a short help vs a long help (i.e. varying levels of detail depending on if -h or --help was used) ([ef1b24c3](https://github.com/kbknapp/clap-rs/commit/ef1b24c3a0dff2f58c5e2e90880fbc2b69df20ee))
|
||||
* **clap_app!:** adds support for arg names with hyphens similar to longs with hyphens ([f7a88779](https://github.com/kbknapp/clap-rs/commit/f7a8877978c8f90e6543d4f0d9600c086cf92cd7), closes [#869](https://github.com/kbknapp/clap-rs/issues/869))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* fixes a bug that wasn't allowing help and version to be properly overridden ([8b2ceb83](https://github.com/kbknapp/clap-rs/commit/8b2ceb8368bcb70689fadf1c7f4b9549184926c1), closes [#922](https://github.com/kbknapp/clap-rs/issues/922))
|
||||
|
||||
#### Documentation
|
||||
|
||||
* **clap_app!:** documents the `--("some-arg")` method for using args with hyphens inside them ([bc08ef3e](https://github.com/kbknapp/clap-rs/commit/bc08ef3e185393073d969d301989b6319c616c1f), closes [#919](https://github.com/kbknapp/clap-rs/issues/919))
|
||||
|
||||
|
||||
|
||||
<a name="v2.22.2"></a>
|
||||
### v2.22.2 (2017-03-30)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
|
||||
name = "clap"
|
||||
version = "2.22.2"
|
||||
version = "2.23.0"
|
||||
authors = ["Kevin K. <kbknapp@gmail.com>"]
|
||||
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
|
||||
repository = "https://github.com/kbknapp/clap-rs.git"
|
||||
|
|
20
README.md
20
README.md
|
@ -45,12 +45,24 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
|
|||
|
||||
## What's New
|
||||
|
||||
Here's the highlights for v2.22.2
|
||||
Here's the highlights for v2.23.0
|
||||
|
||||
* allows specifying a short help vs a long help (i.e. varying levels of detail depending on if -h or --help was used)
|
||||
* **clap_app!:** adds support for arg names with hyphens similar to longs with hyphens
|
||||
* fixes a bug that wasn't allowing help and version to be properly overridden
|
||||
* This may break code that was relying on this bug! If you add a flag with a long of `help` manually *and* rely on the help message to be printed automatically your code could break. Please see the commit link in the full CHANGELOG.md
|
||||
* `App::long_about`
|
||||
* `App::long_version`
|
||||
* `App::print_long_help`
|
||||
* `App::write_long_help`
|
||||
* `App::print_long_version`
|
||||
* `App::write_long_version`
|
||||
* `Arg::long_help`
|
||||
* **clap_app!:** documents the `--("some-arg")` method for using args with hyphens inside them
|
||||
|
||||
Here's the highlights for v2.21.0 to v2.22.2
|
||||
|
||||
* fixes the usage string regression when using help templates
|
||||
|
||||
Here's the highlights for v2.21.0 to v2.22.1
|
||||
|
||||
* fixes a big regression with custom usage strings
|
||||
* adds the ability to change the name of the App instance after creation
|
||||
* adds ability to hide the default value of an argument from the help string
|
||||
|
|
|
@ -89,6 +89,7 @@ pub struct Help<'a> {
|
|||
cizer: Colorizer,
|
||||
longest: usize,
|
||||
force_next_line: bool,
|
||||
use_long: bool,
|
||||
}
|
||||
|
||||
// Public Functions
|
||||
|
@ -100,7 +101,8 @@ impl<'a> Help<'a> {
|
|||
color: bool,
|
||||
cizer: Colorizer,
|
||||
term_w: Option<usize>,
|
||||
max_w: Option<usize>)
|
||||
max_w: Option<usize>,
|
||||
use_long: bool)
|
||||
-> Self {
|
||||
debugln!("Help::new;");
|
||||
Help {
|
||||
|
@ -121,21 +123,22 @@ impl<'a> Help<'a> {
|
|||
cizer: cizer,
|
||||
longest: 0,
|
||||
force_next_line: false,
|
||||
use_long: use_long,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads help settings from an App
|
||||
/// and write its help to the wrapped stream.
|
||||
pub fn write_app_help(w: &'a mut Write, app: &App) -> ClapResult<()> {
|
||||
pub fn write_app_help(w: &'a mut Write, app: &App, use_long: bool) -> ClapResult<()> {
|
||||
debugln!("Help::write_app_help;");
|
||||
Self::write_parser_help(w, &app.p)
|
||||
Self::write_parser_help(w, &app.p, use_long)
|
||||
}
|
||||
|
||||
/// Reads help settings from a Parser
|
||||
/// and write its help to the wrapped stream.
|
||||
pub fn write_parser_help(w: &'a mut Write, parser: &Parser) -> ClapResult<()> {
|
||||
pub fn write_parser_help(w: &'a mut Write, parser: &Parser, use_long: bool) -> ClapResult<()> {
|
||||
debugln!("Help::write_parser_help;");
|
||||
Self::_write_parser_help(w, parser, false)
|
||||
Self::_write_parser_help(w, parser, false, use_long)
|
||||
}
|
||||
|
||||
/// Reads help settings from a Parser
|
||||
|
@ -143,11 +146,11 @@ impl<'a> Help<'a> {
|
|||
/// formatting when required.
|
||||
pub fn write_parser_help_to_stderr(w: &'a mut Write, parser: &Parser) -> ClapResult<()> {
|
||||
debugln!("Help::write_parser_help;");
|
||||
Self::_write_parser_help(w, parser, true)
|
||||
Self::_write_parser_help(w, parser, true, false)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn _write_parser_help(w: &'a mut Write, parser: &Parser, stderr: bool) -> ClapResult<()> {
|
||||
pub fn _write_parser_help(w: &'a mut Write, parser: &Parser, stderr: bool, use_long: bool) -> ClapResult<()> {
|
||||
debugln!("Help::write_parser_help;");
|
||||
let nlh = parser.is_set(AppSettings::NextLineHelp);
|
||||
let hide_v = parser.is_set(AppSettings::HidePossibleValuesInHelp);
|
||||
|
@ -162,8 +165,9 @@ impl<'a> Help<'a> {
|
|||
color,
|
||||
cizer,
|
||||
parser.meta.term_w,
|
||||
parser.meta.max_w)
|
||||
.write_help(parser)
|
||||
parser.meta.max_w,
|
||||
use_long)
|
||||
.write_help(parser)
|
||||
}
|
||||
|
||||
/// Writes the parser help to the wrapped stream.
|
||||
|
@ -191,8 +195,9 @@ impl<'a> Help<'a> {
|
|||
self.longest = 2;
|
||||
let mut arg_v = Vec::with_capacity(10);
|
||||
for arg in args.filter(|arg| {
|
||||
!(arg.is_set(ArgSettings::Hidden)) || arg.is_set(ArgSettings::NextLineHelp)
|
||||
}) {
|
||||
!(arg.is_set(ArgSettings::Hidden)) ||
|
||||
arg.is_set(ArgSettings::NextLineHelp)
|
||||
}) {
|
||||
if arg.longest_filter() {
|
||||
self.longest = cmp::max(self.longest, arg.to_string().len());
|
||||
}
|
||||
|
@ -432,8 +437,12 @@ impl<'a> Help<'a> {
|
|||
fn help<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>, spec_vals: &str) -> io::Result<()> {
|
||||
debugln!("Help::help;");
|
||||
let mut help = String::new();
|
||||
let h = arg.help().unwrap_or("");
|
||||
let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp);
|
||||
let h = if self.use_long {
|
||||
arg.long_help().unwrap_or(arg.help().unwrap_or(""))
|
||||
} else {
|
||||
arg.help().unwrap_or(arg.long_help().unwrap_or(""))
|
||||
};
|
||||
let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) || self.use_long;
|
||||
debugln!("Help::help: Next Line...{:?}", nlh);
|
||||
|
||||
let spcs = if nlh || self.force_next_line {
|
||||
|
@ -513,7 +522,8 @@ impl<'a> Help<'a> {
|
|||
debugln!("Help::spec_vals: Found aliases...{:?}", aliases);
|
||||
spec_vals.push(format!(" [aliases: {}]",
|
||||
if self.color {
|
||||
aliases.iter()
|
||||
aliases
|
||||
.iter()
|
||||
.map(|v| format!("{}", self.cizer.good(v)))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
|
@ -525,14 +535,14 @@ impl<'a> Help<'a> {
|
|||
if let Some(pv) = a.possible_vals() {
|
||||
debugln!("Help::spec_vals: Found possible vals...{:?}", pv);
|
||||
spec_vals.push(if self.color {
|
||||
format!(" [values: {}]",
|
||||
pv.iter()
|
||||
.map(|v| format!("{}", self.cizer.good(v)))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "))
|
||||
} else {
|
||||
format!(" [values: {}]", pv.join(", "))
|
||||
});
|
||||
format!(" [values: {}]",
|
||||
pv.iter()
|
||||
.map(|v| format!("{}", self.cizer.good(v)))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "))
|
||||
} else {
|
||||
format!(" [values: {}]", pv.join(", "))
|
||||
});
|
||||
}
|
||||
}
|
||||
spec_vals.join(" ")
|
||||
|
@ -548,7 +558,10 @@ impl<'a> Help<'a> {
|
|||
pub fn write_all_args(&mut self, parser: &Parser) -> ClapResult<()> {
|
||||
debugln!("Help::write_all_args;");
|
||||
let flags = parser.has_flags();
|
||||
let pos = parser.positionals().filter(|arg| !arg.is_set(ArgSettings::Hidden)).count() > 0;
|
||||
let pos = parser
|
||||
.positionals()
|
||||
.filter(|arg| !arg.is_set(ArgSettings::Hidden))
|
||||
.count() > 0;
|
||||
let opts = parser.has_opts();
|
||||
let subcmds = parser.has_subcommands();
|
||||
|
||||
|
@ -557,7 +570,8 @@ impl<'a> Help<'a> {
|
|||
let mut first = true;
|
||||
|
||||
if unified_help && (flags || opts) {
|
||||
let opts_flags = parser.flags()
|
||||
let opts_flags = parser
|
||||
.flags()
|
||||
.map(as_arg_trait)
|
||||
.chain(parser.opts().map(as_arg_trait));
|
||||
try!(color!(self, "OPTIONS:\n", warning));
|
||||
|
@ -566,8 +580,7 @@ impl<'a> Help<'a> {
|
|||
} else {
|
||||
if flags {
|
||||
try!(color!(self, "FLAGS:\n", warning));
|
||||
try!(self.write_args(parser.flags()
|
||||
.map(as_arg_trait)));
|
||||
try!(self.write_args(parser.flags().map(as_arg_trait)));
|
||||
first = false;
|
||||
}
|
||||
if opts {
|
||||
|
@ -606,8 +619,13 @@ impl<'a> Help<'a> {
|
|||
// The shortest an arg can legally be is 2 (i.e. '-x')
|
||||
self.longest = 2;
|
||||
let mut ord_m = VecMap::new();
|
||||
for sc in parser.subcommands.iter().filter(|s| !s.p.is_set(AppSettings::Hidden)) {
|
||||
let btm = ord_m.entry(sc.p.meta.disp_ord).or_insert(BTreeMap::new());
|
||||
for sc in parser
|
||||
.subcommands
|
||||
.iter()
|
||||
.filter(|s| !s.p.is_set(AppSettings::Hidden)) {
|
||||
let btm = ord_m
|
||||
.entry(sc.p.meta.disp_ord)
|
||||
.or_insert(BTreeMap::new());
|
||||
self.longest = cmp::max(self.longest, sc.p.meta.name.len());
|
||||
btm.insert(sc.p.meta.name.clone(), sc.clone());
|
||||
}
|
||||
|
@ -861,9 +879,9 @@ impl<'a> Help<'a> {
|
|||
|
||||
debugln!("Help::write_template_help:iter: tag_buf={};", unsafe {
|
||||
String::from_utf8_unchecked(tag_buf.get_ref()[0..tag_length]
|
||||
.iter()
|
||||
.map(|&i| i)
|
||||
.collect::<Vec<_>>())
|
||||
.iter()
|
||||
.map(|&i| i)
|
||||
.collect::<Vec<_>>())
|
||||
});
|
||||
match &tag_buf.get_ref()[0..tag_length] {
|
||||
b"?" => {
|
||||
|
@ -894,22 +912,20 @@ impl<'a> Help<'a> {
|
|||
try!(self.write_all_args(&parser));
|
||||
}
|
||||
b"unified" => {
|
||||
let opts_flags = parser.flags()
|
||||
let opts_flags = parser
|
||||
.flags()
|
||||
.map(as_arg_trait)
|
||||
.chain(parser.opts().map(as_arg_trait));
|
||||
try!(self.write_args(opts_flags));
|
||||
}
|
||||
b"flags" => {
|
||||
try!(self.write_args(parser.flags()
|
||||
.map(as_arg_trait)));
|
||||
try!(self.write_args(parser.flags().map(as_arg_trait)));
|
||||
}
|
||||
b"options" => {
|
||||
try!(self.write_args(parser.opts()
|
||||
.map(as_arg_trait)));
|
||||
try!(self.write_args(parser.opts().map(as_arg_trait)));
|
||||
}
|
||||
b"positionals" => {
|
||||
try!(self.write_args(parser.positionals()
|
||||
.map(as_arg_trait)));
|
||||
try!(self.write_args(parser.positionals().map(as_arg_trait)));
|
||||
}
|
||||
b"subcommands" => {
|
||||
try!(self.write_subcommands(&parser));
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct AppMeta<'b> {
|
||||
pub name: String,
|
||||
pub bin_name: Option<String>,
|
||||
pub author: Option<&'b str>,
|
||||
pub version: Option<&'b str>,
|
||||
pub long_version: Option<&'b str>,
|
||||
pub about: Option<&'b str>,
|
||||
pub long_about: Option<&'b str>,
|
||||
pub more_help: Option<&'b str>,
|
||||
pub pre_help: Option<&'b str>,
|
||||
pub aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
|
||||
|
@ -18,51 +21,7 @@ pub struct AppMeta<'b> {
|
|||
pub template: Option<&'b str>,
|
||||
}
|
||||
|
||||
impl<'b> Default for AppMeta<'b> {
|
||||
fn default() -> Self {
|
||||
AppMeta {
|
||||
name: String::new(),
|
||||
author: None,
|
||||
about: None,
|
||||
more_help: None,
|
||||
pre_help: None,
|
||||
version: None,
|
||||
usage_str: None,
|
||||
usage: None,
|
||||
bin_name: None,
|
||||
help_str: None,
|
||||
disp_ord: 999,
|
||||
template: None,
|
||||
aliases: None,
|
||||
term_w: None,
|
||||
max_w: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> AppMeta<'b> {
|
||||
pub fn new() -> Self { Default::default() }
|
||||
pub fn with_name(s: String) -> Self { AppMeta { name: s, ..Default::default() } }
|
||||
}
|
||||
|
||||
impl<'b> Clone for AppMeta<'b> {
|
||||
fn clone(&self) -> Self {
|
||||
AppMeta {
|
||||
name: self.name.clone(),
|
||||
author: self.author,
|
||||
about: self.about,
|
||||
more_help: self.more_help,
|
||||
pre_help: self.pre_help,
|
||||
version: self.version,
|
||||
usage_str: self.usage_str,
|
||||
usage: self.usage.clone(),
|
||||
bin_name: self.bin_name.clone(),
|
||||
help_str: self.help_str,
|
||||
disp_ord: self.disp_ord,
|
||||
template: self.template,
|
||||
aliases: self.aliases.clone(),
|
||||
term_w: self.term_w,
|
||||
max_w: self.max_w,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn with_name(s: String) -> Self { AppMeta { name: s, disp_ord: 999, ..Default::default() } }
|
||||
}
|
183
src/app/mod.rs
183
src/app/mod.rs
|
@ -200,7 +200,13 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
}
|
||||
|
||||
/// Sets a string describing what the program does. This will be displayed when displaying help
|
||||
/// information.
|
||||
/// information with `-h`.
|
||||
///
|
||||
/// **NOTE:** If only `about` is provided, and not [`App::long_about`] but the user requests
|
||||
/// `--help` clap will still display the contents of `about` appropriately
|
||||
///
|
||||
/// **NOTE:** Only [`App::about`] is used in completion script generation in order to be
|
||||
/// concise
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -210,11 +216,38 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
/// .about("Does really amazing things to great people")
|
||||
/// # ;
|
||||
/// ```
|
||||
/// [`App::long_about`]: ./struct.App.html#method.long_about
|
||||
pub fn about<S: Into<&'b str>>(mut self, about: S) -> Self {
|
||||
self.p.meta.about = Some(about.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a string describing what the program does. This will be displayed when displaying help
|
||||
/// information.
|
||||
///
|
||||
/// **NOTE:** If only `long_about` is provided, and not [`App::about`] but the user requests
|
||||
/// `-h` clap will still display the contents of `long_about` appropriately
|
||||
///
|
||||
/// **NOTE:** Only [`App::about`] is used in completion script generation in order to be
|
||||
/// concise
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap::{App, Arg};
|
||||
/// App::new("myprog")
|
||||
/// .long_about(
|
||||
/// "Does really amazing things to great people. Now let's talk a little
|
||||
/// more in depth about how this subcommand really works. It may take about
|
||||
/// a few lines of text, but that's ok!")
|
||||
/// # ;
|
||||
/// ```
|
||||
/// [`App::about`]: ./struct.App.html#method.about
|
||||
pub fn long_about<S: Into<&'b str>>(mut self, about: S) -> Self {
|
||||
self.p.meta.long_about = Some(about.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the program's name. This will be displayed when displaying help information.
|
||||
///
|
||||
/// **Pro-top:** This function is particularly useful when configuring a program via
|
||||
|
@ -277,7 +310,10 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
}
|
||||
|
||||
/// Sets a string of the version number to be displayed when displaying version or help
|
||||
/// information.
|
||||
/// information with `-V`.
|
||||
///
|
||||
/// **NOTE:** If only `version` is provided, and not [`App::long_version`] but the user
|
||||
/// requests `--version` clap will still display the contents of `version` appropriately
|
||||
///
|
||||
/// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your
|
||||
/// application's version to the same thing as your crate at compile time. See the [`examples/`]
|
||||
|
@ -293,11 +329,43 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
/// ```
|
||||
/// [`crate_version!`]: ./macro.crate_version!.html
|
||||
/// [`examples/`]: https://github.com/kbknapp/clap-rs/tree/master/examples
|
||||
/// [`App::long_version`]: ./struct.App.html#method.long_version
|
||||
pub fn version<S: Into<&'b str>>(mut self, ver: S) -> Self {
|
||||
self.p.meta.version = Some(ver.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a string of the version number to be displayed when displaying version or help
|
||||
/// information with `--version`.
|
||||
///
|
||||
/// **NOTE:** If only `long_version` is provided, and not [`App::version`] but the user
|
||||
/// requests `-V` clap will still display the contents of `long_version` appropriately
|
||||
///
|
||||
/// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your
|
||||
/// application's version to the same thing as your crate at compile time. See the [`examples/`]
|
||||
/// directory for more information
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap::{App, Arg};
|
||||
/// App::new("myprog")
|
||||
/// .long_version(
|
||||
/// "v0.1.24
|
||||
/// commit: abcdef89726d
|
||||
/// revision: 123
|
||||
/// release: 2
|
||||
/// binary: myprog")
|
||||
/// # ;
|
||||
/// ```
|
||||
/// [`crate_version!`]: ./macro.crate_version!.html
|
||||
/// [`examples/`]: https://github.com/kbknapp/clap-rs/tree/master/examples
|
||||
/// [`App::version`]: ./struct.App.html#method.version
|
||||
pub fn long_version<S: Into<&'b str>>(mut self, ver: S) -> Self {
|
||||
self.p.meta.long_version = Some(ver.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a custom usage string to override the auto-generated usage string.
|
||||
///
|
||||
/// This will be displayed to the user when errors are found in argument parsing, or when you
|
||||
|
@ -1062,7 +1130,11 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Prints the full help message to [`io::stdout()`] using a [`BufWriter`]
|
||||
/// Prints the full help message to [`io::stdout()`] using a [`BufWriter`] using the same
|
||||
/// method as if someone ran `-h` to request the help message
|
||||
///
|
||||
/// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
|
||||
/// depending on if the user ran [`-h` (short)] or [`--help` (long)]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -1073,6 +1145,8 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
/// ```
|
||||
/// [`io::stdout()`]: https://doc.rust-lang.org/std/io/fn.stdout.html
|
||||
/// [`BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html
|
||||
/// [`-h` (short)]: ./struct.Arg.html#method.help
|
||||
/// [`--help` (long)]: ./struct.Arg.html#method.long_help
|
||||
pub fn print_help(&mut self) -> ClapResult<()> {
|
||||
// If there are global arguments, or settings we need to propgate them down to subcommands
|
||||
// before parsing incase we run into a subcommand
|
||||
|
@ -1086,7 +1160,45 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
self.write_help(&mut buf_w)
|
||||
}
|
||||
|
||||
/// Writes the full help message to the user to a [`io::Write`] object
|
||||
/// Prints the full help message to [`io::stdout()`] using a [`BufWriter`] using the same
|
||||
/// method as if someone ran `-h` to request the help message
|
||||
///
|
||||
/// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
|
||||
/// depending on if the user ran [`-h` (short)] or [`--help` (long)]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap::App;
|
||||
/// let mut app = App::new("myprog");
|
||||
/// app.print_long_help();
|
||||
/// ```
|
||||
/// [`io::stdout()`]: https://doc.rust-lang.org/std/io/fn.stdout.html
|
||||
/// [`BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html
|
||||
/// [`-h` (short)]: ./struct.Arg.html#method.help
|
||||
/// [`--help` (long)]: ./struct.Arg.html#method.long_help
|
||||
pub fn print_long_help(&mut self) -> ClapResult<()> {
|
||||
// If there are global arguments, or settings we need to propgate them down to subcommands
|
||||
// before parsing incase we run into a subcommand
|
||||
self.p.propogate_globals();
|
||||
self.p.propogate_settings();
|
||||
self.p.derive_display_order();
|
||||
|
||||
self.p.create_help_and_version();
|
||||
let out = io::stdout();
|
||||
let mut buf_w = BufWriter::new(out.lock());
|
||||
self.write_long_help(&mut buf_w)
|
||||
}
|
||||
|
||||
/// Writes the full help message to the user to a [`io::Write`] object in the same method as if
|
||||
/// the user ran `-h`
|
||||
///
|
||||
/// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
|
||||
/// depending on if the user ran [`-h` (short)] or [`--help` (long)]
|
||||
///
|
||||
/// **NOTE:** There is a known bug where this method does not write propogated global arguments
|
||||
/// or autogenerated arguments (i.e. the default help/version args). Prefer
|
||||
/// [`App::write_long_help`] instead if possibe!
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -1098,6 +1210,8 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
/// app.write_help(&mut out).expect("failed to write to stdout");
|
||||
/// ```
|
||||
/// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
|
||||
/// [`-h` (short)]: ./struct.Arg.html#method.help
|
||||
/// [`--help` (long)]: ./struct.Arg.html#method.long_help
|
||||
pub fn write_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
|
||||
// PENDING ISSUE: 808
|
||||
// https://github.com/kbknapp/clap-rs/issues/808
|
||||
|
@ -1108,10 +1222,40 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
// self.p.derive_display_order();
|
||||
// self.p.create_help_and_version();
|
||||
|
||||
Help::write_app_help(w, self)
|
||||
Help::write_app_help(w, self, false)
|
||||
}
|
||||
|
||||
/// Writes the version message to the user to a [`io::Write`] object
|
||||
/// Writes the full help message to the user to a [`io::Write`] object in the same method as if
|
||||
/// the user ran `--help`
|
||||
///
|
||||
/// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
|
||||
/// depending on if the user ran [`-h` (short)] or [`--help` (long)]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap::App;
|
||||
/// use std::io;
|
||||
/// let mut app = App::new("myprog");
|
||||
/// let mut out = io::stdout();
|
||||
/// app.write_long_help(&mut out).expect("failed to write to stdout");
|
||||
/// ```
|
||||
/// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
|
||||
/// [`-h` (short)]: ./struct.Arg.html#method.help
|
||||
/// [`--help` (long)]: ./struct.Arg.html#method.long_help
|
||||
pub fn write_long_help<W: Write>(&mut self, w: &mut W) -> ClapResult<()> {
|
||||
self.p.propogate_globals();
|
||||
self.p.propogate_settings();
|
||||
self.p.derive_display_order();
|
||||
self.p.create_help_and_version();
|
||||
|
||||
Help::write_app_help(w, self, true)
|
||||
}
|
||||
|
||||
/// Writes the version message to the user to a [`io::Write`] object as if the user ran `-V`.
|
||||
///
|
||||
/// **NOTE:** clap has the ability to distinguish between "short" and "long" version messages
|
||||
/// depending on if the user ran [`-V` (short)] or [`--version` (long)]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -1123,10 +1267,32 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
/// app.write_version(&mut out).expect("failed to write to stdout");
|
||||
/// ```
|
||||
/// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
|
||||
/// [`-V` (short)]: ./struct.App.html#method.version
|
||||
/// [`--version` (long)]: ./struct.App.html#method.long_version
|
||||
pub fn write_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
|
||||
self.p.write_version(w).map_err(From::from)
|
||||
self.p.write_version(w, false).map_err(From::from)
|
||||
}
|
||||
|
||||
/// Writes the version message to the user to a [`io::Write`] object
|
||||
///
|
||||
/// **NOTE:** clap has the ability to distinguish between "short" and "long" version messages
|
||||
/// depending on if the user ran [`-V` (short)] or [`--version` (long)]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap::App;
|
||||
/// use std::io;
|
||||
/// let mut app = App::new("myprog");
|
||||
/// let mut out = io::stdout();
|
||||
/// app.write_long_version(&mut out).expect("failed to write to stdout");
|
||||
/// ```
|
||||
/// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
|
||||
/// [`-V` (short)]: ./struct.App.html#method.version
|
||||
/// [`--version` (long)]: ./struct.App.html#method.long_version
|
||||
pub fn write_long_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
|
||||
self.p.write_version(w, true).map_err(From::from)
|
||||
}
|
||||
|
||||
/// Generate a completions file for a specified shell at compile time.
|
||||
///
|
||||
|
@ -1183,7 +1349,7 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
/// build = "build.rs"
|
||||
///
|
||||
/// [build-dependencies]
|
||||
/// clap = "2.9"
|
||||
/// clap = "2.23"
|
||||
/// ```
|
||||
///
|
||||
/// Next, we place a `build.rs` in our project root.
|
||||
|
@ -1622,6 +1788,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for App<'n, 'e> {
|
|||
fn val_delim(&self) -> Option<char> { None }
|
||||
fn takes_value(&self) -> bool { true }
|
||||
fn help(&self) -> Option<&'e str> { self.p.meta.about }
|
||||
fn long_help(&self) -> Option<&'e str> { self.p.meta.long_about }
|
||||
fn default_val(&self) -> Option<&'e OsStr> { None }
|
||||
fn default_vals_ifs(&self) -> Option<vec_map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
|
||||
None
|
||||
|
|
|
@ -63,7 +63,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
where 'a: 'b
|
||||
{
|
||||
pub fn with_name(n: String) -> Self {
|
||||
Parser { meta: AppMeta::with_name(n), ..Default::default() }
|
||||
Parser {
|
||||
meta: AppMeta::with_name(n),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn help_short(&mut self, s: &str) {
|
||||
|
@ -98,11 +101,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
use std::error::Error;
|
||||
|
||||
let out_dir = PathBuf::from(od);
|
||||
let name = &*self.meta
|
||||
.bin_name
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.clone();
|
||||
let name = &*self.meta.bin_name.as_ref().unwrap().clone();
|
||||
let file_name = match for_shell {
|
||||
Shell::Bash => format!("{}.bash-completion", name),
|
||||
Shell::Fish => format!("{}.fish", name),
|
||||
|
@ -146,7 +145,9 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
global and required",
|
||||
a.b.name);
|
||||
if a.b.is_set(ArgSettings::Last) {
|
||||
assert!(!self.positionals.values().any(|p| p.b.is_set(ArgSettings::Last)),
|
||||
assert!(!self.positionals
|
||||
.values()
|
||||
.any(|p| p.b.is_set(ArgSettings::Last)),
|
||||
"Only one positional argument may have last(true) set. Found two.");
|
||||
assert!(a.s.long.is_none(),
|
||||
"Flags or Options may not have last(true) set. {} has both a long and last(true) set.",
|
||||
|
@ -190,7 +191,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
if a.is_set(ArgSettings::Required) {
|
||||
// If the arg is required, add all it's requirements to master required list
|
||||
if let Some(ref areqs) = a.b.requires {
|
||||
for name in areqs.iter().filter(|&&(val, _)| val.is_none()).map(|&(_, name)| name) {
|
||||
for name in areqs
|
||||
.iter()
|
||||
.filter(|&&(val, _)| val.is_none())
|
||||
.map(|&(_, name)| name) {
|
||||
self.required.push(name);
|
||||
}
|
||||
}
|
||||
|
@ -206,6 +210,13 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
self.set(AS::DontCollapseArgsInUsage);
|
||||
self.set(AS::ContainsLast);
|
||||
}
|
||||
if let Some(l) = a.s.long {
|
||||
if l == "version" {
|
||||
self.unset(AS::NeedsLongVersion);
|
||||
} else if l == "help" {
|
||||
self.unset(AS::NeedsLongHelp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// actually adds the arguments
|
||||
|
@ -225,7 +236,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
} else {
|
||||
a.index.unwrap() as usize
|
||||
};
|
||||
self.positionals.insert(i, PosBuilder::from_arg(a, i as u64));
|
||||
self.positionals
|
||||
.insert(i, PosBuilder::from_arg(a, i as u64));
|
||||
} else if a.is_set(ArgSettings::TakesValue) {
|
||||
let mut ob = OptBuilder::from(a);
|
||||
ob.s.unified_ord = self.flags.len() + self.opts.len();
|
||||
|
@ -319,11 +331,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
if vsc {
|
||||
sc.p.set(AS::DisableVersion);
|
||||
}
|
||||
if gv &&
|
||||
sc.p
|
||||
.meta
|
||||
.version
|
||||
.is_none() && self.meta.version.is_some() {
|
||||
if gv && sc.p.meta.version.is_none() && self.meta.version.is_some() {
|
||||
sc.p.set(AS::GlobalVersion);
|
||||
sc.p.meta.version = Some(self.meta.version.unwrap());
|
||||
}
|
||||
|
@ -397,7 +405,9 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
if self.flags.is_empty() {
|
||||
return false;
|
||||
}
|
||||
self.flags.iter().any(|f| !f.is_set(ArgSettings::Hidden))
|
||||
self.flags
|
||||
.iter()
|
||||
.any(|f| !f.is_set(ArgSettings::Hidden))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -405,7 +415,9 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
if self.positionals.is_empty() {
|
||||
return false;
|
||||
}
|
||||
self.positionals.values().any(|p| !p.is_set(ArgSettings::Hidden))
|
||||
self.positionals
|
||||
.values()
|
||||
.any(|p| !p.is_set(ArgSettings::Hidden))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -433,10 +445,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
// Firt we verify that the index highest supplied index, is equal to the number of
|
||||
// positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
|
||||
// but no 2)
|
||||
if let Some((idx, p)) = self.positionals
|
||||
.iter()
|
||||
.rev()
|
||||
.next() {
|
||||
if let Some((idx, p)) = self.positionals.iter().rev().next() {
|
||||
assert!(!(idx != self.positionals.len()),
|
||||
"Found positional argument \"{}\" who's index is {} but there \
|
||||
are only {} positional arguments defined",
|
||||
|
@ -446,10 +455,12 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
}
|
||||
|
||||
// Next we verify that only the highest index has a .multiple(true) (if any)
|
||||
if self.positionals.values().any(|a| {
|
||||
a.b.is_set(ArgSettings::Multiple) &&
|
||||
(a.index as usize != self.positionals.len())
|
||||
}) {
|
||||
if self.positionals
|
||||
.values()
|
||||
.any(|a| {
|
||||
a.b.is_set(ArgSettings::Multiple) &&
|
||||
(a.index as usize != self.positionals.len())
|
||||
}) {
|
||||
let mut it = self.positionals.values().rev();
|
||||
let last = it.next().unwrap();
|
||||
let second_to_last = it.next().unwrap();
|
||||
|
@ -535,10 +546,11 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
}
|
||||
}
|
||||
}
|
||||
if self.positionals.values().any(|p| {
|
||||
p.b.is_set(ArgSettings::Last) &&
|
||||
p.b.is_set(ArgSettings::Required)
|
||||
}) && self.has_subcommands() &&
|
||||
if self.positionals
|
||||
.values()
|
||||
.any(|p| {
|
||||
p.b.is_set(ArgSettings::Last) && p.b.is_set(ArgSettings::Required)
|
||||
}) && self.has_subcommands() &&
|
||||
!self.is_set(AS::SubcommandsNegateReqs) {
|
||||
panic!("Having a required positional argument with .last(true) set *and* child \
|
||||
subcommands without setting SubcommandsNegateReqs isn't compatible.");
|
||||
|
@ -587,10 +599,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
.iter()
|
||||
.filter(|s| {
|
||||
starts(&s.p.meta.name[..], &*arg_os) ||
|
||||
(s.p
|
||||
.meta
|
||||
.aliases
|
||||
.is_some() &&
|
||||
(s.p.meta.aliases.is_some() &&
|
||||
s.p
|
||||
.meta
|
||||
.aliases
|
||||
|
@ -673,7 +682,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
if sc.meta.bin_name != self.meta.bin_name {
|
||||
sc.meta.bin_name = Some(format!("{} {}", bin_name, sc.meta.name));
|
||||
}
|
||||
sc._help()
|
||||
sc._help(false)
|
||||
}
|
||||
|
||||
// allow wrong self convention due to self.valid_neg_num = true and it's a private method
|
||||
|
@ -743,11 +752,16 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
debugln!("Parser::get_matches_with;");
|
||||
// Verify all positional assertions pass
|
||||
debug_assert!(self.verify_positionals());
|
||||
if self.positionals.values().any(|a| {
|
||||
a.b.is_set(ArgSettings::Multiple) &&
|
||||
(a.index as usize != self.positionals.len())
|
||||
}) &&
|
||||
self.positionals.values().last().map_or(false, |p| !p.is_set(ArgSettings::Last)) {
|
||||
if self.positionals
|
||||
.values()
|
||||
.any(|a| {
|
||||
a.b.is_set(ArgSettings::Multiple) &&
|
||||
(a.index as usize != self.positionals.len())
|
||||
}) &&
|
||||
self.positionals
|
||||
.values()
|
||||
.last()
|
||||
.map_or(false, |p| !p.is_set(ArgSettings::Last)) {
|
||||
self.settings.set(AS::LowIndexMultiplePositional);
|
||||
}
|
||||
let has_args = self.has_args();
|
||||
|
@ -836,7 +850,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
!self.is_set(AS::InferSubcommands) {
|
||||
if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(),
|
||||
sc_names!(self)) {
|
||||
return Err(Error::invalid_subcommand(arg_os.to_string_lossy()
|
||||
return Err(Error::invalid_subcommand(arg_os
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
cdate,
|
||||
self.meta
|
||||
|
@ -955,7 +970,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
None),
|
||||
self.color()));
|
||||
} else {
|
||||
return Err(Error::unrecognized_subcommand(arg_os.to_string_lossy()
|
||||
return Err(Error::unrecognized_subcommand(arg_os
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
self.meta
|
||||
.bin_name
|
||||
|
@ -977,10 +993,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
};
|
||||
try!(self.parse_subcommand(&*sc_name, matcher, it));
|
||||
} else if self.is_set(AS::SubcommandRequired) {
|
||||
let bn = self.meta
|
||||
.bin_name
|
||||
.as_ref()
|
||||
.unwrap_or(&self.meta.name);
|
||||
let bn = self.meta.bin_name.as_ref().unwrap_or(&self.meta.name);
|
||||
return Err(Error::missing_subcommand(bn,
|
||||
&usage::create_error_usage(self, matcher, None),
|
||||
self.color()));
|
||||
|
@ -1011,10 +1024,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
debugln!("Parser::build_bin_names;");
|
||||
for sc in &mut self.subcommands {
|
||||
debug!("Parser::build_bin_names:iter: bin_name set...");
|
||||
if sc.p
|
||||
.meta
|
||||
.bin_name
|
||||
.is_none() {
|
||||
if sc.p.meta.bin_name.is_none() {
|
||||
sdebugln!("No");
|
||||
let bin_name = format!("{}{}{}",
|
||||
self.meta
|
||||
|
@ -1052,10 +1062,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
debugln!("Parser::parse_subcommand;");
|
||||
let mut mid_string = String::new();
|
||||
if !self.is_set(AS::SubcommandsNegateReqs) {
|
||||
let mut hs: Vec<&str> = self.required
|
||||
.iter()
|
||||
.map(|n| &**n)
|
||||
.collect();
|
||||
let mut hs: Vec<&str> = self.required.iter().map(|n| &**n).collect();
|
||||
for k in matcher.arg_names() {
|
||||
hs.push(k);
|
||||
}
|
||||
|
@ -1066,41 +1073,35 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
}
|
||||
}
|
||||
mid_string.push_str(" ");
|
||||
if let Some(ref mut sc) = self.subcommands.iter_mut().find(|s| &s.p.meta.name == &sc_name) {
|
||||
if let Some(ref mut sc) = self.subcommands
|
||||
.iter_mut()
|
||||
.find(|s| &s.p.meta.name == &sc_name) {
|
||||
let mut sc_matcher = ArgMatcher::new();
|
||||
// bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
|
||||
// a space
|
||||
sc.p.meta.usage = Some(format!("{}{}{}",
|
||||
self.meta
|
||||
.bin_name
|
||||
.as_ref()
|
||||
.unwrap_or(&String::new()),
|
||||
self.meta.bin_name.as_ref().unwrap_or(&String::new()),
|
||||
if self.meta.bin_name.is_some() {
|
||||
&*mid_string
|
||||
} else {
|
||||
""
|
||||
},
|
||||
&*sc.p.meta.name));
|
||||
sc.p.meta.bin_name = Some(format!("{}{}{}",
|
||||
self.meta
|
||||
.bin_name
|
||||
.as_ref()
|
||||
.unwrap_or(&String::new()),
|
||||
if self.meta.bin_name.is_some() {
|
||||
" "
|
||||
} else {
|
||||
""
|
||||
},
|
||||
&*sc.p.meta.name));
|
||||
sc.p.meta.bin_name =
|
||||
Some(format!("{}{}{}",
|
||||
self.meta.bin_name.as_ref().unwrap_or(&String::new()),
|
||||
if self.meta.bin_name.is_some() {
|
||||
" "
|
||||
} else {
|
||||
""
|
||||
},
|
||||
&*sc.p.meta.name));
|
||||
debugln!("Parser::parse_subcommand: About to parse sc={}",
|
||||
sc.p.meta.name);
|
||||
debugln!("Parser::parse_subcommand: sc settings={:#?}", sc.p.settings);
|
||||
try!(sc.p.get_matches_with(&mut sc_matcher, it));
|
||||
matcher.subcommand(SubCommand {
|
||||
name: sc.p
|
||||
.meta
|
||||
.name
|
||||
.clone(),
|
||||
name: sc.p.meta.name.clone(),
|
||||
matches: sc_matcher.into(),
|
||||
});
|
||||
}
|
||||
|
@ -1211,7 +1212,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
let arg = FlagBuilder {
|
||||
b: Base {
|
||||
name: "vclap_version",
|
||||
help: self.version_message.or(Some("Prints version information")),
|
||||
help: self.version_message
|
||||
.or(Some("Prints version information")),
|
||||
..Default::default()
|
||||
},
|
||||
s: Switched {
|
||||
|
@ -1239,11 +1241,11 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
arg.to_str().unwrap());
|
||||
if arg == "help" && self.is_set(AS::NeedsLongHelp) {
|
||||
sdebugln!("Help");
|
||||
try!(self._help());
|
||||
try!(self._help(true));
|
||||
}
|
||||
if arg == "version" && self.is_set(AS::NeedsLongVersion) {
|
||||
sdebugln!("Version");
|
||||
try!(self._version());
|
||||
try!(self._version(true));
|
||||
}
|
||||
sdebugln!("Neither");
|
||||
|
||||
|
@ -1257,22 +1259,37 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
if let Some(h) = self.help_short {
|
||||
if arg == h && self.is_set(AS::NeedsLongHelp) {
|
||||
sdebugln!("Help");
|
||||
try!(self._help());
|
||||
try!(self._help(false));
|
||||
}
|
||||
}
|
||||
if let Some(v) = self.version_short {
|
||||
if arg == v && self.is_set(AS::NeedsLongVersion) {
|
||||
sdebugln!("Version");
|
||||
try!(self._version());
|
||||
try!(self._version(false));
|
||||
}
|
||||
}
|
||||
sdebugln!("Neither");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _help(&self) -> ClapResult<()> {
|
||||
fn use_long_help(&self) -> bool {
|
||||
let ul = self.flags.iter().any(|f| f.b.long_help.is_some()) ||
|
||||
self.opts.iter().any(|o| o.b.long_help.is_some()) ||
|
||||
self.positionals
|
||||
.values()
|
||||
.any(|p| p.b.long_help.is_some()) ||
|
||||
self.subcommands
|
||||
.iter()
|
||||
.any(|s| s.p.meta.long_about.is_some());
|
||||
debugln!("Parser::use_long_help: ret={:?}", ul);
|
||||
ul
|
||||
}
|
||||
|
||||
fn _help(&self, mut use_long: bool) -> ClapResult<()> {
|
||||
debugln!("Parser::_help: use_long={:?}", use_long);
|
||||
use_long = use_long && self.use_long_help();
|
||||
let mut buf = vec![];
|
||||
try!(Help::write_parser_help(&mut buf, self));
|
||||
try!(Help::write_parser_help(&mut buf, self, use_long));
|
||||
Err(Error {
|
||||
message: unsafe { String::from_utf8_unchecked(buf) },
|
||||
kind: ErrorKind::HelpDisplayed,
|
||||
|
@ -1280,10 +1297,11 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
})
|
||||
}
|
||||
|
||||
fn _version(&self) -> ClapResult<()> {
|
||||
fn _version(&self, use_long: bool) -> ClapResult<()> {
|
||||
debugln!("Parser::_version: ");
|
||||
let out = io::stdout();
|
||||
let mut buf_w = BufWriter::new(out.lock());
|
||||
try!(self.print_version(&mut buf_w));
|
||||
try!(self.print_version(&mut buf_w, use_long));
|
||||
Err(Error {
|
||||
message: String::new(),
|
||||
kind: ErrorKind::VersionDisplayed,
|
||||
|
@ -1344,7 +1362,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
}
|
||||
|
||||
debugln!("Parser::parse_long_arg: Didn't match anything");
|
||||
self.did_you_mean_error(arg.to_str().expect(INVALID_UTF8), matcher).map(|_| None)
|
||||
self.did_you_mean_error(arg.to_str().expect(INVALID_UTF8), matcher)
|
||||
.map(|_| None)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "lints", allow(len_zero))]
|
||||
|
@ -1470,7 +1489,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
|
||||
matcher.inc_occurrence_of(opt.b.name);
|
||||
// Increment or create the group "args"
|
||||
self.groups_for_arg(opt.b.name).and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
|
||||
self.groups_for_arg(opt.b.name)
|
||||
.and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
|
||||
|
||||
if val.is_none() ||
|
||||
!has_eq &&
|
||||
|
@ -1556,7 +1576,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
|
||||
matcher.inc_occurrence_of(flag.b.name);
|
||||
// Increment or create the group "args"
|
||||
self.groups_for_arg(flag.b.name).and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
|
||||
self.groups_for_arg(flag.b.name)
|
||||
.and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1589,30 +1610,30 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
}
|
||||
|
||||
// Prints the version to the user and exits if quit=true
|
||||
fn print_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
|
||||
try!(self.write_version(w));
|
||||
fn print_version<W: Write>(&self, w: &mut W, use_long: bool) -> ClapResult<()> {
|
||||
try!(self.write_version(w, use_long));
|
||||
w.flush().map_err(Error::from)
|
||||
}
|
||||
|
||||
pub fn write_version<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
pub fn write_version<W: Write>(&self, w: &mut W, use_long: bool) -> io::Result<()> {
|
||||
let ver = if use_long {
|
||||
self.meta
|
||||
.long_version
|
||||
.unwrap_or(self.meta.version.unwrap_or("".into()))
|
||||
} else {
|
||||
self.meta
|
||||
.version
|
||||
.unwrap_or(self.meta.long_version.unwrap_or("".into()))
|
||||
};
|
||||
if let Some(bn) = self.meta.bin_name.as_ref() {
|
||||
if bn.contains(' ') {
|
||||
// Incase we're dealing with subcommands i.e. git mv is translated to git-mv
|
||||
write!(w,
|
||||
"{} {}",
|
||||
bn.replace(" ", "-"),
|
||||
self.meta.version.unwrap_or("".into()))
|
||||
write!(w, "{} {}", bn.replace(" ", "-"), ver)
|
||||
} else {
|
||||
write!(w,
|
||||
"{} {}",
|
||||
&self.meta.name[..],
|
||||
self.meta.version.unwrap_or("".into()))
|
||||
write!(w, "{} {}", &self.meta.name[..], ver)
|
||||
}
|
||||
} else {
|
||||
write!(w,
|
||||
"{} {}",
|
||||
&self.meta.name[..],
|
||||
self.meta.version.unwrap_or("".into()))
|
||||
write!(w, "{} {}", &self.meta.name[..], ver)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1623,7 +1644,11 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
}
|
||||
|
||||
pub fn write_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
|
||||
Help::write_parser_help(w, self)
|
||||
Help::write_parser_help(w, self, false)
|
||||
}
|
||||
|
||||
pub fn write_long_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
|
||||
Help::write_parser_help(w, self, true)
|
||||
}
|
||||
|
||||
pub fn write_help_err<W: Write>(&self, w: &mut W) -> ClapResult<()> {
|
||||
|
@ -1730,20 +1755,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
pub fn find_subcommand(&'b self, sc: &str) -> Option<&'b App<'a, 'b>> {
|
||||
debugln!("Parser::find_subcommand: sc={}", sc);
|
||||
debugln!("Parser::find_subcommand: Currently in Parser...{}",
|
||||
self.meta
|
||||
.bin_name
|
||||
.as_ref()
|
||||
.unwrap());
|
||||
self.meta.bin_name.as_ref().unwrap());
|
||||
for s in self.subcommands.iter() {
|
||||
if s.p
|
||||
.meta
|
||||
.bin_name
|
||||
.as_ref()
|
||||
.unwrap_or(&String::new()) == sc ||
|
||||
(s.p
|
||||
.meta
|
||||
.aliases
|
||||
.is_some() &&
|
||||
if s.p.meta.bin_name.as_ref().unwrap_or(&String::new()) == sc ||
|
||||
(s.p.meta.aliases.is_some() &&
|
||||
s.p
|
||||
.meta
|
||||
.aliases
|
||||
|
@ -1751,12 +1766,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
.unwrap()
|
||||
.iter()
|
||||
.any(|&(s, _)| {
|
||||
s ==
|
||||
sc.split(' ')
|
||||
.rev()
|
||||
.next()
|
||||
.expect(INTERNAL_ERROR_MSG)
|
||||
})) {
|
||||
s == sc.split(' ').rev().next().expect(INTERNAL_ERROR_MSG)
|
||||
})) {
|
||||
return Some(s);
|
||||
}
|
||||
if let Some(app) = s.p.find_subcommand(sc) {
|
||||
|
|
|
@ -32,6 +32,7 @@ pub trait AnyArg<'n, 'e>: std_fmt::Display {
|
|||
fn takes_value(&self) -> bool;
|
||||
fn val_names(&self) -> Option<&VecMap<&'e str>>;
|
||||
fn help(&self) -> Option<&'e str>;
|
||||
fn long_help(&self) -> Option<&'e str>;
|
||||
fn default_val(&self) -> Option<&'e OsStr>;
|
||||
fn default_vals_ifs(&self) -> Option<vec_map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>>;
|
||||
fn longest_filter(&self) -> bool;
|
||||
|
|
|
@ -103,6 +103,7 @@ impl<'a, 'b> Arg<'a, 'b> {
|
|||
"long" => yaml_to_str!(a, v, long),
|
||||
"aliases" => yaml_vec_or_str!(v, a, alias),
|
||||
"help" => yaml_to_str!(a, v, help),
|
||||
"long_help" => yaml_to_str!(a, v, long_help),
|
||||
"required" => yaml_to_bool!(a, v, required),
|
||||
"required_if" => yaml_tuple2!(a, v, required_if),
|
||||
"required_ifs" => yaml_tuple2!(a, v, required_if),
|
||||
|
@ -489,8 +490,14 @@ impl<'a, 'b> Arg<'a, 'b> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Sets the help text of the argument that will be displayed to the user when they print the
|
||||
/// usage/help information.
|
||||
/// Sets the short help text of the argument that will be displayed to the user when they print
|
||||
/// the help information with `-h`. Typically, this is a short (one line) description of the
|
||||
/// arg.
|
||||
///
|
||||
/// **NOTE:** If only `Arg::help` is provided, and not [`Arg::long_help`] but the user requests
|
||||
/// `--help` clap will still display the contents of `help` appropriately
|
||||
///
|
||||
/// **NOTE:** Only `Arg::help` is used in completion script generation in order to be concise
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -532,11 +539,83 @@ impl<'a, 'b> Arg<'a, 'b> {
|
|||
/// -h, --help Prints help information
|
||||
/// -V, --version Prints version information
|
||||
/// ```
|
||||
/// [`Arg::long_help`]: ./struct.Arg.html#method.long_help
|
||||
pub fn help(mut self, h: &'b str) -> Self {
|
||||
self.b.help = Some(h);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the long help text of the argument that will be displayed to the user when they print
|
||||
/// the help information with `--help`. Typically this a more detailed (multi-line) message
|
||||
/// that describes the arg.
|
||||
///
|
||||
/// **NOTE:** If only `long_help` is provided, and not [`Arg::help`] but the user requests `-h`
|
||||
/// clap will still display the contents of `long_help` appropriately
|
||||
///
|
||||
/// **NOTE:** Only [`Arg::help`] is used in completion script generation in order to be concise
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Any valid UTF-8 is allowed in the help text. The one exception is when one wishes to
|
||||
/// include a newline in the help text and have the following text be properly aligned with all
|
||||
/// the other help text.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap::{App, Arg};
|
||||
/// Arg::with_name("config")
|
||||
/// .long_help(
|
||||
/// "The config file used by the myprog must be in JSON format
|
||||
/// with only valid keys and may not contain other nonsense
|
||||
/// that cannot be read by this program. Obviously I'm going on
|
||||
/// and on, so I'll stop now.")
|
||||
/// # ;
|
||||
/// ```
|
||||
///
|
||||
/// Setting `help` displays a short message to the side of the argument when the user passes
|
||||
/// `-h` or `--help` (by default).
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap::{App, Arg};
|
||||
/// let m = App::new("prog")
|
||||
/// .arg(Arg::with_name("cfg")
|
||||
/// .long("config")
|
||||
/// .long_help(
|
||||
/// "The config file used by the myprog must be in JSON format
|
||||
/// with only valid keys and may not contain other nonsense
|
||||
/// that cannot be read by this program. Obviously I'm going on
|
||||
/// and on, so I'll stop now."))
|
||||
/// .get_matches_from(vec![
|
||||
/// "prog", "--help"
|
||||
/// ]);
|
||||
/// ```
|
||||
///
|
||||
/// The above example displays
|
||||
///
|
||||
/// ```notrust
|
||||
/// helptest
|
||||
///
|
||||
/// USAGE:
|
||||
/// helptest [FLAGS]
|
||||
///
|
||||
/// FLAGS:
|
||||
/// --config
|
||||
/// The config file used by the myprog must be in JSON format
|
||||
/// with only valid keys and may not contain other nonsense
|
||||
/// that cannot be read by this program. Obviously I'm going on
|
||||
/// and on, so I'll stop now.
|
||||
///
|
||||
/// -h, --help
|
||||
/// Prints help information
|
||||
///
|
||||
/// -V, --version
|
||||
/// Prints version information
|
||||
/// ```
|
||||
/// [`Arg::help`]: ./struct.Arg.html#method.help
|
||||
pub fn long_help(mut self, h: &'b str) -> Self {
|
||||
self.b.long_help = Some(h);
|
||||
self
|
||||
}
|
||||
|
||||
/// Specifies that this arg is the last, or final, positional argument (i.e. has the highest
|
||||
/// index) and is *only* able to be accessed via the `--` syntax (i.e. `$ prog args --
|
||||
/// last_arg`). Even, if no other arguments are left to parse, if the user omits the `--` syntax
|
||||
|
|
|
@ -7,6 +7,7 @@ pub struct Base<'a, 'b>
|
|||
{
|
||||
pub name: &'a str,
|
||||
pub help: Option<&'b str>,
|
||||
pub long_help: Option<&'b str>,
|
||||
pub blacklist: Option<Vec<&'a str>>,
|
||||
pub settings: ArgFlags,
|
||||
pub r_unless: Option<Vec<&'a str>>,
|
||||
|
|
|
@ -79,6 +79,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> {
|
|||
fn long(&self) -> Option<&'e str> { self.s.long }
|
||||
fn val_delim(&self) -> Option<char> { None }
|
||||
fn help(&self) -> Option<&'e str> { self.b.help }
|
||||
fn long_help(&self) -> Option<&'e str> { self.b.long_help }
|
||||
fn val_terminator(&self) -> Option<&'e str> { None }
|
||||
fn default_val(&self) -> Option<&'e OsStr> { None }
|
||||
fn default_vals_ifs(&self) -> Option<vec_map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
|
||||
|
|
|
@ -129,6 +129,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for OptBuilder<'n, 'e> {
|
|||
fn val_delim(&self) -> Option<char> { self.v.val_delim }
|
||||
fn takes_value(&self) -> bool { true }
|
||||
fn help(&self) -> Option<&'e str> { self.b.help }
|
||||
fn long_help(&self) -> Option<&'e str> { self.b.long_help }
|
||||
fn default_val(&self) -> Option<&'e OsStr> { self.v.default_val }
|
||||
fn default_vals_ifs(&self) -> Option<vec_map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
|
||||
self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
|
||||
|
|
|
@ -126,6 +126,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for PosBuilder<'n, 'e> {
|
|||
fn val_delim(&self) -> Option<char> { self.v.val_delim }
|
||||
fn takes_value(&self) -> bool { true }
|
||||
fn help(&self) -> Option<&'e str> { self.b.help }
|
||||
fn long_help(&self) -> Option<&'e str> { self.b.long_help }
|
||||
fn default_vals_ifs(&self) -> Option<vec_map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
|
||||
self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
|
||||
}
|
||||
|
|
|
@ -562,6 +562,8 @@ macro_rules! app_from_crate {
|
|||
///
|
||||
/// * A single hyphen followed by a character (such as `-c`) sets the [`Arg::short`]
|
||||
/// * A double hyphen followed by a character or word (such as `--config`) sets [`Arg::long`]
|
||||
/// * If one wishes to use a [`Arg::long`] with a hyphen inside (i.e. `--config-file`), you
|
||||
/// must use `--("config-file")` due to limitations of the Rust macro system.
|
||||
/// * Three dots (`...`) sets [`Arg::multiple(true)`]
|
||||
/// * Angled brackets after either a short or long will set [`Arg::value_name`] and
|
||||
/// `Arg::required(true)` such as `--config <FILE>` = `Arg::value_name("FILE")` and
|
||||
|
@ -595,6 +597,13 @@ macro_rules! app_from_crate {
|
|||
#[macro_export]
|
||||
macro_rules! clap_app {
|
||||
(@app ($builder:expr)) => { $builder };
|
||||
(@app ($builder:expr) (@arg ($name:expr): $($tail:tt)*) $($tt:tt)*) => {
|
||||
clap_app!{ @app
|
||||
($builder.arg(
|
||||
clap_app!{ @arg ($crate::Arg::with_name($name)) (-) $($tail)* }))
|
||||
$($tt)*
|
||||
}
|
||||
};
|
||||
(@app ($builder:expr) (@arg $name:ident: $($tail:tt)*) $($tt:tt)*) => {
|
||||
clap_app!{ @app
|
||||
($builder.arg(
|
||||
|
|
|
@ -831,3 +831,16 @@ fn hidden_default_val() {
|
|||
.default_value("default-argument"));
|
||||
assert!(test::compare_output(app2, "default --help", HIDE_DEFAULT_VAL, false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn override_help() {
|
||||
let m = App::new("test")
|
||||
.author("Kevin K.")
|
||||
.about("tests stuff")
|
||||
.version("1.3")
|
||||
.arg(Arg::from_usage("-H, --help 'some help'"))
|
||||
.get_matches_from_safe(vec!["test", "--help"]);
|
||||
|
||||
assert!(m.is_ok());
|
||||
assert!(m.unwrap().is_present("help"));
|
||||
}
|
|
@ -110,3 +110,40 @@ fn quoted_arg_long_name() {
|
|||
.expect("Expected to successfully match the given args.");
|
||||
assert!(matches.is_present("option2"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quoted_arg_name() {
|
||||
let app = clap_app!(claptests =>
|
||||
(version: "0.1")
|
||||
(about: "tests clap library")
|
||||
(author: "Kevin K. <kbknapp@gmail.com>")
|
||||
(@arg opt: -o --option +takes_value ... "tests options")
|
||||
(@arg ("positional-arg"): index(1) "tests positionals")
|
||||
(@arg flag: -f --flag ... +global "tests flags")
|
||||
(@arg flag2: -F conflicts_with[flag] requires[option2]
|
||||
"tests flags with exclusions")
|
||||
(@arg option2: --("long-option-2") conflicts_with[option] requires[positional2]
|
||||
"tests long options with exclusions")
|
||||
(@arg positional2: index(2) "tests positionals with exclusions")
|
||||
(@arg option3: -O --Option +takes_value possible_value[fast slow]
|
||||
"tests options with specific value sets")
|
||||
(@arg ("positional-3"): index(3) ... possible_value[vi emacs]
|
||||
"tests positionals with specific values")
|
||||
(@arg multvals: --multvals +takes_value value_name[one two]
|
||||
"Tests mutliple values, not mult occs")
|
||||
(@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
|
||||
"Tests mutliple values, not mult occs")
|
||||
(@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
|
||||
(@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
|
||||
(@subcommand subcmd =>
|
||||
(about: "tests subcommands")
|
||||
(version: "0.1")
|
||||
(author: "Kevin K. <kbknapp@gmail.com>")
|
||||
(@arg scoption: -o --option ... +takes_value "tests options")
|
||||
(@arg scpositional: index(1) "tests positionals"))
|
||||
);
|
||||
|
||||
let matches = app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"])
|
||||
.expect("Expected to successfully match the given args.");
|
||||
assert!(matches.is_present("option2"));
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ extern crate regex;
|
|||
|
||||
use std::str;
|
||||
|
||||
use clap::{App, ErrorKind};
|
||||
use clap::{App, Arg, ErrorKind};
|
||||
|
||||
include!("../clap-test.rs");
|
||||
|
||||
|
@ -43,3 +43,16 @@ fn complex_version_output() {
|
|||
a.write_version(&mut ver).unwrap();
|
||||
assert_eq!(str::from_utf8(&ver).unwrap(), VERSION);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn override_ver() {
|
||||
let m = App::new("test")
|
||||
.author("Kevin K.")
|
||||
.about("tests stuff")
|
||||
.version("1.3")
|
||||
.arg(Arg::from_usage("-v, --version 'some version'"))
|
||||
.get_matches_from_safe(vec!["test", "--version"]);
|
||||
|
||||
assert!(m.is_ok());
|
||||
assert!(m.unwrap().is_present("version"));
|
||||
}
|
Loading…
Reference in a new issue