mirror of
https://github.com/clap-rs/clap
synced 2024-09-20 14:31:58 +00:00
feat(errors): colorizes output red on error
This commit is contained in:
parent
8891d92917
commit
f8b26b13da
3 changed files with 33 additions and 14 deletions
|
@ -3,7 +3,7 @@
|
|||
name = "clap"
|
||||
version = "0.7.6"
|
||||
authors = ["Kevin K. <kbknapp@gmail.com>"]
|
||||
exclude = ["docs/*", "examples/*", "claptests/*"]
|
||||
exclude = ["examples/*", "clap-tests/*"]
|
||||
description = "A simple to use, efficient, and full featured Command Line Argument Parser"
|
||||
repository = "https://github.com/kbknapp/clap-rs.git"
|
||||
documentation = "http://kbknapp.github.io/clap-rs"
|
||||
|
@ -14,8 +14,9 @@ keywords = ["argument", "command", "arg", "parser", "parse"]
|
|||
license = "MIT"
|
||||
|
||||
[features]
|
||||
default=["suggestions"]
|
||||
default=["suggestions", "color"]
|
||||
suggestions=["strsim"]
|
||||
color = ["ansi_term"]
|
||||
|
||||
# for building with nightly and unstable features
|
||||
unstable=[]
|
||||
|
@ -24,3 +25,6 @@ unstable=[]
|
|||
version = "*"
|
||||
optional = true
|
||||
|
||||
[dependencies.ansi_term]
|
||||
version = "*"
|
||||
optional = true
|
||||
|
|
37
src/app.rs
37
src/app.rs
|
@ -13,20 +13,22 @@ use args::ArgGroup;
|
|||
|
||||
#[cfg(feature = "suggestions")]
|
||||
use strsim;
|
||||
#[cfg(feature = "color")]
|
||||
use ansi_term::Colour::Red;
|
||||
|
||||
/// Produces a string from a given list of possible values which is similar to
|
||||
/// Produces a string from a given list of possible values which is similar to
|
||||
/// the passed in value `v` with a certain confidence.
|
||||
/// Thus in a list of possible values like ["foo", "bar"], the value "fop" will yield
|
||||
/// `Some("foo")`, whereas "blark" would yield `None`.
|
||||
#[cfg(feature = "suggestions")]
|
||||
fn did_you_mean<'a, T, I>(v: &str, possible_values: I) -> Option<&'a str>
|
||||
fn did_you_mean<'a, T, I>(v: &str, possible_values: I) -> Option<&'a str>
|
||||
where T: AsRef<str> + 'a,
|
||||
I: IntoIterator<Item=&'a T> {
|
||||
|
||||
let mut candidate: Option<(f64, &str)> = None;
|
||||
for pv in possible_values.into_iter() {
|
||||
let confidence = strsim::jaro_winkler(v, pv.as_ref());
|
||||
if confidence > 0.8 && (candidate.is_none() ||
|
||||
if confidence > 0.8 && (candidate.is_none() ||
|
||||
(candidate.as_ref().unwrap().0 < confidence)) {
|
||||
candidate = Some((confidence, pv.as_ref()));
|
||||
}
|
||||
|
@ -38,9 +40,9 @@ fn did_you_mean<'a, T, I>(v: &str, possible_values: I) -> Option<&'a str>
|
|||
}
|
||||
|
||||
#[cfg(not(feature = "suggestions"))]
|
||||
fn did_you_mean<'a, T, I>(_: &str, _: I) -> Option<&'a str>
|
||||
fn did_you_mean<'a, T, I>(_: &str, _: I) -> Option<&'a str>
|
||||
where T: AsRef<str> + 'a,
|
||||
I: IntoIterator<Item=&'a T> {
|
||||
I: IntoIterator<Item=&'a T> {
|
||||
None
|
||||
}
|
||||
|
||||
|
@ -1154,12 +1156,23 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
|
|||
}
|
||||
|
||||
// Reports and error to the users screen along with an optional usage statement and quits
|
||||
#[cfg(not(feature = "color"))]
|
||||
fn report_error(&self, msg: String, usage: bool, quit: bool, matches: Option<Vec<&str>>) {
|
||||
println!("{}", msg);
|
||||
if usage { self.print_usage(true, matches); }
|
||||
if quit { self.exit(1); }
|
||||
}
|
||||
|
||||
#[cfg(feature = "color")]
|
||||
fn report_error(&self, msg: String, usage: bool, quit: bool, matches: Option<Vec<&str>>) {
|
||||
println!("{}", Red.paint(&msg[..]));
|
||||
if usage {
|
||||
print!("{}",Red.paint(&self.create_usage(matches)[..]));
|
||||
println!("{}",Red.paint("\nFor more information try --help"));
|
||||
}
|
||||
if quit { self.exit(1); }
|
||||
}
|
||||
|
||||
// Starts the parsing process. Called on top level parent app **ONLY** then recursively calls
|
||||
// the real parsing function for subcommands
|
||||
pub fn get_matches(mut self) -> ArgMatches<'ar, 'ar> {
|
||||
|
@ -1224,9 +1237,9 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns a suffix that can be empty, or is the standard 'did you mean phrase
|
||||
/// Returns a suffix that can be empty, or is the standard 'did you mean phrase
|
||||
fn did_you_mean_suffix<'z, T, I>(arg: &str, values: I, style: DidYouMeanMessageStyle)
|
||||
-> String
|
||||
-> String
|
||||
where T: AsRef<str> + 'z,
|
||||
I: IntoIterator<Item=&'z T> {
|
||||
match did_you_mean(arg, values) {
|
||||
|
@ -1247,9 +1260,9 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
|
|||
}
|
||||
}
|
||||
|
||||
fn possible_values_error(&self, arg: &str, opt: &str, p_vals: &BTreeSet<&str>,
|
||||
fn possible_values_error(&self, arg: &str, opt: &str, p_vals: &BTreeSet<&str>,
|
||||
matches: &ArgMatches<'ar, 'ar>) {
|
||||
let suffix = App::did_you_mean_suffix(arg, p_vals.iter(),
|
||||
let suffix = App::did_you_mean_suffix(arg, p_vals.iter(),
|
||||
DidYouMeanMessageStyle::EnumValue);
|
||||
|
||||
self.report_error(format!("\"{}\" isn't a valid value for '{}'{}{}",
|
||||
|
@ -1282,7 +1295,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
|
|||
if let Some(ref p_vals) = opt.possible_vals {
|
||||
if !p_vals.is_empty() {
|
||||
if !p_vals.contains(arg_slice) {
|
||||
self.possible_values_error(arg_slice, &opt.to_string(),
|
||||
self.possible_values_error(arg_slice, &opt.to_string(),
|
||||
p_vals, matches);
|
||||
}
|
||||
}
|
||||
|
@ -1411,7 +1424,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
|
|||
if let Some(ref p_vals) = p.possible_vals {
|
||||
if !p_vals.is_empty() {
|
||||
if !p_vals.contains(arg_slice) {
|
||||
self.possible_values_error(arg_slice, &p.to_string(),
|
||||
self.possible_values_error(arg_slice, &p.to_string(),
|
||||
p_vals, matches);
|
||||
}
|
||||
}
|
||||
|
@ -1699,7 +1712,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
|
|||
if let Some(ref av) = arg_val {
|
||||
if !p_vals.contains(&av[..]) {
|
||||
self.possible_values_error(
|
||||
arg_val.as_ref().map(|v| &**v).unwrap_or(arg),
|
||||
arg_val.as_ref().map(|v| &**v).unwrap_or(arg),
|
||||
&v.to_string(), p_vals, matches);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -350,6 +350,8 @@
|
|||
//! - `Arg::mutually_excludes_all()` -> `Arg::conflicts_with_all()`
|
||||
#[cfg(feature = "suggestions")]
|
||||
extern crate strsim;
|
||||
#[cfg(feature = "color")]
|
||||
extern crate ansi_term;
|
||||
|
||||
pub use args::{Arg, SubCommand, ArgMatches, ArgGroup};
|
||||
pub use app::App;
|
||||
|
|
Loading…
Reference in a new issue