mirror of
https://github.com/clap-rs/clap
synced 2024-12-14 23:02:31 +00:00
Auto merge of #520 - kbknapp:issues-512,518,519, r=kbknapp
Issues 512,518,519
This commit is contained in:
commit
a77c800da7
16 changed files with 802 additions and 187 deletions
147
'
Normal file
147
'
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
||||||
|
use ansi_term::Colour::{Green, Red, Yellow};
|
||||||
|
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
||||||
|
use ansi_term::ANSIString;
|
||||||
|
|
||||||
|
#[cfg(color)]
|
||||||
|
use libc;
|
||||||
|
|
||||||
|
#[cfg(color)]
|
||||||
|
const STDERR: i32 = libc::STDERR_FILENO;
|
||||||
|
#[cfg(color)]
|
||||||
|
const STDOUT: i32 = libc::STDOUT_FILENO;
|
||||||
|
#[cfg(not(color))]
|
||||||
|
const STDERR: i32 = 0;
|
||||||
|
#[cfg(not(color))]
|
||||||
|
const STDOUT: i32 = 0;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum ColorWhen {
|
||||||
|
Auto, // Default
|
||||||
|
Always,
|
||||||
|
Never
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(color)]
|
||||||
|
pub fn is_a_tty(stderr: bool) -> bool {
|
||||||
|
let fd = if stderr { STDERR } else { STDOUT };
|
||||||
|
unsafe { libc::isatty(fd) != 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(color))]
|
||||||
|
pub fn is_a_tty(stderr: bool) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub struct Colorizer {
|
||||||
|
use_stderr: bool,
|
||||||
|
when: ColorWhen
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! color {
|
||||||
|
($_self:ident, $c:ident, $m:expr) => {
|
||||||
|
match $_self.when {
|
||||||
|
ColorWhen::Auto => if is_a_tty($_self.use_stderr) {
|
||||||
|
Format::$c($m)
|
||||||
|
} else {
|
||||||
|
$m
|
||||||
|
},
|
||||||
|
ColorWhen::Always => Format::$c($m),
|
||||||
|
ColorWhen::Never => $m,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Colorizer {
|
||||||
|
pub fn good<T>(&self, msg: T) -> &fmt::Display where T: fmt::Display {
|
||||||
|
use Format::Good;
|
||||||
|
color!(self, Good, msg)
|
||||||
|
}
|
||||||
|
pub fn warning<T>(&self, msg: T) -> &fmt::Display where T: fmt::Display {
|
||||||
|
use Format::Warning;
|
||||||
|
color!(self, Warning, msg)
|
||||||
|
}
|
||||||
|
pub fn error<T>(&self, msg: T) -> &fmt::Display where T: fmt::Display {
|
||||||
|
use Format::Error;
|
||||||
|
color!(self, Error, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Colorizer {
|
||||||
|
fn default() -> Self {
|
||||||
|
Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: ColorWhen::Auto
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Defines styles for different types of error messages. Defaults to Error=Red, Warning=Yellow,
|
||||||
|
/// and Good=Green
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub enum Format<T> {
|
||||||
|
/// Defines the style used for errors, defaults to Red
|
||||||
|
Error(T),
|
||||||
|
/// Defines the style used for warnings, defaults to Yellow
|
||||||
|
Warning(T),
|
||||||
|
/// Defines the style used for good values, defaults to Green
|
||||||
|
Good(T),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
||||||
|
impl<T: AsRef<str>> Format<T> {
|
||||||
|
fn format(&self) -> ANSIString {
|
||||||
|
match *self {
|
||||||
|
Format::Error(ref e) => Red.bold().paint(e.as_ref()),
|
||||||
|
Format::Warning(ref e) => Yellow.paint(e.as_ref()),
|
||||||
|
Format::Good(ref e) => Green.paint(e.as_ref()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
||||||
|
impl<T: AsRef<str>> fmt::Display for Format<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", &self.format())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "color"), target_os = "windows"))]
|
||||||
|
impl<T: fmt::Display> Format<T> {
|
||||||
|
fn format(&self) -> &T {
|
||||||
|
match *self {
|
||||||
|
Format::Error(ref e) => e,
|
||||||
|
Format::Warning(ref e) => e,
|
||||||
|
Format::Good(ref e) => e,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "color"), target_os = "windows"))]
|
||||||
|
impl<T: fmt::Display> fmt::Display for Format<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", &self.format())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(test, feature = "color", not(target_os = "windows")))]
|
||||||
|
mod test {
|
||||||
|
use super::Format;
|
||||||
|
use ansi_term::Colour::{Green, Red, Yellow};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn colored_output() {
|
||||||
|
let err = Format::Error("error");
|
||||||
|
assert_eq!(&*format!("{}", err),
|
||||||
|
&*format!("{}", Red.bold().paint("error")));
|
||||||
|
let good = Format::Good("good");
|
||||||
|
assert_eq!(&*format!("{}", good), &*format!("{}", Green.paint("good")));
|
||||||
|
let warn = Format::Warning("warn");
|
||||||
|
assert_eq!(&*format!("{}", warn), &*format!("{}", Yellow.paint("warn")));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
|
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.5.2"
|
version = "2.6.0"
|
||||||
authors = ["Kevin K. <kbknapp@gmail.com>"]
|
authors = ["Kevin K. <kbknapp@gmail.com>"]
|
||||||
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
|
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
|
||||||
description = "A simple to use, efficient, and full featured Command Line Argument Parser"
|
description = "A simple to use, efficient, and full featured Command Line Argument Parser"
|
||||||
|
@ -27,7 +27,7 @@ regex = "~0.1.69"
|
||||||
[features]
|
[features]
|
||||||
default = ["suggestions", "color", "wrap_help"]
|
default = ["suggestions", "color", "wrap_help"]
|
||||||
suggestions = ["strsim"]
|
suggestions = ["strsim"]
|
||||||
color = ["ansi_term"]
|
color = ["ansi_term", "libc"]
|
||||||
yaml = ["yaml-rust"]
|
yaml = ["yaml-rust"]
|
||||||
wrap_help = ["libc", "unicode-width"]
|
wrap_help = ["libc", "unicode-width"]
|
||||||
lints = ["clippy", "nightly"]
|
lints = ["clippy", "nightly"]
|
||||||
|
|
|
@ -497,7 +497,7 @@ features = [ "suggestions", "color" ]
|
||||||
The following is a list of optional `clap` features:
|
The following is a list of optional `clap` features:
|
||||||
|
|
||||||
* **"suggestions"**: Turns on the `Did you mean '--myoption' ?` feature for when users make typos. (builds dependency `strsim`)
|
* **"suggestions"**: Turns on the `Did you mean '--myoption' ?` feature for when users make typos. (builds dependency `strsim`)
|
||||||
* **"color"**: Turns on colored error messages. This feature only works on non-Windows OSs. (builds dependency `ansi-term`)
|
* **"color"**: Turns on colored error messages. This feature only works on non-Windows OSs. (builds dependency `ansi-term` and `libc`)
|
||||||
* **"wrap_help"**: Automatically detects terminal width and wraps long help text lines with proper indentation alignment (builds dependency `libc` and 'unicode-width')
|
* **"wrap_help"**: Automatically detects terminal width and wraps long help text lines with proper indentation alignment (builds dependency `libc` and 'unicode-width')
|
||||||
* **"lints"**: This is **not** included by default and should only be used while developing to run basic lints against changes. This can only be used on Rust nightly. (builds dependency `clippy`)
|
* **"lints"**: This is **not** included by default and should only be used while developing to run basic lints against changes. This can only be used on Rust nightly. (builds dependency `clippy`)
|
||||||
* **"debug"**: This is **not** included by default and should only be used while developing to display debugging information.
|
* **"debug"**: This is **not** included by default and should only be used while developing to display debugging information.
|
||||||
|
|
123
src/app/help.rs
123
src/app/help.rs
|
@ -10,7 +10,7 @@ use errors::{Error, Result as ClapResult};
|
||||||
use args::{AnyArg, ArgSettings, DispOrder};
|
use args::{AnyArg, ArgSettings, DispOrder};
|
||||||
use app::{App, AppSettings};
|
use app::{App, AppSettings};
|
||||||
use app::parser::Parser;
|
use app::parser::Parser;
|
||||||
use fmt::Format;
|
use fmt::{Format, Colorizer};
|
||||||
|
|
||||||
use term;
|
use term;
|
||||||
|
|
||||||
|
@ -57,18 +57,18 @@ impl<'b, 'c> DispOrder for App<'b, 'c> {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! color {
|
macro_rules! color {
|
||||||
($_self:ident, $nc:expr, $c:ident) => {
|
($_self:ident, $s:expr, $c:ident) => {
|
||||||
if $_self.color {
|
if $_self.color {
|
||||||
write!($_self.writer, "{}", Format::$c($nc))
|
write!($_self.writer, "{}", $_self.cizer.$c($s))
|
||||||
} else {
|
} else {
|
||||||
write!($_self.writer, "{}", $nc)
|
write!($_self.writer, "{}", $s)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($_self:ident, $nc:expr, $i:expr, $c:ident) => {
|
($_self:ident, $fmt_s:expr, $v:expr, $c:ident) => {
|
||||||
if $_self.color {
|
if $_self.color {
|
||||||
write!($_self.writer, "{}", Format::$c(format!($nc, $i)))
|
write!($_self.writer, "{}", $_self.cizer.$c(format!($fmt_s, $v)))
|
||||||
} else {
|
} else {
|
||||||
write!($_self.writer, $nc, $i)
|
write!($_self.writer, $fmt_s, $v)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -82,12 +82,13 @@ pub struct Help<'a> {
|
||||||
hide_pv: bool,
|
hide_pv: bool,
|
||||||
term_w: Option<usize>,
|
term_w: Option<usize>,
|
||||||
color: bool,
|
color: bool,
|
||||||
|
cizer: Colorizer,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public Functions
|
// Public Functions
|
||||||
impl<'a> Help<'a> {
|
impl<'a> Help<'a> {
|
||||||
/// Create a new `Help` instance.
|
/// Create a new `Help` instance.
|
||||||
pub fn new(w: &'a mut Write, next_line_help: bool, hide_pv: bool, color: bool) -> Self {
|
pub fn new(w: &'a mut Write, next_line_help: bool, hide_pv: bool, color: bool, cizer: Colorizer) -> Self {
|
||||||
debugln!("fn=Help::new;");
|
debugln!("fn=Help::new;");
|
||||||
Help {
|
Help {
|
||||||
writer: w,
|
writer: w,
|
||||||
|
@ -95,6 +96,7 @@ impl<'a> Help<'a> {
|
||||||
hide_pv: hide_pv,
|
hide_pv: hide_pv,
|
||||||
term_w: term::dimensions().map(|(w, _)| w),
|
term_w: term::dimensions().map(|(w, _)| w),
|
||||||
color: color,
|
color: color,
|
||||||
|
cizer: cizer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,11 +110,29 @@ impl<'a> Help<'a> {
|
||||||
/// Reads help settings from a Parser
|
/// Reads help settings from a Parser
|
||||||
/// and write its help to the wrapped stream.
|
/// 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) -> ClapResult<()> {
|
||||||
|
debugln!("fn=Help::write_parser_help;");
|
||||||
|
Self::_write_parser_help(w, parser, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads help settings from a Parser
|
||||||
|
/// and write its help to the wrapped stream which will be stderr. This method prevents
|
||||||
|
/// formatting when required.
|
||||||
|
pub fn write_parser_help_to_stderr(w: &'a mut Write, parser: &Parser) -> ClapResult<()> {
|
||||||
|
debugln!("fn=Help::write_parser_help;");
|
||||||
|
Self::_write_parser_help(w, parser, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn _write_parser_help(w: &'a mut Write, parser: &Parser, stderr: bool) -> ClapResult<()> {
|
||||||
debugln!("fn=Help::write_parser_help;");
|
debugln!("fn=Help::write_parser_help;");
|
||||||
let nlh = parser.is_set(AppSettings::NextLineHelp);
|
let nlh = parser.is_set(AppSettings::NextLineHelp);
|
||||||
let hide_v = parser.is_set(AppSettings::HidePossibleValuesInHelp);
|
let hide_v = parser.is_set(AppSettings::HidePossibleValuesInHelp);
|
||||||
let color = parser.is_set(AppSettings::ColoredHelp);
|
let color = parser.is_set(AppSettings::ColoredHelp);
|
||||||
Self::new(w, nlh, hide_v, color).write_help(&parser)
|
let cizer = Colorizer {
|
||||||
|
use_stderr: stderr,
|
||||||
|
when: parser.color(),
|
||||||
|
};
|
||||||
|
Self::new(w, nlh, hide_v, color, cizer).write_help(&parser)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the parser help to the wrapped stream.
|
/// Writes the parser help to the wrapped stream.
|
||||||
|
@ -135,7 +155,6 @@ impl<'a> Help<'a> {
|
||||||
fn write_args_unsorted<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()>
|
fn write_args_unsorted<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()>
|
||||||
where I: Iterator<Item = &'d ArgWithOrder<'b, 'c>>
|
where I: Iterator<Item = &'d ArgWithOrder<'b, 'c>>
|
||||||
{
|
{
|
||||||
debugln!("fn=write_args_unsorted;");
|
|
||||||
let mut longest = 0;
|
let mut longest = 0;
|
||||||
let mut arg_v = Vec::with_capacity(10);
|
let mut arg_v = Vec::with_capacity(10);
|
||||||
for arg in args.filter(|arg| {
|
for arg in args.filter(|arg| {
|
||||||
|
@ -210,7 +229,7 @@ impl<'a> Help<'a> {
|
||||||
debugln!("fn=short;");
|
debugln!("fn=short;");
|
||||||
try!(write!(self.writer, "{}", TAB));
|
try!(write!(self.writer, "{}", TAB));
|
||||||
if let Some(s) = arg.short() {
|
if let Some(s) = arg.short() {
|
||||||
color!(self, "-{}", s, Good)
|
color!(self, "-{}", s, good)
|
||||||
} else if arg.has_switch() {
|
} else if arg.has_switch() {
|
||||||
write!(self.writer, "{}", TAB)
|
write!(self.writer, "{}", TAB)
|
||||||
} else {
|
} else {
|
||||||
|
@ -229,7 +248,7 @@ impl<'a> Help<'a> {
|
||||||
if arg.short().is_some() {
|
if arg.short().is_some() {
|
||||||
try!(write!(self.writer, ", "));
|
try!(write!(self.writer, ", "));
|
||||||
}
|
}
|
||||||
try!(color!(self, "--{}", l, Good))
|
try!(color!(self, "--{}", l, good))
|
||||||
}
|
}
|
||||||
try!(write!(self.writer, " "));
|
try!(write!(self.writer, " "));
|
||||||
} else {
|
} else {
|
||||||
|
@ -237,7 +256,7 @@ impl<'a> Help<'a> {
|
||||||
if arg.short().is_some() {
|
if arg.short().is_some() {
|
||||||
try!(write!(self.writer, ", "));
|
try!(write!(self.writer, ", "));
|
||||||
}
|
}
|
||||||
try!(color!(self, "--{}", l, Good));
|
try!(color!(self, "--{}", l, good));
|
||||||
if !self.next_line_help || !arg.is_set(ArgSettings::NextLineHelp) {
|
if !self.next_line_help || !arg.is_set(ArgSettings::NextLineHelp) {
|
||||||
write_nspaces!(self.writer, (longest + 4) - (l.len() + 2));
|
write_nspaces!(self.writer, (longest + 4) - (l.len() + 2));
|
||||||
}
|
}
|
||||||
|
@ -260,27 +279,27 @@ impl<'a> Help<'a> {
|
||||||
if let Some(ref vec) = arg.val_names() {
|
if let Some(ref vec) = arg.val_names() {
|
||||||
let mut it = vec.iter().peekable();
|
let mut it = vec.iter().peekable();
|
||||||
while let Some((_, val)) = it.next() {
|
while let Some((_, val)) = it.next() {
|
||||||
try!(color!(self, "<{}>", val, Good));
|
try!(color!(self, "<{}>", val, good));
|
||||||
if it.peek().is_some() {
|
if it.peek().is_some() {
|
||||||
try!(write!(self.writer, " "));
|
try!(write!(self.writer, " "));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let num = vec.len();
|
let num = vec.len();
|
||||||
if arg.is_set(ArgSettings::Multiple) && num == 1 {
|
if arg.is_set(ArgSettings::Multiple) && num == 1 {
|
||||||
try!(color!(self, "...", Good));
|
try!(color!(self, "...", good));
|
||||||
}
|
}
|
||||||
} else if let Some(num) = arg.num_vals() {
|
} else if let Some(num) = arg.num_vals() {
|
||||||
let mut it = (0..num).peekable();
|
let mut it = (0..num).peekable();
|
||||||
while let Some(_) = it.next() {
|
while let Some(_) = it.next() {
|
||||||
try!(color!(self, "<{}>", arg.name(), Good));
|
try!(color!(self, "<{}>", arg.name(), good));
|
||||||
if it.peek().is_some() {
|
if it.peek().is_some() {
|
||||||
try!(write!(self.writer, " "));
|
try!(write!(self.writer, " "));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if arg.has_switch() {
|
} else if arg.has_switch() {
|
||||||
try!(color!(self, "<{}>", arg.name(), Good));
|
try!(color!(self, "<{}>", arg.name(), good));
|
||||||
} else {
|
} else {
|
||||||
try!(color!(self, "{}", arg, Good));
|
try!(color!(self, "{}", arg, good));
|
||||||
}
|
}
|
||||||
if arg.has_switch() {
|
if arg.has_switch() {
|
||||||
if !(self.next_line_help || arg.is_set(ArgSettings::NextLineHelp)) {
|
if !(self.next_line_help || arg.is_set(ArgSettings::NextLineHelp)) {
|
||||||
|
@ -421,9 +440,9 @@ impl<'a> Help<'a> {
|
||||||
debugln!("Writing defaults");
|
debugln!("Writing defaults");
|
||||||
return format!(" [default: {}] {}",
|
return format!(" [default: {}] {}",
|
||||||
if self.color {
|
if self.color {
|
||||||
format!("{}", Format::Good(pv))
|
self.cizer.good(pv)
|
||||||
} else {
|
} else {
|
||||||
pv.to_string()
|
Format::None(pv)
|
||||||
},
|
},
|
||||||
if self.hide_pv {
|
if self.hide_pv {
|
||||||
"".into()
|
"".into()
|
||||||
|
@ -432,7 +451,7 @@ impl<'a> Help<'a> {
|
||||||
if self.color {
|
if self.color {
|
||||||
format!(" [values: {}]",
|
format!(" [values: {}]",
|
||||||
pv.iter()
|
pv.iter()
|
||||||
.map(|v| format!("{}", Format::Good(v)))
|
.map(|v| format!("{}", self.cizer.good(v)))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", "))
|
.join(", "))
|
||||||
} else {
|
} else {
|
||||||
|
@ -449,7 +468,7 @@ impl<'a> Help<'a> {
|
||||||
return if self.color {
|
return if self.color {
|
||||||
format!(" [values: {}]",
|
format!(" [values: {}]",
|
||||||
pv.iter()
|
pv.iter()
|
||||||
.map(|v| format!("{}", Format::Good(v)))
|
.map(|v| format!("{}", self.cizer.good(v)))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", "))
|
.join(", "))
|
||||||
} else {
|
} else {
|
||||||
|
@ -475,34 +494,46 @@ impl<'a> Help<'a> {
|
||||||
|
|
||||||
let unified_help = parser.is_set(AppSettings::UnifiedHelpMessage);
|
let unified_help = parser.is_set(AppSettings::UnifiedHelpMessage);
|
||||||
|
|
||||||
|
let mut first = true;
|
||||||
|
|
||||||
if unified_help && (flags || opts) {
|
if unified_help && (flags || opts) {
|
||||||
let opts_flags = parser.iter_flags()
|
let opts_flags = parser.iter_flags()
|
||||||
.map(as_arg_trait)
|
.map(as_arg_trait)
|
||||||
.chain(parser.iter_opts().map(as_arg_trait));
|
.chain(parser.iter_opts().map(as_arg_trait));
|
||||||
try!(color!(self, "OPTIONS:\n", Warning));
|
try!(color!(self, "OPTIONS:\n", warning));
|
||||||
try!(self.write_args(opts_flags));
|
try!(self.write_args(opts_flags));
|
||||||
|
first = false;
|
||||||
} else {
|
} else {
|
||||||
if flags {
|
if flags {
|
||||||
try!(color!(self, "FLAGS:\n", Warning));
|
try!(color!(self, "FLAGS:\n", warning));
|
||||||
try!(self.write_args(parser.iter_flags()
|
try!(self.write_args(parser.iter_flags()
|
||||||
.map(as_arg_trait)));
|
.map(as_arg_trait)));
|
||||||
|
first = false;
|
||||||
}
|
}
|
||||||
if opts {
|
if opts {
|
||||||
try!(self.writer.write(b"\n\n"));
|
if !first {
|
||||||
try!(color!(self, "OPTIONS:\n", Warning));
|
try!(self.writer.write(b"\n\n"));
|
||||||
|
}
|
||||||
|
try!(color!(self, "OPTIONS:\n", warning));
|
||||||
try!(self.write_args(parser.iter_opts().map(as_arg_trait)));
|
try!(self.write_args(parser.iter_opts().map(as_arg_trait)));
|
||||||
|
first = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pos {
|
if pos {
|
||||||
try!(self.writer.write(b"\n\n"));
|
if !first {
|
||||||
try!(color!(self, "ARGS:\n", Warning));
|
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)));
|
try!(self.write_args_unsorted(parser.iter_positionals().map(as_arg_trait)));
|
||||||
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if subcmds {
|
if subcmds {
|
||||||
try!(self.writer.write(b"\n\n"));
|
if !first {
|
||||||
try!(color!(self, "SUBCOMMANDS:\n", Warning));
|
try!(self.writer.write(b"\n\n"));
|
||||||
|
}
|
||||||
|
try!(color!(self, "SUBCOMMANDS:\n", warning));
|
||||||
try!(self.write_subcommands(&parser));
|
try!(self.write_subcommands(&parser));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,7 +542,7 @@ impl<'a> Help<'a> {
|
||||||
|
|
||||||
/// Writes help for subcommands of a Parser Object to the wrapped stream.
|
/// Writes help for subcommands of a Parser Object to the wrapped stream.
|
||||||
fn write_subcommands(&mut self, parser: &Parser) -> io::Result<()> {
|
fn write_subcommands(&mut self, parser: &Parser) -> io::Result<()> {
|
||||||
debugln!("exec=write_subcommands;");
|
debugln!("exec=write_subcommands;");
|
||||||
let mut longest = 0;
|
let mut longest = 0;
|
||||||
|
|
||||||
let mut ord_m = VecMap::new();
|
let mut ord_m = VecMap::new();
|
||||||
|
@ -525,12 +556,12 @@ impl<'a> Help<'a> {
|
||||||
for (_, btm) in ord_m.into_iter() {
|
for (_, btm) in ord_m.into_iter() {
|
||||||
for (_, sc) in btm.into_iter() {
|
for (_, sc) in btm.into_iter() {
|
||||||
if !first {
|
if !first {
|
||||||
debugln!("Writing newline...");
|
debugln!("Writing newline...");
|
||||||
try!(self.writer.write(b"\n"));
|
try!(self.writer.write(b"\n"));
|
||||||
} else {
|
} else {
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
debugln!("Writing sc...{}", sc);
|
debugln!("Writing sc...{}", sc);
|
||||||
try!(self.write_arg(sc, longest));
|
try!(self.write_arg(sc, longest));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -548,12 +579,12 @@ impl<'a> Help<'a> {
|
||||||
if let Some(bn) = parser.meta.bin_name.as_ref() {
|
if let Some(bn) = parser.meta.bin_name.as_ref() {
|
||||||
if bn.contains(' ') {
|
if bn.contains(' ') {
|
||||||
// Incase we're dealing with subcommands i.e. git mv is translated to git-mv
|
// Incase we're dealing with subcommands i.e. git mv is translated to git-mv
|
||||||
try!(color!(self, bn.replace(" ", "-"), Good))
|
try!(color!(self, bn.replace(" ", "-"), good))
|
||||||
} else {
|
} else {
|
||||||
try!(color!(self, &parser.meta.name[..], Good))
|
try!(color!(self, &parser.meta.name[..], good))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try!(color!(self, &parser.meta.name[..], Good))
|
try!(color!(self, &parser.meta.name[..], good))
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -578,7 +609,7 @@ impl<'a> Help<'a> {
|
||||||
try!(write!(self.writer, "{}\n", about));
|
try!(write!(self.writer, "{}\n", about));
|
||||||
}
|
}
|
||||||
|
|
||||||
try!(color!(self, "\nUSAGE:", Warning));
|
try!(color!(self, "\nUSAGE:", warning));
|
||||||
try!(write!(self.writer,
|
try!(write!(self.writer,
|
||||||
"\n{}{}\n\n",
|
"\n{}{}\n\n",
|
||||||
TAB,
|
TAB,
|
||||||
|
@ -643,7 +674,7 @@ fn copy_until<R: Read, W: Write>(r: &mut R, w: &mut W, delimiter_byte: u8) -> Co
|
||||||
|
|
||||||
/// Copies the contents of a reader into a writer until a {tag} is found,
|
/// Copies the contents of a reader into a writer until a {tag} is found,
|
||||||
/// copying the tag content to a buffer and returning its size.
|
/// copying the tag content to a buffer and returning its size.
|
||||||
/// In addition to Errors, there are three possible outputs:
|
/// In addition to errors, there are three possible outputs:
|
||||||
/// - None: The reader was consumed.
|
/// - None: The reader was consumed.
|
||||||
/// - Some(Ok(0)): No tag was captured but the reader still contains data.
|
/// - Some(Ok(0)): No tag was captured but the reader still contains data.
|
||||||
/// - Some(Ok(length>0)): a tag with `length` was captured to the tag_buffer.
|
/// - Some(Ok(length>0)): a tag with `length` was captured to the tag_buffer.
|
||||||
|
@ -748,12 +779,12 @@ impl<'a> Help<'a> {
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
debugln!("iter;tag_buf={};", unsafe {
|
debugln!("iter;tag_buf={};", unsafe {
|
||||||
String::from_utf8_unchecked(tag_buf.get_ref()[0..tag_length]
|
String::from_utf8_unchecked(tag_buf.get_ref()[0..tag_length]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&i|i)
|
.map(|&i|i)
|
||||||
.collect::<Vec<_>>())
|
.collect::<Vec<_>>())
|
||||||
});
|
});
|
||||||
match &tag_buf.get_ref()[0..tag_length] {
|
match &tag_buf.get_ref()[0..tag_length] {
|
||||||
b"?" => {
|
b"?" => {
|
||||||
try!(self.writer.write(b"Could not decode tag name"));
|
try!(self.writer.write(b"Could not decode tag name"));
|
||||||
|
@ -797,8 +828,8 @@ impl<'a> Help<'a> {
|
||||||
.map(as_arg_trait)));
|
.map(as_arg_trait)));
|
||||||
}
|
}
|
||||||
b"positionals" => {
|
b"positionals" => {
|
||||||
try!(self.write_args_unsorted(parser.iter_positionals()
|
try!(self.write_args(parser.iter_positionals()
|
||||||
.map(as_arg_trait)));
|
.map(as_arg_trait)));
|
||||||
}
|
}
|
||||||
b"subcommands" => {
|
b"subcommands" => {
|
||||||
try!(self.write_subcommands(&parser));
|
try!(self.write_subcommands(&parser));
|
||||||
|
|
|
@ -102,7 +102,7 @@ macro_rules! validate_multiples {
|
||||||
debugln!("macro=validate_multiples!;");
|
debugln!("macro=validate_multiples!;");
|
||||||
if $m.contains(&$a.name) && !$a.settings.is_set(ArgSettings::Multiple) {
|
if $m.contains(&$a.name) && !$a.settings.is_set(ArgSettings::Multiple) {
|
||||||
// Not the first time, and we don't allow multiples
|
// Not the first time, and we don't allow multiples
|
||||||
return Err(Error::unexpected_multiple_usage($a, &*$_self.create_current_usage($m)))
|
return Err(Error::unexpected_multiple_usage($a, &*$_self.create_current_usage($m), $_self.color()))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -435,6 +435,53 @@ impl<'a, 'b> App<'a, 'b> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enables a single setting that is propogated *down* through all child [`SubCommand`]s.
|
||||||
|
///
|
||||||
|
/// See [`AppSettings`] for a full list of possibilities and examples.
|
||||||
|
///
|
||||||
|
/// **NOTE**: The setting is *only* propogated *down* and not up through parent commands.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// # use clap::{App, Arg, AppSettings};
|
||||||
|
/// App::new("myprog")
|
||||||
|
/// .global_setting(AppSettings::SubcommandRequired)
|
||||||
|
/// # ;
|
||||||
|
/// ```
|
||||||
|
/// [`SubCommand`]: ./struct.SubCommand.html
|
||||||
|
/// [`AppSettings`]: ./enum.AppSettings.html
|
||||||
|
pub fn global_setting(mut self, setting: AppSettings) -> Self {
|
||||||
|
self.p.set(setting);
|
||||||
|
self.p.g_settings.push(setting);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables multiple settings which are propogated *down* through all child [`SubCommand`]s.
|
||||||
|
///
|
||||||
|
/// See [`AppSettings`] for a full list of possibilities and examples.
|
||||||
|
///
|
||||||
|
/// **NOTE**: The setting is *only* propogated *down* and not up through parent commands.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// # use clap::{App, Arg, AppSettings};
|
||||||
|
/// App::new("myprog")
|
||||||
|
/// .global_settings(&[AppSettings::SubcommandRequired,
|
||||||
|
/// AppSettings::ColoredHelp])
|
||||||
|
/// # ;
|
||||||
|
/// ```
|
||||||
|
/// [`SubCommand`]: ./struct.SubCommand.html
|
||||||
|
/// [`AppSettings`]: ./enum.AppSettings.html
|
||||||
|
pub fn global_settings(mut self, settings: &[AppSettings]) -> Self {
|
||||||
|
for s in settings {
|
||||||
|
self.p.set(*s);
|
||||||
|
self.p.g_settings.push(*s)
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds an [argument] to the list of valid possibilties.
|
/// Adds an [argument] to the list of valid possibilties.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
|
|
@ -20,7 +20,7 @@ use INVALID_UTF8;
|
||||||
use suggestions;
|
use suggestions;
|
||||||
use INTERNAL_ERROR_MSG;
|
use INTERNAL_ERROR_MSG;
|
||||||
use SubCommand;
|
use SubCommand;
|
||||||
use fmt::Format;
|
use fmt::{Format, ColorWhen};
|
||||||
use osstringext::OsStrExt2;
|
use osstringext::OsStrExt2;
|
||||||
use app::meta::AppMeta;
|
use app::meta::AppMeta;
|
||||||
use args::MatchedArg;
|
use args::MatchedArg;
|
||||||
|
@ -49,6 +49,7 @@ pub struct Parser<'a, 'b>
|
||||||
help_short: Option<char>,
|
help_short: Option<char>,
|
||||||
version_short: Option<char>,
|
version_short: Option<char>,
|
||||||
settings: AppFlags,
|
settings: AppFlags,
|
||||||
|
pub g_settings: Vec<AppSettings>,
|
||||||
pub meta: AppMeta<'b>,
|
pub meta: AppMeta<'b>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ impl<'a, 'b> Default for Parser<'a, 'b> {
|
||||||
groups: HashMap::new(),
|
groups: HashMap::new(),
|
||||||
global_args: vec![],
|
global_args: vec![],
|
||||||
overrides: vec![],
|
overrides: vec![],
|
||||||
|
g_settings: vec![],
|
||||||
settings: AppFlags::new(),
|
settings: AppFlags::new(),
|
||||||
meta: AppMeta::new(),
|
meta: AppMeta::new(),
|
||||||
}
|
}
|
||||||
|
@ -217,6 +219,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
if self.settings.is_set(AppSettings::DeriveDisplayOrder) {
|
if self.settings.is_set(AppSettings::DeriveDisplayOrder) {
|
||||||
subcmd.p.meta.disp_ord = self.subcommands.len();
|
subcmd.p.meta.disp_ord = self.subcommands.len();
|
||||||
}
|
}
|
||||||
|
for s in &self.g_settings {
|
||||||
|
subcmd.p.set(*s);
|
||||||
|
subcmd.p.g_settings.push(*s);
|
||||||
|
}
|
||||||
self.subcommands.push(subcmd);
|
self.subcommands.push(subcmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,7 +537,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
self.meta
|
self.meta
|
||||||
.bin_name
|
.bin_name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap_or(&self.meta.name)));
|
.unwrap_or(&self.meta.name),
|
||||||
|
self.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sc.clone()
|
sc.clone()
|
||||||
|
@ -551,7 +558,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
.bin_name
|
.bin_name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap_or(&self.meta.name),
|
.unwrap_or(&self.meta.name),
|
||||||
&*self.create_current_usage(matcher)));
|
&*self.create_current_usage(matcher),
|
||||||
|
self.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,7 +573,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
if let None = a.to_str() {
|
if let None = a.to_str() {
|
||||||
if !self.settings.is_set(AppSettings::StrictUtf8) {
|
if !self.settings.is_set(AppSettings::StrictUtf8) {
|
||||||
return Err(
|
return Err(
|
||||||
Error::invalid_utf8(&*self.create_current_usage(matcher))
|
Error::invalid_utf8(&*self.create_current_usage(matcher), self.color())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -579,7 +587,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
|
return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
|
||||||
"",
|
"",
|
||||||
&*self.create_current_usage(matcher)));
|
&*self.create_current_usage(matcher),
|
||||||
|
self.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -595,7 +604,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
if should_err {
|
if should_err {
|
||||||
return Err(Error::empty_value(o, &*self.create_current_usage(matcher)));
|
return Err(Error::empty_value(o, &*self.create_current_usage(matcher), self.color()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::empty_value(self.positionals
|
return Err(Error::empty_value(self.positionals
|
||||||
|
@ -603,7 +612,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
.filter(|p| &p.name == &a)
|
.filter(|p| &p.name == &a)
|
||||||
.next()
|
.next()
|
||||||
.expect(INTERNAL_ERROR_MSG),
|
.expect(INTERNAL_ERROR_MSG),
|
||||||
&*self.create_current_usage(matcher)));
|
&*self.create_current_usage(matcher),
|
||||||
|
self.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,10 +649,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
try!(self.parse_subcommand(sc_name, matcher, it));
|
try!(self.parse_subcommand(sc_name, matcher, it));
|
||||||
} else if self.is_set(AppSettings::SubcommandRequired) {
|
} else if self.is_set(AppSettings::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, &self.create_current_usage(matcher)));
|
return Err(Error::missing_subcommand(bn, &self.create_current_usage(matcher), self.color()));
|
||||||
} else if self.is_set(AppSettings::SubcommandRequiredElseHelp) {
|
} else if self.is_set(AppSettings::SubcommandRequiredElseHelp) {
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
try!(self.write_help(&mut out));
|
try!(self.write_help_err(&mut out));
|
||||||
return Err(Error {
|
return Err(Error {
|
||||||
message: String::from_utf8_lossy(&*out).into_owned(),
|
message: String::from_utf8_lossy(&*out).into_owned(),
|
||||||
kind: ErrorKind::MissingArgumentOrSubcommand,
|
kind: ErrorKind::MissingArgumentOrSubcommand,
|
||||||
|
@ -652,7 +662,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
if matcher.is_empty() && matcher.subcommand_name().is_none() &&
|
if matcher.is_empty() && matcher.subcommand_name().is_none() &&
|
||||||
self.is_set(AppSettings::ArgRequiredElseHelp) {
|
self.is_set(AppSettings::ArgRequiredElseHelp) {
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
try!(self.write_help(&mut out));
|
try!(self.write_help_err(&mut out));
|
||||||
return Err(Error {
|
return Err(Error {
|
||||||
message: String::from_utf8_lossy(&*out).into_owned(),
|
message: String::from_utf8_lossy(&*out).into_owned(),
|
||||||
kind: ErrorKind::MissingArgumentOrSubcommand,
|
kind: ErrorKind::MissingArgumentOrSubcommand,
|
||||||
|
@ -1074,7 +1084,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
arg.push(c);
|
arg.push(c);
|
||||||
return Err(Error::unknown_argument(&*arg,
|
return Err(Error::unknown_argument(&*arg,
|
||||||
"",
|
"",
|
||||||
&*self.create_current_usage(matcher)));
|
&*self.create_current_usage(matcher),
|
||||||
|
self.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
@ -1093,7 +1104,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
let v = fv.trim_left_matches(b'=');
|
let v = fv.trim_left_matches(b'=');
|
||||||
if !opt.is_set(ArgSettings::EmptyValues) && v.len_() == 0 {
|
if !opt.is_set(ArgSettings::EmptyValues) && v.len_() == 0 {
|
||||||
sdebugln!("Found Empty - Error");
|
sdebugln!("Found Empty - Error");
|
||||||
return Err(Error::empty_value(opt, &*self.create_current_usage(matcher)));
|
return Err(Error::empty_value(opt, &*self.create_current_usage(matcher), self.color()));
|
||||||
}
|
}
|
||||||
sdebugln!("Found - {:?}, len: {}", v, v.len_());
|
sdebugln!("Found - {:?}, len: {}", v, v.len_());
|
||||||
try!(self.add_val_to_arg(opt, v, matcher));
|
try!(self.add_val_to_arg(opt, v, matcher));
|
||||||
|
@ -1165,7 +1176,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
{
|
{
|
||||||
debugln!("fn=validate_value; val={:?}", val);
|
debugln!("fn=validate_value; val={:?}", val);
|
||||||
if self.is_set(AppSettings::StrictUtf8) && val.to_str().is_none() {
|
if self.is_set(AppSettings::StrictUtf8) && val.to_str().is_none() {
|
||||||
return Err(Error::invalid_utf8(&*self.create_current_usage(matcher)));
|
return Err(Error::invalid_utf8(&*self.create_current_usage(matcher), self.color()));
|
||||||
}
|
}
|
||||||
if let Some(ref p_vals) = arg.possible_vals() {
|
if let Some(ref p_vals) = arg.possible_vals() {
|
||||||
let val_str = val.to_string_lossy();
|
let val_str = val.to_string_lossy();
|
||||||
|
@ -1173,16 +1184,17 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
return Err(Error::invalid_value(val_str,
|
return Err(Error::invalid_value(val_str,
|
||||||
p_vals,
|
p_vals,
|
||||||
arg,
|
arg,
|
||||||
&*self.create_current_usage(matcher)));
|
&*self.create_current_usage(matcher),
|
||||||
|
self.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_() &&
|
if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_() &&
|
||||||
matcher.contains(&*arg.name()) {
|
matcher.contains(&*arg.name()) {
|
||||||
return Err(Error::empty_value(arg, &*self.create_current_usage(matcher)));
|
return Err(Error::empty_value(arg, &*self.create_current_usage(matcher), self.color()));
|
||||||
}
|
}
|
||||||
if let Some(ref vtor) = arg.validator() {
|
if let Some(ref vtor) = arg.validator() {
|
||||||
if let Err(e) = vtor(val.to_string_lossy().into_owned()) {
|
if let Err(e) = vtor(val.to_string_lossy().into_owned()) {
|
||||||
return Err(Error::value_validation(e));
|
return Err(Error::value_validation(e, self.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if matcher.needs_more_vals(arg) {
|
if matcher.needs_more_vals(arg) {
|
||||||
|
@ -1216,19 +1228,19 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
let usg = $me.create_current_usage($matcher);
|
let usg = $me.create_current_usage($matcher);
|
||||||
if let Some(f) = $me.flags.iter().filter(|f| f.name == $name).next() {
|
if let Some(f) = $me.flags.iter().filter(|f| f.name == $name).next() {
|
||||||
debugln!("It was a flag...");
|
debugln!("It was a flag...");
|
||||||
Error::argument_conflict(f, c_with, &*usg)
|
Error::argument_conflict(f, c_with, &*usg, self.color())
|
||||||
} else if let Some(o) = $me.opts.iter()
|
} else if let Some(o) = $me.opts.iter()
|
||||||
.filter(|o| o.name == $name)
|
.filter(|o| o.name == $name)
|
||||||
.next() {
|
.next() {
|
||||||
debugln!("It was an option...");
|
debugln!("It was an option...");
|
||||||
Error::argument_conflict(o, c_with, &*usg)
|
Error::argument_conflict(o, c_with, &*usg, self.color())
|
||||||
} else {
|
} else {
|
||||||
match $me.positionals.values()
|
match $me.positionals.values()
|
||||||
.filter(|p| p.name == $name)
|
.filter(|p| p.name == $name)
|
||||||
.next() {
|
.next() {
|
||||||
Some(p) => {
|
Some(p) => {
|
||||||
debugln!("It was a positional...");
|
debugln!("It was a positional...");
|
||||||
Error::argument_conflict(p, c_with, &*usg)
|
Error::argument_conflict(p, c_with, &*usg, self.color())
|
||||||
},
|
},
|
||||||
None => panic!(INTERNAL_ERROR_MSG)
|
None => panic!(INTERNAL_ERROR_MSG)
|
||||||
}
|
}
|
||||||
|
@ -1304,7 +1316,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
} else {
|
} else {
|
||||||
"ere"
|
"ere"
|
||||||
},
|
},
|
||||||
&*self.create_current_usage(matcher)));
|
&*self.create_current_usage(matcher),
|
||||||
|
self.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(num) = a.max_vals() {
|
if let Some(num) = a.max_vals() {
|
||||||
|
@ -1320,7 +1333,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
.to_str()
|
.to_str()
|
||||||
.expect(INVALID_UTF8),
|
.expect(INVALID_UTF8),
|
||||||
a,
|
a,
|
||||||
&*self.create_current_usage(matcher)));
|
&*self.create_current_usage(matcher),
|
||||||
|
self.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(num) = a.min_vals() {
|
if let Some(num) = a.min_vals() {
|
||||||
|
@ -1330,7 +1344,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
return Err(Error::too_few_values(a,
|
return Err(Error::too_few_values(a,
|
||||||
num,
|
num,
|
||||||
ma.vals.len(),
|
ma.vals.len(),
|
||||||
&*self.create_current_usage(matcher)));
|
&*self.create_current_usage(matcher),
|
||||||
|
self.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1375,7 +1390,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
.iter()
|
.iter()
|
||||||
.fold(String::new(),
|
.fold(String::new(),
|
||||||
|acc, s| acc + &format!("\n {}", Format::Error(s))[..]),
|
|acc, s| acc + &format!("\n {}", Format::Error(s))[..]),
|
||||||
&*self.create_current_usage(matcher))
|
&*self.create_current_usage(matcher),
|
||||||
|
self.color())
|
||||||
};
|
};
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
@ -1439,7 +1455,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
}
|
}
|
||||||
|
|
||||||
let used_arg = format!("--{}", arg);
|
let used_arg = format!("--{}", arg);
|
||||||
Err(Error::unknown_argument(&*used_arg, &*suffix.0, &*self.create_current_usage(matcher)))
|
Err(Error::unknown_argument(&*used_arg, &*suffix.0, &*self.create_current_usage(matcher), self.color()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a usage string if one was not provided by the user manually. This happens just
|
// Creates a usage string if one was not provided by the user manually. This happens just
|
||||||
|
@ -1498,7 +1514,17 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
}
|
}
|
||||||
if self.has_positionals() &&
|
if self.has_positionals() &&
|
||||||
self.positionals.values().any(|a| !a.settings.is_set(ArgSettings::Required)) {
|
self.positionals.values().any(|a| !a.settings.is_set(ArgSettings::Required)) {
|
||||||
usage.push_str(" [ARGS]");
|
if self.positionals.len() == 1 {
|
||||||
|
let p = self.positionals.values().next().expect(INTERNAL_ERROR_MSG);
|
||||||
|
if !self.groups.values().any(|g| g.args.iter().any(|a| a == &p.name)) {
|
||||||
|
usage.push_str(&*format!(" [{}]{}", p.name_no_brackets(),
|
||||||
|
p.multiple_str()));
|
||||||
|
} else {
|
||||||
|
usage.push_str(" [ARGS]");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
usage.push_str(" [ARGS]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1578,6 +1604,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
Help::write_parser_help(w, &self)
|
Help::write_parser_help(w, &self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_help_err<W: Write>(&self, w: &mut W) -> ClapResult<()> {
|
||||||
|
Help::write_parser_help_to_stderr(w, &self)
|
||||||
|
}
|
||||||
|
|
||||||
fn add_defaults(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
|
fn add_defaults(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
|
||||||
macro_rules! add_val {
|
macro_rules! add_val {
|
||||||
($_self:ident, $a:ident, $m:ident) => {
|
($_self:ident, $a:ident, $m:ident) => {
|
||||||
|
@ -1609,6 +1639,23 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
pub fn iter_positionals(&self) -> vec_map::Values<PosBuilder> {
|
pub fn iter_positionals(&self) -> vec_map::Values<PosBuilder> {
|
||||||
self.positionals.values()
|
self.positionals.values()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should we color the output? None=determined by output location, true=yes, false=no
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn color(&self) -> ColorWhen {
|
||||||
|
debugln!("exec=color;");
|
||||||
|
debug!("Color setting...");
|
||||||
|
if self.is_set(AppSettings::ColorNever) {
|
||||||
|
sdebugln!("Never");
|
||||||
|
ColorWhen::Never
|
||||||
|
} else if self.is_set(AppSettings::ColorAlways) {
|
||||||
|
sdebugln!("Always");
|
||||||
|
ColorWhen::Always
|
||||||
|
} else {
|
||||||
|
sdebugln!("Auto");
|
||||||
|
ColorWhen::Auto
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Clone for Parser<'a, 'b>
|
impl<'a, 'b> Clone for Parser<'a, 'b>
|
||||||
|
@ -1630,6 +1677,7 @@ impl<'a, 'b> Clone for Parser<'a, 'b>
|
||||||
help_short: self.help_short,
|
help_short: self.help_short,
|
||||||
version_short: self.version_short,
|
version_short: self.version_short,
|
||||||
settings: self.settings.clone(),
|
settings: self.settings.clone(),
|
||||||
|
g_settings: self.g_settings.clone(),
|
||||||
meta: self.meta.clone(),
|
meta: self.meta.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,29 +3,32 @@ use std::ascii::AsciiExt;
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
flags Flags: u32 {
|
flags Flags: u32 {
|
||||||
const SC_NEGATE_REQS = 0b00000000000000000000001,
|
const SC_NEGATE_REQS = 0b00000000000000000000000001,
|
||||||
const SC_REQUIRED = 0b00000000000000000000010,
|
const SC_REQUIRED = 0b00000000000000000000000010,
|
||||||
const A_REQUIRED_ELSE_HELP = 0b00000000000000000000100,
|
const A_REQUIRED_ELSE_HELP = 0b00000000000000000000000100,
|
||||||
const GLOBAL_VERSION = 0b00000000000000000001000,
|
const GLOBAL_VERSION = 0b00000000000000000000001000,
|
||||||
const VERSIONLESS_SC = 0b00000000000000000010000,
|
const VERSIONLESS_SC = 0b00000000000000000000010000,
|
||||||
const UNIFIED_HELP = 0b00000000000000000100000,
|
const UNIFIED_HELP = 0b00000000000000000000100000,
|
||||||
const WAIT_ON_ERROR = 0b00000000000000001000000,
|
const WAIT_ON_ERROR = 0b00000000000000000001000000,
|
||||||
const SC_REQUIRED_ELSE_HELP= 0b00000000000000010000000,
|
const SC_REQUIRED_ELSE_HELP= 0b00000000000000000010000000,
|
||||||
const NEEDS_LONG_HELP = 0b00000000000000100000000,
|
const NEEDS_LONG_HELP = 0b00000000000000000100000000,
|
||||||
const NEEDS_LONG_VERSION = 0b00000000000001000000000,
|
const NEEDS_LONG_VERSION = 0b00000000000000001000000000,
|
||||||
const NEEDS_SC_HELP = 0b00000000000010000000000,
|
const NEEDS_SC_HELP = 0b00000000000000010000000000,
|
||||||
const DISABLE_VERSION = 0b00000000000100000000000,
|
const DISABLE_VERSION = 0b00000000000000100000000000,
|
||||||
const HIDDEN = 0b00000000001000000000000,
|
const HIDDEN = 0b00000000000001000000000000,
|
||||||
const TRAILING_VARARG = 0b00000000010000000000000,
|
const TRAILING_VARARG = 0b00000000000010000000000000,
|
||||||
const NO_BIN_NAME = 0b00000000100000000000000,
|
const NO_BIN_NAME = 0b00000000000100000000000000,
|
||||||
const ALLOW_UNK_SC = 0b00000001000000000000000,
|
const ALLOW_UNK_SC = 0b00000000001000000000000000,
|
||||||
const UTF8_STRICT = 0b00000010000000000000000,
|
const UTF8_STRICT = 0b00000000010000000000000000,
|
||||||
const UTF8_NONE = 0b00000100000000000000000,
|
const UTF8_NONE = 0b00000000100000000000000000,
|
||||||
const LEADING_HYPHEN = 0b00001000000000000000000,
|
const LEADING_HYPHEN = 0b00000001000000000000000000,
|
||||||
const NO_POS_VALUES = 0b00010000000000000000000,
|
const NO_POS_VALUES = 0b00000010000000000000000000,
|
||||||
const NEXT_LINE_HELP = 0b00100000000000000000000,
|
const NEXT_LINE_HELP = 0b00000100000000000000000000,
|
||||||
const DERIVE_DISP_ORDER = 0b01000000000000000000000,
|
const DERIVE_DISP_ORDER = 0b00001000000000000000000000,
|
||||||
const COLORED_HELP = 0b10000000000000000000000,
|
const COLORED_HELP = 0b00010000000000000000000000,
|
||||||
|
const COLOR_ALWAYS = 0b00100000000000000000000000,
|
||||||
|
const COLOR_AUTO = 0b01000000000000000000000000,
|
||||||
|
const COLOR_NEVER = 0b10000000000000000000000000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +44,7 @@ impl Clone for AppFlags {
|
||||||
|
|
||||||
impl Default for AppFlags {
|
impl Default for AppFlags {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
AppFlags(NEEDS_LONG_VERSION | NEEDS_LONG_HELP | NEEDS_SC_HELP | UTF8_NONE)
|
AppFlags(NEEDS_LONG_VERSION | NEEDS_LONG_HELP | NEEDS_SC_HELP | UTF8_NONE | COLOR_AUTO)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +76,10 @@ impl AppFlags {
|
||||||
HidePossibleValuesInHelp => NO_POS_VALUES,
|
HidePossibleValuesInHelp => NO_POS_VALUES,
|
||||||
NextLineHelp => NEXT_LINE_HELP,
|
NextLineHelp => NEXT_LINE_HELP,
|
||||||
ColoredHelp => COLORED_HELP,
|
ColoredHelp => COLORED_HELP,
|
||||||
DeriveDisplayOrder => DERIVE_DISP_ORDER
|
DeriveDisplayOrder => DERIVE_DISP_ORDER,
|
||||||
|
ColorAlways => COLOR_ALWAYS,
|
||||||
|
ColorAuto => COLOR_AUTO,
|
||||||
|
ColorNever => COLOR_NEVER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,6 +498,59 @@ pub enum AppSettings {
|
||||||
/// .get_matches();
|
/// .get_matches();
|
||||||
/// ```
|
/// ```
|
||||||
ColoredHelp,
|
ColoredHelp,
|
||||||
|
/// Enables colored output only when the output is going to a terminal or TTY.
|
||||||
|
///
|
||||||
|
/// **NOTE:** This is the default behavior of `clap`
|
||||||
|
///
|
||||||
|
/// **NOTE:** Must be compiled with the `color` cargo feature
|
||||||
|
///
|
||||||
|
/// # Platform Specific
|
||||||
|
///
|
||||||
|
/// This setting only applies to Unix, Linux, and OSX (i.e. non-Windows platforms)
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// # use clap::{App, Arg, SubCommand, AppSettings};
|
||||||
|
/// App::new("myprog")
|
||||||
|
/// .setting(AppSettings::ColorAuto)
|
||||||
|
/// .get_matches();
|
||||||
|
/// ```
|
||||||
|
ColorAuto,
|
||||||
|
/// Enables colored output regardless of whether or not the output is going to a terminal/TTY.
|
||||||
|
///
|
||||||
|
/// **NOTE:** Must be compiled with the `color` cargo feature
|
||||||
|
///
|
||||||
|
/// # Platform Specific
|
||||||
|
///
|
||||||
|
/// This setting only applies to Unix, Linux, and OSX (i.e. non-Windows platforms)
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// # use clap::{App, Arg, SubCommand, AppSettings};
|
||||||
|
/// App::new("myprog")
|
||||||
|
/// .setting(AppSettings::ColorAlways)
|
||||||
|
/// .get_matches();
|
||||||
|
/// ```
|
||||||
|
ColorAlways,
|
||||||
|
/// Disables colored output no matter if the output is going to a terminal/TTY, or not.
|
||||||
|
///
|
||||||
|
/// **NOTE:** Must be compiled with the `color` cargo feature
|
||||||
|
///
|
||||||
|
/// # Platform Specific
|
||||||
|
///
|
||||||
|
/// This setting only applies to Unix, Linux, and OSX (i.e. non-Windows platforms)
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// # use clap::{App, Arg, SubCommand, AppSettings};
|
||||||
|
/// App::new("myprog")
|
||||||
|
/// .setting(AppSettings::ColorNever)
|
||||||
|
/// .get_matches();
|
||||||
|
/// ```
|
||||||
|
ColorNever,
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
NeedsLongVersion,
|
NeedsLongVersion,
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::fmt::{Display, Formatter, Result};
|
use std::fmt::{Display, Formatter, Result};
|
||||||
use std::result::Result as StdResult;
|
use std::result::Result as StdResult;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use vec_map::VecMap;
|
use vec_map::VecMap;
|
||||||
|
|
||||||
|
@ -108,6 +109,25 @@ impl<'n, 'e> PosBuilder<'n, 'e> {
|
||||||
}
|
}
|
||||||
pb
|
pb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn multiple_str(&self) -> &str {
|
||||||
|
if self.settings.is_set(ArgSettings::Multiple) && self.val_names.is_none() {
|
||||||
|
"..."
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name_no_brackets(&self) -> Cow<str> {
|
||||||
|
if let Some(ref names) = self.val_names {
|
||||||
|
Cow::Owned(names.values()
|
||||||
|
.map(|n| format!("<{}>", n))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" "))
|
||||||
|
} else {
|
||||||
|
Cow::Borrowed(self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'n, 'e> Display for PosBuilder<'n, 'e> {
|
impl<'n, 'e> Display for PosBuilder<'n, 'e> {
|
||||||
|
|
223
src/errors.rs
223
src/errors.rs
|
@ -6,7 +6,7 @@ use std::io::{self, Write};
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::result::Result as StdResult;
|
use std::result::Result as StdResult;
|
||||||
|
|
||||||
use fmt::Format;
|
use fmt;
|
||||||
use suggestions;
|
use suggestions;
|
||||||
use args::any_arg::AnyArg;
|
use args::any_arg::AnyArg;
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ use args::any_arg::AnyArg;
|
||||||
/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
|
/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
|
||||||
pub type Result<T> = StdResult<T, Error>;
|
pub type Result<T> = StdResult<T, Error>;
|
||||||
|
|
||||||
|
|
||||||
/// Command line argument parser kind of error
|
/// Command line argument parser kind of error
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub enum ErrorKind {
|
pub enum ErrorKind {
|
||||||
|
@ -382,54 +383,62 @@ impl Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn argument_conflict<'a, 'b, A, O, U>(arg: &A, other: Option<O>, usage: U) -> Self
|
pub fn argument_conflict<'a, 'b, A, O, U>(arg: &A, other: Option<O>, usage: U, color: fmt::ColorWhen) -> Self
|
||||||
where A: AnyArg<'a, 'b> + Display,
|
where A: AnyArg<'a, 'b> + Display,
|
||||||
O: Into<String>,
|
O: Into<String>,
|
||||||
U: Display
|
U: Display
|
||||||
{
|
{
|
||||||
let mut v = vec![arg.name().to_owned()];
|
let mut v = vec![arg.name().to_owned()];
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} The argument '{}' cannot be used with {}\n\n\
|
message: format!("{} The argument '{}' cannot be used with {}\n\n\
|
||||||
{}\n\n\
|
{}\n\n\
|
||||||
For more information try {}",
|
For more information try {}",
|
||||||
Format::Error("error:"),
|
c.error("error:"),
|
||||||
Format::Warning(arg.to_string()),
|
c.warning(&*arg.to_string()),
|
||||||
match other {
|
match other {
|
||||||
Some(name) => {
|
Some(name) => {
|
||||||
let n = name.into();
|
let n = name.into();
|
||||||
v.push(n.clone());
|
v.push(n.clone());
|
||||||
format!("'{}'", Format::Warning(n))
|
c.warning(format!("'{}'", n))
|
||||||
}
|
}
|
||||||
None => "one or more of the other specified arguments".to_owned(),
|
None => c.none("one or more of the other specified arguments".to_owned()),
|
||||||
},
|
},
|
||||||
usage,
|
usage,
|
||||||
Format::Good("--help")),
|
c.good("--help")),
|
||||||
kind: ErrorKind::ArgumentConflict,
|
kind: ErrorKind::ArgumentConflict,
|
||||||
info: Some(v),
|
info: Some(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn empty_value<'a, 'b, A, U>(arg: &A, usage: U) -> Self
|
pub fn empty_value<'a, 'b, A, U>(arg: &A, usage: U, color: fmt::ColorWhen) -> Self
|
||||||
where A: AnyArg<'a, 'b> + Display,
|
where A: AnyArg<'a, 'b> + Display,
|
||||||
U: Display
|
U: Display
|
||||||
{
|
{
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} The argument '{}' requires a value but none was supplied\
|
message: format!("{} The argument '{}' requires a value but none was supplied\
|
||||||
\n\n\
|
\n\n\
|
||||||
{}\n\n\
|
{}\n\n\
|
||||||
For more information try {}",
|
For more information try {}",
|
||||||
Format::Error("error:"),
|
c.error("error:"),
|
||||||
Format::Warning(arg.to_string()),
|
c.warning(arg.to_string()),
|
||||||
usage,
|
usage,
|
||||||
Format::Good("--help")),
|
c.good("--help")),
|
||||||
kind: ErrorKind::EmptyValue,
|
kind: ErrorKind::EmptyValue,
|
||||||
info: Some(vec![arg.name().to_owned()]),
|
info: Some(vec![arg.name().to_owned()]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn invalid_value<'a, 'b, B, G, A, U>(bad_val: B, good_vals: &[G], arg: &A, usage: U) -> Self
|
pub fn invalid_value<'a, 'b, B, G, A, U>(bad_val: B, good_vals: &[G], arg: &A, usage: U, color: fmt::ColorWhen) -> Self
|
||||||
where B: AsRef<str>,
|
where B: AsRef<str>,
|
||||||
G: AsRef<str> + Display,
|
G: AsRef<str> + Display,
|
||||||
A: AnyArg<'a, 'b> + Display,
|
A: AnyArg<'a, 'b> + Display,
|
||||||
|
@ -446,32 +455,40 @@ impl Error {
|
||||||
}
|
}
|
||||||
sorted.sort();
|
sorted.sort();
|
||||||
let valid_values = sorted.join(" ");
|
let valid_values = sorted.join(" ");
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} '{}' isn't a valid value for '{}'\n\t\
|
message: format!("{} '{}' isn't a valid value for '{}'\n\t\
|
||||||
[values:{}]\n\
|
[values:{}]\n\
|
||||||
{}\n\n\
|
{}\n\n\
|
||||||
{}\n\n\
|
{}\n\n\
|
||||||
For more information try {}",
|
For more information try {}",
|
||||||
Format::Error("error:"),
|
c.error("error:"),
|
||||||
Format::Warning(bad_val.as_ref()),
|
c.warning(bad_val.as_ref()),
|
||||||
Format::Warning(arg.to_string()),
|
c.warning(arg.to_string()),
|
||||||
valid_values,
|
valid_values,
|
||||||
suffix.0,
|
suffix.0,
|
||||||
usage,
|
usage,
|
||||||
Format::Good("--help")),
|
c.good("--help")),
|
||||||
kind: ErrorKind::InvalidValue,
|
kind: ErrorKind::InvalidValue,
|
||||||
info: Some(vec![arg.name().to_owned(), bad_val.as_ref().to_owned()]),
|
info: Some(vec![arg.name().to_owned(), bad_val.as_ref().to_owned()]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn invalid_subcommand<S, D, N, U>(subcmd: S, did_you_mean: D, name: N, usage: U) -> Self
|
pub fn invalid_subcommand<S, D, N, U>(subcmd: S, did_you_mean: D, name: N, usage: U, color: fmt::ColorWhen) -> Self
|
||||||
where S: Into<String>,
|
where S: Into<String>,
|
||||||
D: AsRef<str> + Display,
|
D: AsRef<str> + Display,
|
||||||
N: Display,
|
N: Display,
|
||||||
U: Display
|
U: Display
|
||||||
{
|
{
|
||||||
let s = subcmd.into();
|
let s = subcmd.into();
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} The subcommand '{}' wasn't recognized\n\t\
|
message: format!("{} The subcommand '{}' wasn't recognized\n\t\
|
||||||
Did you mean '{}' ?\n\n\
|
Did you mean '{}' ?\n\n\
|
||||||
|
@ -479,70 +496,82 @@ impl Error {
|
||||||
re-running with '{} {} {}'\n\n\
|
re-running with '{} {} {}'\n\n\
|
||||||
{}\n\n\
|
{}\n\n\
|
||||||
For more information try {}",
|
For more information try {}",
|
||||||
Format::Error("error:"),
|
c.error("error:"),
|
||||||
Format::Warning(&*s),
|
c.warning(&*s),
|
||||||
Format::Good(did_you_mean.as_ref()),
|
c.good(did_you_mean.as_ref()),
|
||||||
name,
|
name,
|
||||||
Format::Good("--"),
|
c.good("--"),
|
||||||
&*s,
|
&*s,
|
||||||
usage,
|
usage,
|
||||||
Format::Good("--help")),
|
c.good("--help")),
|
||||||
kind: ErrorKind::InvalidSubcommand,
|
kind: ErrorKind::InvalidSubcommand,
|
||||||
info: Some(vec![s]),
|
info: Some(vec![s]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn unrecognized_subcommand<S, N>(subcmd: S, name: N) -> Self
|
pub fn unrecognized_subcommand<S, N>(subcmd: S, name: N, color: fmt::ColorWhen) -> Self
|
||||||
where S: Into<String>,
|
where S: Into<String>,
|
||||||
N: Display
|
N: Display
|
||||||
{
|
{
|
||||||
let s = subcmd.into();
|
let s = subcmd.into();
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} The subcommand '{}' wasn't recognized\n\n\
|
message: format!("{} The subcommand '{}' wasn't recognized\n\n\
|
||||||
USAGE:\n\t\
|
USAGE:\n\t\
|
||||||
{} help <subcommands>...\n\n\
|
{} help <subcommands>...\n\n\
|
||||||
For more information try {}",
|
For more information try {}",
|
||||||
Format::Error("error:"),
|
c.error("error:"),
|
||||||
Format::Warning(&*s),
|
c.warning(&*s),
|
||||||
name,
|
name,
|
||||||
Format::Good("--help")),
|
c.good("--help")),
|
||||||
kind: ErrorKind::UnrecognizedSubcommand,
|
kind: ErrorKind::UnrecognizedSubcommand,
|
||||||
info: Some(vec![s]),
|
info: Some(vec![s]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn missing_required_argument<R, U>(required: R, usage: U) -> Self
|
pub fn missing_required_argument<R, U>(required: R, usage: U, color: fmt::ColorWhen) -> Self
|
||||||
where R: Display,
|
where R: Display,
|
||||||
U: Display
|
U: Display
|
||||||
{
|
{
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} The following required arguments were not provided:{}\n\n\
|
message: format!("{} The following required arguments were not provided:{}\n\n\
|
||||||
{}\n\n\
|
{}\n\n\
|
||||||
For more information try {}",
|
For more information try {}",
|
||||||
Format::Error("error:"),
|
c.error("error:"),
|
||||||
required,
|
required,
|
||||||
usage,
|
usage,
|
||||||
Format::Good("--help")),
|
c.good("--help")),
|
||||||
kind: ErrorKind::MissingRequiredArgument,
|
kind: ErrorKind::MissingRequiredArgument,
|
||||||
info: None,
|
info: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn missing_subcommand<N, U>(name: N, usage: U) -> Self
|
pub fn missing_subcommand<N, U>(name: N, usage: U, color: fmt::ColorWhen) -> Self
|
||||||
where N: AsRef<str> + Display,
|
where N: AsRef<str> + Display,
|
||||||
U: Display
|
U: Display
|
||||||
{
|
{
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} '{}' requires a subcommand, but one was not provided\n\n\
|
message: format!("{} '{}' requires a subcommand, but one was not provided\n\n\
|
||||||
{}\n\n\
|
{}\n\n\
|
||||||
For more information try {}",
|
For more information try {}",
|
||||||
Format::Error("error:"),
|
c.error("error:"),
|
||||||
Format::Warning(name),
|
c.warning(name),
|
||||||
usage,
|
usage,
|
||||||
Format::Good("--help")),
|
c.good("--help")),
|
||||||
kind: ErrorKind::MissingSubcommand,
|
kind: ErrorKind::MissingSubcommand,
|
||||||
info: None,
|
info: None,
|
||||||
}
|
}
|
||||||
|
@ -550,158 +579,208 @@ impl Error {
|
||||||
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn invalid_utf8<U>(usage: U) -> Self
|
pub fn invalid_utf8<U>(usage: U, color: fmt::ColorWhen) -> Self
|
||||||
where U: Display
|
where U: Display
|
||||||
{
|
{
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} Invalid UTF-8 was detected in one or more arguments\n\n\
|
message: format!("{} Invalid UTF-8 was detected in one or more arguments\n\n\
|
||||||
{}\n\n\
|
{}\n\n\
|
||||||
For more information try {}",
|
For more information try {}",
|
||||||
Format::Error("error:"),
|
c.error("error:"),
|
||||||
usage,
|
usage,
|
||||||
Format::Good("--help")),
|
c.good("--help")),
|
||||||
kind: ErrorKind::InvalidUtf8,
|
kind: ErrorKind::InvalidUtf8,
|
||||||
info: None,
|
info: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn too_many_values<'a, 'b, V, A, U>(val: V, arg: &A, usage: U) -> Self
|
pub fn too_many_values<'a, 'b, V, A, U>(val: V, arg: &A, usage: U, color: fmt::ColorWhen) -> Self
|
||||||
where V: AsRef<str> + Display + ToOwned,
|
where V: AsRef<str> + Display + ToOwned,
|
||||||
A: AnyArg<'a, 'b> + Display,
|
A: AnyArg<'a, 'b> + Display,
|
||||||
U: Display
|
U: Display
|
||||||
{
|
{
|
||||||
let v = val.as_ref();
|
let v = val.as_ref();
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} The value '{}' was provided to '{}', but it wasn't expecting \
|
message: format!("{} The value '{}' was provided to '{}', but it wasn't expecting \
|
||||||
any more values\n\n\
|
any more values\n\n\
|
||||||
{}\n\n\
|
{}\n\n\
|
||||||
For more information try {}",
|
For more information try {}",
|
||||||
Format::Error("error:"),
|
c.error("error:"),
|
||||||
Format::Warning(v),
|
c.warning(v),
|
||||||
Format::Warning(arg.to_string()),
|
c.warning(arg.to_string()),
|
||||||
usage,
|
usage,
|
||||||
Format::Good("--help")),
|
c.good("--help")),
|
||||||
kind: ErrorKind::TooManyValues,
|
kind: ErrorKind::TooManyValues,
|
||||||
info: Some(vec![arg.name().to_owned(), v.to_owned()]),
|
info: Some(vec![arg.name().to_owned(), v.to_owned()]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn too_few_values<'a, 'b, A, U>(arg: &A, min_vals: u64, curr_vals: usize, usage: U) -> Self
|
pub fn too_few_values<'a, 'b, A, U>(arg: &A, min_vals: u64, curr_vals: usize, usage: U, color: fmt::ColorWhen) -> Self
|
||||||
where A: AnyArg<'a, 'b> + Display,
|
where A: AnyArg<'a, 'b> + Display,
|
||||||
U: Display
|
U: Display
|
||||||
{
|
{
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} The argument '{}' requires at least {} values, but only {} w{} \
|
message: format!("{} The argument '{}' requires at least {} values, but only {} w{} \
|
||||||
provided\n\n\
|
provided\n\n\
|
||||||
{}\n\n\
|
{}\n\n\
|
||||||
For more information try {}",
|
For more information try {}",
|
||||||
Format::Error("error:"),
|
c.error("error:"),
|
||||||
Format::Warning(arg.to_string()),
|
c.warning(arg.to_string()),
|
||||||
Format::Warning(min_vals.to_string()),
|
c.warning(min_vals.to_string()),
|
||||||
Format::Warning(curr_vals.to_string()),
|
c.warning(curr_vals.to_string()),
|
||||||
if curr_vals > 1 {
|
if curr_vals > 1 {
|
||||||
"ere"
|
"ere"
|
||||||
} else {
|
} else {
|
||||||
"as"
|
"as"
|
||||||
},
|
},
|
||||||
usage,
|
usage,
|
||||||
Format::Good("--help")),
|
c.good("--help")),
|
||||||
kind: ErrorKind::TooFewValues,
|
kind: ErrorKind::TooFewValues,
|
||||||
info: Some(vec![arg.name().to_owned()]),
|
info: Some(vec![arg.name().to_owned()]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn value_validation(err: String) -> Self {
|
pub fn value_validation(err: String, color: fmt::ColorWhen) -> Self {
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} {}", Format::Error("error:"), err),
|
message: format!("{} {}", c.error("error:"), err),
|
||||||
kind: ErrorKind::ValueValidation,
|
kind: ErrorKind::ValueValidation,
|
||||||
info: None,
|
info: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn value_validation_auto(err: String) -> Self {
|
||||||
|
Error::value_validation(err, fmt::ColorWhen::Auto)
|
||||||
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn wrong_number_of_values<'a, 'b, A, S, U>(arg: &A,
|
pub fn wrong_number_of_values<'a, 'b, A, S, U>(arg: &A,
|
||||||
num_vals: u64,
|
num_vals: u64,
|
||||||
curr_vals: usize,
|
curr_vals: usize,
|
||||||
suffix: S,
|
suffix: S,
|
||||||
usage: U)
|
usage: U, color: fmt::ColorWhen)
|
||||||
-> Self
|
-> Self
|
||||||
where A: AnyArg<'a, 'b> + Display,
|
where A: AnyArg<'a, 'b> + Display,
|
||||||
S: Display,
|
S: Display,
|
||||||
U: Display
|
U: Display
|
||||||
{
|
{
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} The argument '{}' requires {} values, but {} w{} \
|
message: format!("{} The argument '{}' requires {} values, but {} w{} \
|
||||||
provided\n\n\
|
provided\n\n\
|
||||||
{}\n\n\
|
{}\n\n\
|
||||||
For more information try {}",
|
For more information try {}",
|
||||||
Format::Error("error:"),
|
c.error("error:"),
|
||||||
Format::Warning(arg.to_string()),
|
c.warning(arg.to_string()),
|
||||||
Format::Warning(num_vals.to_string()),
|
c.warning(num_vals.to_string()),
|
||||||
Format::Warning(curr_vals.to_string()),
|
c.warning(curr_vals.to_string()),
|
||||||
suffix,
|
suffix,
|
||||||
usage,
|
usage,
|
||||||
Format::Good("--help")),
|
c.good("--help")),
|
||||||
kind: ErrorKind::WrongNumberOfValues,
|
kind: ErrorKind::WrongNumberOfValues,
|
||||||
info: Some(vec![arg.name().to_owned()]),
|
info: Some(vec![arg.name().to_owned()]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn unexpected_multiple_usage<'a, 'b, A, U>(arg: &A, usage: U) -> Self
|
pub fn unexpected_multiple_usage<'a, 'b, A, U>(arg: &A, usage: U, color: fmt::ColorWhen) -> Self
|
||||||
where A: AnyArg<'a, 'b> + Display,
|
where A: AnyArg<'a, 'b> + Display,
|
||||||
U: Display
|
U: Display
|
||||||
{
|
{
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} The argument '{}' was provided more than once, but cannot \
|
message: format!("{} The argument '{}' was provided more than once, but cannot \
|
||||||
be used multiple times\n\n\
|
be used multiple times\n\n\
|
||||||
{}\n\n\
|
{}\n\n\
|
||||||
For more information try {}",
|
For more information try {}",
|
||||||
Format::Error("error:"),
|
c.error("error:"),
|
||||||
Format::Warning(arg.to_string()),
|
c.warning(arg.to_string()),
|
||||||
usage,
|
usage,
|
||||||
Format::Good("--help")),
|
c.good("--help")),
|
||||||
kind: ErrorKind::UnexpectedMultipleUsage,
|
kind: ErrorKind::UnexpectedMultipleUsage,
|
||||||
info: Some(vec![arg.name().to_owned()]),
|
info: Some(vec![arg.name().to_owned()]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn unknown_argument<A, U>(arg: A, did_you_mean: &str, usage: U) -> Self
|
pub fn unknown_argument<A, U>(arg: A, did_you_mean: &str, usage: U, color: fmt::ColorWhen) -> Self
|
||||||
where A: Into<String>,
|
where A: Into<String>,
|
||||||
U: Display
|
U: Display
|
||||||
{
|
{
|
||||||
let a = arg.into();
|
let a = arg.into();
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} Found argument '{}' which wasn't expected, or isn't valid in \
|
message: format!("{} Found argument '{}' which wasn't expected, or isn't valid in \
|
||||||
this context{}\n\
|
this context{}\n\
|
||||||
{}\n\n\
|
{}\n\n\
|
||||||
For more information try {}",
|
For more information try {}",
|
||||||
Format::Error("error:"),
|
c.error("error:"),
|
||||||
Format::Warning(&*a),
|
c.warning(&*a),
|
||||||
if did_you_mean.is_empty() {
|
if did_you_mean.is_empty() {
|
||||||
"\n".to_owned()
|
"\n".to_owned()
|
||||||
} else {
|
} else {
|
||||||
format!("{}\n", did_you_mean)
|
format!("{}\n", did_you_mean)
|
||||||
},
|
},
|
||||||
usage,
|
usage,
|
||||||
Format::Good("--help")),
|
c.good("--help")),
|
||||||
kind: ErrorKind::UnknownArgument,
|
kind: ErrorKind::UnknownArgument,
|
||||||
info: Some(vec![a]),
|
info: Some(vec![a]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn argument_not_found<A>(arg: A) -> Self
|
pub fn io_error(e: &Error, color: fmt::ColorWhen) -> Self {
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: color
|
||||||
|
};
|
||||||
|
Error {
|
||||||
|
message: format!("{} {}", c.error("error:"), e.description()),
|
||||||
|
kind: ErrorKind::Io,
|
||||||
|
info: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn argument_not_found_auto<A>(arg: A) -> Self
|
||||||
where A: Into<String>
|
where A: Into<String>
|
||||||
{
|
{
|
||||||
let a = arg.into();
|
let a = arg.into();
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: fmt::ColorWhen::Auto
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} The argument '{}' wasn't found",
|
message: format!("{} The argument '{}' wasn't found",
|
||||||
Format::Error("error:"),
|
c.error("error:"),
|
||||||
a.clone()),
|
a.clone()),
|
||||||
kind: ErrorKind::ArgumentNotFound,
|
kind: ErrorKind::ArgumentNotFound,
|
||||||
info: Some(vec![a]),
|
info: Some(vec![a]),
|
||||||
|
@ -723,8 +802,12 @@ impl Display for Error {
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
impl From<io::Error> for Error {
|
||||||
fn from(e: io::Error) -> Self {
|
fn from(e: io::Error) -> Self {
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: fmt::ColorWhen::Auto
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} {}", Format::Error("error:"), e.description()),
|
message: format!("{} {}", c.error("error:"), e.description()),
|
||||||
kind: ErrorKind::Io,
|
kind: ErrorKind::Io,
|
||||||
info: None,
|
info: None,
|
||||||
}
|
}
|
||||||
|
@ -733,8 +816,12 @@ impl From<io::Error> for Error {
|
||||||
|
|
||||||
impl From<std_fmt::Error> for Error {
|
impl From<std_fmt::Error> for Error {
|
||||||
fn from(e: std_fmt::Error) -> Self {
|
fn from(e: std_fmt::Error) -> Self {
|
||||||
|
let c = fmt::Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: fmt::ColorWhen::Auto
|
||||||
|
};
|
||||||
Error {
|
Error {
|
||||||
message: format!("{} {}", Format::Error("error:"), e),
|
message: format!("{} {}", c.error("error:"), e),
|
||||||
kind: ErrorKind::Format,
|
kind: ErrorKind::Format,
|
||||||
info: None,
|
info: None,
|
||||||
}
|
}
|
||||||
|
|
107
src/fmt.rs
107
src/fmt.rs
|
@ -5,6 +5,91 @@ use ansi_term::Colour::{Green, Red, Yellow};
|
||||||
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
||||||
use ansi_term::ANSIString;
|
use ansi_term::ANSIString;
|
||||||
|
|
||||||
|
#[cfg(feature = "color")]
|
||||||
|
use libc;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
||||||
|
const STDERR: i32 = libc::STDERR_FILENO;
|
||||||
|
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
||||||
|
const STDOUT: i32 = libc::STDOUT_FILENO;
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "color"), target_os = "windows"))]
|
||||||
|
const STDERR: i32 = 0;
|
||||||
|
#[cfg(any(not(feature = "color"), target_os = "windows"))]
|
||||||
|
const STDOUT: i32 = 0;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub enum ColorWhen {
|
||||||
|
Auto,
|
||||||
|
Always,
|
||||||
|
Never
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "color")]
|
||||||
|
pub fn is_a_tty(stderr: bool) -> bool {
|
||||||
|
debugln!("exec=is_a_tty;");
|
||||||
|
debugln!("Use stderr...{:?}", stderr);
|
||||||
|
let fd = if stderr { STDERR } else { STDOUT };
|
||||||
|
unsafe { libc::isatty(fd) != 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "color"))]
|
||||||
|
pub fn is_a_tty(_: bool) -> bool {
|
||||||
|
debugln!("exec=is_a_tty;");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub struct Colorizer {
|
||||||
|
pub use_stderr: bool,
|
||||||
|
pub when: ColorWhen
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! color {
|
||||||
|
($_self:ident, $c:ident, $m:expr) => {
|
||||||
|
match $_self.when {
|
||||||
|
ColorWhen::Auto => if is_a_tty($_self.use_stderr) {
|
||||||
|
Format::$c($m)
|
||||||
|
} else {
|
||||||
|
Format::None($m)
|
||||||
|
},
|
||||||
|
ColorWhen::Always => Format::$c($m),
|
||||||
|
ColorWhen::Never => Format::None($m),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Colorizer {
|
||||||
|
pub fn good<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str> {
|
||||||
|
debugln!("exec=good;");
|
||||||
|
color!(self, Good, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn warning<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str> {
|
||||||
|
debugln!("exec=warning;");
|
||||||
|
color!(self, Warning, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn error<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str> {
|
||||||
|
debugln!("exec=error;");
|
||||||
|
color!(self, Error, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn none<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str> {
|
||||||
|
debugln!("exec=none;");
|
||||||
|
Format::None(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Colorizer {
|
||||||
|
fn default() -> Self {
|
||||||
|
Colorizer {
|
||||||
|
use_stderr: true,
|
||||||
|
when: ColorWhen::Auto
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Defines styles for different types of error messages. Defaults to Error=Red, Warning=Yellow,
|
/// Defines styles for different types of error messages. Defaults to Error=Red, Warning=Yellow,
|
||||||
/// and Good=Green
|
/// and Good=Green
|
||||||
|
@ -17,6 +102,8 @@ pub enum Format<T> {
|
||||||
Warning(T),
|
Warning(T),
|
||||||
/// Defines the style used for good values, defaults to Green
|
/// Defines the style used for good values, defaults to Green
|
||||||
Good(T),
|
Good(T),
|
||||||
|
/// Defines no formatting style
|
||||||
|
None(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
||||||
|
@ -26,17 +113,11 @@ impl<T: AsRef<str>> Format<T> {
|
||||||
Format::Error(ref e) => Red.bold().paint(e.as_ref()),
|
Format::Error(ref e) => Red.bold().paint(e.as_ref()),
|
||||||
Format::Warning(ref e) => Yellow.paint(e.as_ref()),
|
Format::Warning(ref e) => Yellow.paint(e.as_ref()),
|
||||||
Format::Good(ref e) => Green.paint(e.as_ref()),
|
Format::Good(ref e) => Green.paint(e.as_ref()),
|
||||||
|
Format::None(ref e) => ANSIString::from(e.as_ref()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
|
||||||
impl<T: AsRef<str>> fmt::Display for Format<T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", &self.format())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(not(feature = "color"), target_os = "windows"))]
|
#[cfg(any(not(feature = "color"), target_os = "windows"))]
|
||||||
impl<T: fmt::Display> Format<T> {
|
impl<T: fmt::Display> Format<T> {
|
||||||
fn format(&self) -> &T {
|
fn format(&self) -> &T {
|
||||||
|
@ -44,10 +125,19 @@ impl<T: fmt::Display> Format<T> {
|
||||||
Format::Error(ref e) => e,
|
Format::Error(ref e) => e,
|
||||||
Format::Warning(ref e) => e,
|
Format::Warning(ref e) => e,
|
||||||
Format::Good(ref e) => e,
|
Format::Good(ref e) => e,
|
||||||
|
Format::None(ref e) => e,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
||||||
|
impl<T: AsRef<str>> fmt::Display for Format<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", &self.format())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(not(feature = "color"), target_os = "windows"))]
|
#[cfg(any(not(feature = "color"), target_os = "windows"))]
|
||||||
impl<T: fmt::Display> fmt::Display for Format<T> {
|
impl<T: fmt::Display> fmt::Display for Format<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
@ -59,6 +149,7 @@ impl<T: fmt::Display> fmt::Display for Format<T> {
|
||||||
mod test {
|
mod test {
|
||||||
use super::Format;
|
use super::Format;
|
||||||
use ansi_term::Colour::{Green, Red, Yellow};
|
use ansi_term::Colour::{Green, Red, Yellow};
|
||||||
|
use ansi_term::ANSIString;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn colored_output() {
|
fn colored_output() {
|
||||||
|
@ -69,5 +160,7 @@ mod test {
|
||||||
assert_eq!(&*format!("{}", good), &*format!("{}", Green.paint("good")));
|
assert_eq!(&*format!("{}", good), &*format!("{}", Green.paint("good")));
|
||||||
let warn = Format::Warning("warn");
|
let warn = Format::Warning("warn");
|
||||||
assert_eq!(&*format!("{}", warn), &*format!("{}", Yellow.paint("warn")));
|
assert_eq!(&*format!("{}", warn), &*format!("{}", Yellow.paint("warn")));
|
||||||
|
let none = Format::None("none");
|
||||||
|
assert_eq!(&*format!("{}", none), &*format!("{}", ANSIString::from("none")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -407,7 +407,7 @@ extern crate strsim;
|
||||||
extern crate ansi_term;
|
extern crate ansi_term;
|
||||||
#[cfg(feature = "yaml")]
|
#[cfg(feature = "yaml")]
|
||||||
extern crate yaml_rust;
|
extern crate yaml_rust;
|
||||||
#[cfg(all(feature = "wrap_help", not(target_os = "windows")))]
|
#[cfg(any(feature = "wrap_help", feature = "color"))]
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
#[cfg(all(feature = "wrap_help", not(target_os = "windows")))]
|
#[cfg(all(feature = "wrap_help", not(target_os = "windows")))]
|
||||||
extern crate unicode_width;
|
extern crate unicode_width;
|
||||||
|
|
|
@ -63,11 +63,11 @@ macro_rules! value_t {
|
||||||
match v.parse::<$t>() {
|
match v.parse::<$t>() {
|
||||||
Ok(val) => Ok(val),
|
Ok(val) => Ok(val),
|
||||||
Err(_) =>
|
Err(_) =>
|
||||||
Err(::clap::Error::value_validation(
|
Err(::clap::Error::value_validation_auto(
|
||||||
format!("The argument '{}' isn't a valid value", v))),
|
format!("The argument '{}' isn't a valid value", v))),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(::clap::Error::argument_not_found($v))
|
Err(::clap::Error::argument_not_found_auto($v))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -108,11 +108,11 @@ macro_rules! value_t_or_exit {
|
||||||
match v.parse::<$t>() {
|
match v.parse::<$t>() {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
Err(_) =>
|
Err(_) =>
|
||||||
::clap::Error::value_validation(
|
::clap::Error::value_validation_auto(
|
||||||
format!("The argument '{}' isn't a valid value", v)).exit(),
|
format!("The argument '{}' isn't a valid value", v)).exit(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
::clap::Error::argument_not_found($v).exit()
|
::clap::Error::argument_not_found_auto($v).exit()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ macro_rules! values_t {
|
||||||
match pv.parse::<$t>() {
|
match pv.parse::<$t>() {
|
||||||
Ok(rv) => tmp.push(rv),
|
Ok(rv) => tmp.push(rv),
|
||||||
Err(..) => {
|
Err(..) => {
|
||||||
err = Some(::clap::Error::value_validation(
|
err = Some(::clap::Error::value_validation_auto(
|
||||||
format!("The argument '{}' isn't a valid value", pv)));
|
format!("The argument '{}' isn't a valid value", pv)));
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ macro_rules! values_t {
|
||||||
None => Ok(tmp),
|
None => Ok(tmp),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(::clap::Error::argument_not_found($v))
|
Err(::clap::Error::argument_not_found_auto($v))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -215,11 +215,11 @@ macro_rules! values_t_or_exit {
|
||||||
($m:ident.values_of($v:expr), $t:ty) => {
|
($m:ident.values_of($v:expr), $t:ty) => {
|
||||||
if let Some(vals) = $m.values_of($v) {
|
if let Some(vals) = $m.values_of($v) {
|
||||||
vals.map(|v| v.parse::<$t>().unwrap_or_else(|_|{
|
vals.map(|v| v.parse::<$t>().unwrap_or_else(|_|{
|
||||||
::clap::Error::value_validation(
|
::clap::Error::value_validation_auto(
|
||||||
format!("One or more arguments aren't valid values")).exit()
|
format!("One or more arguments aren't valid values")).exit()
|
||||||
})).collect::<Vec<$t>>()
|
})).collect::<Vec<$t>>()
|
||||||
} else {
|
} else {
|
||||||
::clap::Error::argument_not_found($v).exit()
|
::clap::Error::argument_not_found_auto($v).exit()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ Kevin K.
|
||||||
tests stuff
|
tests stuff
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
test [OPTIONS] [ARGS]
|
test [OPTIONS] [arg1]
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
-f, --flag some flag
|
-f, --flag some flag
|
||||||
|
@ -125,7 +125,7 @@ Kevin K.
|
||||||
tests stuff
|
tests stuff
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
test [FLAGS] [OPTIONS] [ARGS]
|
test [FLAGS] [OPTIONS] [arg1]
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
|
@ -137,3 +137,48 @@ OPTIONS:
|
||||||
ARGS:
|
ARGS:
|
||||||
<arg1> some pos arg"));
|
<arg1> some pos arg"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn global_setting() {
|
||||||
|
let app = App::new("test")
|
||||||
|
.global_setting(AppSettings::ColoredHelp)
|
||||||
|
.subcommand(SubCommand::with_name("subcmd"));
|
||||||
|
assert!(app.p
|
||||||
|
.subcommands
|
||||||
|
.iter()
|
||||||
|
.filter(|s| s.p
|
||||||
|
.meta
|
||||||
|
.name == "subcmd")
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.p
|
||||||
|
.is_set(AppSettings::ColoredHelp));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn global_settings() {
|
||||||
|
let app = App::new("test")
|
||||||
|
.global_settings(&[AppSettings::ColoredHelp, AppSettings::TrailingVarArg])
|
||||||
|
.subcommand(SubCommand::with_name("subcmd"));
|
||||||
|
assert!(app.p
|
||||||
|
.subcommands
|
||||||
|
.iter()
|
||||||
|
.filter(|s| s.p
|
||||||
|
.meta
|
||||||
|
.name == "subcmd")
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.p
|
||||||
|
.is_set(AppSettings::ColoredHelp));
|
||||||
|
assert!(app.p
|
||||||
|
.subcommands
|
||||||
|
.iter()
|
||||||
|
.filter(|s| s.p
|
||||||
|
.meta
|
||||||
|
.name == "subcmd")
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.p
|
||||||
|
.is_set(AppSettings::TrailingVarArg));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ Kevin K. <kbknapp@gmail.com>
|
||||||
tests subcommands
|
tests subcommands
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
subcmd [FLAGS] [OPTIONS] [--] [ARGS]
|
subcmd [FLAGS] [OPTIONS] [--] [scpositional]
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-f, --flag tests flags
|
-f, --flag tests flags
|
||||||
|
|
|
@ -176,3 +176,41 @@ fn default_values_user_value() {
|
||||||
assert!(m.is_present("arg"));
|
assert!(m.is_present("arg"));
|
||||||
assert_eq!(m.value_of("arg").unwrap(), "value");
|
assert_eq!(m.value_of("arg").unwrap(), "value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single_positional_usage_string() {
|
||||||
|
let m = App::new("test").arg_from_usage("[FILE] 'some file'").get_matches_from(vec!["test"]);
|
||||||
|
assert_eq!(m.usage(), "USAGE:\n test [FLAGS] [FILE]");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single_positional_multiple_usage_string() {
|
||||||
|
let m = App::new("test").arg_from_usage("[FILE]... 'some file'").get_matches_from(vec!["test"]);
|
||||||
|
assert_eq!(m.usage(), "USAGE:\n test [FLAGS] [FILE]...");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn multiple_positional_usage_string() {
|
||||||
|
let m = App::new("test")
|
||||||
|
.arg_from_usage("[FILE] 'some file'")
|
||||||
|
.arg_from_usage("[FILES]... 'some file'")
|
||||||
|
.get_matches_from(vec!["test"]);
|
||||||
|
assert_eq!(m.usage(), "USAGE:\n test [FLAGS] [ARGS]");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn multiple_positional_one_required_usage_string() {
|
||||||
|
let m = App::new("test")
|
||||||
|
.arg_from_usage("<FILE> 'some file'")
|
||||||
|
.arg_from_usage("[FILES]... 'some file'")
|
||||||
|
.get_matches_from(vec!["test", "file"]);
|
||||||
|
assert_eq!(m.usage(), "USAGE:\n test [FLAGS] <FILE> [ARGS]");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single_positional_required_usage_string() {
|
||||||
|
let m = App::new("test")
|
||||||
|
.arg_from_usage("<FILE> 'some file'")
|
||||||
|
.get_matches_from(vec!["test", "file"]);
|
||||||
|
assert_eq!(m.usage(), "USAGE:\n test [FLAGS] <FILE>");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue