diff --git a/CHANGELOG.md b/CHANGELOG.md
index c8c6beab..19ee5e55 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,34 @@
+
+## 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))
+
+
+
### v2.22.2 (2017-03-30)
diff --git a/Cargo.toml b/Cargo.toml
index b41c32ac..306fd5c9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "clap"
-version = "2.22.2"
+version = "2.23.0"
authors = ["Kevin K. "]
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
repository = "https://github.com/kbknapp/clap-rs.git"
diff --git a/README.md b/README.md
index 876e9eb7..36b8677e 100644
--- a/README.md
+++ b/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
diff --git a/src/app/help.rs b/src/app/help.rs
index 1b400ef4..c79142fe 100644
--- a/src/app/help.rs
+++ b/src/app/help.rs
@@ -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,
- max_w: Option)
+ max_w: Option,
+ 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::>()
.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::>()
- .join(", "))
- } else {
- format!(" [values: {}]", pv.join(", "))
- });
+ format!(" [values: {}]",
+ pv.iter()
+ .map(|v| format!("{}", self.cizer.good(v)))
+ .collect::>()
+ .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::>())
+ .iter()
+ .map(|&i| i)
+ .collect::>())
});
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));
diff --git a/src/app/meta.rs b/src/app/meta.rs
index 33b2f355..6fbf412c 100644
--- a/src/app/meta.rs
+++ b/src/app/meta.rs
@@ -1,11 +1,14 @@
#[doc(hidden)]
#[allow(missing_debug_implementations)]
+#[derive(Default, Clone)]
pub struct AppMeta<'b> {
pub name: String,
pub bin_name: Option,
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>, // (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() } }
+}
\ No newline at end of file
diff --git a/src/app/mod.rs b/src/app/mod.rs
index 428bcdbd..0c9f9aee 100644
--- a/src/app/mod.rs
+++ b/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>(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>(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>(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>(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(&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(&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(&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(&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 { 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, &'e OsStr)>> {
None
diff --git a/src/app/parser.rs b/src/app/parser.rs
index d0cdae9e..4c6b8664 100644
--- a/src/app/parser.rs
+++ b/src/app/parser.rs
@@ -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 + [] + 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(&self, w: &mut W) -> ClapResult<()> {
- try!(self.write_version(w));
+ fn print_version(&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(&self, w: &mut W) -> io::Result<()> {
+ pub fn write_version(&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(&self, w: &mut W) -> ClapResult<()> {
- Help::write_parser_help(w, self)
+ Help::write_parser_help(w, self, false)
+ }
+
+ pub fn write_long_help(&self, w: &mut W) -> ClapResult<()> {
+ Help::write_parser_help(w, self, true)
}
pub fn write_help_err(&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) {
diff --git a/src/args/any_arg.rs b/src/args/any_arg.rs
index 55245dba..5f8615fc 100644
--- a/src/args/any_arg.rs
+++ b/src/args/any_arg.rs
@@ -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, &'e OsStr)>>;
fn longest_filter(&self) -> bool;
diff --git a/src/args/arg.rs b/src/args/arg.rs
index 9f57a883..860477c6 100644
--- a/src/args/arg.rs
+++ b/src/args/arg.rs
@@ -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
diff --git a/src/args/arg_builder/base.rs b/src/args/arg_builder/base.rs
index 8b566e38..5990bc08 100644
--- a/src/args/arg_builder/base.rs
+++ b/src/args/arg_builder/base.rs
@@ -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>,
pub settings: ArgFlags,
pub r_unless: Option>,
diff --git a/src/args/arg_builder/flag.rs b/src/args/arg_builder/flag.rs
index d1c16690..e3e9dd01 100644
--- a/src/args/arg_builder/flag.rs
+++ b/src/args/arg_builder/flag.rs
@@ -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 { 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, &'e OsStr)>> {
diff --git a/src/args/arg_builder/option.rs b/src/args/arg_builder/option.rs
index 342ccbdc..64dd9c46 100644
--- a/src/args/arg_builder/option.rs
+++ b/src/args/arg_builder/option.rs
@@ -129,6 +129,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for OptBuilder<'n, 'e> {
fn val_delim(&self) -> Option { 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, &'e OsStr)>> {
self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
diff --git a/src/args/arg_builder/positional.rs b/src/args/arg_builder/positional.rs
index ddbd8964..c77976b1 100644
--- a/src/args/arg_builder/positional.rs
+++ b/src/args/arg_builder/positional.rs
@@ -126,6 +126,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for PosBuilder<'n, 'e> {
fn val_delim(&self) -> Option { 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, &'e OsStr)>> {
self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
}
diff --git a/src/macros.rs b/src/macros.rs
index 6fc7763a..650042fb 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -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 ` = `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(
diff --git a/tests/help.rs b/tests/help.rs
index 3f273931..89ed7ec6 100644
--- a/tests/help.rs
+++ b/tests/help.rs
@@ -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"));
+}
\ No newline at end of file
diff --git a/tests/macros.rs b/tests/macros.rs
index cc25e1bf..035983bb 100644
--- a/tests/macros.rs
+++ b/tests/macros.rs
@@ -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. ")
+ (@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. ")
+ (@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"));
+}
diff --git a/tests/version.rs b/tests/version.rs
index f6e9ff8b..de0f8179 100644
--- a/tests/version.rs
+++ b/tests/version.rs
@@ -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"));
+}
\ No newline at end of file