mirror of
https://github.com/clap-rs/clap
synced 2025-03-04 23:37:32 +00:00
commit
e1d33f8f22
10 changed files with 157 additions and 222 deletions
147
'
147
'
|
@ -1,147 +0,0 @@
|
|||
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")));
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ sudo: false
|
|||
language: rust
|
||||
rust:
|
||||
- nightly
|
||||
- nightly-2016-04-28
|
||||
- nightly-2016-06-05
|
||||
- beta
|
||||
- stable
|
||||
# Only while clippy is failing
|
||||
|
|
|
@ -18,7 +18,7 @@ libc = { version = "~0.2.9", optional = true }
|
|||
ansi_term = { version = "~0.7.2", optional = true }
|
||||
strsim = { version = "~0.4.0", optional = true }
|
||||
yaml-rust = { version = "~0.3.2", optional = true }
|
||||
clippy = { version = "=0.0.64", optional = true }
|
||||
clippy = { version = "~0.0.74", optional = true }
|
||||
unicode-width = { version = "~0.1.3", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -132,7 +132,7 @@ impl<'a> Help<'a> {
|
|||
use_stderr: stderr,
|
||||
when: parser.color(),
|
||||
};
|
||||
Self::new(w, nlh, hide_v, color, cizer).write_help(&parser)
|
||||
Self::new(w, nlh, hide_v, color, cizer).write_help(parser)
|
||||
}
|
||||
|
||||
/// Writes the parser help to the wrapped stream.
|
||||
|
@ -485,6 +485,7 @@ impl<'a> Help<'a> {
|
|||
impl<'a> Help<'a> {
|
||||
/// Writes help for all arguments (options, flags, args, subcommands)
|
||||
/// including titles of a Parser Object to the wrapped stream.
|
||||
#[cfg_attr(feature = "lints", allow(useless_let_if_seq))]
|
||||
pub fn write_all_args(&mut self, parser: &Parser) -> ClapResult<()> {
|
||||
|
||||
let flags = parser.has_flags();
|
||||
|
@ -542,7 +543,7 @@ impl<'a> Help<'a> {
|
|||
|
||||
/// Writes help for subcommands of a Parser Object to the wrapped stream.
|
||||
fn write_subcommands(&mut self, parser: &Parser) -> io::Result<()> {
|
||||
debugln!("exec=write_subcommands;");
|
||||
debugln!("exec=write_subcommands;");
|
||||
let mut longest = 0;
|
||||
|
||||
let mut ord_m = VecMap::new();
|
||||
|
@ -556,12 +557,10 @@ impl<'a> Help<'a> {
|
|||
for (_, btm) in ord_m.into_iter() {
|
||||
for (_, sc) in btm.into_iter() {
|
||||
if !first {
|
||||
debugln!("Writing newline...");
|
||||
try!(self.writer.write(b"\n"));
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
debugln!("Writing sc...{}", sc);
|
||||
try!(self.write_arg(sc, longest));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,8 +76,7 @@ macro_rules! _handle_group_reqs{
|
|||
use args::AnyArg;
|
||||
debugln!("macro=_handle_group_reqs!;");
|
||||
for grp in $me.groups.values() {
|
||||
let mut found = false;
|
||||
if grp.args.contains(&$arg.name()) {
|
||||
let found = if grp.args.contains(&$arg.name()) {
|
||||
vec_remove!($me.required, &$arg.name());
|
||||
if let Some(ref reqs) = grp.requires {
|
||||
$me.required.extend(reqs);
|
||||
|
@ -85,8 +84,10 @@ macro_rules! _handle_group_reqs{
|
|||
if let Some(ref bl) = grp.conflicts {
|
||||
$me.blacklist.extend(bl);
|
||||
}
|
||||
found = true; // What if arg is in more than one group with different reqs?
|
||||
}
|
||||
true // What if arg is in more than one group with different reqs?
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if found {
|
||||
vec_remove_all!($me.required, &grp.args);
|
||||
debugln!("Adding args from group to blacklist...{:?}", grp.args);
|
||||
|
@ -112,27 +113,26 @@ macro_rules! parse_positional {
|
|||
$_self:ident,
|
||||
$p:ident,
|
||||
$arg_os:ident,
|
||||
$pos_only:ident,
|
||||
$pos_counter:ident,
|
||||
$matcher:ident
|
||||
) => {
|
||||
debugln!("macro=parse_positional!;");
|
||||
validate_multiples!($_self, $p, $matcher);
|
||||
|
||||
if let Err(e) = $_self.add_val_to_arg($p, &$arg_os, $matcher) {
|
||||
return Err(e);
|
||||
}
|
||||
if !$pos_only &&
|
||||
if !$_self.trailing_vals &&
|
||||
($_self.settings.is_set(AppSettings::TrailingVarArg) &&
|
||||
$pos_counter == $_self.positionals.len()) {
|
||||
$pos_only = true;
|
||||
$_self.trailing_vals = true;
|
||||
}
|
||||
if let Err(e) = $_self.add_val_to_arg($p, &$arg_os, $matcher) {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
$matcher.inc_occurrence_of($p.name);
|
||||
let _ = $_self.groups_for_arg($p.name)
|
||||
.and_then(|vec| Some($matcher.inc_occurrences_of(&*vec)));
|
||||
arg_post_processing!($_self, $p, $matcher);
|
||||
// Only increment the positional counter if it doesn't allow multiples
|
||||
// Only increment the positional counter if it doesn't allow multiples
|
||||
if !$p.settings.is_set(ArgSettings::Multiple) {
|
||||
$pos_counter += 1;
|
||||
}
|
||||
|
|
|
@ -840,7 +840,7 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
/// ```
|
||||
/// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
|
||||
pub fn write_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
|
||||
Help::write_app_help(w, &self)
|
||||
Help::write_app_help(w, self)
|
||||
}
|
||||
|
||||
/// Writes the version message to the user to a [`io::Write`] object
|
||||
|
|
|
@ -51,6 +51,7 @@ pub struct Parser<'a, 'b>
|
|||
settings: AppFlags,
|
||||
pub g_settings: Vec<AppSettings>,
|
||||
pub meta: AppMeta<'b>,
|
||||
trailing_vals: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Default for Parser<'a, 'b> {
|
||||
|
@ -72,6 +73,7 @@ impl<'a, 'b> Default for Parser<'a, 'b> {
|
|||
g_settings: vec![],
|
||||
settings: AppFlags::new(),
|
||||
meta: AppMeta::new(),
|
||||
trailing_vals: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -136,10 +138,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
argument\n\n\tPerhaps try .multiple(true) to allow one positional argument \
|
||||
to take multiple values",
|
||||
a.name));
|
||||
let pb = PosBuilder::from_arg(&a, i as u64, &mut self.required);
|
||||
let pb = PosBuilder::from_arg(a, i as u64, &mut self.required);
|
||||
self.positionals.insert(i, pb);
|
||||
} else if a.is_set(ArgSettings::TakesValue) {
|
||||
let mut ob = OptBuilder::from_arg(&a, &mut self.required);
|
||||
let mut ob = OptBuilder::from_arg(a, &mut self.required);
|
||||
if self.settings.is_set(AppSettings::DeriveDisplayOrder) && a.disp_ord == 999 {
|
||||
ob.disp_ord = if self.settings.is_set(AppSettings::UnifiedHelpMessage) {
|
||||
self.flags.len() + self.opts.len()
|
||||
|
@ -307,7 +309,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
c_opt.dedup();
|
||||
grps.dedup();
|
||||
let mut args_in_groups = vec![];
|
||||
for g in grps.iter() {
|
||||
for g in &grps {
|
||||
for a in self.arg_names_in_group(g).into_iter() {
|
||||
args_in_groups.push(a);
|
||||
}
|
||||
|
@ -327,11 +329,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
}
|
||||
debugln!("args_in_groups={:?}", args_in_groups);
|
||||
for (_, s) in pmap {
|
||||
if !args_in_groups.is_empty() {
|
||||
if args_in_groups.contains(&&*s) {
|
||||
continue;
|
||||
}
|
||||
if (!args_in_groups.is_empty()) && (args_in_groups.contains(&&*s)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret_val.push_back(s);
|
||||
}
|
||||
macro_rules! write_arg {
|
||||
|
@ -456,7 +457,6 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
// necessary
|
||||
self.create_help_and_version();
|
||||
|
||||
let mut pos_only = false;
|
||||
let mut subcmd_name: Option<String> = None;
|
||||
let mut needs_val_of: Option<&str> = None;
|
||||
let mut pos_counter = 1;
|
||||
|
@ -475,7 +475,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
};
|
||||
|
||||
// Has the user already passed '--'?
|
||||
if !pos_only {
|
||||
if !self.trailing_vals {
|
||||
// Does the arg match a subcommand name, or any of it's aliases (if defined)
|
||||
let pos_sc = self.subcommands
|
||||
.iter()
|
||||
|
@ -501,7 +501,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
if arg_os.len_() == 2 {
|
||||
// The user has passed '--' which means only positional args follow no
|
||||
// matter what they start with
|
||||
pos_only = true;
|
||||
self.trailing_vals = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -564,7 +564,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
}
|
||||
|
||||
if let Some(p) = self.positionals.get(pos_counter) {
|
||||
parse_positional!(self, p, arg_os, pos_only, pos_counter, matcher);
|
||||
parse_positional!(self, p, arg_os, pos_counter, matcher);
|
||||
} else {
|
||||
if self.settings.is_set(AppSettings::AllowExternalSubcommands) {
|
||||
let mut sc_m = ArgMatcher::new();
|
||||
|
@ -1131,13 +1131,17 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
{
|
||||
debugln!("fn=add_val_to_arg;");
|
||||
let mut ret = None;
|
||||
if let Some(delim) = arg.val_delim() {
|
||||
if val.is_empty_() {
|
||||
ret = try!(self.add_single_val_to_arg(arg, val, matcher));
|
||||
} else {
|
||||
for v in val.split(delim as u32 as u8) {
|
||||
ret = try!(self.add_single_val_to_arg(arg, v, matcher));
|
||||
if !(self.trailing_vals && self.is_set(AppSettings::DontDelimitTrailingValues)) {
|
||||
if let Some(delim) = arg.val_delim() {
|
||||
if val.is_empty_() {
|
||||
ret = try!(self.add_single_val_to_arg(arg, val, matcher));
|
||||
} else {
|
||||
for v in val.split(delim as u32 as u8) {
|
||||
ret = try!(self.add_single_val_to_arg(arg, v, matcher));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = try!(self.add_single_val_to_arg(arg, val, matcher));
|
||||
}
|
||||
} else {
|
||||
ret = try!(self.add_single_val_to_arg(arg, val, matcher));
|
||||
|
@ -1253,7 +1257,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
debugln!("groups contains it...");
|
||||
for n in self.arg_names_in_group(name) {
|
||||
debugln!("Checking arg '{}' in group...", n);
|
||||
if matcher.contains(&n) {
|
||||
if matcher.contains(n) {
|
||||
debugln!("matcher contains it...");
|
||||
return Err(build_err!(self, n, matcher));
|
||||
}
|
||||
|
@ -1465,7 +1469,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
debugln!("fn=create_usage;");
|
||||
let mut usage = String::with_capacity(75);
|
||||
usage.push_str("USAGE:\n ");
|
||||
usage.push_str(&self.create_usage_no_title(&used));
|
||||
usage.push_str(&self.create_usage_no_title(used));
|
||||
usage
|
||||
}
|
||||
|
||||
|
@ -1601,11 +1605,11 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
}
|
||||
|
||||
pub fn write_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
|
||||
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)
|
||||
Help::write_parser_help_to_stderr(w, self)
|
||||
}
|
||||
|
||||
fn add_defaults(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
|
||||
|
@ -1679,6 +1683,7 @@ impl<'a, 'b> Clone for Parser<'a, 'b>
|
|||
settings: self.settings.clone(),
|
||||
g_settings: self.g_settings.clone(),
|
||||
meta: self.meta.clone(),
|
||||
trailing_vals: self.trailing_vals,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,32 +3,33 @@ use std::ascii::AsciiExt;
|
|||
|
||||
bitflags! {
|
||||
flags Flags: u32 {
|
||||
const SC_NEGATE_REQS = 0b00000000000000000000000001,
|
||||
const SC_REQUIRED = 0b00000000000000000000000010,
|
||||
const A_REQUIRED_ELSE_HELP = 0b00000000000000000000000100,
|
||||
const GLOBAL_VERSION = 0b00000000000000000000001000,
|
||||
const VERSIONLESS_SC = 0b00000000000000000000010000,
|
||||
const UNIFIED_HELP = 0b00000000000000000000100000,
|
||||
const WAIT_ON_ERROR = 0b00000000000000000001000000,
|
||||
const SC_REQUIRED_ELSE_HELP= 0b00000000000000000010000000,
|
||||
const NEEDS_LONG_HELP = 0b00000000000000000100000000,
|
||||
const NEEDS_LONG_VERSION = 0b00000000000000001000000000,
|
||||
const NEEDS_SC_HELP = 0b00000000000000010000000000,
|
||||
const DISABLE_VERSION = 0b00000000000000100000000000,
|
||||
const HIDDEN = 0b00000000000001000000000000,
|
||||
const TRAILING_VARARG = 0b00000000000010000000000000,
|
||||
const NO_BIN_NAME = 0b00000000000100000000000000,
|
||||
const ALLOW_UNK_SC = 0b00000000001000000000000000,
|
||||
const UTF8_STRICT = 0b00000000010000000000000000,
|
||||
const UTF8_NONE = 0b00000000100000000000000000,
|
||||
const LEADING_HYPHEN = 0b00000001000000000000000000,
|
||||
const NO_POS_VALUES = 0b00000010000000000000000000,
|
||||
const NEXT_LINE_HELP = 0b00000100000000000000000000,
|
||||
const DERIVE_DISP_ORDER = 0b00001000000000000000000000,
|
||||
const COLORED_HELP = 0b00010000000000000000000000,
|
||||
const COLOR_ALWAYS = 0b00100000000000000000000000,
|
||||
const COLOR_AUTO = 0b01000000000000000000000000,
|
||||
const COLOR_NEVER = 0b10000000000000000000000000,
|
||||
const SC_NEGATE_REQS = 0b000000000000000000000000001,
|
||||
const SC_REQUIRED = 0b000000000000000000000000010,
|
||||
const A_REQUIRED_ELSE_HELP = 0b000000000000000000000000100,
|
||||
const GLOBAL_VERSION = 0b000000000000000000000001000,
|
||||
const VERSIONLESS_SC = 0b000000000000000000000010000,
|
||||
const UNIFIED_HELP = 0b000000000000000000000100000,
|
||||
const WAIT_ON_ERROR = 0b000000000000000000001000000,
|
||||
const SC_REQUIRED_ELSE_HELP= 0b000000000000000000010000000,
|
||||
const NEEDS_LONG_HELP = 0b000000000000000000100000000,
|
||||
const NEEDS_LONG_VERSION = 0b000000000000000001000000000,
|
||||
const NEEDS_SC_HELP = 0b000000000000000010000000000,
|
||||
const DISABLE_VERSION = 0b000000000000000100000000000,
|
||||
const HIDDEN = 0b000000000000001000000000000,
|
||||
const TRAILING_VARARG = 0b000000000000010000000000000,
|
||||
const NO_BIN_NAME = 0b000000000000100000000000000,
|
||||
const ALLOW_UNK_SC = 0b000000000001000000000000000,
|
||||
const UTF8_STRICT = 0b000000000010000000000000000,
|
||||
const UTF8_NONE = 0b000000000100000000000000000,
|
||||
const LEADING_HYPHEN = 0b000000001000000000000000000,
|
||||
const NO_POS_VALUES = 0b000000010000000000000000000,
|
||||
const NEXT_LINE_HELP = 0b000000100000000000000000000,
|
||||
const DERIVE_DISP_ORDER = 0b000001000000000000000000000,
|
||||
const COLORED_HELP = 0b000010000000000000000000000,
|
||||
const COLOR_ALWAYS = 0b000100000000000000000000000,
|
||||
const COLOR_AUTO = 0b001000000000000000000000000,
|
||||
const COLOR_NEVER = 0b010000000000000000000000000,
|
||||
const DONT_DELIM_TRAIL = 0b100000000000000000000000000,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,7 +80,8 @@ impl AppFlags {
|
|||
DeriveDisplayOrder => DERIVE_DISP_ORDER,
|
||||
ColorAlways => COLOR_ALWAYS,
|
||||
ColorAuto => COLOR_AUTO,
|
||||
ColorNever => COLOR_NEVER
|
||||
ColorNever => COLOR_NEVER,
|
||||
DontDelimitTrailingValues => DONT_DELIM_TRAIL
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -551,6 +553,24 @@ pub enum AppSettings {
|
|||
/// .get_matches();
|
||||
/// ```
|
||||
ColorNever,
|
||||
/// Disables the automatic delimiting of values when `--` or [`AppSettings::TrailingVarArg`]
|
||||
/// was used.
|
||||
///
|
||||
/// **NOTE:** The same thing can be done manually by setting the final positional argument to
|
||||
/// [`Arg::use_delimiter(false)`]. Using this setting is safer, because it's easier to locate
|
||||
/// when making changes.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap::{App, Arg, SubCommand, AppSettings};
|
||||
/// App::new("myprog")
|
||||
/// .setting(AppSettings::DontDelimitTrailingValues)
|
||||
/// .get_matches();
|
||||
/// ```
|
||||
/// [`AppSettings::TrailingVarArg`]: ./enum.AppSettings.html#variant.TrailingVarArg
|
||||
/// [`Arg::use_delimiter(false)`]: ./struct.Arg.html#method.use_delimiter
|
||||
DontDelimitTrailingValues,
|
||||
#[doc(hidden)]
|
||||
NeedsLongVersion,
|
||||
#[doc(hidden)]
|
||||
|
@ -584,6 +604,10 @@ impl FromStr for AppSettings {
|
|||
"nextlinehelp" => Ok(AppSettings::NextLineHelp),
|
||||
"derivedisplayorder" => Ok(AppSettings::DeriveDisplayOrder),
|
||||
"coloredhelp" => Ok(AppSettings::ColoredHelp),
|
||||
"dontdelimittrailingvalues" => Ok(AppSettings::DontDelimitTrailingValues),
|
||||
"colorauto" => Ok(AppSettings::ColorAuto),
|
||||
"coloralways" => Ok(AppSettings::ColorAlways),
|
||||
"colornever" => Ok(AppSettings::ColorNever),
|
||||
_ => Err("unknown AppSetting, cannot convert from str".to_owned()),
|
||||
}
|
||||
}
|
||||
|
@ -629,6 +653,8 @@ mod test {
|
|||
AppSettings::ColoredHelp);
|
||||
assert_eq!("hidden".parse::<AppSettings>().unwrap(),
|
||||
AppSettings::Hidden);
|
||||
assert_eq!("dontdelimittrailingvalues".parse::<AppSettings>().unwrap(),
|
||||
AppSettings::DontDelimitTrailingValues);
|
||||
assert!("hahahaha".parse::<AppSettings>().is_err());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,24 +55,24 @@ impl OsStrExt2 for OsStr {
|
|||
fn split_at_byte(&self, byte: u8) -> (&OsStr, &OsStr) {
|
||||
for (i, b) in self.as_bytes().iter().enumerate() {
|
||||
if b == &byte {
|
||||
return (&OsStr::from_bytes(&self.as_bytes()[..i]),
|
||||
&OsStr::from_bytes(&self.as_bytes()[i + 1..]));
|
||||
return (OsStr::from_bytes(&self.as_bytes()[..i]),
|
||||
OsStr::from_bytes(&self.as_bytes()[i + 1..]));
|
||||
}
|
||||
}
|
||||
(&*self, &OsStr::from_bytes(&self.as_bytes()[self.len_()..self.len_()]))
|
||||
(&*self, OsStr::from_bytes(&self.as_bytes()[self.len_()..self.len_()]))
|
||||
}
|
||||
|
||||
fn trim_left_matches(&self, byte: u8) -> &OsStr {
|
||||
for (i, b) in self.as_bytes().iter().enumerate() {
|
||||
if b != &byte {
|
||||
return &OsStr::from_bytes(&self.as_bytes()[i..]);
|
||||
return OsStr::from_bytes(&self.as_bytes()[i..]);
|
||||
}
|
||||
}
|
||||
&*self
|
||||
}
|
||||
|
||||
fn split_at(&self, i: usize) -> (&OsStr, &OsStr) {
|
||||
(&OsStr::from_bytes(&self.as_bytes()[..i]), &OsStr::from_bytes(&self.as_bytes()[i..]))
|
||||
(OsStr::from_bytes(&self.as_bytes()[..i]), OsStr::from_bytes(&self.as_bytes()[i..]))
|
||||
}
|
||||
|
||||
fn len_(&self) -> usize {
|
||||
|
@ -109,10 +109,10 @@ impl<'a> Iterator for OsSplit<'a> {
|
|||
for b in &self.val[start..] {
|
||||
self.pos += 1;
|
||||
if *b == self.sep {
|
||||
return Some(&OsStr::from_bytes(&self.val[start..self.pos - 1]));
|
||||
return Some(OsStr::from_bytes(&self.val[start..self.pos - 1]));
|
||||
}
|
||||
}
|
||||
Some(&OsStr::from_bytes(&self.val[start..]))
|
||||
Some(OsStr::from_bytes(&self.val[start..]))
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let mut count = 0;
|
||||
|
@ -137,9 +137,9 @@ impl<'a> DoubleEndedIterator for OsSplit<'a> {
|
|||
for b in self.val[..self.pos].iter().rev() {
|
||||
self.pos -= 1;
|
||||
if *b == self.sep {
|
||||
return Some(&OsStr::from_bytes(&self.val[self.pos + 1..start]));
|
||||
return Some(OsStr::from_bytes(&self.val[self.pos + 1..start]));
|
||||
}
|
||||
}
|
||||
Some(&OsStr::from_bytes(&self.val[..start]))
|
||||
Some(OsStr::from_bytes(&self.val[..start]))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,3 +182,55 @@ fn global_settings() {
|
|||
.is_set(AppSettings::TrailingVarArg));
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stop_delim_values_only_pos_follows() {
|
||||
let r = App::new("onlypos")
|
||||
.setting(AppSettings::DontDelimitTrailingValues)
|
||||
.args(&[Arg::from_usage("-f [flag] 'some opt'"),
|
||||
Arg::from_usage("[arg]... 'some arg'")])
|
||||
.get_matches_from_safe(vec!["", "--", "-f", "-g,x"]);
|
||||
assert!(r.is_ok());
|
||||
let m = r.unwrap();
|
||||
assert!(m.is_present("arg"));
|
||||
assert!(!m.is_present("f"));
|
||||
assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g,x"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dont_delim_values_trailingvararg() {
|
||||
let m = App::new("positional")
|
||||
.setting(AppSettings::TrailingVarArg)
|
||||
.setting(AppSettings::DontDelimitTrailingValues)
|
||||
.arg(
|
||||
Arg::from_usage("[opt]... 'some pos'"),
|
||||
)
|
||||
.get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]);
|
||||
assert!(m.is_present("opt"));
|
||||
assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl,-bar"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delim_values_only_pos_follows() {
|
||||
let r = App::new("onlypos")
|
||||
.args(&[Arg::from_usage("-f [flag] 'some opt'"),
|
||||
Arg::from_usage("[arg]... 'some arg'")])
|
||||
.get_matches_from_safe(vec!["", "--", "-f", "-g,x"]);
|
||||
assert!(r.is_ok());
|
||||
let m = r.unwrap();
|
||||
assert!(m.is_present("arg"));
|
||||
assert!(!m.is_present("f"));
|
||||
assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g", "x"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delim_values_trailingvararg() {
|
||||
let m = App::new("positional")
|
||||
.setting(AppSettings::TrailingVarArg)
|
||||
.arg(
|
||||
Arg::from_usage("[opt]... 'some pos'"),
|
||||
)
|
||||
.get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]);
|
||||
assert!(m.is_present("opt"));
|
||||
assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl", "-bar"]);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue