2 #[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
3 use std
::os
::unix
::ffi
::OsStrExt
;
6 ffi
::{OsStr, OsString}
,
9 io
::{self, BufWriter, Write}
,
16 #[cfg(all(feature = "debug", any(target_os = "windows", target_arch = "wasm32")))]
17 use crate::osstringext
::OsStrExt3
;
18 #[cfg(any(target_os = "windows", target_arch = "wasm32"))]
19 use crate::osstringext
::OsStrExt3
;
22 help
::Help
, meta
::AppMeta
, settings
::AppFlags
, settings
::AppSettings
as AS
, usage
,
23 validator
::Validator
, App
,
26 settings
::ArgSettings
, AnyArg
, Arg
, ArgGroup
, ArgMatcher
, Base
, FlagBuilder
, OptBuilder
,
29 completions
::{ComplGen, Shell}
,
30 errors
::Result
as ClapResult
,
31 errors
::{Error, ErrorKind}
,
34 osstringext
::OsStrExt2
,
35 suggestions
, SubCommand
, INTERNAL_ERROR_MSG
, INVALID_UTF8
,
38 #[derive(Debug, PartialEq, Copy, Clone)]
40 pub enum ParseResult
<'a
> {
50 #[allow(missing_debug_implementations)]
52 #[derive(Clone, Default)]
53 pub struct Parser
<'a
, 'b
>
57 pub meta
: AppMeta
<'b
>,
59 pub g_settings
: AppFlags
,
60 pub flags
: Vec
<FlagBuilder
<'a
, 'b
>>,
61 pub opts
: Vec
<OptBuilder
<'a
, 'b
>>,
62 pub positionals
: VecMap
<PosBuilder
<'a
, 'b
>>,
63 pub subcommands
: Vec
<App
<'a
, 'b
>>,
64 pub groups
: Vec
<ArgGroup
<'a
>>,
65 pub global_args
: Vec
<Arg
<'a
, 'b
>>,
66 pub required
: Vec
<&'a
str>,
67 pub r_ifs
: Vec
<(&'a
str, &'b
str, &'a
str)>,
68 pub overrides
: Vec
<(&'b
str, &'a
str)>,
69 help_short
: Option
<char>,
70 version_short
: Option
<char>,
71 cache
: Option
<&'a
str>,
72 pub help_message
: Option
<&'a
str>,
73 pub version_message
: Option
<&'a
str>,
77 impl<'a
, 'b
> Parser
<'a
, 'b
>
81 pub fn with_name(n
: String
) -> Self {
83 meta
: AppMeta
::with_name(n
),
84 g_settings
: AppFlags
::zeroed(),
85 cur_idx
: Cell
::new(0),
90 pub fn help_short(&mut self, s
: &str) {
92 .trim_left_matches(|c
| c
== '
-'
)
96 self.help_short
= Some(c
);
99 pub fn version_short(&mut self, s
: &str) {
101 .trim_left_matches(|c
| c
== '
-'
)
105 self.version_short
= Some(c
);
108 pub fn gen_completions_to
<W
: Write
>(&mut self, for_shell
: Shell
, buf
: &mut W
) {
109 if !self.is_set(AS
::Propagated
) {
110 self.propagate_help_version();
111 self.build_bin_names();
112 self.propagate_globals();
113 self.propagate_settings();
114 self.set(AS
::Propagated
);
117 ComplGen
::new(self).generate(for_shell
, buf
)
120 pub fn gen_completions(&mut self, for_shell
: Shell
, od
: OsString
) {
121 use std
::error
::Error
;
123 let out_dir
= PathBuf
::from(od
);
124 let name
= &*self.meta
.bin_name
.as_ref().unwrap().clone();
125 let file_name
= match for_shell
{
126 Shell
::Bash
=> format
!("{}.bash", name
),
127 Shell
::Fish
=> format
!("{}.fish", name
),
128 Shell
::Zsh
=> format
!("_{}", name
),
129 Shell
::PowerShell
=> format
!("_{}.ps1", name
),
130 Shell
::Elvish
=> format
!("{}.elv", name
),
133 let mut file
= match File
::create(out_dir
.join(file_name
)) {
134 Err(why
) => panic
!("couldn't create completion file: {}", why
.description()),
137 self.gen_completions_to(for_shell
, &mut file
)
141 fn app_debug_asserts(&self) -> bool
{
142 assert
!(self.verify_positionals());
143 let should_err
= self.groups
.iter().all(|g
| {
144 g
.args
.iter().all(|arg
| {
145 self.flags
.iter().any(|f
| &f
.b
.name
== arg
)
146 || self.opts
.iter().any(|o
| &o
.b
.name
== arg
)
147 || self.positionals
.values().any(|p
| &p
.b
.name
== arg
)
148 || self.groups
.iter().any(|g
| &g
.name
== arg
)
151 let g
= self.groups
.iter().find(|g
| {
152 g
.args
.iter().any(|arg
| {
153 !(self.flags
.iter().any(|f
| &f
.b
.name
== arg
)
154 || self.opts
.iter().any(|o
| &o
.b
.name
== arg
)
155 || self.positionals
.values().any(|p
| &p
.b
.name
== arg
)
156 || self.groups
.iter().any(|g
| &g
.name
== arg
))
161 "The group '{}' contains the arg '{}' that doesn't actually exist.",
166 .find(|arg
| !(self.flags
.iter().any(|f
| &&f
.b
.name
== arg
)
167 || self.opts
.iter().any(|o
| &&o
.b
.name
== arg
)
168 || self.positionals
.values().any(|p
| &&p
.b
.name
== arg
)
169 || self.groups
.iter().any(|g
| &&g
.name
== arg
)))
176 fn debug_asserts(&self, a
: &Arg
) -> bool
{
178 !arg_names
!(self).any(|name
| name
== a
.b
.name
),
179 "Non-unique argument name: {} is already in use",
182 if let Some(l
) = a
.s
.long
{
184 !self.contains_long(l
),
185 "Argument long must be unique\n\n\t--{} is already in use",
189 if let Some(s
) = a
.s
.short
{
191 !self.contains_short(s
),
192 "Argument short must be unique\n\n\t-{} is already in use",
196 let i
= if a
.index
.is_none() {
197 self.positionals
.len() + 1
199 a
.index
.unwrap() as usize
202 !self.positionals
.contains_key(i
),
203 "Argument \"{}\" has the same index as another positional \
204 argument\n\n\tPerhaps try .multiple(true) to allow one positional argument \
205 to take multiple values",
209 !(a
.is_set(ArgSettings
::Required
) && a
.is_set(ArgSettings
::Global
)),
210 "Global arguments cannot be required.\n\n\t'{}' is marked as \
211 global and required",
214 if a
.b
.is_set(ArgSettings
::Last
) {
219 .any(|p
| p
.b
.is_set(ArgSettings
::Last
)),
220 "Only one positional argument may have last(true) set. Found two."
222 assert
!(a
.s
.long
.is_none(),
223 "Flags or Options may not have last(true) set. {} has both a long and last(true) set.",
225 assert
!(a
.s
.short
.is_none(),
226 "Flags or Options may not have last(true) set. {} has both a short and last(true) set.",
233 fn add_conditional_reqs(&mut self, a
: &Arg
<'a
, 'b
>) {
234 if let Some(ref r_ifs
) = a
.r_ifs
{
235 for &(arg
, val
) in r_ifs
{
236 self.r_ifs
.push((arg
, val
, a
.b
.name
));
242 fn add_arg_groups(&mut self, a
: &Arg
<'a
, 'b
>) {
243 if let Some(ref grps
) = a
.b
.groups
{
245 let mut found
= false;
246 if let Some(ref mut ag
) = self.groups
.iter_mut().find(|grp
| &grp
.name
== g
) {
247 ag
.args
.push(a
.b
.name
);
251 let mut ag
= ArgGroup
::with_name(g
);
252 ag
.args
.push(a
.b
.name
);
253 self.groups
.push(ag
);
260 fn add_reqs(&mut self, a
: &Arg
<'a
, 'b
>) {
261 if a
.is_set(ArgSettings
::Required
) {
262 // If the arg is required, add all it's requirements to master required list
263 self.required
.push(a
.b
.name
);
264 if let Some(ref areqs
) = a
.b
.requires
{
267 .filter(|&&(val
, _
)| val
.is_none())
268 .map(|&(_
, name
)| name
)
270 self.required
.push(name
);
277 fn implied_settings(&mut self, a
: &Arg
<'a
, 'b
>) {
278 if a
.is_set(ArgSettings
::Last
) {
279 // if an arg has `Last` set, we need to imply DontCollapseArgsInUsage so that args
280 // in the usage string don't get confused or left out.
281 self.set(AS
::DontCollapseArgsInUsage
);
282 self.set(AS
::ContainsLast
);
284 if let Some(l
) = a
.s
.long
{
286 self.unset(AS
::NeedsLongVersion
);
287 } else if l
== "help" {
288 self.unset(AS
::NeedsLongHelp
);
293 // actually adds the arguments
294 pub fn add_arg(&mut self, a
: Arg
<'a
, 'b
>) {
295 // if it's global we have to clone anyways
296 if a
.is_set(ArgSettings
::Global
) {
297 return self.add_arg_ref(&a
);
299 debug_assert
!(self.debug_asserts(&a
));
300 self.add_conditional_reqs(&a
);
301 self.add_arg_groups(&a
);
303 self.implied_settings(&a
);
304 if a
.index
.is_some() || (a
.s
.short
.is_none() && a
.s
.long
.is_none()) {
305 let i
= if a
.index
.is_none() {
306 self.positionals
.len() + 1
308 a
.index
.unwrap() as usize
311 .insert(i
, PosBuilder
::from_arg(a
, i
as u64));
312 } else if a
.is_set(ArgSettings
::TakesValue
) {
313 let mut ob
= OptBuilder
::from(a
);
314 ob
.s
.unified_ord
= self.flags
.len() + self.opts
.len();
317 let mut fb
= FlagBuilder
::from(a
);
318 fb
.s
.unified_ord
= self.flags
.len() + self.opts
.len();
322 // actually adds the arguments but from a borrow (which means we have to do some cloning)
323 pub fn add_arg_ref(&mut self, a
: &Arg
<'a
, 'b
>) {
324 debug_assert
!(self.debug_asserts(a
));
325 self.add_conditional_reqs(a
);
326 self.add_arg_groups(a
);
328 self.implied_settings(a
);
329 if a
.index
.is_some() || (a
.s
.short
.is_none() && a
.s
.long
.is_none()) {
330 let i
= if a
.index
.is_none() {
331 self.positionals
.len() + 1
333 a
.index
.unwrap() as usize
335 let pb
= PosBuilder
::from_arg_ref(a
, i
as u64);
336 self.positionals
.insert(i
, pb
);
337 } else if a
.is_set(ArgSettings
::TakesValue
) {
338 let mut ob
= OptBuilder
::from(a
);
339 ob
.s
.unified_ord
= self.flags
.len() + self.opts
.len();
342 let mut fb
= FlagBuilder
::from(a
);
343 fb
.s
.unified_ord
= self.flags
.len() + self.opts
.len();
346 if a
.is_set(ArgSettings
::Global
) {
347 self.global_args
.push(a
.into());
351 pub fn add_group(&mut self, group
: ArgGroup
<'a
>) {
353 self.required
.push(group
.name
);
354 if let Some(ref reqs
) = group
.requires
{
355 self.required
.extend_from_slice(reqs
);
357 // if let Some(ref bl) = group.conflicts {
358 // self.blacklist.extend_from_slice(bl);
361 if self.groups
.iter().any(|g
| g
.name
== group
.name
) {
365 .find(|g
| g
.name
== group
.name
)
366 .expect(INTERNAL_ERROR_MSG
);
367 grp
.args
.extend_from_slice(&group
.args
);
368 grp
.requires
= group
.requires
.clone();
369 grp
.conflicts
= group
.conflicts
.clone();
370 grp
.required
= group
.required
;
372 self.groups
.push(group
);
376 pub fn add_subcommand(&mut self, mut subcmd
: App
<'a
, 'b
>) {
378 "Parser::add_subcommand: term_w={:?}, name={}",
382 subcmd
.p
.meta
.term_w
= self.meta
.term_w
;
383 if subcmd
.p
.meta
.name
== "help" {
384 self.unset(AS
::NeedsSubcommandHelp
);
387 self.subcommands
.push(subcmd
);
390 pub fn propagate_settings(&mut self) {
392 "Parser::propagate_settings: self={}, g_settings={:#?}",
396 for sc
in &mut self.subcommands
{
398 "Parser::propagate_settings: sc={}, settings={:#?}, g_settings={:#?}",
403 // We have to create a new scope in order to tell rustc the borrow of `sc` is
404 // done and to recursively call this method
406 let vsc
= self.settings
.is_set(AS
::VersionlessSubcommands
);
407 let gv
= self.settings
.is_set(AS
::GlobalVersion
);
410 sc
.p
.set(AS
::DisableVersion
);
412 if gv
&& sc
.p
.meta
.version
.is_none() && self.meta
.version
.is_some() {
413 sc
.p
.set(AS
::GlobalVersion
);
414 sc
.p
.meta
.version
= Some(self.meta
.version
.unwrap());
416 sc
.p
.settings
= sc
.p
.settings
| self.g_settings
;
417 sc
.p
.g_settings
= sc
.p
.g_settings
| self.g_settings
;
418 sc
.p
.meta
.term_w
= self.meta
.term_w
;
419 sc
.p
.meta
.max_w
= self.meta
.max_w
;
421 sc
.p
.propagate_settings();
425 pub fn derive_display_order(&mut self) {
426 if self.is_set(AS
::DeriveDisplayOrder
) {
427 let unified
= self.is_set(AS
::UnifiedHelpMessage
);
432 .filter(|&(_
, ref o
)| o
.s
.disp_ord
== 999)
434 o
.s
.disp_ord
= if unified { o.s.unified_ord }
else { i }
;
440 .filter(|&(_
, ref f
)| f
.s
.disp_ord
== 999)
442 f
.s
.disp_ord
= if unified { f.s.unified_ord }
else { i }
;
444 for (i
, sc
) in &mut self
448 .filter(|&(_
, ref sc
)| sc
.p
.meta
.disp_ord
== 999)
450 sc
.p
.meta
.disp_ord
= i
;
453 for sc
in &mut self.subcommands
{
454 sc
.p
.derive_display_order();
458 pub fn required(&self) -> Iter
<&str> {
463 pub fn has_args(&self) -> bool
{
464 !(self.flags
.is_empty() && self.opts
.is_empty() && self.positionals
.is_empty())
468 pub fn has_opts(&self) -> bool
{
469 !self.opts
.is_empty()
473 pub fn has_flags(&self) -> bool
{
474 !self.flags
.is_empty()
478 pub fn has_positionals(&self) -> bool
{
479 !self.positionals
.is_empty()
483 pub fn has_subcommands(&self) -> bool
{
484 !self.subcommands
.is_empty()
488 pub fn has_visible_opts(&self) -> bool
{
489 if self.opts
.is_empty() {
492 self.opts
.iter().any(|o
| !o
.is_set(ArgSettings
::Hidden
))
496 pub fn has_visible_flags(&self) -> bool
{
497 if self.flags
.is_empty() {
500 self.flags
.iter().any(|f
| !f
.is_set(ArgSettings
::Hidden
))
504 pub fn has_visible_positionals(&self) -> bool
{
505 if self.positionals
.is_empty() {
510 .any(|p
| !p
.is_set(ArgSettings
::Hidden
))
514 pub fn has_visible_subcommands(&self) -> bool
{
515 self.has_subcommands()
519 .filter(|sc
| sc
.p
.meta
.name
!= "help")
520 .any(|sc
| !sc
.p
.is_set(AS
::Hidden
))
524 pub fn is_set(&self, s
: AS
) -> bool
{
525 self.settings
.is_set(s
)
529 pub fn set(&mut self, s
: AS
) {
534 pub fn unset(&mut self, s
: AS
) {
535 self.settings
.unset(s
)
538 pub fn verify_positionals(&self) -> bool
{
539 // Because you must wait until all arguments have been supplied, this is the first chance
540 // to make assertions on positional argument indexes
542 // First we verify that the index highest supplied index, is equal to the number of
543 // positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
545 if let Some((idx
, p
)) = self.positionals
.iter().rev().next() {
547 !(idx
!= self.positionals
.len()),
548 "Found positional argument \"{}\" whose index is {} but there \
549 are only {} positional arguments defined",
552 self.positionals
.len()
556 // Next we verify that only the highest index has a .multiple(true) (if any)
557 if self.positionals
.values().any(|a
| {
558 a
.b
.is_set(ArgSettings
::Multiple
) && (a
.index
as usize != self.positionals
.len())
560 let mut it
= self.positionals
.values().rev();
561 let last
= it
.next().unwrap();
562 let second_to_last
= it
.next().unwrap();
563 // Either the final positional is required
564 // Or the second to last has a terminator or .last(true) set
565 let ok
= last
.is_set(ArgSettings
::Required
)
566 || (second_to_last
.v
.terminator
.is_some()
567 || second_to_last
.b
.is_set(ArgSettings
::Last
))
568 || last
.is_set(ArgSettings
::Last
);
571 "When using a positional argument with .multiple(true) that is *not the \
572 last* positional argument, the last positional argument (i.e the one \
573 with the highest index) *must* have .required(true) or .last(true) set."
575 let ok
= second_to_last
.is_set(ArgSettings
::Multiple
) || last
.is_set(ArgSettings
::Last
);
578 "Only the last positional argument, or second to last positional \
579 argument may be set to .multiple(true)"
585 .filter(|p
| p
.b
.settings
.is_set(ArgSettings
::Multiple
) && p
.v
.num_vals
.is_none())
588 || (last
.is_set(ArgSettings
::Last
)
589 && last
.is_set(ArgSettings
::Multiple
)
590 && second_to_last
.is_set(ArgSettings
::Multiple
)
594 "Only one positional argument with .multiple(true) set is allowed per \
595 command, unless the second one also has .last(true) set"
599 let mut found
= false;
600 if self.is_set(AS
::AllowMissingPositional
) {
601 // Check that if a required positional argument is found, all positions with a lower
602 // index are also required.
603 let mut foundx2
= false;
604 for p
in self.positionals
.values().rev() {
605 if foundx2
&& !p
.b
.settings
.is_set(ArgSettings
::Required
) {
607 p
.b
.is_set(ArgSettings
::Required
),
608 "Found positional argument which is not required with a lower \
609 index than a required positional argument by two or more: {:?} \
614 } else if p
.b
.is_set(ArgSettings
::Required
) && !p
.b
.is_set(ArgSettings
::Last
) {
615 // Args that .last(true) don't count since they can be required and have
616 // positionals with a lower index that aren't required
617 // Imagine: prog <req1> [opt1] -- <req2>
618 // Both of these are valid invocations:
620 // $ prog r1 o1 -- r2
632 // Check that if a required positional argument is found, all positions with a lower
633 // index are also required
634 for p
in self.positionals
.values().rev() {
637 p
.b
.is_set(ArgSettings
::Required
),
638 "Found positional argument which is not required with a lower \
639 index than a required positional argument: {:?} index {}",
643 } else if p
.b
.is_set(ArgSettings
::Required
) && !p
.b
.is_set(ArgSettings
::Last
) {
644 // Args that .last(true) don't count since they can be required and have
645 // positionals with a lower index that aren't required
646 // Imagine: prog <req1> [opt1] -- <req2>
647 // Both of these are valid invocations:
649 // $ prog r1 o1 -- r2
658 .any(|p
| p
.b
.is_set(ArgSettings
::Last
) && p
.b
.is_set(ArgSettings
::Required
))
659 && self.has_subcommands()
660 && !self.is_set(AS
::SubcommandsNegateReqs
)
663 "Having a required positional argument with .last(true) set *and* child \
664 subcommands without setting SubcommandsNegateReqs isn't compatible."
671 pub fn propagate_globals(&mut self) {
672 for sc
in &mut self.subcommands
{
673 // We have to create a new scope in order to tell rustc the borrow of `sc` is
674 // done and to recursively call this method
676 for a
in &self.global_args
{
680 sc
.p
.propagate_globals();
684 // Checks if the arg matches a subcommand name, or any of it's aliases (if defined)
685 fn possible_subcommand(&self, arg_os
: &OsStr
) -> (bool
, Option
<&str>) {
686 debugln
!("Parser::possible_subcommand: arg={:?}", arg_os
);
687 fn starts(h
: &str, n
: &OsStr
) -> bool
{
688 let n_bytes
= n
.as_bytes();
689 let h_bytes
= OsStr
::new(h
).as_bytes();
691 h_bytes
.starts_with(n_bytes
)
694 if self.is_set(AS
::ArgsNegateSubcommands
) && self.is_set(AS
::ValidArgFound
) {
695 return (false, None
);
697 if !self.is_set(AS
::InferSubcommands
) {
698 if let Some(sc
) = find_subcmd
!(self, arg_os
) {
699 return (true, Some(&sc
.p
.meta
.name
));
706 starts(&s
.p
.meta
.name
[..], &*arg_os
)
707 || (s
.p
.meta
.aliases
.is_some()
714 .filter(|&&(a
, _
)| starts(a
, &*arg_os
))
718 .map(|sc
| &sc
.p
.meta
.name
)
719 .collect
::<Vec
<_
>>();
722 if OsStr
::new(sc
) == arg_os
{
723 return (true, Some(sc
));
728 return (true, Some(v
[0]));
734 fn parse_help_subcommand
<I
, T
>(&self, it
: &mut I
) -> ClapResult
<ParseResult
<'a
>>
736 I
: Iterator
<Item
= T
>,
739 debugln
!("Parser::parse_help_subcommand;");
740 let cmds
: Vec
<OsString
> = it
.map(|c
| c
.into()).collect();
741 let mut help_help
= false;
742 let mut bin_name
= self
746 .unwrap_or(&self.meta
.name
)
749 let mut sc
: &Parser
= self;
750 for (i
, cmd
) in cmds
.iter().enumerate() {
751 if &*cmd
.to_string_lossy() == "help" {
758 .find(|s
| &*s
.p
.meta
.name
== cmd
)
762 if i
== cmds
.len() - 1 {
765 } else if let Some(c
) = sc
769 if let Some(ref als
) = s
.p
.meta
.aliases
{
770 als
.iter().any(|&(a
, _
)| a
== &*cmd
.to_string_lossy())
778 if i
== cmds
.len() - 1 {
782 return Err(Error
::unrecognized_subcommand(
783 cmd
.to_string_lossy().into_owned(),
784 self.meta
.bin_name
.as_ref().unwrap_or(&self.meta
.name
),
788 bin_name
= format
!("{} {}", bin_name
, &*sc
.meta
.name
);
793 let mut pb
= PosBuilder
::new("subcommand", 1);
794 pb
.b
.help
= Some("The subcommand whose help message to display");
795 pb
.set(ArgSettings
::Multiple
);
796 sc
.positionals
.insert(1, pb
);
797 sc
.settings
= sc
.settings
| self.g_settings
;
799 sc
.create_help_and_version();
801 if sc
.meta
.bin_name
!= self.meta
.bin_name
{
802 sc
.meta
.bin_name
= Some(format
!("{} {}", bin_name
, sc
.meta
.name
));
807 // allow wrong self convention due to self.valid_neg_num = true and it's a private method
808 #[cfg_attr(feature = "lints", allow(wrong_self_convention))]
809 fn is_new_arg(&mut self, arg_os
: &OsStr
, needs_val_of
: ParseResult
) -> bool
{
810 debugln
!("Parser::is_new_arg:{:?}:{:?}", arg_os
, needs_val_of
);
811 let app_wide_settings
= if self.is_set(AS
::AllowLeadingHyphen
) {
813 } else if self.is_set(AS
::AllowNegativeNumbers
) {
814 let a
= arg_os
.to_string_lossy();
815 if a
.parse
::<i64>().is_ok() || a
.parse
::<f64>().is_ok() {
816 self.set(AS
::ValidNegNumFound
);
824 let arg_allows_tac
= match needs_val_of
{
825 ParseResult
::Opt(name
) => {
829 .find(|o
| o
.b
.name
== name
)
830 .expect(INTERNAL_ERROR_MSG
);
831 o
.is_set(ArgSettings
::AllowLeadingHyphen
) || app_wide_settings
833 ParseResult
::Pos(name
) => {
837 .find(|p
| p
.b
.name
== name
)
838 .expect(INTERNAL_ERROR_MSG
);
839 p
.is_set(ArgSettings
::AllowLeadingHyphen
) || app_wide_settings
841 ParseResult
::ValuesDone
=> return true,
844 debugln
!("Parser::is_new_arg: arg_allows_tac={:?}", arg_allows_tac
);
846 // Is this a new argument, or values from a previous option?
847 let mut ret
= if arg_os
.starts_with(b
"--") {
848 debugln
!("Parser::is_new_arg: -- found");
849 if arg_os
.len() == 2 && !arg_allows_tac
{
850 return true; // We have to return true so override everything else
851 } else if arg_allows_tac
{
855 } else if arg_os
.starts_with(b
"-") {
856 debugln
!("Parser::is_new_arg: - found");
857 // a singe '-' by itself is a value and typically means "stdin" on unix systems
860 debugln
!("Parser::is_new_arg: probably value");
864 ret
= ret
&& !arg_allows_tac
;
866 debugln
!("Parser::is_new_arg: starts_new_arg={:?}", ret
);
870 // The actual parsing function
872 feature
= "cargo-clippy",
873 allow(clippy
::while_let_on_iterator
, clippy
::nonminimal_bool
)
875 pub fn get_matches_with
<I
, T
>(
877 matcher
: &mut ArgMatcher
<'a
>,
878 it
: &mut Peekable
<I
>,
881 I
: Iterator
<Item
= T
>,
882 T
: Into
<OsString
> + Clone
,
884 debugln
!("Parser::get_matches_with;");
885 // Verify all positional assertions pass
886 debug_assert
!(self.app_debug_asserts());
887 if self.positionals
.values().any(|a
| {
888 a
.b
.is_set(ArgSettings
::Multiple
) && (a
.index
as usize != self.positionals
.len())
893 .map_or(false, |p
| !p
.is_set(ArgSettings
::Last
))
895 self.settings
.set(AS
::LowIndexMultiplePositional
);
897 let has_args
= self.has_args();
899 // Next we create the `--help` and `--version` arguments and add them if
901 self.create_help_and_version();
903 let mut subcmd_name
: Option
<String
> = None
;
904 let mut needs_val_of
: ParseResult
<'a
> = ParseResult
::NotFound
;
905 let mut pos_counter
= 1;
906 let mut sc_is_external
= false;
907 while let Some(arg
) = it
.next() {
908 let arg_os
= arg
.into();
910 "Parser::get_matches_with: Begin parsing '{:?}' ({:?})",
915 self.unset(AS
::ValidNegNumFound
);
916 // Is this a new argument, or values from a previous option?
917 let starts_new_arg
= self.is_new_arg(&arg_os
, needs_val_of
);
918 if !self.is_set(AS
::TrailingValues
)
919 && arg_os
.starts_with(b
"--")
923 debugln
!("Parser::get_matches_with: setting TrailingVals=true");
924 self.set(AS
::TrailingValues
);
928 // Has the user already passed '--'? Meaning only positional args follow
929 if !self.is_set(AS
::TrailingValues
) {
930 // Does the arg match a subcommand name, or any of it's aliases (if defined)
933 ParseResult
::Opt(_
) | ParseResult
::Pos(_
) => (),
935 let (is_match
, sc_name
) = self.possible_subcommand(&arg_os
);
937 "Parser::get_matches_with: possible_sc={:?}, sc={:?}",
942 let sc_name
= sc_name
.expect(INTERNAL_ERROR_MSG
);
943 if sc_name
== "help" && self.is_set(AS
::NeedsSubcommandHelp
) {
944 self.parse_help_subcommand(it
)?
;
946 subcmd_name
= Some(sc_name
.to_owned());
954 let check_all
= self.is_set(AS
::AllArgsOverrideSelf
);
956 let any_arg
= find_any_by_name
!(self, self.cache
.unwrap_or(""));
957 matcher
.process_arg_overrides(
965 if arg_os
.starts_with(b
"--") {
966 needs_val_of
= self.parse_long_arg(matcher
, &arg_os
, it
)?
;
968 "Parser:get_matches_with: After parse_long_arg {:?}",
972 ParseResult
::Flag
| ParseResult
::Opt(..) | ParseResult
::ValuesDone
=> {
977 } else if arg_os
.starts_with(b
"-") && arg_os
.len() != 1 {
978 // Try to parse short args like normal, if AllowLeadingHyphen or
979 // AllowNegativeNumbers is set, parse_short_arg will *not* throw
980 // an error, and instead return Ok(None)
981 needs_val_of
= self.parse_short_arg(matcher
, &arg_os
)?
;
982 // If it's None, we then check if one of those two AppSettings was set
984 "Parser:get_matches_with: After parse_short_arg {:?}",
988 ParseResult
::MaybeNegNum
=> {
989 if !(arg_os
.to_string_lossy().parse
::<i64>().is_ok()
990 || arg_os
.to_string_lossy().parse
::<f64>().is_ok())
992 return Err(Error
::unknown_argument(
993 &*arg_os
.to_string_lossy(),
995 &*usage
::create_error_usage(self, matcher
, None
),
1000 ParseResult
::Opt(..) | ParseResult
::Flag
| ParseResult
::ValuesDone
=> {
1006 } else if let ParseResult
::Opt(name
) = needs_val_of
{
1007 // Check to see if parsing a value from a previous arg
1011 .find(|o
| o
.b
.name
== name
)
1012 .expect(INTERNAL_ERROR_MSG
);
1013 // get the OptBuilder so we can check the settings
1014 needs_val_of
= self.add_val_to_arg(arg
, &arg_os
, matcher
)?
;
1015 // get the next value from the iterator
1020 if !(self.is_set(AS
::ArgsNegateSubcommands
) && self.is_set(AS
::ValidArgFound
))
1021 && !self.is_set(AS
::InferSubcommands
)
1022 && !self.is_set(AS
::AllowExternalSubcommands
)
1024 if let Some(cdate
) =
1025 suggestions
::did_you_mean(&*arg_os
.to_string_lossy(), sc_names
!(self))
1027 return Err(Error
::invalid_subcommand(
1028 arg_os
.to_string_lossy().into_owned(),
1030 self.meta
.bin_name
.as_ref().unwrap_or(&self.meta
.name
),
1031 &*usage
::create_error_usage(self, matcher
, None
),
1037 let low_index_mults
= self.is_set(AS
::LowIndexMultiplePositional
)
1038 && pos_counter
== (self.positionals
.len() - 1);
1039 let missing_pos
= self.is_set(AS
::AllowMissingPositional
)
1040 && (pos_counter
== (self.positionals
.len() - 1)
1041 && !self.is_set(AS
::TrailingValues
));
1043 "Parser::get_matches_with: Positional counter...{}",
1047 "Parser::get_matches_with: Low index multiples...{:?}",
1050 if low_index_mults
|| missing_pos
{
1051 if let Some(na
) = it
.peek() {
1052 let n
= (*na
).clone().into();
1053 needs_val_of
= if needs_val_of
!= ParseResult
::ValuesDone
{
1054 if let Some(p
) = self.positionals
.get(pos_counter
) {
1055 ParseResult
::Pos(p
.b
.name
)
1057 ParseResult
::ValuesDone
1060 ParseResult
::ValuesDone
1062 let sc_match
= { self.possible_subcommand(&n).0 }
;
1063 if self.is_new_arg(&n
, needs_val_of
)
1065 || suggestions
::did_you_mean(&n
.to_string_lossy(), sc_names
!(self))
1068 debugln
!("Parser::get_matches_with: Bumping the positional counter...");
1072 debugln
!("Parser::get_matches_with: Bumping the positional counter...");
1075 } else if (self.is_set(AS
::AllowMissingPositional
) && self.is_set(AS
::TrailingValues
))
1076 || (self.is_set(AS
::ContainsLast
) && self.is_set(AS
::TrailingValues
))
1078 // Came to -- and one postional has .last(true) set, so we go immediately
1079 // to the last (highest index) positional
1080 debugln
!("Parser::get_matches_with: .last(true) and --, setting last pos");
1081 pos_counter
= self.positionals
.len();
1083 if let Some(p
) = self.positionals
.get(pos_counter
) {
1084 if p
.is_set(ArgSettings
::Last
) && !self.is_set(AS
::TrailingValues
) {
1085 return Err(Error
::unknown_argument(
1086 &*arg_os
.to_string_lossy(),
1088 &*usage
::create_error_usage(self, matcher
, None
),
1092 if !self.is_set(AS
::TrailingValues
)
1093 && (self.is_set(AS
::TrailingVarArg
) && pos_counter
== self.positionals
.len())
1095 self.settings
.set(AS
::TrailingValues
);
1097 if self.cache
.map_or(true, |name
| name
!= p
.b
.name
) {
1098 let check_all
= self.is_set(AS
::AllArgsOverrideSelf
);
1100 let any_arg
= find_any_by_name
!(self, self.cache
.unwrap_or(""));
1101 matcher
.process_arg_overrides(
1103 &mut self.overrides
,
1108 self.cache
= Some(p
.b
.name
);
1110 let _
= self.add_val_to_arg(p
, &arg_os
, matcher
)?
;
1112 matcher
.inc_occurrence_of(p
.b
.name
);
1114 .groups_for_arg(p
.b
.name
)
1115 .map(|vec
| matcher
.inc_occurrences_of(&*vec
));
1117 self.settings
.set(AS
::ValidArgFound
);
1118 // Only increment the positional counter if it doesn't allow multiples
1119 if !p
.b
.settings
.is_set(ArgSettings
::Multiple
) {
1122 self.settings
.set(AS
::ValidArgFound
);
1123 } else if self.is_set(AS
::AllowExternalSubcommands
) {
1124 // Get external subcommand name
1125 let sc_name
= match arg_os
.to_str() {
1126 Some(s
) => s
.to_string(),
1128 if !self.is_set(AS
::StrictUtf8
) {
1129 return Err(Error
::invalid_utf8(
1130 &*usage
::create_error_usage(self, matcher
, None
),
1134 arg_os
.to_string_lossy().into_owned()
1138 // Collect the external subcommand args
1139 let mut sc_m
= ArgMatcher
::new();
1140 // Due to borrow rules, this has to be a while let...
1141 #[cfg_attr(feature = "cargo-clippy", allow(clippy::while_let_on_iterator))]
1142 while let Some(v
) = it
.next() {
1144 if a
.to_str().is_none() && !self.is_set(AS
::StrictUtf8
) {
1145 return Err(Error
::invalid_utf8(
1146 &*usage
::create_error_usage(self, matcher
, None
),
1150 sc_m
.add_val_to("", &a
);
1153 matcher
.subcommand(SubCommand
{
1155 matches
: sc_m
.into(),
1157 sc_is_external
= true;
1158 } else if !((self.is_set(AS
::AllowLeadingHyphen
)
1159 || self.is_set(AS
::AllowNegativeNumbers
))
1160 && arg_os
.starts_with(b
"-"))
1161 && !self.is_set(AS
::InferSubcommands
)
1163 return Err(Error
::unknown_argument(
1164 &*arg_os
.to_string_lossy(),
1166 &*usage
::create_error_usage(self, matcher
, None
),
1169 } else if !has_args
|| self.is_set(AS
::InferSubcommands
) && self.has_subcommands() {
1170 if let Some(cdate
) =
1171 suggestions
::did_you_mean(&*arg_os
.to_string_lossy(), sc_names
!(self))
1173 return Err(Error
::invalid_subcommand(
1174 arg_os
.to_string_lossy().into_owned(),
1176 self.meta
.bin_name
.as_ref().unwrap_or(&self.meta
.name
),
1177 &*usage
::create_error_usage(self, matcher
, None
),
1181 return Err(Error
::unrecognized_subcommand(
1182 arg_os
.to_string_lossy().into_owned(),
1183 self.meta
.bin_name
.as_ref().unwrap_or(&self.meta
.name
),
1188 return Err(Error
::unknown_argument(
1189 &*arg_os
.to_string_lossy(),
1191 &*usage
::create_error_usage(self, matcher
, None
),
1197 if !sc_is_external
{
1198 if let Some(ref pos_sc_name
) = subcmd_name
{
1200 find_subcmd
!(self, pos_sc_name
)
1201 .expect(INTERNAL_ERROR_MSG
)
1207 self.parse_subcommand(&*sc_name
, matcher
, it
)?
;
1208 } else if self.is_set(AS
::SubcommandRequired
) {
1209 let bn
= self.meta
.bin_name
.as_ref().unwrap_or(&self.meta
.name
);
1210 return Err(Error
::missing_subcommand(
1212 &usage
::create_error_usage(self, matcher
, None
),
1215 } else if self.is_set(AS
::SubcommandRequiredElseHelp
) {
1216 debugln
!("Parser::get_matches_with: SubcommandRequiredElseHelp=true");
1217 let mut out
= vec
![];
1218 self.write_help_err(&mut out
)?
;
1220 message
: String
::from_utf8_lossy(&*out
).into_owned(),
1221 kind
: ErrorKind
::MissingArgumentOrSubcommand
,
1227 // In case the last arg was new, we need to process it's overrides
1228 let check_all
= self.is_set(AS
::AllArgsOverrideSelf
);
1230 let any_arg
= find_any_by_name
!(self, self.cache
.unwrap_or(""));
1231 matcher
.process_arg_overrides(
1233 &mut self.overrides
,
1239 self.remove_overrides(matcher
);
1241 Validator
::new(self).validate(needs_val_of
, subcmd_name
, matcher
)
1244 fn remove_overrides(&mut self, matcher
: &mut ArgMatcher
) {
1245 debugln
!("Parser::remove_overrides:{:?};", self.overrides
);
1246 for &(overr
, name
) in &self.overrides
{
1247 debugln
!("Parser::remove_overrides:iter:({},{});", overr
, name
);
1248 if matcher
.is_present(overr
) {
1250 "Parser::remove_overrides:iter:({},{}): removing {};",
1255 matcher
.remove(name
);
1256 for i
in (0..self.required
.len()).rev() {
1258 "Parser::remove_overrides:iter:({},{}): removing required {};",
1263 if self.required
[i
] == name
{
1264 self.required
.swap_remove(i
);
1272 fn propagate_help_version(&mut self) {
1273 debugln
!("Parser::propagate_help_version;");
1274 self.create_help_and_version();
1275 for sc
in &mut self.subcommands
{
1276 sc
.p
.propagate_help_version();
1280 fn build_bin_names(&mut self) {
1281 debugln
!("Parser::build_bin_names;");
1282 for sc
in &mut self.subcommands
{
1283 debug
!("Parser::build_bin_names:iter: bin_name set...");
1284 if sc
.p
.meta
.bin_name
.is_none() {
1286 let bin_name
= format
!(
1291 .unwrap_or(&self.meta
.name
.clone()),
1292 if self.meta
.bin_name
.is_some() {
1300 "Parser::build_bin_names:iter: Setting bin_name of {} to {}",
1304 sc
.p
.meta
.bin_name
= Some(bin_name
);
1306 sdebugln
!("yes ({:?})", sc
.p
.meta
.bin_name
);
1309 "Parser::build_bin_names:iter: Calling build_bin_names from...{}",
1312 sc
.p
.build_bin_names();
1316 fn parse_subcommand
<I
, T
>(
1319 matcher
: &mut ArgMatcher
<'a
>,
1320 it
: &mut Peekable
<I
>,
1323 I
: Iterator
<Item
= T
>,
1324 T
: Into
<OsString
> + Clone
,
1326 use std
::fmt
::Write
;
1327 debugln
!("Parser::parse_subcommand;");
1328 let mut mid_string
= String
::new();
1329 if !self.is_set(AS
::SubcommandsNegateReqs
) {
1330 let mut hs
: Vec
<&str> = self.required
.iter().map(|n
| &**n
).collect();
1331 for k
in matcher
.arg_names() {
1334 let reqs
= usage
::get_required_usage_from(self, &hs
, Some(matcher
), None
, false);
1337 write
!(&mut mid_string
, " {}", s
).expect(INTERNAL_ERROR_MSG
);
1340 mid_string
.push(' '
);
1341 if let Some(ref mut sc
) = self
1344 .find(|s
| s
.p
.meta
.name
== sc_name
)
1346 let mut sc_matcher
= ArgMatcher
::new();
1347 // bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
1349 sc
.p
.meta
.usage
= Some(format
!(
1351 self.meta
.bin_name
.as_ref().unwrap_or(&String
::new()),
1352 if self.meta
.bin_name
.is_some() {
1359 sc
.p
.meta
.bin_name
= Some(format
!(
1361 self.meta
.bin_name
.as_ref().unwrap_or(&String
::new()),
1362 if self.meta
.bin_name
.is_some() {
1370 "Parser::parse_subcommand: About to parse sc={}",
1373 debugln
!("Parser::parse_subcommand: sc settings={:#?}", sc
.p
.settings
);
1374 sc
.p
.get_matches_with(&mut sc_matcher
, it
)?
;
1375 matcher
.subcommand(SubCommand
{
1376 name
: sc
.p
.meta
.name
.clone(),
1377 matches
: sc_matcher
.into(),
1383 pub fn groups_for_arg(&self, name
: &str) -> Option
<Vec
<&'a
str>> {
1384 debugln
!("Parser::groups_for_arg: name={}", name
);
1386 if self.groups
.is_empty() {
1387 debugln
!("Parser::groups_for_arg: No groups defined");
1390 let mut res
= vec
![];
1391 debugln
!("Parser::groups_for_arg: Searching through groups...");
1392 for grp
in &self.groups
{
1393 for a
in &grp
.args
{
1395 sdebugln
!("\tFound '{}'", grp
.name
);
1396 res
.push(&*grp
.name
);
1407 pub fn args_in_group(&self, group
: &str) -> Vec
<String
> {
1408 debug_assert
!(self.app_debug_asserts());
1410 let mut g_vec
= vec
![];
1411 let mut args
= vec
![];
1416 .find(|g
| g
.name
== group
)
1417 .expect(INTERNAL_ERROR_MSG
)
1420 if let Some(f
) = self.flags
.iter().find(|f
| &f
.b
.name
== n
) {
1421 args
.push(f
.to_string());
1422 } else if let Some(f
) = self.opts
.iter().find(|o
| &o
.b
.name
== n
) {
1423 args
.push(f
.to_string());
1424 } else if let Some(p
) = self.positionals
.values().find(|p
| &p
.b
.name
== n
) {
1425 args
.push(p
.b
.name
.to_owned());
1431 for av
in g_vec
.iter().map(|g
| self.args_in_group(g
)) {
1435 args
.iter().map(ToOwned
::to_owned
).collect()
1438 pub fn arg_names_in_group(&self, group
: &str) -> Vec
<&'a
str> {
1439 let mut g_vec
= vec
![];
1440 let mut args
= vec
![];
1445 .find(|g
| g
.name
== group
)
1446 .expect(INTERNAL_ERROR_MSG
)
1449 if self.groups
.iter().any(|g
| g
.name
== *n
) {
1450 args
.extend(self.arg_names_in_group(n
));
1452 } else if !args
.contains(n
) {
1457 args
.iter().copied().collect()
1460 pub fn create_help_and_version(&mut self) {
1461 debugln
!("Parser::create_help_and_version;");
1462 // name is "hclap_help" because flags are sorted by name
1463 if !self.is_set(AS
::DisableHelpFlags
) && !self.contains_long("help") {
1464 debugln
!("Parser::create_help_and_version: Building --help");
1465 if self.help_short
.is_none() && !self.contains_short('h'
) {
1466 self.help_short
= Some('h'
);
1468 let arg
= FlagBuilder
{
1471 help
: self.help_message
.or(Some("Prints help information")),
1472 ..Default
::default()
1475 short
: self.help_short
,
1477 ..Default
::default()
1480 self.flags
.push(arg
);
1482 if !self.is_set(AS
::DisableVersion
) && !self.contains_long("version") {
1483 debugln
!("Parser::create_help_and_version: Building --version");
1484 if self.version_short
.is_none() && !self.contains_short('V'
) {
1485 self.version_short
= Some('V'
);
1487 // name is "vclap_version" because flags are sorted by name
1488 let arg
= FlagBuilder
{
1490 name
: "vclap_version",
1491 help
: self.version_message
.or(Some("Prints version information")),
1492 ..Default
::default()
1495 short
: self.version_short
,
1496 long
: Some("version"),
1497 ..Default
::default()
1500 self.flags
.push(arg
);
1502 if !self.subcommands
.is_empty()
1503 && !self.is_set(AS
::DisableHelpSubcommand
)
1504 && self.is_set(AS
::NeedsSubcommandHelp
)
1506 debugln
!("Parser::create_help_and_version: Building help");
1507 self.subcommands
.push(
1509 .about("Prints this message or the help of the given subcommand(s)"),
1514 // Retrieves the names of all args the user has supplied thus far, except required ones
1515 // because those will be listed in self.required
1516 fn check_for_help_and_version_str(&self, arg
: &OsStr
) -> ClapResult
<()> {
1517 debugln
!("Parser::check_for_help_and_version_str;");
1519 "Parser::check_for_help_and_version_str: Checking if --{} is help or version...",
1520 arg
.to_str().unwrap()
1522 if arg
== "help" && self.is_set(AS
::NeedsLongHelp
) {
1524 return Err(self._help(true));
1526 if arg
== "version" && self.is_set(AS
::NeedsLongVersion
) {
1527 sdebugln
!("Version");
1528 return Err(self._version(true));
1530 sdebugln
!("Neither");
1535 fn check_for_help_and_version_char(&self, arg
: char) -> ClapResult
<()> {
1536 debugln
!("Parser::check_for_help_and_version_char;");
1538 "Parser::check_for_help_and_version_char: Checking if -{} is help or version...",
1541 if let Some(h
) = self.help_short
{
1542 if arg
== h
&& self.is_set(AS
::NeedsLongHelp
) {
1544 return Err(self._help(false));
1547 if let Some(v
) = self.version_short
{
1548 if arg
== v
&& self.is_set(AS
::NeedsLongVersion
) {
1549 sdebugln
!("Version");
1550 return Err(self._version(false));
1553 sdebugln
!("Neither");
1557 fn use_long_help(&self) -> bool
{
1558 // In this case, both must be checked. This allows the retention of
1559 // original formatting, but also ensures that the actual -h or --help
1560 // specified by the user is sent through. If HiddenShortHelp is not included,
1561 // then items specified with hidden_short_help will also be hidden.
1562 let should_long
= |v
: &Base
| {
1563 v
.long_help
.is_some()
1564 || v
.is_set(ArgSettings
::HiddenLongHelp
)
1565 || v
.is_set(ArgSettings
::HiddenShortHelp
)
1568 self.meta
.long_about
.is_some()
1569 || self.flags
.iter().any(|f
| should_long(&f
.b
))
1570 || self.opts
.iter().any(|o
| should_long(&o
.b
))
1571 || self.positionals
.values().any(|p
| should_long(&p
.b
))
1575 .any(|s
| s
.p
.meta
.long_about
.is_some())
1578 fn _help(&self, mut use_long
: bool
) -> Error
{
1579 debugln
!("Parser::_help: use_long={:?}", use_long
);
1580 use_long
= use_long
&& self.use_long_help();
1581 let mut buf
= vec
![];
1582 match Help
::write_parser_help(&mut buf
, self, use_long
) {
1585 message
: String
::from_utf8(buf
).unwrap_or_default(),
1586 kind
: ErrorKind
::HelpDisplayed
,
1592 fn _version(&self, use_long
: bool
) -> Error
{
1593 debugln
!("Parser::_version: ");
1594 let out
= io
::stdout();
1595 let mut buf_w
= BufWriter
::new(out
.lock());
1596 match self.print_version(&mut buf_w
, use_long
) {
1599 message
: String
::new(),
1600 kind
: ErrorKind
::VersionDisplayed
,
1606 fn parse_long_arg
<I
, T
>(
1608 matcher
: &mut ArgMatcher
<'a
>,
1610 it
: &mut Peekable
<I
>,
1611 ) -> ClapResult
<ParseResult
<'a
>>
1613 I
: Iterator
<Item
= T
>,
1614 T
: Into
<OsString
> + Clone
,
1616 // maybe here lifetime should be 'a
1617 debugln
!("Parser::parse_long_arg;");
1619 // Update the current index
1620 self.cur_idx
.set(self.cur_idx
.get() + 1);
1623 debug
!("Parser::parse_long_arg: Does it contain '='...");
1624 let arg
= if full_arg
.contains_byte(b'
='
) {
1625 let (p0
, p1
) = full_arg
.trim_left_matches(b'
-'
).split_at_byte(b'
='
);
1626 sdebugln
!("Yes '{:?}'", p1
);
1631 full_arg
.trim_left_matches(b'
-'
)
1634 if let Some(opt
) = find_opt_by_long
!(@os
self, arg
) {
1636 "Parser::parse_long_arg: Found valid opt '{}'",
1639 self.settings
.set(AS
::ValidArgFound
);
1640 let ret
= self.parse_opt(val
, opt
, val
.is_some(), matcher
)?
;
1641 if self.cache
.map_or(true, |name
| name
!= opt
.b
.name
) {
1642 self.cache
= Some(opt
.b
.name
);
1646 } else if let Some(flag
) = find_flag_by_long
!(@os
self, arg
) {
1648 "Parser::parse_long_arg: Found valid flag '{}'",
1651 self.settings
.set(AS
::ValidArgFound
);
1652 // Only flags could be help or version, and we need to check the raw long
1653 // so this is the first point to check
1654 self.check_for_help_and_version_str(arg
)?
;
1656 self.parse_flag(flag
, matcher
)?
;
1658 // Handle conflicts, requirements, etc.
1659 if self.cache
.map_or(true, |name
| name
!= flag
.b
.name
) {
1660 self.cache
= Some(flag
.b
.name
);
1663 return Ok(ParseResult
::Flag
);
1664 } else if self.is_set(AS
::AllowLeadingHyphen
) {
1665 return Ok(ParseResult
::MaybeHyphenValue
);
1666 } else if self.is_set(AS
::ValidNegNumFound
) {
1667 return Ok(ParseResult
::MaybeNegNum
);
1670 debugln
!("Parser::parse_long_arg: Didn't match anything");
1672 let args_rest
: Vec
<_
> = it
.map(|x
| x
.into()).collect();
1673 let args_rest2
: Vec
<_
> = args_rest
1675 .map(|x
| x
.to_str().expect(INVALID_UTF8
))
1677 self.did_you_mean_error(arg
.to_str().expect(INVALID_UTF8
), matcher
, &args_rest2
[..])
1678 .map(|_
| ParseResult
::NotFound
)
1683 matcher
: &mut ArgMatcher
<'a
>,
1685 ) -> ClapResult
<ParseResult
<'a
>> {
1686 debugln
!("Parser::parse_short_arg: full_arg={:?}", full_arg
);
1687 let arg_os
= full_arg
.trim_left_matches(b'
-'
);
1688 let arg
= arg_os
.to_string_lossy();
1690 // If AllowLeadingHyphen is set, we want to ensure `-val` gets parsed as `-val` and not
1691 // `-v` `-a` `-l` assuming `v` `a` and `l` are all, or mostly, valid shorts.
1692 if self.is_set(AS
::AllowLeadingHyphen
) {
1693 if arg
.chars().any(|c
| !self.contains_short(c
)) {
1695 "Parser::parse_short_arg: LeadingHyphenAllowed yet -{} isn't valid",
1698 return Ok(ParseResult
::MaybeHyphenValue
);
1700 } else if self.is_set(AS
::ValidNegNumFound
) {
1701 // TODO: Add docs about having AllowNegativeNumbers and `-2` as a valid short
1702 // May be better to move this to *after* not finding a valid flag/opt?
1703 debugln
!("Parser::parse_short_arg: Valid negative num...");
1704 return Ok(ParseResult
::MaybeNegNum
);
1707 let mut ret
= ParseResult
::NotFound
;
1708 for c
in arg
.chars() {
1709 debugln
!("Parser::parse_short_arg:iter:{}", c
);
1711 // update each index because `-abcd` is four indices to clap
1712 self.cur_idx
.set(self.cur_idx
.get() + 1);
1714 // Check for matching short options, and return the name if there is no trailing
1715 // concatenated value: -oval
1718 if let Some(opt
) = find_opt_by_short
!(self, c
) {
1719 debugln
!("Parser::parse_short_arg:iter:{}: Found valid opt", c
);
1720 self.settings
.set(AS
::ValidArgFound
);
1721 // Check for trailing concatenated value
1722 let p
: Vec
<_
> = arg
.splitn(2, c
).collect();
1724 "Parser::parse_short_arg:iter:{}: p[0]={:?}, p[1]={:?}",
1729 let i
= p
[0].as_bytes().len() + 1;
1730 let val
= if !p
[1].as_bytes().is_empty() {
1732 "Parser::parse_short_arg:iter:{}: val={:?} (bytes), val={:?} (ascii)",
1734 arg_os
.split_at(i
).1.as_bytes(),
1735 arg_os
.split_at(i
).1
1737 Some(arg_os
.split_at(i
).1)
1742 // Default to "we're expecting a value later"
1743 let ret
= self.parse_opt(val
, opt
, false, matcher
)?
;
1745 if self.cache
.map_or(true, |name
| name
!= opt
.b
.name
) {
1746 self.cache
= Some(opt
.b
.name
);
1750 } else if let Some(flag
) = find_flag_by_short
!(self, c
) {
1751 debugln
!("Parser::parse_short_arg:iter:{}: Found valid flag", c
);
1752 self.settings
.set(AS
::ValidArgFound
);
1753 // Only flags can be help or version
1754 self.check_for_help_and_version_char(c
)?
;
1755 ret
= self.parse_flag(flag
, matcher
)?
;
1757 // Handle conflicts, requirements, overrides, etc.
1758 // Must be called here due to mutabililty
1759 if self.cache
.map_or(true, |name
| name
!= flag
.b
.name
) {
1760 self.cache
= Some(flag
.b
.name
);
1763 let arg
= format
!("-{}", c
);
1764 return Err(Error
::unknown_argument(
1767 &*usage
::create_error_usage(self, matcher
, None
),
1777 val
: Option
<&OsStr
>,
1778 opt
: &OptBuilder
<'a
, 'b
>,
1780 matcher
: &mut ArgMatcher
<'a
>,
1781 ) -> ClapResult
<ParseResult
<'a
>> {
1782 debugln
!("Parser::parse_opt; opt={}, val={:?}", opt
.b
.name
, val
);
1783 debugln
!("Parser::parse_opt; opt.settings={:?}", opt
.b
.settings
);
1784 let mut has_eq
= false;
1785 let no_val
= val
.is_none();
1786 let empty_vals
= opt
.is_set(ArgSettings
::EmptyValues
);
1787 let min_vals_zero
= opt
.v
.min_vals
.unwrap_or(1) == 0;
1788 let needs_eq
= opt
.is_set(ArgSettings
::RequireEquals
);
1790 debug
!("Parser::parse_opt; Checking for val...");
1791 if let Some(fv
) = val
{
1792 has_eq
= fv
.starts_with(&[b'
='
]) || had_eq
;
1793 let v
= fv
.trim_left_matches(b'
='
);
1794 if !empty_vals
&& (v
.is_empty() || (needs_eq
&& !has_eq
)) {
1795 sdebugln
!("Found Empty - Error");
1796 return Err(Error
::empty_value(
1798 &*usage
::create_error_usage(self, matcher
, None
),
1802 sdebugln
!("Found - {:?}, len: {}", v
, v
.len());
1804 "Parser::parse_opt: {:?} contains '='...{:?}",
1806 fv
.starts_with(&[b'
='
])
1808 self.add_val_to_arg(opt
, v
, matcher
)?
;
1809 } else if needs_eq
&& !(empty_vals
|| min_vals_zero
) {
1810 sdebugln
!("None, but requires equals...Error");
1811 return Err(Error
::empty_value(
1813 &*usage
::create_error_usage(self, matcher
, None
),
1820 matcher
.inc_occurrence_of(opt
.b
.name
);
1821 // Increment or create the group "args"
1822 if let Some(vec
) = self.groups_for_arg(opt
.b
.name
) {
1823 matcher
.inc_occurrences_of(&*vec
);
1826 let needs_delim
= opt
.is_set(ArgSettings
::RequireDelimiter
);
1827 let mult
= opt
.is_set(ArgSettings
::Multiple
);
1828 if no_val
&& min_vals_zero
&& !has_eq
&& needs_eq
{
1829 debugln
!("Parser::parse_opt: More arg vals not required...");
1830 return Ok(ParseResult
::ValuesDone
);
1831 } else if no_val
|| (mult
&& !needs_delim
) && !has_eq
&& matcher
.needs_more_vals(opt
) {
1832 debugln
!("Parser::parse_opt: More arg vals required...");
1833 return Ok(ParseResult
::Opt(opt
.b
.name
));
1835 debugln
!("Parser::parse_opt: More arg vals not required...");
1836 Ok(ParseResult
::ValuesDone
)
1839 fn add_val_to_arg
<A
>(
1843 matcher
: &mut ArgMatcher
<'a
>,
1844 ) -> ClapResult
<ParseResult
<'a
>>
1846 A
: AnyArg
<'a
, 'b
> + Display
,
1848 debugln
!("Parser::add_val_to_arg; arg={}, val={:?}", arg
.name(), val
);
1850 "Parser::add_val_to_arg; trailing_vals={:?}, DontDelimTrailingVals={:?}",
1851 self.is_set(AS
::TrailingValues
),
1852 self.is_set(AS
::DontDelimitTrailingValues
)
1854 if !(self.is_set(AS
::TrailingValues
) && self.is_set(AS
::DontDelimitTrailingValues
)) {
1855 if let Some(delim
) = arg
.val_delim() {
1857 Ok(self.add_single_val_to_arg(arg
, val
, matcher
)?
)
1859 let mut iret
= ParseResult
::ValuesDone
;
1860 for v
in val
.split(delim
as u32 as u8) {
1861 iret
= self.add_single_val_to_arg(arg
, v
, matcher
)?
;
1863 // If there was a delimiter used, we're not looking for more values
1864 if val
.contains_byte(delim
as u32 as u8)
1865 || arg
.is_set(ArgSettings
::RequireDelimiter
)
1867 iret
= ParseResult
::ValuesDone
;
1872 self.add_single_val_to_arg(arg
, val
, matcher
)
1875 self.add_single_val_to_arg(arg
, val
, matcher
)
1879 fn add_single_val_to_arg
<A
>(
1883 matcher
: &mut ArgMatcher
<'a
>,
1884 ) -> ClapResult
<ParseResult
<'a
>>
1886 A
: AnyArg
<'a
, 'b
> + Display
,
1888 debugln
!("Parser::add_single_val_to_arg;");
1889 debugln
!("Parser::add_single_val_to_arg: adding val...{:?}", v
);
1891 // update the current index because each value is a distinct index to clap
1892 self.cur_idx
.set(self.cur_idx
.get() + 1);
1894 // @TODO @docs @p4: docs for indices should probably note that a terminator isn't a value
1895 // and therefore not reported in indices
1896 if let Some(t
) = arg
.val_terminator() {
1898 return Ok(ParseResult
::ValuesDone
);
1902 matcher
.add_val_to(arg
.name(), v
);
1903 matcher
.add_index_to(arg
.name(), self.cur_idx
.get());
1905 // Increment or create the group "args"
1906 if let Some(grps
) = self.groups_for_arg(arg
.name()) {
1908 matcher
.add_val_to(&*grp
, v
);
1912 if matcher
.needs_more_vals(arg
) {
1913 return Ok(ParseResult
::Opt(arg
.name()));
1915 Ok(ParseResult
::ValuesDone
)
1920 flag
: &FlagBuilder
<'a
, 'b
>,
1921 matcher
: &mut ArgMatcher
<'a
>,
1922 ) -> ClapResult
<ParseResult
<'a
>> {
1923 debugln
!("Parser::parse_flag;");
1925 matcher
.inc_occurrence_of(flag
.b
.name
);
1926 matcher
.add_index_to(flag
.b
.name
, self.cur_idx
.get());
1928 // Increment or create the group "args"
1929 if let Some(vec
) = self.groups_for_arg(flag
.b
.name
) {
1930 matcher
.inc_occurrences_of(&*vec
);
1933 Ok(ParseResult
::Flag
)
1936 fn did_you_mean_error(
1939 matcher
: &mut ArgMatcher
<'a
>,
1941 ) -> ClapResult
<()> {
1942 // Didn't match a flag or option
1944 suggestions
::did_you_mean_flag_suffix(arg
, args_rest
, longs
!(self), &self.subcommands
);
1946 // Add the arg to the matches to build a proper usage string
1947 if let Some(name
) = suffix
.1 {
1948 if let Some(opt
) = find_opt_by_long
!(self, name
) {
1949 if let Some(grps
) = self.groups_for_arg(&*opt
.b
.name
) {
1950 matcher
.inc_occurrences_of(&*grps
);
1952 matcher
.insert(&*opt
.b
.name
);
1953 } else if let Some(flg
) = find_flag_by_long
!(self, name
) {
1954 if let Some(grps
) = self.groups_for_arg(&*flg
.b
.name
) {
1955 matcher
.inc_occurrences_of(&*grps
);
1957 matcher
.insert(&*flg
.b
.name
);
1961 let used_arg
= format
!("--{}", arg
);
1962 Err(Error
::unknown_argument(
1965 &*usage
::create_error_usage(self, matcher
, None
),
1970 // Prints the version to the user and exits if quit=true
1971 fn print_version
<W
: Write
>(&self, w
: &mut W
, use_long
: bool
) -> ClapResult
<()> {
1972 self.write_version(w
, use_long
)?
;
1973 w
.flush().map_err(Error
::from
)
1976 pub fn write_version
<W
: Write
>(&self, w
: &mut W
, use_long
: bool
) -> io
::Result
<()> {
1977 let ver
= if use_long
{
1980 .unwrap_or_else(|| self.meta
.version
.unwrap_or(""))
1984 .unwrap_or_else(|| self.meta
.long_version
.unwrap_or(""))
1986 if let Some(bn
) = self.meta
.bin_name
.as_ref() {
1987 if bn
.contains(' '
) {
1988 // Incase we're dealing with subcommands i.e. git mv is translated to git-mv
1989 write
!(w
, "{} {}", bn
.replace(" ", "-"), ver
)
1991 write
!(w
, "{} {}", &self.meta
.name
[..], ver
)
1994 write
!(w
, "{} {}", &self.meta
.name
[..], ver
)
1998 pub fn print_help(&self) -> ClapResult
<()> {
1999 let out
= io
::stdout();
2000 let mut buf_w
= BufWriter
::new(out
.lock());
2001 self.write_help(&mut buf_w
)
2004 pub fn write_help
<W
: Write
>(&self, w
: &mut W
) -> ClapResult
<()> {
2005 Help
::write_parser_help(w
, self, false)
2008 pub fn write_long_help
<W
: Write
>(&self, w
: &mut W
) -> ClapResult
<()> {
2009 Help
::write_parser_help(w
, self, true)
2012 pub fn write_help_err
<W
: Write
>(&self, w
: &mut W
) -> ClapResult
<()> {
2013 Help
::write_parser_help_to_stderr(w
, self)
2016 pub fn add_defaults(&mut self, matcher
: &mut ArgMatcher
<'a
>) -> ClapResult
<()> {
2017 debugln
!("Parser::add_defaults;");
2018 macro_rules
! add_val
{
2019 (@
default $_self
:ident
, $a
:ident
, $m
:ident
) => {
2020 if let Some(ref val
) = $a
.v
.default_val
{
2021 debugln
!("Parser::add_defaults:iter:{}: has default vals", $a
.b
.name
);
2022 if $m
.get($a
.b
.name
).map(|ma
| ma
.vals
.len()).map(|len
| len
== 0).unwrap_or(false) {
2023 debugln
!("Parser::add_defaults:iter:{}: has no user defined vals", $a
.b
.name
);
2024 $_self
.add_val_to_arg($a
, OsStr
::new(val
), $m
)?
;
2026 if $_self
.cache
.map_or(true, |name
| name
!= $a
.name()) {
2027 $_self
.cache
= Some($a
.name());
2029 } else if $m
.get($a
.b
.name
).is_some() {
2030 debugln
!("Parser::add_defaults:iter:{}: has user defined vals", $a
.b
.name
);
2032 debugln
!("Parser::add_defaults:iter:{}: wasn't used", $a
.b
.name
);
2034 $_self
.add_val_to_arg($a
, OsStr
::new(val
), $m
)?
;
2036 if $_self
.cache
.map_or(true, |name
| name
!= $a
.name()) {
2037 $_self
.cache
= Some($a
.name());
2041 debugln
!("Parser::add_defaults:iter:{}: doesn't have default vals", $a
.b
.name
);
2044 ($_self
:ident
, $a
:ident
, $m
:ident
) => {
2045 if let Some(ref vm
) = $a
.v
.default_vals_ifs
{
2046 sdebugln
!(" has conditional defaults");
2047 let mut done
= false;
2048 if $m
.get($a
.b
.name
).is_none() {
2049 for &(arg
, val
, default) in vm
.values() {
2050 let add
= if let Some(a
) = $m
.get(arg
) {
2051 if let Some(v
) = val
{
2052 a
.vals
.iter().any(|value
| v
== value
)
2060 $_self
.add_val_to_arg($a
, OsStr
::new(default), $m
)?
;
2061 if $_self
.cache
.map_or(true, |name
| name
!= $a
.name()) {
2062 $_self
.cache
= Some($a
.name());
2071 continue; // outer loop (outside macro)
2074 sdebugln
!(" doesn't have conditional defaults");
2076 add_val
!(@
default $_self
, $a
, $m
)
2080 for o
in &self.opts
{
2081 debug
!("Parser::add_defaults:iter:{}:", o
.b
.name
);
2082 add_val
!(self, o
, matcher
);
2084 for p
in self.positionals
.values() {
2085 debug
!("Parser::add_defaults:iter:{}:", p
.b
.name
);
2086 add_val
!(self, p
, matcher
);
2091 pub fn add_env(&mut self, matcher
: &mut ArgMatcher
<'a
>) -> ClapResult
<()> {
2092 macro_rules
! add_val
{
2093 ($_self
:ident
, $a
:ident
, $m
:ident
) => {
2094 if let Some(ref val
) = $a
.v
.env
{
2097 .map(|ma
| ma
.vals
.len())
2098 .map(|len
| len
== 0)
2101 if let Some(ref val
) = val
.1 {
2102 $_self
.add_val_to_arg($a
, OsStr
::new(val
), $m
)?
;
2104 if $_self
.cache
.map_or(true, |name
| name
!= $a
.name()) {
2105 $_self
.cache
= Some($a
.name());
2109 if let Some(ref val
) = val
.1 {
2110 $_self
.add_val_to_arg($a
, OsStr
::new(val
), $m
)?
;
2112 if $_self
.cache
.map_or(true, |name
| name
!= $a
.name()) {
2113 $_self
.cache
= Some($a
.name());
2121 for o
in &self.opts
{
2122 add_val
!(self, o
, matcher
);
2124 for p
in self.positionals
.values() {
2125 add_val
!(self, p
, matcher
);
2130 pub fn flags(&self) -> Iter
<FlagBuilder
<'a
, 'b
>> {
2134 pub fn opts(&self) -> Iter
<OptBuilder
<'a
, 'b
>> {
2138 pub fn positionals(&self) -> map
::Values
<PosBuilder
<'a
, 'b
>> {
2139 self.positionals
.values()
2142 pub fn subcommands(&self) -> Iter
<App
> {
2143 self.subcommands
.iter()
2146 // Should we color the output? None=determined by output location, true=yes, false=no
2148 pub fn color(&self) -> ColorWhen
{
2149 debugln
!("Parser::color;");
2150 debug
!("Parser::color: Color setting...");
2151 if self.is_set(AS
::ColorNever
) {
2154 } else if self.is_set(AS
::ColorAlways
) {
2155 sdebugln
!("Always");
2163 pub fn find_any_arg(&self, name
: &str) -> Option
<&AnyArg
<'a
, 'b
>> {
2164 if let Some(f
) = find_by_name
!(self, name
, flags
, iter
) {
2167 if let Some(o
) = find_by_name
!(self, name
, opts
, iter
) {
2170 if let Some(p
) = find_by_name
!(self, name
, positionals
, values
) {
2176 /// Check is a given string matches the binary name for this parser
2177 fn is_bin_name(&self, value
: &str) -> bool
{
2181 .map(|name
| value
== name
)
2185 /// Check is a given string is an alias for this parser
2186 fn is_alias(&self, value
: &str) -> bool
{
2191 for alias
in aliases
{
2192 if alias
.0 == value
{
2201 // Only used for completion scripts due to bin_name messiness
2202 #[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))]
2203 pub fn find_subcommand(&'b
self, sc
: &str) -> Option
<&'b App
<'a
, 'b
>> {
2204 debugln
!("Parser::find_subcommand: sc={}", sc
);
2206 "Parser::find_subcommand: Currently in Parser...{}",
2207 self.meta
.bin_name
.as_ref().unwrap()
2209 for s
in &self.subcommands
{
2210 if s
.p
.is_bin_name(sc
) {
2213 // XXX: why do we split here?
2214 // isn't `sc` supposed to be single word already?
2215 let last
= sc
.split(' '
).rev().next().expect(INTERNAL_ERROR_MSG
);
2216 if s
.p
.is_alias(last
) {
2220 if let Some(app
) = s
.p
.find_subcommand(sc
) {
2228 fn contains_long(&self, l
: &str) -> bool
{
2229 longs
!(self).any(|al
| al
== &l
)
2233 fn contains_short(&self, s
: char) -> bool
{
2234 shorts
!(self).any(|arg_s
| arg_s
== &s
)