Skip to content

Commit

Permalink
Auto merge of #487 - kbknapp:issue-483, r=kbknapp
Browse files Browse the repository at this point in the history
Issue 483
  • Loading branch information
homu committed Apr 18, 2016
2 parents fdbd12e + 770397b commit 25d5cbc
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 67 deletions.
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
<a name="v2.3.0"></a>
## v2.3.0 (2016-04-18)


#### Improvements

* **macros.rs:** Added write_nspaces macro (a new version of write_spaces) ([9d757e86](https://github.com/kbknapp/clap-rs/commit/9d757e8678e334e5a740ac750c76a9ed4e785cba))
* **parser.rs:**
* Provide a way to create a usage string without the USAGE: title ([a91d378b](https://github.com/kbknapp/clap-rs/commit/a91d378ba0c91b5796457f8c6e881b13226ab735))
* Make Parser's create_usage public allowing to have function outside the parser to generate the help ([d51945f8](https://github.com/kbknapp/clap-rs/commit/d51945f8b82ebb0963f4f40b384a9e8335783091))
* Expose Parser's flags, opts and positionals argument as iterators ([9b23e7ee](https://github.com/kbknapp/clap-rs/commit/9b23e7ee40e51f7a823644c4496be955dc6c9d3a))
* **src/args:** Exposes argument display order by introducing a new Trait ([1321630e](https://github.com/kbknapp/clap-rs/commit/1321630ef56955f152c73376d4d85cceb0bb4a12))
* **srs/args:** Added longest_filter to AnyArg trait ([65b3f667](https://github.com/kbknapp/clap-rs/commit/65b3f667532685f854c699ddd264d326599cf7e5))

#### Features

* **Authors Macro:** adds a crate_authors macro ([38fb59ab](https://github.com/kbknapp/clap-rs/commit/38fb59abf480eb2b6feca269097412f8b00b5b54), closes [#447](https://github.com/kbknapp/clap-rs/issues/447))
* **HELP:**
* implements optional colored help messages ([abc8f669](https://github.com/kbknapp/clap-rs/commit/abc8f669c3c8193ffc3a3b0ac6c3ac2198794d4f), closes [#483](https://github.com/kbknapp/clap-rs/issues/483))
* Add a Templated Help system. ([81e121ed](https://github.com/kbknapp/clap-rs/commit/81e121edd616f7285593f11120c63bcccae0d23e))

#### Bug Fixes

* **HELP:** Adjust Help to semantic changes introduced in 6933b84 ([8d23806b](https://github.com/kbknapp/clap-rs/commit/8d23806bd67530ad412c34a1dcdcb1435555573d))

<a name="v2.2.6"></a>
### v2.2.6 (2016-04-11)

Expand Down
10 changes: 10 additions & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,40 @@
The following is a list of contributors to the [clap](https://github.com/kbknapp/clap-rs) project, in alphabetical order:

* [Alexander Bulaev](https://github.com/alexbool)
* [Alexander Kuvaev](https://github.com/Vinatorul) <<[email protected]>>
* [Alex Gulyás](https://github.com/alex-gulyas)
* [Benjamin Sago](https://github.com/ogham) <<[email protected]>>
* [Bilal Syed Hussain](https://github.com/Bilalh)
* [Brad Urani](https://github.com/bradurani)
* [Ceri Storey](https://github.com/cstorey)
* [Dabo Ross](https://github.com/daboross) <<[email protected]>>
* [Georg Brandl](https://github.com/birkenfeld) <<[email protected]>>
* [Paul Blouët](https://github.com/Georgi) <<[email protected]>>
* [Ian C](https://github.com/GrappigPanda)
* [grossws](https://github.com/grossws)
* [Ivan Dmitrievsky](https://github.com/idmit) <<[email protected]>>
* [Hernan Grecco](https://github.com/hgrecco)
* [Holger Rapp](https://github.com/SirVer) <<[email protected]>>
* [Homu](https://github.com/homu)
* [Huon Wilson](https://github.com/huonw)
* [J/A](https://github.com/archer884)
* [Jacob Helwig](https://github.com/jhelwig) <<[email protected]>>
* [James McGlashan](https://github.com/james-darkfox)
* [Jimmy Cuadra](https://github.com/jimmycuadra)
* [Jorge Aparicio](https://github.com/japaric) <<[email protected]>>
* [Kevin K.](https://github.com/kbknapp) <<[email protected]>>
* [Markus Unterwaditzer](https://github.com/untitaker) <<[email protected]>>
* [messense](https://github.com/messense) <<[email protected]>>
* [Nelson Chen](https://github.com/nelsonjchen)
* [panicbit](https://github.com/panicbit) <<[email protected]>>
* [Paul Blouët](https://github.com/Geogi) <<[email protected]>>
* [Ross Nelson](https://github.com/rnelson) <<[email protected]>>
* [Roman A. Taycher](https://github.com/rtaycher) <<[email protected]>>
* [Sebastian Thiel](https://github.com/Byron) <<[email protected]>>
* [Severen Redwood](https://github.com/SShrike) <<[email protected]>>
* [SungRim Huh](https://github.com/sru) <<[email protected]>>
* [Tshepang Lekhonkhobe](https://github.com/tshepang) <<[email protected]>>
* [Vincent Prouillet](https://github.com/Keats)
* [Vlad](https://github.com/N-006)
* [Vladislav Supalov](https://github.com/th4t)
* [Yo-Bot](https://github.com/yo-bot)
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

name = "clap"
version = "2.2.6"
version = "2.3.0"
authors = ["Kevin K. <[email protected]>"]
exclude = ["examples/*", "clap-tests/*", "tests/*", "benches/*", "*.png", "clap-perf/*"]
description = "A simple to use, efficient, and full featured Command Line Argument Parser"
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,22 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)

## What's New

Here's the highlights from v2.3.0

* **New Help Template Engine!**: Now you have full control over the layout of your help message. Major thanks to @hgrecco
* **Pull crate Authors from Cargo.toml**: One can now use the `crate_authors!` macro to automatically pull the crate authors from their Cargo.toml file (requires `unstable` cargo feature to enable)
* **Colored Help Messages**: Help messages can now be optionally colored (See the `AppSettings::ColoredHelp` setting). Screenshot below.
* A bunch of bug fixes

Here's the highlights from v2.2.1

* **Help text auto wraps and aligns at for subcommands too!** - Long help strings of subcommands will now properly wrap and align to term width on Linux and OSX. This can be turned off as well.
* Bug fixes

An example of the optional colored help:

![screenshot](http://i.imgur.com/7fs2h5j.png)

Here's the highlights from v2.2.0

#### Features
Expand Down
111 changes: 67 additions & 44 deletions src/app/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use errors::{Error, Result as ClapResult};
use args::{AnyArg, ArgSettings, DispOrder};
use app::{App, AppSettings};
use app::parser::Parser;
use fmt::Format;

use term;

Expand All @@ -30,7 +31,6 @@ fn str_width(s: &str) -> usize {
UnicodeWidthStr::width(s)
}


const TAB: &'static str = " ";

// These are just convenient traits to make the code easier to read.
Expand Down Expand Up @@ -58,6 +58,22 @@ impl<'b, 'c> DispOrder for App<'b, 'c> {
}
}

macro_rules! color {
($_self:ident, $nc:expr, $c:ident) => {
if $_self.color {
write!($_self.writer, "{}", Format::$c($nc))
} else {
write!($_self.writer, "{}", $nc)
}
};
($_self:ident, $nc:expr, $i:expr, $c:ident) => {
if $_self.color {
write!($_self.writer, "{}", Format::$c(format!($nc, $i)))
} else {
write!($_self.writer, $nc, $i)
}
};
}

/// CLAP Help Writer.
///
Expand All @@ -67,17 +83,19 @@ pub struct Help<'a> {
next_line_help: bool,
hide_pv: bool,
term_w: Option<usize>,
color: bool,
}

// Public Functions
impl<'a> Help<'a> {
/// Create a new Help instance.
pub fn new(w: &'a mut Write, next_line_help: bool, hide_pv: bool) -> Self {
pub fn new(w: &'a mut Write, next_line_help: bool, hide_pv: bool, color: bool) -> Self {
Help {
writer: w,
next_line_help: next_line_help,
hide_pv: hide_pv,
term_w: term::dimensions().map(|(w, _)| w),
color: color,
}
}

Expand All @@ -92,7 +110,8 @@ impl<'a> Help<'a> {
pub fn write_parser_help(w: &'a mut Write, parser: &Parser) -> ClapResult<()> {
let nlh = parser.is_set(AppSettings::NextLineHelp);
let hide_v = parser.is_set(AppSettings::HidePossibleValuesInHelp);
Self::new(w, nlh, hide_v).write_help(&parser)
let color = parser.is_set(AppSettings::ColoredHelp);
Self::new(w, nlh, hide_v, color).write_help(&parser)
}

/// Writes the parser help to the wrapped stream.
Expand Down Expand Up @@ -176,7 +195,7 @@ impl<'a> Help<'a> {
debugln!("fn=short;");
try!(write!(self.writer, "{}", TAB));
if let Some(s) = arg.short() {
write!(self.writer, "-{}", s)
color!(self, "-{}", s, Good)
} else if arg.has_switch() {
write!(self.writer, "{}", TAB)
} else {
Expand All @@ -192,26 +211,18 @@ impl<'a> Help<'a> {
}
if arg.takes_value() {
if let Some(l) = arg.long() {
try!(write!(self.writer,
"{}--{}",
if arg.short().is_some() {
", "
} else {
""
},
l));
if arg.short().is_some() {
try!(write!(self.writer, ", "));
}
try!(color!(self, "--{}", l, Good))
}
try!(write!(self.writer, " "));
} else {
if let Some(l) = arg.long() {
try!(write!(self.writer,
"{}--{}",
if arg.short().is_some() {
", "
} else {
""
},
l));
if arg.short().is_some() {
try!(write!(self.writer, ", "));
}
try!(color!(self, "--{}", l, Good));
if !self.next_line_help || !arg.is_set(ArgSettings::NextLineHelp) {
write_nspaces!(self.writer, (longest + 4) - (l.len() + 2));
}
Expand All @@ -234,27 +245,27 @@ impl<'a> Help<'a> {
if let Some(ref vec) = arg.val_names() {
let mut it = vec.iter().peekable();
while let Some((_, val)) = it.next() {
try!(write!(self.writer, "<{}>", val));
try!(color!(self, "<{}>", val, Good));
if it.peek().is_some() {
try!(write!(self.writer, " "));
}
}
let num = vec.len();
if arg.is_set(ArgSettings::Multiple) && num == 1 {
try!(write!(self.writer, "..."));
try!(color!(self, "...", Good));
}
} else if let Some(num) = arg.num_vals() {
let mut it = (0..num).peekable();
while let Some(_) = it.next() {
try!(write!(self.writer, "<{}>", arg.name()));
try!(color!(self, "<{}>", arg.name(), Good));
if it.peek().is_some() {
try!(write!(self.writer, " "));
}
}
} else if arg.has_switch() {
try!(write!(self.writer, "<{}>", arg.name()));
try!(color!(self, "<{}>", arg.name(), Good));
} else {
try!(write!(self.writer, "{}", arg));
try!(color!(self, "{}", arg, Good));
}
if arg.has_switch() {
if !(self.next_line_help || arg.is_set(ArgSettings::NextLineHelp)) {
Expand Down Expand Up @@ -394,21 +405,33 @@ impl<'a> Help<'a> {
if let Some(ref pv) = a.default_val() {
debugln!("Writing defaults");
return format!(" [default: {}] {}",
pv,
if self.hide_pv {
if self.color {
format!("{}", Format::Good(pv))
} else {
format!("{}", pv)
},
if self.hide_pv {
"".into()
} else {
if let Some(ref pv) = a.possible_vals() {
format!(" [values: {}]", pv.join(", "))
} else {
} else {
if let Some(ref pv) = a.possible_vals() {
if self.color {
format!(" [values: {}]", pv.iter().map(|v| format!("{}", Format::Good(v))).collect::<Vec<_>>().join(", "))
} else {
format!(" [values: {}]", pv.join(", "))
}
} else {
"".into()
}
});
}
});
} else if !self.hide_pv {
debugln!("Writing values");
if let Some(ref pv) = a.possible_vals() {
debugln!("Possible vals...{:?}", pv);
return format!(" [values: {}]", pv.join(", "));
return if self.color {
format!(" [values: {}]", pv.iter().map(|v| format!("{}", Format::Good(v))).collect::<Vec<_>>().join(", "))
} else {
format!(" [values: {}]", pv.join(", "))
};
}
}
String::new()
Expand All @@ -435,12 +458,12 @@ impl<'a> Help<'a> {
let opts_flags = parser.iter_flags()
.map(as_arg_trait)
.chain(parser.iter_opts().map(as_arg_trait));
try!(write!(self.writer, "OPTIONS:\n"));
try!(color!(self, "OPTIONS:\n", Warning));
try!(self.write_args(opts_flags));
first = false;
} else {
if flags {
try!(write!(self.writer, "FLAGS:\n"));
try!(color!(self, "FLAGS:\n", Warning));
try!(self.write_args(parser.iter_flags()
.map(as_arg_trait)));
first = false;
Expand All @@ -449,7 +472,7 @@ impl<'a> Help<'a> {
if !first {
try!(self.writer.write(b"\n"));
}
try!(write!(self.writer, "OPTIONS:\n"));
try!(color!(self, "OPTIONS:\n", Warning));
try!(self.write_args(parser.iter_opts().map(as_arg_trait)));
first = false;
}
Expand All @@ -459,7 +482,7 @@ impl<'a> Help<'a> {
if !first {
try!(self.writer.write(b"\n"));
}
try!(write!(self.writer, "ARGS:\n"));
try!(color!(self, "ARGS:\n", Warning));
try!(self.write_args_unsorted(parser.iter_positionals().map(as_arg_trait)));
first = false;
}
Expand All @@ -468,7 +491,7 @@ impl<'a> Help<'a> {
if !first {
try!(self.writer.write(b"\n"));
}
try!(write!(self.writer, "SUBCOMMANDS:\n"));
try!(color!(self, "SUBCOMMANDS:\n", Warning));
try!(self.write_subcommands(&parser));
}

Expand Down Expand Up @@ -505,12 +528,12 @@ impl<'a> Help<'a> {
if let Some(bn) = parser.meta.bin_name.as_ref() {
if bn.contains(' ') {
// Incase we're dealing with subcommands i.e. git mv is translated to git-mv
try!(write!(self.writer, "{}", bn.replace(" ", "-")))
try!(color!(self, bn.replace(" ", "-"), Good))
} else {
try!(write!(self.writer, "{}", &parser.meta.name[..]))
try!(color!(self, &parser.meta.name[..], Good))
}
} else {
try!(write!(self.writer, "{}", &parser.meta.name[..]))
try!(color!(self, &parser.meta.name[..], Good))
}
Ok(())
}
Expand All @@ -530,8 +553,8 @@ impl<'a> Help<'a> {
try!(write!(self.writer, "{}\n", about));
}

try!(write!(self.writer,
"\nUSAGE:\n{}{}\n\n",
try!(color!(self, "\nUSAGE:", Warning));
try!(write!(self.writer, "\n{}{}\n\n",
TAB,
parser.create_usage_no_title(&[])));

Expand Down
Loading

0 comments on commit 25d5cbc

Please sign in to comment.