diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3b0d75d0..2d7d4395 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,24 @@
+
+### v2.5.2 (2016-05-31)
+
+
+#### Improvements
+
+* removes extra newline from help output ([86e61d19](https://github.com/kbknapp/clap-rs/commit/86e61d19a748fb9870fcf1175308984e51ca1115))
+* allows printing version to any io::Write object ([921f5f79](https://github.com/kbknapp/clap-rs/commit/921f5f7916597f1d028cd4a65bfe76a01c801724))
+* removes extra newline when printing version ([7e2e2cbb](https://github.com/kbknapp/clap-rs/commit/7e2e2cbb4a8a0f050bb8072a376f742fc54b8589))
+
+#### Bug Fixes
+
+* fixes bug where args are printed out of order with templates ([3935431d](https://github.com/kbknapp/clap-rs/commit/3935431d5633f577c0826ae2142794b301f4b8ca))
+* fixes bug where one can't override version or help flags ([90d7d6a2](https://github.com/kbknapp/clap-rs/commit/90d7d6a2ea8240122dd9bf8d82d3c4f5ebb5c703), closes [#514](https://github.com/kbknapp/clap-rs/issues/514))
+* fixes issue where before_help wasn't printed ([b3faff60](https://github.com/kbknapp/clap-rs/commit/b3faff6030f76a23f26afcfa6a90169002ed7106))
+
+#### Documentation
+
+* inter-links all types and pages ([3312893d](https://github.com/kbknapp/clap-rs/commit/3312893ddaef3f44d68d8d26ed3d08010be50d97), closes [#505](https://github.com/kbknapp/clap-rs/issues/505))
+* makes all publicly available types viewable in docs ([52ca6505](https://github.com/kbknapp/clap-rs/commit/52ca6505b4fec7b5c2d53d160c072d395eb21da6))
+
### v2.5.1 (2016-05-11)
@@ -6,8 +27,6 @@
* **Subcommand Aliases**: fixes lifetime issue when setting multiple aliases at once ([ac42f6cf0](https://github.com/kbknapp/clap-rs/commit/ac42f6cf0de6c4920f703807d63061803930b18d))
-
-
## v2.5.0 (2016-05-10)
diff --git a/Cargo.toml b/Cargo.toml
index 76e1e723..a94b8f42 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "clap"
-version = "2.5.1"
+version = "2.5.2"
authors = ["Kevin K. "]
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
description = "A simple to use, efficient, and full featured Command Line Argument Parser"
diff --git a/README.md b/README.md
index 62cce930..b2dbdf3a 100644
--- a/README.md
+++ b/README.md
@@ -38,6 +38,16 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
## What's New
+Here's what's new in v.2.5.2
+
+* Removes trailing newlines from help and version output
+* Allows printing version to any io::Write object
+* Inter-links all types and pages
+* Makes all publicly available types viewable in docs
+* Fixes bug where one can't override version or help flags
+* Fixes bug where args are printed out of order when using templates
+* Fixes issue where `App::before_help` wasn't printed properly
+
Here's what's new in v.2.5.0
* Subcommands now support aliases - think of them as hidden subcommands that dispatch to said subcommand automatically
@@ -50,12 +60,12 @@ Here's what's new in v2.4.3
* Improvements
* Positional arguments which are part of a group are now formatted in a more readable way (fewer brackets)
* Positional arguments use the standard `<>` brackets to reduce confusion
- * The default help string for the `help` subcommand has been shortened to fit in 80 columns
+ * The default help string for the `help` subcommand has been shortened to fit in 80 columns
Here's the highlights from v2.4.0
-* **Before Help:** adds support for displaying info before help message
-* **Required Unless:** adds support for allowing args that are required unless certain other args are present
+* **Before Help:** adds support for displaying info before help message
+* **Required Unless:** adds support for allowing args that are required unless certain other args are present
* Bug fixes
Here's the highlights from v2.3.0
diff --git a/clap-test.rs b/clap-test.rs
index d2becbe3..e3425d60 100644
--- a/clap-test.rs
+++ b/clap-test.rs
@@ -60,6 +60,16 @@ mod test {
assert_eq!(str::from_utf8(&help).unwrap(), out);
}
+ pub fn check_version(mut a: App, out: &str) {
+ // We call a get_matches method to cause --help and --version to be built
+ let _ = a.get_matches_from_safe_borrow(vec![""]);
+
+ // Now we check the output of print_version()
+ let mut ver = vec![];
+ a.write_version(&mut ver).ok().expect("failed to print help");
+ assert_eq!(str::from_utf8(&ver).unwrap(), out);
+ }
+
pub fn check_complex_output(args: &str, out: &str) {
let mut w = vec![];
let matches = complex_app().get_matches_from(args.split(' ').collect::>());
diff --git a/src/app/help.rs b/src/app/help.rs
index 7cbc2d81..cdf90f16 100644
--- a/src/app/help.rs
+++ b/src/app/help.rs
@@ -88,6 +88,7 @@ pub struct Help<'a> {
impl<'a> Help<'a> {
/// Create a new `Help` instance.
pub fn new(w: &'a mut Write, next_line_help: bool, hide_pv: bool, color: bool) -> Self {
+ debugln!("fn=Help::new;");
Help {
writer: w,
next_line_help: next_line_help,
@@ -100,12 +101,14 @@ impl<'a> Help<'a> {
/// 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<()> {
+ debugln!("fn=Help::write_app_help;");
Self::write_parser_help(w, &app.p)
}
/// 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<()> {
+ debugln!("fn=Help::write_parser_help;");
let nlh = parser.is_set(AppSettings::NextLineHelp);
let hide_v = parser.is_set(AppSettings::HidePossibleValuesInHelp);
let color = parser.is_set(AppSettings::ColoredHelp);
@@ -114,8 +117,9 @@ impl<'a> Help<'a> {
/// Writes the parser help to the wrapped stream.
pub fn write_help(&mut self, parser: &Parser) -> ClapResult<()> {
+ debugln!("fn=Help::write_help;");
if let Some(h) = parser.meta.help_str {
- try!(writeln!(self.writer, "{}", h).map_err(Error::from));
+ try!(write!(self.writer, "{}", h).map_err(Error::from));
} else if let Some(ref tmpl) = parser.meta.template {
try!(self.write_templated_help(&parser, tmpl));
} else {
@@ -131,6 +135,7 @@ impl<'a> Help<'a> {
fn write_args_unsorted<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()>
where I: Iterator- >
{
+ debugln!("fn=write_args_unsorted;");
let mut longest = 0;
let mut arg_v = Vec::with_capacity(10);
for arg in args.filter(|arg| {
@@ -143,7 +148,13 @@ impl<'a> Help<'a> {
arg_v.push(arg)
}
}
+ let mut first = true;
for arg in arg_v {
+ if !first {
+ try!(self.writer.write(b"\n"));
+ } else {
+ first = false;
+ };
try!(self.write_arg(arg.as_base(), longest));
}
Ok(())
@@ -153,6 +164,7 @@ impl<'a> Help<'a> {
fn write_args<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()>
where I: Iterator
- >
{
+ debugln!("fn=write_args;");
let mut longest = 0;
let mut ord_m = VecMap::new();
for arg in args.filter(|arg| {
@@ -166,8 +178,14 @@ impl<'a> Help<'a> {
btm.insert(arg.name(), arg);
}
}
+ let mut first = true;
for (_, btm) in ord_m.into_iter() {
for (_, arg) in btm.into_iter() {
+ if !first {
+ try!(self.writer.write(b"\n"));
+ } else {
+ first = false;
+ }
try!(self.write_arg(arg.as_base(), longest));
}
}
@@ -179,12 +197,11 @@ impl<'a> Help<'a> {
arg: &ArgWithDisplay<'b, 'c>,
longest: usize)
-> io::Result<()> {
- debugln!("fn=write_to;");
+ debugln!("fn=write_arg;");
try!(self.short(arg));
try!(self.long(arg, longest));
try!(self.val(arg, longest));
try!(self.help(arg, longest));
- try!(self.writer.write(b"\n"));
Ok(())
}
@@ -458,45 +475,33 @@ impl<'a> Help<'a> {
let unified_help = parser.is_set(AppSettings::UnifiedHelpMessage);
- let mut first = true;
-
if unified_help && (flags || opts) {
let opts_flags = parser.iter_flags()
.map(as_arg_trait)
.chain(parser.iter_opts().map(as_arg_trait));
try!(color!(self, "OPTIONS:\n", Warning));
try!(self.write_args(opts_flags));
- first = false;
} else {
if flags {
try!(color!(self, "FLAGS:\n", Warning));
try!(self.write_args(parser.iter_flags()
.map(as_arg_trait)));
- first = false;
}
if opts {
- if !first {
- try!(self.writer.write(b"\n"));
- }
+ try!(self.writer.write(b"\n\n"));
try!(color!(self, "OPTIONS:\n", Warning));
try!(self.write_args(parser.iter_opts().map(as_arg_trait)));
- first = false;
}
}
if pos {
- if !first {
- try!(self.writer.write(b"\n"));
- }
+ try!(self.writer.write(b"\n\n"));
try!(color!(self, "ARGS:\n", Warning));
try!(self.write_args_unsorted(parser.iter_positionals().map(as_arg_trait)));
- first = false;
}
if subcmds {
- if !first {
- try!(self.writer.write(b"\n"));
- }
+ try!(self.writer.write(b"\n\n"));
try!(color!(self, "SUBCOMMANDS:\n", Warning));
try!(self.write_subcommands(&parser));
}
@@ -506,6 +511,7 @@ impl<'a> Help<'a> {
/// Writes help for subcommands of a Parser Object to the wrapped stream.
fn write_subcommands(&mut self, parser: &Parser) -> io::Result<()> {
+ debugln!("exec=write_subcommands;");
let mut longest = 0;
let mut ord_m = VecMap::new();
@@ -515,8 +521,16 @@ impl<'a> Help<'a> {
longest = cmp::max(longest, sc.p.meta.name.len());
}
+ let mut first = true;
for (_, btm) in ord_m.into_iter() {
for (_, sc) in btm.into_iter() {
+ if !first {
+ debugln!("Writing newline...");
+ try!(self.writer.write(b"\n"));
+ } else {
+ first = false;
+ }
+ debugln!("Writing sc...{}", sc);
try!(self.write_arg(sc, longest));
}
}
@@ -546,6 +560,11 @@ impl<'a> Help<'a> {
/// Writes default help for a Parser Object to the wrapped stream.
pub fn write_default_help(&mut self, parser: &Parser) -> ClapResult<()> {
+ debugln!("fn=write_default_help;");
+ if let Some(h) = parser.meta.pre_help {
+ try!(write!(self.writer, "{}", h));
+ try!(self.writer.write(b"\n\n"));
+ }
// Print the version
try!(self.write_bin_name(&parser));
@@ -575,7 +594,10 @@ impl<'a> Help<'a> {
}
if let Some(h) = parser.meta.more_help {
- try!(write!(self.writer, "{}\n", h));
+ if flags || opts || pos || subcmds {
+ try!(self.writer.write(b"\n\n"));
+ }
+ try!(write!(self.writer, "{}", h));
}
self.writer.flush().map_err(Error::from)
@@ -708,6 +730,7 @@ impl<'a> Help<'a> {
/// The template system is, on purpose, very simple. Therefore the tags have to writen
/// in the lowercase and without spacing.
fn write_templated_help(&mut self, parser: &Parser, template: &str) -> ClapResult<()> {
+ debugln!("fn=write_templated_help;");
let mut tmplr = Cursor::new(&template);
let mut tag_buf = Cursor::new(vec![0u8; 15]);
@@ -725,6 +748,12 @@ impl<'a> Help<'a> {
_ => continue,
};
+ debugln!("iter;tag_buf={};", unsafe {
+ String::from_utf8_unchecked(tag_buf.get_ref()[0..tag_length]
+ .iter()
+ .map(|&i|i)
+ .collect::>())
+ });
match &tag_buf.get_ref()[0..tag_length] {
b"?" => {
try!(self.writer.write(b"Could not decode tag name"));
@@ -768,8 +797,8 @@ impl<'a> Help<'a> {
.map(as_arg_trait)));
}
b"positionals" => {
- try!(self.write_args(parser.iter_positionals()
- .map(as_arg_trait)));
+ try!(self.write_args_unsorted(parser.iter_positionals()
+ .map(as_arg_trait)));
}
b"subcommands" => {
try!(self.write_subcommands(&parser));
@@ -791,7 +820,6 @@ impl<'a> Help<'a> {
try!(self.writer.write(b"}"));
}
}
-
}
}
}
diff --git a/src/app/mod.rs b/src/app/mod.rs
index 87c2888c..283c8791 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -796,6 +796,22 @@ impl<'a, 'b> App<'a, 'b> {
Help::write_app_help(w, &self)
}
+ /// Writes the version message to the user to a [`io::Write`] object
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::App;
+ /// use std::io;
+ /// let mut app = App::new("myprog");
+ /// let mut out = io::stdout();
+ /// app.write_version(&mut out).ok().expect("failed to write to stdout");
+ /// ```
+ /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+ pub fn write_version(&self, w: &mut W) -> ClapResult<()> {
+ self.p.write_version(w).map_err(From::from)
+ }
+
/// Starts the parsing process, upon a failed parse an error will be displayed to the user and
/// the process with exit with the appropriate error code. By default this method gets all user
/// provided arguments from [`env::args_os`] in order to allow for invalid UTF-8 code points,
diff --git a/src/app/parser.rs b/src/app/parser.rs
index ecdaaa85..20e4791a 100644
--- a/src/app/parser.rs
+++ b/src/app/parser.rs
@@ -115,9 +115,9 @@ impl<'a, 'b> Parser<'a, 'b>
l));
self.long_list.push(l);
if l == "help" {
- self.set(AppSettings::NeedsLongHelp);
+ self.unset(AppSettings::NeedsLongHelp);
} else if l == "version" {
- self.set(AppSettings::NeedsLongVersion);
+ self.unset(AppSettings::NeedsLongVersion);
}
}
if a.is_set(ArgSettings::Required) {
@@ -378,6 +378,10 @@ impl<'a, 'b> Parser<'a, 'b>
self.settings.set(s)
}
+ pub fn unset(&mut self, s: AppSettings) {
+ self.settings.unset(s)
+ }
+
pub fn verify_positionals(&mut self) {
// Because you must wait until all arguments have been supplied, this is the first chance
// to make assertions on positional argument indexes
@@ -929,13 +933,13 @@ impl<'a, 'b> Parser<'a, 'b>
debug!("Checking if -{} is help or version...", arg);
if let Some(h) = self.help_short {
sdebugln!("Help");
- if arg == h {
+ if arg == h && self.settings.is_set(AppSettings::NeedsLongHelp) {
try!(self._help());
}
}
if let Some(v) = self.version_short {
sdebugln!("Help");
- if arg == v {
+ if arg == v && self.settings.is_set(AppSettings::NeedsLongVersion) {
try!(self._version());
}
}
@@ -1542,22 +1546,22 @@ impl<'a, 'b> Parser<'a, 'b>
w.flush().map_err(Error::from)
}
- fn write_version(&self, w: &mut W) -> io::Result<()> {
+ pub fn write_version(&self, w: &mut W) -> io::Result<()> {
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
- writeln!(w,
+ write!(w,
"{} {}",
bn.replace(" ", "-"),
self.meta.version.unwrap_or("".into()))
} else {
- writeln!(w,
+ write!(w,
"{} {}",
&self.meta.name[..],
self.meta.version.unwrap_or("".into()))
}
} else {
- writeln!(w,
+ write!(w,
"{} {}",
&self.meta.name[..],
self.meta.version.unwrap_or("".into()))
@@ -1570,7 +1574,6 @@ impl<'a, 'b> Parser<'a, 'b>
self.write_help(&mut buf_w)
}
- #[cfg_attr(feature = "lints", allow(for_kv_map))]
pub fn write_help(&self, w: &mut W) -> ClapResult<()> {
Help::write_parser_help(w, &self)
}
diff --git a/tests/app_settings.rs b/tests/app_settings.rs
index 54df0c15..7acbbe4b 100644
--- a/tests/app_settings.rs
+++ b/tests/app_settings.rs
@@ -102,7 +102,7 @@ OPTIONS:
-V, --version Prints version information
ARGS:
- some pos arg\n"));
+ some pos arg"));
}
#[test]
@@ -135,5 +135,5 @@ OPTIONS:
-o, --opt some option
ARGS:
- some pos arg\n"));
+ some pos arg"));
}
diff --git a/tests/help.rs b/tests/help.rs
index 41ae717d..30cce9a8 100644
--- a/tests/help.rs
+++ b/tests/help.rs
@@ -34,8 +34,21 @@ ARGS:
SUBCOMMANDS:
help Prints this message or the help of the given subcommand(s)
- subcmd tests subcommands
-";
+ subcmd tests subcommands";
+
+static AFTER_HELP: &'static str = "some text that comes before the help
+
+clap-test v1.4.8
+tests clap library
+
+USAGE:
+ clap-test [FLAGS]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+some text that comes after the help";
static SC_HELP: &'static str = "subcmd 0.1
Kevin K.
@@ -51,8 +64,7 @@ OPTIONS:
-o, --option ... tests options
ARGS:
- tests positionals
-";
+ tests positionals";
#[test]
fn help_short() {
@@ -137,6 +149,16 @@ fn complex_help_output() {
test::check_help(test::complex_app(), HELP);
}
+#[test]
+fn after_and_before_help_output() {
+ let app = App::new("clap-test")
+ .version("v1.4.8")
+ .about("tests clap library")
+ .before_help("some text that comes before the help")
+ .after_help("some text that comes after the help");
+ test::check_help(app, AFTER_HELP);
+}
+
#[test]
fn complex_subcommand_help_output() {
let mut a = test::complex_app();
diff --git a/tests/hidden_args.rs b/tests/hidden_args.rs
index 91eced4e..cf52e485 100644
--- a/tests/hidden_args.rs
+++ b/tests/hidden_args.rs
@@ -30,5 +30,5 @@ FLAGS:
-V, --version Prints version information
OPTIONS:
- --option some option\n"));
+ --option some option"));
}
diff --git a/tests/template_help.rs b/tests/template_help.rs
index 313479c3..420111e1 100644
--- a/tests/template_help.rs
+++ b/tests/template_help.rs
@@ -7,6 +7,41 @@ use clap::{App, SubCommand};
static EXAMPLE1_TMPL_S : &'static str = include_str!("example1_tmpl_simple.txt");
static EXAMPLE1_TMPS_F : &'static str = include_str!("example1_tmpl_full.txt");
+static CUSTOM_TEMPL_HELP: &'static str = "MyApp 1.0
+Kevin K.
+Does awesome things
+
+USAGE:
+ MyApp [FLAGS] [OPTIONS]