]> git.proxmox.com Git - rustc.git/blame - src/vendor/clap/src/app/parser.rs
New upstream version 1.22.1+dfsg1
[rustc.git] / src / vendor / clap / src / app / parser.rs
CommitLineData
8bb4bdeb 1// Std
8bb4bdeb
XL
2use std::ffi::{OsStr, OsString};
3use std::fmt::Display;
4use std::fs::File;
5use std::io::{self, BufWriter, Write};
6#[cfg(feature = "debug")]
7use std::os::unix::ffi::OsStrExt;
8use std::path::PathBuf;
9use std::slice::Iter;
10use std::iter::Peekable;
11
12// Third Party
13use vec_map::{self, VecMap};
14
15// Internal
16use INTERNAL_ERROR_MSG;
17use INVALID_UTF8;
18use SubCommand;
19use app::App;
20use app::help::Help;
21use app::meta::AppMeta;
041b39d2 22use app::settings::AppFlags;
8bb4bdeb 23use args::{AnyArg, ArgMatcher, Base, Switched, Arg, ArgGroup, FlagBuilder, OptBuilder, PosBuilder};
8bb4bdeb
XL
24use args::settings::ArgSettings;
25use completions::ComplGen;
26use errors::{Error, ErrorKind};
27use errors::Result as ClapResult;
041b39d2 28use fmt::ColorWhen;
8bb4bdeb
XL
29use osstringext::OsStrExt2;
30use completions::Shell;
31use suggestions;
041b39d2
XL
32use app::settings::AppSettings as AS;
33use app::validator::Validator;
34use app::usage;
35
36#[derive(Debug, PartialEq, Copy, Clone)]
37#[doc(hidden)]
38pub enum ParseResult<'a> {
39 Flag,
40 Opt(&'a str),
41 Pos(&'a str),
42 MaybeHyphenValue,
43 MaybeNegNum,
44 NotFound,
45 ValuesDone,
46}
8bb4bdeb
XL
47
48#[allow(missing_debug_implementations)]
49#[doc(hidden)]
041b39d2 50#[derive(Clone, Default)]
8bb4bdeb
XL
51pub struct Parser<'a, 'b>
52 where 'a: 'b
53{
041b39d2
XL
54 pub meta: AppMeta<'b>,
55 settings: AppFlags,
56 pub g_settings: AppFlags,
8bb4bdeb 57 pub flags: Vec<FlagBuilder<'a, 'b>>,
8bb4bdeb 58 pub opts: Vec<OptBuilder<'a, 'b>>,
8bb4bdeb 59 pub positionals: VecMap<PosBuilder<'a, 'b>>,
8bb4bdeb 60 pub subcommands: Vec<App<'a, 'b>>,
041b39d2
XL
61 pub groups: Vec<ArgGroup<'a>>,
62 pub global_args: Vec<Arg<'a, 'b>>,
63 pub required: Vec<&'a str>,
64 pub r_ifs: Vec<(&'a str, &'b str, &'a str)>,
65 pub blacklist: Vec<&'b str>,
66 pub overrides: Vec<&'b str>,
8bb4bdeb
XL
67 help_short: Option<char>,
68 version_short: Option<char>,
041b39d2
XL
69 cache: Option<&'a str>,
70 pub help_message: Option<&'a str>,
71 pub version_message: Option<&'a str>,
8bb4bdeb
XL
72}
73
74impl<'a, 'b> Parser<'a, 'b>
75 where 'a: 'b
76{
77 pub fn with_name(n: String) -> Self {
041b39d2
XL
78 Parser {
79 meta: AppMeta::with_name(n),
80 ..Default::default()
81 }
8bb4bdeb
XL
82 }
83
84 pub fn help_short(&mut self, s: &str) {
041b39d2 85 let c = s.trim_left_matches(|c| c == '-')
8bb4bdeb 86 .chars()
041b39d2
XL
87 .nth(0)
88 .unwrap_or('h');
89 self.help_short = Some(c);
8bb4bdeb
XL
90 }
91
92 pub fn version_short(&mut self, s: &str) {
041b39d2 93 let c = s.trim_left_matches(|c| c == '-')
8bb4bdeb 94 .chars()
041b39d2
XL
95 .nth(0)
96 .unwrap_or('V');
97 self.version_short = Some(c);
8bb4bdeb
XL
98 }
99
100 pub fn gen_completions_to<W: Write>(&mut self, for_shell: Shell, buf: &mut W) {
041b39d2
XL
101 if !self.is_set(AS::Propogated) {
102 self.propogate_help_version();
103 self.build_bin_names();
104 self.propogate_globals();
105 self.propogate_settings();
106 self.set(AS::Propogated);
107 }
8bb4bdeb
XL
108
109 ComplGen::new(self).generate(for_shell, buf)
110 }
111
112 pub fn gen_completions(&mut self, for_shell: Shell, od: OsString) {
113 use std::error::Error;
114
115 let out_dir = PathBuf::from(od);
7cac9316 116 let name = &*self.meta.bin_name.as_ref().unwrap().clone();
8bb4bdeb
XL
117 let file_name = match for_shell {
118 Shell::Bash => format!("{}.bash-completion", name),
119 Shell::Fish => format!("{}.fish", name),
120 Shell::Zsh => format!("_{}", name),
121 Shell::PowerShell => format!("_{}.ps1", name),
122 };
123
124 let mut file = match File::create(out_dir.join(file_name)) {
125 Err(why) => panic!("couldn't create completion file: {}", why.description()),
126 Ok(file) => file,
127 };
128 self.gen_completions_to(for_shell, &mut file)
129 }
130
041b39d2
XL
131 #[inline]
132 fn app_debug_asserts(&mut self) -> bool {
133 assert!(self.verify_positionals());
134 let should_err = self.groups
135 .iter()
136 .all(|g| {
137 g.args
138 .iter()
139 .all(|arg| {
140 (self.flags.iter().any(|f| &f.b.name == arg) ||
141 self.opts.iter().any(|o| &o.b.name == arg) ||
142 self.positionals.values().any(|p| &p.b.name == arg) ||
143 self.groups.iter().any(|g| &g.name == arg))
144 })
145 });
146 let g = self.groups
147 .iter()
148 .find(|g| {
149 g.args
150 .iter()
151 .any(|arg| {
152 !(self.flags.iter().any(|f| &f.b.name == arg) ||
153 self.opts.iter().any(|o| &o.b.name == arg) ||
154 self.positionals.values().any(|p| &p.b.name == arg) ||
155 self.groups.iter().any(|g| &g.name == arg))
156 })
157 });
158 assert!(should_err,
159 "The group '{}' contains the arg '{}' that doesn't actually exist.",
160 g.unwrap().name,
161 g.unwrap()
162 .args
163 .iter()
164 .find(|arg| {
165 !(self.flags.iter().any(|f| &&f.b.name == arg) ||
166 self.opts.iter().any(|o| &&o.b.name == arg) ||
167 self.positionals.values().any(|p| &&p.b.name == arg) ||
168 self.groups.iter().any(|g| &&g.name == arg))
169 })
170 .unwrap());
171 true
172 }
173
174 #[inline]
175 fn debug_asserts(&self, a: &Arg) -> bool {
176 assert!(!arg_names!(self).any(|name| name == a.b.name),
177 format!("Non-unique argument name: {} is already in use", a.b.name));
178 if let Some(l) = a.s.long {
179 assert!(!self.contains_long(l),
180 "Argument long must be unique\n\n\t--{} is already in use",
181 l);
182 }
183 if let Some(s) = a.s.short {
184 assert!(!self.contains_short(s),
185 "Argument short must be unique\n\n\t-{} is already in use",
186 s);
187 }
188 let i = if a.index.is_none() {
189 (self.positionals.len() + 1)
190 } else {
191 a.index.unwrap() as usize
192 };
193 assert!(!self.positionals.contains_key(i),
194 "Argument \"{}\" has the same index as another positional \
195 argument\n\n\tPerhaps try .multiple(true) to allow one positional argument \
196 to take multiple values",
197 a.b.name);
198 assert!(!(a.is_set(ArgSettings::Required) && a.is_set(ArgSettings::Global)),
199 "Global arguments cannot be required.\n\n\t'{}' is marked as \
200 global and required",
201 a.b.name);
202 if a.b.is_set(ArgSettings::Last) {
203 assert!(!self.positionals
204 .values()
205 .any(|p| p.b.is_set(ArgSettings::Last)),
206 "Only one positional argument may have last(true) set. Found two.");
207 assert!(a.s.long.is_none(),
208 "Flags or Options may not have last(true) set. {} has both a long and last(true) set.",
209 a.b.name);
210 assert!(a.s.short.is_none(),
211 "Flags or Options may not have last(true) set. {} has both a short and last(true) set.",
212 a.b.name);
213 }
214 true
215 }
216
217 #[inline]
218 fn add_conditional_reqs(&mut self, a: &Arg<'a, 'b>) {
219 if let Some(ref r_ifs) = a.r_ifs {
220 for &(arg, val) in r_ifs {
221 self.r_ifs.push((arg, val, a.b.name));
8bb4bdeb
XL
222 }
223 }
041b39d2
XL
224 }
225
226 #[inline]
227 fn add_arg_groups(&mut self, a: &Arg<'a, 'b>) {
228 if let Some(ref grps) = a.b.groups {
229 for g in grps {
230 let mut found = false;
231 if let Some(ref mut ag) = self.groups.iter_mut().find(|grp| &grp.name == g) {
232 ag.args.push(a.b.name);
233 found = true;
234 }
235 if !found {
236 let mut ag = ArgGroup::with_name(g);
237 ag.args.push(a.b.name);
238 self.groups.push(ag);
239 }
8bb4bdeb
XL
240 }
241 }
041b39d2
XL
242 }
243
244 #[inline]
245 fn add_reqs(&mut self, a: &Arg<'a, 'b>) {
7cac9316 246 if a.is_set(ArgSettings::Required) {
041b39d2
XL
247 // If the arg is required, add all it's requirements to master required list
248 if let Some(ref areqs) = a.b.requires {
249 for name in areqs
250 .iter()
251 .filter(|&&(val, _)| val.is_none())
252 .map(|&(_, name)| name) {
253 self.required.push(name);
254 }
255 }
256 self.required.push(a.b.name);
257 }
258 }
259
260 #[inline]
261 fn implied_settings(&mut self, a: &Arg<'a, 'b>) {
262 if a.is_set(ArgSettings::Last) {
263 // if an arg has `Last` set, we need to imply DontCollapseArgsInUsage so that args
264 // in the usage string don't get confused or left out.
265 self.set(AS::DontCollapseArgsInUsage);
266 self.set(AS::ContainsLast);
267 }
268 if let Some(l) = a.s.long {
269 if l == "version" {
270 self.unset(AS::NeedsLongVersion);
271 } else if l == "help" {
272 self.unset(AS::NeedsLongHelp);
273 }
cc61c64b 274 }
041b39d2
XL
275 }
276
277 // actually adds the arguments
278 pub fn add_arg(&mut self, a: Arg<'a, 'b>) {
279 // if it's global we have to clone anyways
280 if a.is_set(ArgSettings::Global) {
281 return self.add_arg_ref(&a);
282 }
283 debug_assert!(self.debug_asserts(&a));
284 self.add_conditional_reqs(&a);
285 self.add_arg_groups(&a);
286 self.add_reqs(&a);
287 self.implied_settings(&a);
288 if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) {
cc61c64b
XL
289 let i = if a.index.is_none() {
290 (self.positionals.len() + 1)
291 } else {
292 a.index.unwrap() as usize
293 };
041b39d2
XL
294 self.positionals
295 .insert(i, PosBuilder::from_arg(a, i as u64));
296 } else if a.is_set(ArgSettings::TakesValue) {
297 let mut ob = OptBuilder::from(a);
298 ob.s.unified_ord = self.flags.len() + self.opts.len();
299 self.opts.push(ob);
300 } else {
301 let mut fb = FlagBuilder::from(a);
302 fb.s.unified_ord = self.flags.len() + self.opts.len();
303 self.flags.push(fb);
304 }
305 }
306 // actually adds the arguments but from a borrow (which means we have to do some clonine)
307 pub fn add_arg_ref(&mut self, a: &Arg<'a, 'b>) {
308 debug_assert!(self.debug_asserts(a));
309 self.add_conditional_reqs(a);
310 self.add_arg_groups(a);
311 self.add_reqs(a);
312 self.implied_settings(a);
313 if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) {
314 let i = if a.index.is_none() {
315 (self.positionals.len() + 1)
316 } else {
317 a.index.unwrap() as usize
318 };
319 let pb = PosBuilder::from_arg_ref(a, i as u64);
8bb4bdeb
XL
320 self.positionals.insert(i, pb);
321 } else if a.is_set(ArgSettings::TakesValue) {
041b39d2 322 let mut ob = OptBuilder::from(a);
8bb4bdeb 323 ob.s.unified_ord = self.flags.len() + self.opts.len();
041b39d2 324 self.opts.push(ob);
8bb4bdeb
XL
325 } else {
326 let mut fb = FlagBuilder::from(a);
8bb4bdeb 327 fb.s.unified_ord = self.flags.len() + self.opts.len();
041b39d2 328 self.flags.push(fb);
8bb4bdeb
XL
329 }
330 if a.is_set(ArgSettings::Global) {
8bb4bdeb
XL
331 self.global_args.push(a.into());
332 }
333 }
334
335 pub fn add_group(&mut self, group: ArgGroup<'a>) {
336 if group.required {
041b39d2 337 self.required.push(group.name);
8bb4bdeb
XL
338 if let Some(ref reqs) = group.requires {
339 self.required.extend_from_slice(reqs);
340 }
341 if let Some(ref bl) = group.conflicts {
342 self.blacklist.extend_from_slice(bl);
343 }
344 }
041b39d2
XL
345 if self.groups.iter().any(|g| g.name == group.name) {
346 let grp = self.groups
347 .iter_mut()
348 .find(|g| g.name == group.name)
349 .expect(INTERNAL_ERROR_MSG);
8bb4bdeb
XL
350 grp.args.extend_from_slice(&group.args);
351 grp.requires = group.requires.clone();
352 grp.conflicts = group.conflicts.clone();
353 grp.required = group.required;
041b39d2
XL
354 } else {
355 self.groups.push(group);
8bb4bdeb
XL
356 }
357 }
358
359 pub fn add_subcommand(&mut self, mut subcmd: App<'a, 'b>) {
041b39d2
XL
360 debugln!("Parser::add_subcommand: term_w={:?}, name={}",
361 self.meta.term_w,
362 subcmd.p.meta.name);
8bb4bdeb
XL
363 subcmd.p.meta.term_w = self.meta.term_w;
364 if subcmd.p.meta.name == "help" {
041b39d2 365 self.unset(AS::NeedsSubcommandHelp);
8bb4bdeb
XL
366 }
367
368 self.subcommands.push(subcmd);
369 }
370
371 pub fn propogate_settings(&mut self) {
041b39d2
XL
372 debugln!("Parser::propogate_settings: self={}, g_settings={:#?}",
373 self.meta.name,
374 self.g_settings);
8bb4bdeb 375 for sc in &mut self.subcommands {
041b39d2
XL
376 debugln!("Parser::propogate_settings: sc={}, settings={:#?}, g_settings={:#?}",
377 sc.p.meta.name,
378 sc.p.settings,
379 sc.p.g_settings);
8bb4bdeb
XL
380 // We have to create a new scope in order to tell rustc the borrow of `sc` is
381 // done and to recursively call this method
382 {
041b39d2
XL
383 let vsc = self.settings.is_set(AS::VersionlessSubcommands);
384 let gv = self.settings.is_set(AS::GlobalVersion);
8bb4bdeb
XL
385
386 if vsc {
041b39d2 387 sc.p.set(AS::DisableVersion);
8bb4bdeb 388 }
7cac9316 389 if gv && sc.p.meta.version.is_none() && self.meta.version.is_some() {
041b39d2 390 sc.p.set(AS::GlobalVersion);
8bb4bdeb
XL
391 sc.p.meta.version = Some(self.meta.version.unwrap());
392 }
041b39d2
XL
393 sc.p.settings = sc.p.settings | self.g_settings;
394 sc.p.g_settings = sc.p.g_settings | self.g_settings;
395 sc.p.meta.term_w = self.meta.term_w;
396 sc.p.meta.max_w = self.meta.max_w;
8bb4bdeb
XL
397 }
398 sc.p.propogate_settings();
399 }
400 }
401
402 #[cfg_attr(feature = "lints", allow(needless_borrow))]
403 pub fn derive_display_order(&mut self) {
041b39d2
XL
404 if self.is_set(AS::DeriveDisplayOrder) {
405 let unified = self.is_set(AS::UnifiedHelpMessage);
8bb4bdeb 406 for (i, o) in self.opts
041b39d2
XL
407 .iter_mut()
408 .enumerate()
409 .filter(|&(_, ref o)| o.s.disp_ord == 999) {
8bb4bdeb
XL
410 o.s.disp_ord = if unified { o.s.unified_ord } else { i };
411 }
412 for (i, f) in self.flags
041b39d2
XL
413 .iter_mut()
414 .enumerate()
415 .filter(|&(_, ref f)| f.s.disp_ord == 999) {
8bb4bdeb
XL
416 f.s.disp_ord = if unified { f.s.unified_ord } else { i };
417 }
418 for (i, sc) in &mut self.subcommands
041b39d2
XL
419 .iter_mut()
420 .enumerate()
421 .filter(|&(_, ref sc)| sc.p.meta.disp_ord == 999) {
8bb4bdeb
XL
422 sc.p.meta.disp_ord = i;
423 }
424 }
425 for sc in &mut self.subcommands {
426 sc.p.derive_display_order();
427 }
428 }
429
430 pub fn required(&self) -> Iter<&str> { self.required.iter() }
431
041b39d2
XL
432 #[cfg_attr(feature = "lints", allow(needless_borrow))]
433 #[inline]
434 pub fn has_args(&self) -> bool {
435 !(self.flags.is_empty() && self.opts.is_empty() && self.positionals.is_empty())
8bb4bdeb
XL
436 }
437
438 #[inline]
439 pub fn has_opts(&self) -> bool { !self.opts.is_empty() }
440
441 #[inline]
442 pub fn has_flags(&self) -> bool { !self.flags.is_empty() }
443
444 #[inline]
445 pub fn has_positionals(&self) -> bool { !self.positionals.is_empty() }
446
447 #[inline]
448 pub fn has_subcommands(&self) -> bool { !self.subcommands.is_empty() }
449
450 #[inline]
041b39d2
XL
451 pub fn has_visible_opts(&self) -> bool {
452 if self.opts.is_empty() {
453 return false;
454 }
455 self.opts.iter().any(|o| !o.is_set(ArgSettings::Hidden))
456 }
457
458 #[inline]
459 pub fn has_visible_flags(&self) -> bool {
460 if self.flags.is_empty() {
461 return false;
462 }
463 self.flags.iter().any(|f| !f.is_set(ArgSettings::Hidden))
464 }
465
466 #[inline]
467 pub fn has_visible_positionals(&self) -> bool {
468 if self.positionals.is_empty() {
469 return false;
470 }
471 self.positionals
472 .values()
473 .any(|p| !p.is_set(ArgSettings::Hidden))
474 }
475
476 #[inline]
477 pub fn has_visible_subcommands(&self) -> bool {
ea8adc8c 478 self.has_subcommands() && self.subcommands.iter().filter(|sc| sc.p.meta.name != "help").any(|sc| !sc.p.is_set(AS::Hidden))
041b39d2
XL
479 }
480
481 #[inline]
482 pub fn is_set(&self, s: AS) -> bool { self.settings.is_set(s) }
cc61c64b
XL
483
484 #[inline]
041b39d2 485 pub fn set(&mut self, s: AS) { self.settings.set(s) }
cc61c64b
XL
486
487 #[inline]
041b39d2 488 pub fn unset(&mut self, s: AS) { self.settings.unset(s) }
8bb4bdeb
XL
489
490 #[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))]
041b39d2 491 pub fn verify_positionals(&mut self) -> bool {
8bb4bdeb
XL
492 // Because you must wait until all arguments have been supplied, this is the first chance
493 // to make assertions on positional argument indexes
494 //
495 // Firt we verify that the index highest supplied index, is equal to the number of
496 // positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
497 // but no 2)
7cac9316 498 if let Some((idx, p)) = self.positionals.iter().rev().next() {
041b39d2
XL
499 assert!(!(idx != self.positionals.len()),
500 "Found positional argument \"{}\" whose index is {} but there \
501 are only {} positional arguments defined",
502 p.b.name,
503 idx,
504 self.positionals.len());
8bb4bdeb
XL
505 }
506
507 // Next we verify that only the highest index has a .multiple(true) (if any)
7cac9316 508 if self.positionals
041b39d2
XL
509 .values()
510 .any(|a| {
511 a.b.is_set(ArgSettings::Multiple) &&
512 (a.index as usize != self.positionals.len())
513 }) {
514 let mut it = self.positionals.values().rev();
515 let last = it.next().unwrap();
516 let second_to_last = it.next().unwrap();
517 // Either the final positional is required
518 // Or the second to last has a terminator or .last(true) set
519 let ok = last.is_set(ArgSettings::Required) ||
520 (second_to_last.v.terminator.is_some() ||
521 second_to_last.b.is_set(ArgSettings::Last)) ||
522 last.is_set(ArgSettings::Last);
523 assert!(ok,
524 "When using a positional argument with .multiple(true) that is *not the \
525 last* positional argument, the last positional argument (i.e the one \
526 with the highest index) *must* have .required(true) or .last(true) set.");
527 let ok = second_to_last.is_set(ArgSettings::Multiple) || last.is_set(ArgSettings::Last);
528 assert!(ok,
529 "Only the last positional argument, or second to last positional \
530 argument may be set to .multiple(true)");
531
532 let count = self.positionals
533 .values()
534 .filter(|p| p.b.settings.is_set(ArgSettings::Multiple) && p.v.num_vals.is_none())
535 .count();
536 let ok = count <= 1 ||
537 (last.is_set(ArgSettings::Last) && last.is_set(ArgSettings::Multiple) &&
538 second_to_last.is_set(ArgSettings::Multiple) &&
539 count == 2);
540 assert!(ok,
541 "Only one positional argument with .multiple(true) set is allowed per \
542 command, unless the second one also has .last(true) set");
543 }
544
545
546 if self.is_set(AS::AllowMissingPositional) {
547 // Check that if a required positional argument is found, all positions with a lower
548 // index are also required.
549 let mut found = false;
550 let mut foundx2 = false;
551 for p in self.positionals.values().rev() {
552 if foundx2 && !p.b.settings.is_set(ArgSettings::Required) {
553 assert!(p.b.is_set(ArgSettings::Required),
554 "Found positional argument which is not required with a lower \
555 index than a required positional argument by two or more: {:?} \
556 index {}",
557 p.b.name,
558 p.index);
559 } else if p.b.is_set(ArgSettings::Required) && !p.b.is_set(ArgSettings::Last) {
560 // Args that .last(true) don't count since they can be required and have
561 // positionals with a lower index that aren't required
562 // Imagine: prog <req1> [opt1] -- <req2>
563 // Both of these are valid invocations:
564 // $ prog r1 -- r2
565 // $ prog r1 o1 -- r2
566 if found {
567 foundx2 = true;
568 continue;
569 }
570 found = true;
571 continue;
572 } else {
573 found = false;
574 }
575 }
576 } else {
577 // Check that if a required positional argument is found, all positions with a lower
578 // index are also required
579 let mut found = false;
580 for p in self.positionals.values().rev() {
581 if found {
582 assert!(p.b.is_set(ArgSettings::Required),
583 "Found positional argument which is not required with a lower \
584 index than a required positional argument: {:?} index {}",
585 p.b.name,
586 p.index);
587 } else if p.b.is_set(ArgSettings::Required) && !p.b.is_set(ArgSettings::Last) {
588 // Args that .last(true) don't count since they can be required and have
589 // positionals with a lower index that aren't required
590 // Imagine: prog <req1> [opt1] -- <req2>
591 // Both of these are valid invocations:
592 // $ prog r1 -- r2
593 // $ prog r1 o1 -- r2
594 found = true;
595 continue;
596 }
8bb4bdeb
XL
597 }
598 }
041b39d2
XL
599 if self.positionals
600 .values()
601 .any(|p| {
602 p.b.is_set(ArgSettings::Last) && p.b.is_set(ArgSettings::Required)
603 }) && self.has_subcommands() &&
604 !self.is_set(AS::SubcommandsNegateReqs) {
605 panic!("Having a required positional argument with .last(true) set *and* child \
606 subcommands without setting SubcommandsNegateReqs isn't compatible.");
607 }
608
609 true
8bb4bdeb
XL
610 }
611
612 pub fn propogate_globals(&mut self) {
613 for sc in &mut self.subcommands {
614 // We have to create a new scope in order to tell rustc the borrow of `sc` is
615 // done and to recursively call this method
616 {
617 for a in &self.global_args {
041b39d2 618 sc.p.add_arg_ref(a);
8bb4bdeb
XL
619 }
620 }
621 sc.p.propogate_globals();
622 }
623 }
624
625 // Checks if the arg matches a subcommand name, or any of it's aliases (if defined)
041b39d2
XL
626 fn possible_subcommand(&self, arg_os: &OsStr) -> (bool, Option<&str>) {
627 debugln!("Parser::possible_subcommand: arg={:?}", arg_os);
628 fn starts(h: &str, n: &OsStr) -> bool {
629 #[cfg(not(target_os = "windows"))]
630 use std::os::unix::ffi::OsStrExt;
631 #[cfg(target_os = "windows")]
632 use osstringext::OsStrExt3;
633
634 let n_bytes = n.as_bytes();
635 let h_bytes = OsStr::new(h).as_bytes();
636
637 h_bytes.starts_with(n_bytes)
638 }
639
640 if self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound) {
641 return (false, None);
642 }
643 if !self.is_set(AS::InferSubcommands) {
644 if let Some(sc) = find_subcmd!(self, arg_os) {
645 return (true, Some(&sc.p.meta.name));
646 }
647 } else {
648 let v = self.subcommands
649 .iter()
650 .filter(|s| {
651 starts(&s.p.meta.name[..], &*arg_os) ||
652 (s.p.meta.aliases.is_some() &&
653 s.p
654 .meta
655 .aliases
656 .as_ref()
657 .unwrap()
658 .iter()
659 .filter(|&&(a, _)| starts(a, &*arg_os))
660 .count() == 1)
661 })
662 .map(|sc| &sc.p.meta.name)
663 .collect::<Vec<_>>();
664
665 if v.len() == 1 {
666 return (true, Some(v[0]));
667 }
668 }
669 (false, None)
8bb4bdeb
XL
670 }
671
041b39d2 672 fn parse_help_subcommand<I, T>(&self, it: &mut I) -> ClapResult<ParseResult<'a>>
8bb4bdeb
XL
673 where I: Iterator<Item = T>,
674 T: Into<OsString>
675 {
041b39d2 676 debugln!("Parser::parse_help_subcommand;");
8bb4bdeb
XL
677 let cmds: Vec<OsString> = it.map(|c| c.into()).collect();
678 let mut help_help = false;
679 let mut bin_name = self.meta
680 .bin_name
681 .as_ref()
682 .unwrap_or(&self.meta.name)
683 .clone();
684 let mut sc = {
685 let mut sc: &Parser = self;
686 for (i, cmd) in cmds.iter().enumerate() {
687 if &*cmd.to_string_lossy() == "help" {
688 // cmd help help
689 help_help = true;
690 }
691 if let Some(c) = sc.subcommands
041b39d2
XL
692 .iter()
693 .find(|s| &*s.p.meta.name == cmd)
694 .map(|sc| &sc.p) {
8bb4bdeb
XL
695 sc = c;
696 if i == cmds.len() - 1 {
697 break;
698 }
699 } else if let Some(c) = sc.subcommands
041b39d2
XL
700 .iter()
701 .find(|s| if let Some(ref als) = s.p.meta.aliases {
702 als.iter().any(|&(a, _)| a == &*cmd.to_string_lossy())
703 } else {
704 false
705 })
706 .map(|sc| &sc.p) {
8bb4bdeb
XL
707 sc = c;
708 if i == cmds.len() - 1 {
709 break;
710 }
711 } else {
712 return Err(Error::unrecognized_subcommand(cmd.to_string_lossy().into_owned(),
713 self.meta
714 .bin_name
715 .as_ref()
716 .unwrap_or(&self.meta.name),
717 self.color()));
718 }
041b39d2 719 bin_name = format!("{} {}", bin_name, &*sc.meta.name);
8bb4bdeb
XL
720 }
721 sc.clone()
722 };
723 if help_help {
724 let mut pb = PosBuilder::new("subcommand", 1);
725 pb.b.help = Some("The subcommand whose help message to display");
726 pb.set(ArgSettings::Multiple);
727 sc.positionals.insert(1, pb);
041b39d2 728 sc.settings = sc.settings | self.g_settings;
8bb4bdeb
XL
729 } else {
730 sc.create_help_and_version();
731 }
732 if sc.meta.bin_name != self.meta.bin_name {
733 sc.meta.bin_name = Some(format!("{} {}", bin_name, sc.meta.name));
734 }
041b39d2 735 Err(sc._help(false))
8bb4bdeb
XL
736 }
737
041b39d2
XL
738 // allow wrong self convention due to self.valid_neg_num = true and it's a private method
739 #[cfg_attr(feature = "lints", allow(wrong_self_convention))]
740 fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult<'a>) -> bool {
741 debugln!("Parser::is_new_arg: arg={:?}, Needs Val of={:?}",
742 arg_os,
743 needs_val_of);
744 let app_wide_settings = if self.is_set(AS::AllowLeadingHyphen) {
8bb4bdeb 745 true
041b39d2 746 } else if self.is_set(AS::AllowNegativeNumbers) {
8bb4bdeb
XL
747 let a = arg_os.to_string_lossy();
748 if a.parse::<i64>().is_ok() || a.parse::<f64>().is_ok() {
041b39d2 749 self.set(AS::ValidNegNumFound);
8bb4bdeb
XL
750 true
751 } else {
752 false
753 }
754 } else {
755 false
756 };
041b39d2
XL
757 let arg_allows_tac = match needs_val_of {
758 ParseResult::Opt(name) => {
759 let o = self.opts
760 .iter()
761 .find(|o| o.b.name == name)
762 .expect(INTERNAL_ERROR_MSG);
763 (o.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings)
8bb4bdeb 764 }
041b39d2
XL
765 ParseResult::Pos(name) => {
766 let p = self.positionals
767 .values()
768 .find(|p| p.b.name == name)
769 .expect(INTERNAL_ERROR_MSG);
770 (p.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings)
771 }
772 _ => false,
8bb4bdeb 773 };
041b39d2
XL
774 debugln!("Parser::is_new_arg: Arg::allow_leading_hyphen({:?})",
775 arg_allows_tac);
8bb4bdeb
XL
776
777 // Is this a new argument, or values from a previous option?
8bb4bdeb 778 let mut ret = if arg_os.starts_with(b"--") {
041b39d2
XL
779 debugln!("Parser::is_new_arg: -- found");
780 if arg_os.len_() == 2 && !arg_allows_tac {
8bb4bdeb 781 return true; // We have to return true so override everything else
041b39d2
XL
782 } else if arg_allows_tac {
783 return false;
8bb4bdeb
XL
784 }
785 true
786 } else if arg_os.starts_with(b"-") {
041b39d2 787 debugln!("Parser::is_new_arg: - found");
8bb4bdeb
XL
788 // a singe '-' by itself is a value and typically means "stdin" on unix systems
789 !(arg_os.len_() == 1)
790 } else {
041b39d2 791 debugln!("Parser::is_new_arg: probably value");
8bb4bdeb
XL
792 false
793 };
794
041b39d2 795 ret = ret && !arg_allows_tac;
8bb4bdeb 796
041b39d2 797 debugln!("Parser::is_new_arg: starts_new_arg={:?}", ret);
8bb4bdeb
XL
798 ret
799 }
800
801 // The actual parsing function
041b39d2 802 #[cfg_attr(feature = "lints", allow(while_let_on_iterator, collapsible_if))]
8bb4bdeb
XL
803 pub fn get_matches_with<I, T>(&mut self,
804 matcher: &mut ArgMatcher<'a>,
805 it: &mut Peekable<I>)
806 -> ClapResult<()>
807 where I: Iterator<Item = T>,
808 T: Into<OsString> + Clone
809 {
041b39d2 810 debugln!("Parser::get_matches_with;");
8bb4bdeb 811 // Verify all positional assertions pass
041b39d2
XL
812 debug_assert!(self.app_debug_asserts());
813 if self.positionals
814 .values()
815 .any(|a| {
816 a.b.is_set(ArgSettings::Multiple) &&
817 (a.index as usize != self.positionals.len())
818 }) &&
819 self.positionals
820 .values()
821 .last()
822 .map_or(false, |p| !p.is_set(ArgSettings::Last)) {
823 self.settings.set(AS::LowIndexMultiplePositional);
824 }
825 let has_args = self.has_args();
8bb4bdeb
XL
826
827 // Next we create the `--help` and `--version` arguments and add them if
828 // necessary
829 self.create_help_and_version();
830
831 let mut subcmd_name: Option<String> = None;
041b39d2 832 let mut needs_val_of: ParseResult<'a> = ParseResult::NotFound;
8bb4bdeb
XL
833 let mut pos_counter = 1;
834 while let Some(arg) = it.next() {
835 let arg_os = arg.into();
041b39d2
XL
836 debugln!("Parser::get_matches_with: Begin parsing '{:?}' ({:?})",
837 arg_os,
838 &*arg_os.as_bytes());
8bb4bdeb 839
041b39d2 840 self.unset(AS::ValidNegNumFound);
8bb4bdeb 841 // Is this a new argument, or values from a previous option?
041b39d2
XL
842 let starts_new_arg = self.is_new_arg(&arg_os, needs_val_of);
843 if arg_os.starts_with(b"--") && arg_os.len_() == 2 && starts_new_arg {
844 debugln!("Parser::get_matches_with: setting TrailingVals=true");
845 self.set(AS::TrailingValues);
846 continue;
847 }
8bb4bdeb
XL
848
849 // Has the user already passed '--'? Meaning only positional args follow
041b39d2 850 if !self.is_set(AS::TrailingValues) {
8bb4bdeb 851 // Does the arg match a subcommand name, or any of it's aliases (if defined)
041b39d2
XL
852 {
853 let (is_match, sc_name) = self.possible_subcommand(&arg_os);
854 debugln!("Parser::get_matches_with: possible_sc={:?}, sc={:?}",
855 is_match,
856 sc_name);
857 if is_match {
858 let sc_name = sc_name.expect(INTERNAL_ERROR_MSG);
859 if sc_name == "help" && self.is_set(AS::NeedsSubcommandHelp) {
3b2f2976 860 self.parse_help_subcommand(it)?;
8bb4bdeb 861 }
041b39d2
XL
862 subcmd_name = Some(sc_name.to_owned());
863 break;
8bb4bdeb 864 }
7cac9316 865 }
7cac9316 866
041b39d2
XL
867 if !starts_new_arg {
868 if let ParseResult::Opt(name) = needs_val_of {
869 // Check to see if parsing a value from a previous arg
870 let arg = self.opts
871 .iter()
872 .find(|o| o.b.name == name)
873 .expect(INTERNAL_ERROR_MSG);
874 // get the OptBuilder so we can check the settings
3b2f2976 875 needs_val_of = self.add_val_to_arg(arg, &arg_os, matcher)?;
041b39d2
XL
876 // get the next value from the iterator
877 continue;
878 }
879 } else if arg_os.starts_with(b"--") {
3b2f2976 880 needs_val_of = self.parse_long_arg(matcher, &arg_os)?;
041b39d2
XL
881 debugln!("Parser:get_matches_with: After parse_long_arg {:?}",
882 needs_val_of);
883 match needs_val_of {
884 ParseResult::Flag |
885 ParseResult::Opt(..) |
886 ParseResult::ValuesDone => continue,
887 _ => (),
7cac9316
XL
888 }
889 } else if arg_os.starts_with(b"-") && arg_os.len_() != 1 {
890 // Try to parse short args like normal, if AllowLeadingHyphen or
891 // AllowNegativeNumbers is set, parse_short_arg will *not* throw
892 // an error, and instead return Ok(None)
3b2f2976 893 needs_val_of = self.parse_short_arg(matcher, &arg_os)?;
7cac9316 894 // If it's None, we then check if one of those two AppSettings was set
041b39d2
XL
895 debugln!("Parser:get_matches_with: After parse_short_arg {:?}",
896 needs_val_of);
897 match needs_val_of {
898 ParseResult::MaybeNegNum => {
7cac9316
XL
899 if !(arg_os.to_string_lossy().parse::<i64>().is_ok() ||
900 arg_os.to_string_lossy().parse::<f64>().is_ok()) {
901 return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
041b39d2
XL
902 "",
903 &*usage::create_error_usage(self, matcher, None),
904 self.color()));
8bb4bdeb 905 }
8bb4bdeb 906 }
041b39d2
XL
907 ParseResult::Opt(..) |
908 ParseResult::Flag |
909 ParseResult::ValuesDone => continue,
910 _ => (),
8bb4bdeb
XL
911 }
912 }
913
041b39d2
XL
914 if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound)) &&
915 !self.is_set(AS::InferSubcommands) {
916 if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(),
917 sc_names!(self)) {
918 return Err(Error::invalid_subcommand(arg_os
919 .to_string_lossy()
920 .into_owned(),
921 cdate,
922 self.meta
923 .bin_name
924 .as_ref()
925 .unwrap_or(&self.meta.name),
926 &*usage::create_error_usage(self,
927 matcher,
928 None),
929 self.color()));
8bb4bdeb
XL
930 }
931 }
932 }
933
041b39d2
XL
934 let low_index_mults = self.is_set(AS::LowIndexMultiplePositional) &&
935 pos_counter == (self.positionals.len() - 1);
936 let missing_pos = self.is_set(AS::AllowMissingPositional) &&
937 pos_counter == (self.positionals.len() - 1);
938 debugln!("Parser::get_matches_with: Positional counter...{}",
939 pos_counter);
940 debugln!("Parser::get_matches_with: Low index multiples...{:?}",
941 low_index_mults);
942 if low_index_mults || missing_pos {
8bb4bdeb
XL
943 if let Some(na) = it.peek() {
944 let n = (*na).clone().into();
041b39d2
XL
945 needs_val_of = if needs_val_of != ParseResult::ValuesDone {
946 if let Some(p) = self.positionals.get(pos_counter) {
947 ParseResult::Pos(p.b.name)
948 } else {
949 ParseResult::ValuesDone
950 }
951 } else {
952 ParseResult::ValuesDone
953 };
954 let sc_match = {
955 self.possible_subcommand(&n).0
956 };
957 if self.is_new_arg(&n, needs_val_of) || sc_match ||
958 suggestions::did_you_mean(&n.to_string_lossy(), sc_names!(self)).is_some() {
959 debugln!("Parser::get_matches_with: Bumping the positional counter...");
8bb4bdeb
XL
960 pos_counter += 1;
961 }
962 } else {
041b39d2 963 debugln!("Parser::get_matches_with: Bumping the positional counter...");
8bb4bdeb
XL
964 pos_counter += 1;
965 }
041b39d2
XL
966 } else if self.is_set(AS::ContainsLast) && self.is_set(AS::TrailingValues) {
967 // Came to -- and one postional has .last(true) set, so we go immediately
968 // to the last (highest index) positional
969 debugln!("Parser::get_matches_with: .last(true) and --, setting last pos");
970 pos_counter = self.positionals.len();
8bb4bdeb
XL
971 }
972 if let Some(p) = self.positionals.get(pos_counter) {
041b39d2
XL
973 if p.is_set(ArgSettings::Last) && !self.is_set(AS::TrailingValues) {
974 return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
975 "",
976 &*usage::create_error_usage(self,
977 matcher,
978 None),
979 self.color()));
980 }
8bb4bdeb 981 parse_positional!(self, p, arg_os, pos_counter, matcher);
041b39d2
XL
982 self.settings.set(AS::ValidArgFound);
983 } else if self.is_set(AS::AllowExternalSubcommands) {
8bb4bdeb
XL
984 // Get external subcommand name
985 let sc_name = match arg_os.to_str() {
986 Some(s) => s.to_string(),
987 None => {
041b39d2
XL
988 if !self.is_set(AS::StrictUtf8) {
989 return Err(Error::invalid_utf8(&*usage::create_error_usage(self,
990 matcher,
991 None),
8bb4bdeb
XL
992 self.color()));
993 }
994 arg_os.to_string_lossy().into_owned()
995 }
996 };
997
998 // Collect the external subcommand args
999 let mut sc_m = ArgMatcher::new();
1000 while let Some(v) = it.next() {
1001 let a = v.into();
041b39d2
XL
1002 if a.to_str().is_none() && !self.is_set(AS::StrictUtf8) {
1003 return Err(Error::invalid_utf8(&*usage::create_error_usage(self,
1004 matcher,
1005 None),
8bb4bdeb
XL
1006 self.color()));
1007 }
1008 sc_m.add_val_to("", &a);
1009 }
1010
1011 matcher.subcommand(SubCommand {
041b39d2
XL
1012 name: sc_name,
1013 matches: sc_m.into(),
1014 });
1015 } else if !(self.is_set(AS::AllowLeadingHyphen) ||
1016 self.is_set(AS::AllowNegativeNumbers)) &&
1017 !self.is_set(AS::InferSubcommands) {
8bb4bdeb
XL
1018 return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
1019 "",
041b39d2
XL
1020 &*usage::create_error_usage(self,
1021 matcher,
1022 None),
8bb4bdeb 1023 self.color()));
041b39d2
XL
1024 } else if !has_args || self.is_set(AS::InferSubcommands) && self.has_subcommands() {
1025 if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(),
1026 sc_names!(self)) {
1027 return Err(Error::invalid_subcommand(arg_os.to_string_lossy().into_owned(),
1028 cdate,
1029 self.meta
1030 .bin_name
1031 .as_ref()
1032 .unwrap_or(&self.meta.name),
1033 &*usage::create_error_usage(self,
1034 matcher,
1035 None),
1036 self.color()));
1037 } else {
1038 return Err(Error::unrecognized_subcommand(arg_os
1039 .to_string_lossy()
1040 .into_owned(),
1041 self.meta
1042 .bin_name
1043 .as_ref()
1044 .unwrap_or(&self.meta.name),
1045 self.color()));
1046 }
8bb4bdeb
XL
1047 }
1048 }
1049
1050 if let Some(ref pos_sc_name) = subcmd_name {
041b39d2
XL
1051 let sc_name = {
1052 find_subcmd!(self, pos_sc_name)
1053 .expect(INTERNAL_ERROR_MSG)
1054 .p
1055 .meta
1056 .name
1057 .clone()
cc61c64b 1058 };
3b2f2976 1059 self.parse_subcommand(&*sc_name, matcher, it)?;
041b39d2 1060 } else if self.is_set(AS::SubcommandRequired) {
7cac9316 1061 let bn = self.meta.bin_name.as_ref().unwrap_or(&self.meta.name);
8bb4bdeb 1062 return Err(Error::missing_subcommand(bn,
041b39d2 1063 &usage::create_error_usage(self, matcher, None),
8bb4bdeb 1064 self.color()));
041b39d2
XL
1065 } else if self.is_set(AS::SubcommandRequiredElseHelp) {
1066 debugln!("Parser::get_matches_with: SubcommandRequiredElseHelp=true");
8bb4bdeb 1067 let mut out = vec![];
3b2f2976 1068 self.write_help_err(&mut out)?;
8bb4bdeb 1069 return Err(Error {
041b39d2
XL
1070 message: String::from_utf8_lossy(&*out).into_owned(),
1071 kind: ErrorKind::MissingArgumentOrSubcommand,
1072 info: None,
1073 });
8bb4bdeb
XL
1074 }
1075
041b39d2 1076 Validator::new(self).validate(needs_val_of, subcmd_name, matcher)
8bb4bdeb
XL
1077 }
1078
8bb4bdeb
XL
1079
1080 fn propogate_help_version(&mut self) {
041b39d2 1081 debugln!("Parser::propogate_help_version;");
8bb4bdeb
XL
1082 self.create_help_and_version();
1083 for sc in &mut self.subcommands {
1084 sc.p.propogate_help_version();
1085 }
1086 }
1087
1088 fn build_bin_names(&mut self) {
041b39d2 1089 debugln!("Parser::build_bin_names;");
8bb4bdeb 1090 for sc in &mut self.subcommands {
041b39d2 1091 debug!("Parser::build_bin_names:iter: bin_name set...");
7cac9316 1092 if sc.p.meta.bin_name.is_none() {
8bb4bdeb
XL
1093 sdebugln!("No");
1094 let bin_name = format!("{}{}{}",
041b39d2
XL
1095 self.meta
1096 .bin_name
1097 .as_ref()
1098 .unwrap_or(&self.meta.name.clone()),
1099 if self.meta.bin_name.is_some() {
1100 " "
1101 } else {
1102 ""
1103 },
1104 &*sc.p.meta.name);
1105 debugln!("Parser::build_bin_names:iter: Setting bin_name of {} to {}",
1106 self.meta.name,
1107 bin_name);
8bb4bdeb
XL
1108 sc.p.meta.bin_name = Some(bin_name);
1109 } else {
1110 sdebugln!("yes ({:?})", sc.p.meta.bin_name);
1111 }
041b39d2
XL
1112 debugln!("Parser::build_bin_names:iter: Calling build_bin_names from...{}",
1113 sc.p.meta.name);
8bb4bdeb
XL
1114 sc.p.build_bin_names();
1115 }
1116 }
1117
1118 fn parse_subcommand<I, T>(&mut self,
1119 sc_name: &str,
1120 matcher: &mut ArgMatcher<'a>,
1121 it: &mut Peekable<I>)
1122 -> ClapResult<()>
1123 where I: Iterator<Item = T>,
1124 T: Into<OsString> + Clone
1125 {
1126 use std::fmt::Write;
041b39d2 1127 debugln!("Parser::parse_subcommand;");
8bb4bdeb 1128 let mut mid_string = String::new();
041b39d2 1129 if !self.is_set(AS::SubcommandsNegateReqs) {
7cac9316 1130 let mut hs: Vec<&str> = self.required.iter().map(|n| &**n).collect();
8bb4bdeb
XL
1131 for k in matcher.arg_names() {
1132 hs.push(k);
1133 }
041b39d2 1134 let reqs = usage::get_required_usage_from(self, &hs, Some(matcher), None, false);
8bb4bdeb
XL
1135
1136 for s in &reqs {
1137 write!(&mut mid_string, " {}", s).expect(INTERNAL_ERROR_MSG);
1138 }
1139 }
1140 mid_string.push_str(" ");
7cac9316 1141 if let Some(ref mut sc) = self.subcommands
041b39d2
XL
1142 .iter_mut()
1143 .find(|s| s.p.meta.name == sc_name) {
8bb4bdeb
XL
1144 let mut sc_matcher = ArgMatcher::new();
1145 // bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
1146 // a space
1147 sc.p.meta.usage = Some(format!("{}{}{}",
7cac9316 1148 self.meta.bin_name.as_ref().unwrap_or(&String::new()),
8bb4bdeb
XL
1149 if self.meta.bin_name.is_some() {
1150 &*mid_string
1151 } else {
1152 ""
1153 },
1154 &*sc.p.meta.name));
041b39d2
XL
1155 sc.p.meta.bin_name =
1156 Some(format!("{}{}{}",
1157 self.meta.bin_name.as_ref().unwrap_or(&String::new()),
1158 if self.meta.bin_name.is_some() {
1159 " "
1160 } else {
1161 ""
1162 },
1163 &*sc.p.meta.name));
1164 debugln!("Parser::parse_subcommand: About to parse sc={}",
1165 sc.p.meta.name);
1166 debugln!("Parser::parse_subcommand: sc settings={:#?}", sc.p.settings);
3b2f2976 1167 sc.p.get_matches_with(&mut sc_matcher, it)?;
8bb4bdeb 1168 matcher.subcommand(SubCommand {
041b39d2
XL
1169 name: sc.p.meta.name.clone(),
1170 matches: sc_matcher.into(),
1171 });
8bb4bdeb
XL
1172 }
1173 Ok(())
1174 }
1175
041b39d2
XL
1176 pub fn groups_for_arg(&self, name: &str) -> Option<Vec<&'a str>> {
1177 debugln!("Parser::groups_for_arg: name={}", name);
8bb4bdeb
XL
1178
1179 if self.groups.is_empty() {
041b39d2 1180 debugln!("Parser::groups_for_arg: No groups defined");
8bb4bdeb
XL
1181 return None;
1182 }
1183 let mut res = vec![];
041b39d2
XL
1184 debugln!("Parser::groups_for_arg: Searching through groups...");
1185 for grp in &self.groups {
8bb4bdeb
XL
1186 for a in &grp.args {
1187 if a == &name {
041b39d2
XL
1188 sdebugln!("\tFound '{}'", grp.name);
1189 res.push(&*grp.name);
8bb4bdeb
XL
1190 }
1191 }
1192 }
1193 if res.is_empty() {
1194 return None;
1195 }
1196
1197 Some(res)
1198 }
1199
041b39d2 1200 pub fn args_in_group(&self, group: &str) -> Vec<String> {
8bb4bdeb
XL
1201 let mut g_vec = vec![];
1202 let mut args = vec![];
1203
041b39d2
XL
1204 for n in &self.groups
1205 .iter()
1206 .find(|g| g.name == group)
1207 .expect(INTERNAL_ERROR_MSG)
1208 .args {
8bb4bdeb
XL
1209 if let Some(f) = self.flags.iter().find(|f| &f.b.name == n) {
1210 args.push(f.to_string());
1211 } else if let Some(f) = self.opts.iter().find(|o| &o.b.name == n) {
1212 args.push(f.to_string());
041b39d2 1213 } else if let Some(p) = self.positionals.values().find(|p| &p.b.name == n) {
7cac9316 1214 args.push(p.b.name.to_owned());
041b39d2
XL
1215 } else {
1216 g_vec.push(*n);
8bb4bdeb
XL
1217 }
1218 }
1219
1220 for av in g_vec.iter().map(|g| self.args_in_group(g)) {
1221 args.extend(av);
1222 }
1223 args.dedup();
1224 args.iter().map(ToOwned::to_owned).collect()
1225 }
1226
041b39d2 1227 pub fn arg_names_in_group(&self, group: &str) -> Vec<&'a str> {
8bb4bdeb
XL
1228 let mut g_vec = vec![];
1229 let mut args = vec![];
1230
041b39d2
XL
1231 for n in &self.groups
1232 .iter()
1233 .find(|g| g.name == group)
1234 .expect(INTERNAL_ERROR_MSG)
1235 .args {
1236 if self.groups.iter().any(|g| g.name == *n) {
1237 args.extend(self.arg_names_in_group(n));
8bb4bdeb 1238 g_vec.push(*n);
041b39d2 1239 } else if !args.contains(n) {
7cac9316 1240 args.push(*n);
8bb4bdeb
XL
1241 }
1242 }
1243
8bb4bdeb
XL
1244 args.iter().map(|s| *s).collect()
1245 }
1246
1247 pub fn create_help_and_version(&mut self) {
041b39d2 1248 debugln!("Parser::create_help_and_version;");
8bb4bdeb 1249 // name is "hclap_help" because flags are sorted by name
041b39d2
XL
1250 if !self.contains_long("help") {
1251 debugln!("Parser::create_help_and_version: Building --help");
1252 if self.help_short.is_none() && !self.contains_short('h') {
8bb4bdeb
XL
1253 self.help_short = Some('h');
1254 }
8bb4bdeb
XL
1255 let arg = FlagBuilder {
1256 b: Base {
1257 name: "hclap_help",
041b39d2 1258 help: self.help_message.or(Some("Prints help information")),
8bb4bdeb
XL
1259 ..Default::default()
1260 },
1261 s: Switched {
1262 short: self.help_short,
1263 long: Some("help"),
1264 ..Default::default()
1265 },
1266 };
041b39d2 1267 self.flags.push(arg);
8bb4bdeb 1268 }
041b39d2
XL
1269 if !self.is_set(AS::DisableVersion) && !self.contains_long("version") {
1270 debugln!("Parser::create_help_and_version: Building --version");
1271 if self.version_short.is_none() && !self.contains_short('V') {
8bb4bdeb
XL
1272 self.version_short = Some('V');
1273 }
8bb4bdeb
XL
1274 // name is "vclap_version" because flags are sorted by name
1275 let arg = FlagBuilder {
1276 b: Base {
1277 name: "vclap_version",
041b39d2 1278 help: self.version_message.or(Some("Prints version information")),
8bb4bdeb
XL
1279 ..Default::default()
1280 },
1281 s: Switched {
1282 short: self.version_short,
1283 long: Some("version"),
1284 ..Default::default()
1285 },
1286 };
041b39d2 1287 self.flags.push(arg);
8bb4bdeb 1288 }
041b39d2
XL
1289 if !self.subcommands.is_empty() && !self.is_set(AS::DisableHelpSubcommand) &&
1290 self.is_set(AS::NeedsSubcommandHelp) {
1291 debugln!("Parser::create_help_and_version: Building help");
8bb4bdeb
XL
1292 self.subcommands
1293 .push(App::new("help")
041b39d2 1294 .about("Prints this message or the help of the given subcommand(s)"));
8bb4bdeb
XL
1295 }
1296 }
1297
1298 // Retrieves the names of all args the user has supplied thus far, except required ones
1299 // because those will be listed in self.required
8bb4bdeb 1300 fn check_for_help_and_version_str(&self, arg: &OsStr) -> ClapResult<()> {
041b39d2
XL
1301 debugln!("Parser::check_for_help_and_version_str;");
1302 debug!("Parser::check_for_help_and_version_str: Checking if --{} is help or version...",
8bb4bdeb 1303 arg.to_str().unwrap());
041b39d2 1304 if arg == "help" && self.is_set(AS::NeedsLongHelp) {
8bb4bdeb 1305 sdebugln!("Help");
041b39d2 1306 return Err(self._help(true));
8bb4bdeb 1307 }
041b39d2 1308 if arg == "version" && self.is_set(AS::NeedsLongVersion) {
8bb4bdeb 1309 sdebugln!("Version");
041b39d2 1310 return Err(self._version(true));
8bb4bdeb
XL
1311 }
1312 sdebugln!("Neither");
1313
1314 Ok(())
1315 }
1316
1317 fn check_for_help_and_version_char(&self, arg: char) -> ClapResult<()> {
041b39d2
XL
1318 debugln!("Parser::check_for_help_and_version_char;");
1319 debug!("Parser::check_for_help_and_version_char: Checking if -{} is help or version...",
1320 arg);
8bb4bdeb 1321 if let Some(h) = self.help_short {
041b39d2 1322 if arg == h && self.is_set(AS::NeedsLongHelp) {
8bb4bdeb 1323 sdebugln!("Help");
041b39d2 1324 return Err(self._help(false));
8bb4bdeb
XL
1325 }
1326 }
1327 if let Some(v) = self.version_short {
041b39d2 1328 if arg == v && self.is_set(AS::NeedsLongVersion) {
8bb4bdeb 1329 sdebugln!("Version");
041b39d2 1330 return Err(self._version(false));
8bb4bdeb
XL
1331 }
1332 }
1333 sdebugln!("Neither");
1334 Ok(())
1335 }
1336
041b39d2
XL
1337 #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
1338 fn use_long_help(&self) -> bool {
ea8adc8c
XL
1339 let ul = self.meta.long_about.is_some() ||
1340 self.flags.iter().any(|f| f.b.long_help.is_some()) ||
041b39d2
XL
1341 self.opts.iter().any(|o| o.b.long_help.is_some()) ||
1342 self.positionals.values().any(|p| p.b.long_help.is_some()) ||
1343 self.subcommands
1344 .iter()
1345 .any(|s| s.p.meta.long_about.is_some());
1346 debugln!("Parser::use_long_help: ret={:?}", ul);
1347 ul
1348 }
1349
1350 fn _help(&self, mut use_long: bool) -> Error {
1351 debugln!("Parser::_help: use_long={:?}", use_long);
1352 use_long = use_long && self.use_long_help();
8bb4bdeb 1353 let mut buf = vec![];
041b39d2
XL
1354 match Help::write_parser_help(&mut buf, self, use_long) {
1355 Err(e) => e,
1356 _ => Error {
1357 message: unsafe { String::from_utf8_unchecked(buf) },
1358 kind: ErrorKind::HelpDisplayed,
1359 info: None,
1360 }
1361 }
8bb4bdeb
XL
1362 }
1363
041b39d2
XL
1364 fn _version(&self, use_long: bool) -> Error {
1365 debugln!("Parser::_version: ");
8bb4bdeb
XL
1366 let out = io::stdout();
1367 let mut buf_w = BufWriter::new(out.lock());
041b39d2
XL
1368 match self.print_version(&mut buf_w, use_long) {
1369 Err(e) => e,
1370 _ => Error {
1371 message: String::new(),
1372 kind: ErrorKind::VersionDisplayed,
1373 info: None,
1374 }
1375 }
8bb4bdeb
XL
1376 }
1377
1378 fn parse_long_arg(&mut self,
1379 matcher: &mut ArgMatcher<'a>,
1380 full_arg: &OsStr)
041b39d2 1381 -> ClapResult<ParseResult<'a>> {
8bb4bdeb 1382 // maybe here lifetime should be 'a
041b39d2 1383 debugln!("Parser::parse_long_arg;");
8bb4bdeb 1384 let mut val = None;
041b39d2 1385 debug!("Parser::parse_long_arg: Does it contain '='...");
8bb4bdeb
XL
1386 let arg = if full_arg.contains_byte(b'=') {
1387 let (p0, p1) = full_arg.trim_left_matches(b'-').split_at_byte(b'=');
1388 sdebugln!("Yes '{:?}'", p1);
1389 val = Some(p1);
1390 p0
1391 } else {
1392 sdebugln!("No");
1393 full_arg.trim_left_matches(b'-')
1394 };
1395
041b39d2
XL
1396 if let Some(opt) = find_opt_by_long!(@os self, arg) {
1397 debugln!("Parser::parse_long_arg: Found valid opt '{}'",
1398 opt.to_string());
1399 self.settings.set(AS::ValidArgFound);
3b2f2976 1400 let ret = self.parse_opt(val, opt, val.is_some(), matcher)?;
041b39d2
XL
1401 if self.cache.map_or(true, |name| name != opt.b.name) {
1402 arg_post_processing!(self, opt, matcher);
1403 self.cache = Some(opt.b.name);
1404 }
8bb4bdeb
XL
1405
1406 return Ok(ret);
041b39d2
XL
1407 } else if let Some(flag) = find_flag_by_long!(@os self, arg) {
1408 debugln!("Parser::parse_long_arg: Found valid flag '{}'",
1409 flag.to_string());
1410 self.settings.set(AS::ValidArgFound);
8bb4bdeb
XL
1411 // Only flags could be help or version, and we need to check the raw long
1412 // so this is the first point to check
3b2f2976 1413 self.check_for_help_and_version_str(arg)?;
8bb4bdeb 1414
3b2f2976 1415 self.parse_flag(flag, matcher)?;
8bb4bdeb
XL
1416
1417 // Handle conflicts, requirements, etc.
041b39d2 1418 // if self.cache.map_or(true, |name| name != flag.b.name) {
7cac9316 1419 arg_post_processing!(self, flag, matcher);
041b39d2
XL
1420 // self.cache = Some(flag.b.name);
1421 // }
8bb4bdeb 1422
041b39d2
XL
1423 return Ok(ParseResult::Flag);
1424 } else if self.is_set(AS::AllowLeadingHyphen) {
1425 return Ok(ParseResult::MaybeHyphenValue);
1426 } else if self.is_set(AS::ValidNegNumFound) {
1427 return Ok(ParseResult::MaybeNegNum);
8bb4bdeb
XL
1428 }
1429
041b39d2
XL
1430 debugln!("Parser::parse_long_arg: Didn't match anything");
1431 self.did_you_mean_error(arg.to_str().expect(INVALID_UTF8), matcher)
1432 .map(|_| ParseResult::NotFound)
8bb4bdeb
XL
1433 }
1434
041b39d2 1435 #[cfg_attr(feature = "lints", allow(len_zero))]
8bb4bdeb
XL
1436 fn parse_short_arg(&mut self,
1437 matcher: &mut ArgMatcher<'a>,
1438 full_arg: &OsStr)
041b39d2
XL
1439 -> ClapResult<ParseResult<'a>> {
1440 debugln!("Parser::parse_short_arg: full_arg={:?}", full_arg);
8bb4bdeb
XL
1441 let arg_os = full_arg.trim_left_matches(b'-');
1442 let arg = arg_os.to_string_lossy();
1443
041b39d2
XL
1444 // If AllowLeadingHyphen is set, we want to ensure `-val` gets parsed as `-val` and not
1445 // `-v` `-a` `-l` assuming `v` `a` and `l` are all, or mostly, valid shorts.
1446 if self.is_set(AS::AllowLeadingHyphen) {
1447 if arg.chars().any(|c| !self.contains_short(c)) {
1448 debugln!("Parser::parse_short_arg: LeadingHyphenAllowed yet -{} isn't valid",
1449 arg);
1450 return Ok(ParseResult::MaybeHyphenValue);
8bb4bdeb 1451 }
041b39d2 1452 } else if self.is_set(AS::ValidNegNumFound) {
8bb4bdeb
XL
1453 // TODO: Add docs about having AllowNegativeNumbers and `-2` as a valid short
1454 // May be better to move this to *after* not finding a valid flag/opt?
041b39d2
XL
1455 debugln!("Parser::parse_short_arg: Valid negative num...");
1456 return Ok(ParseResult::MaybeNegNum);
8bb4bdeb
XL
1457 }
1458
041b39d2 1459 let mut ret = ParseResult::NotFound;
8bb4bdeb 1460 for c in arg.chars() {
041b39d2 1461 debugln!("Parser::parse_short_arg:iter:{}", c);
8bb4bdeb
XL
1462 // Check for matching short options, and return the name if there is no trailing
1463 // concatenated value: -oval
1464 // Option: -o
1465 // Value: val
041b39d2
XL
1466 if let Some(opt) = find_opt_by_short!(self, c) {
1467 debugln!("Parser::parse_short_arg:iter:{}: Found valid opt", c);
1468 self.settings.set(AS::ValidArgFound);
8bb4bdeb
XL
1469 // Check for trailing concatenated value
1470 let p: Vec<_> = arg.splitn(2, c).collect();
041b39d2
XL
1471 debugln!("Parser::parse_short_arg:iter:{}: p[0]={:?}, p[1]={:?}",
1472 c,
1473 p[0].as_bytes(),
1474 p[1].as_bytes());
8bb4bdeb
XL
1475 let i = p[0].as_bytes().len() + 1;
1476 let val = if p[1].as_bytes().len() > 0 {
041b39d2
XL
1477 debugln!("Parser::parse_short_arg:iter:{}: val={:?} (bytes), val={:?} (ascii)",
1478 c,
8bb4bdeb
XL
1479 arg_os.split_at(i).1.as_bytes(),
1480 arg_os.split_at(i).1);
1481 Some(arg_os.split_at(i).1)
1482 } else {
1483 None
1484 };
1485
1486 // Default to "we're expecting a value later"
3b2f2976 1487 let ret = self.parse_opt(val, opt, false, matcher)?;
8bb4bdeb 1488
041b39d2
XL
1489 if self.cache.map_or(true, |name| name != opt.b.name) {
1490 arg_post_processing!(self, opt, matcher);
1491 self.cache = Some(opt.b.name);
1492 }
8bb4bdeb
XL
1493
1494 return Ok(ret);
041b39d2
XL
1495 } else if let Some(flag) = find_flag_by_short!(self, c) {
1496 debugln!("Parser::parse_short_arg:iter:{}: Found valid flag", c);
1497 self.settings.set(AS::ValidArgFound);
8bb4bdeb 1498 // Only flags can be help or version
3b2f2976
XL
1499 self.check_for_help_and_version_char(c)?;
1500 ret = self.parse_flag(flag, matcher)?;
041b39d2 1501
8bb4bdeb
XL
1502 // Handle conflicts, requirements, overrides, etc.
1503 // Must be called here due to mutablilty
041b39d2
XL
1504 if self.cache.map_or(true, |name| name != flag.b.name) {
1505 arg_post_processing!(self, flag, matcher);
1506 self.cache = Some(flag.b.name);
1507 }
8bb4bdeb 1508 } else {
041b39d2 1509 let arg = format!("-{}", c);
8bb4bdeb
XL
1510 return Err(Error::unknown_argument(&*arg,
1511 "",
041b39d2
XL
1512 &*usage::create_error_usage(self,
1513 matcher,
1514 None),
8bb4bdeb
XL
1515 self.color()));
1516 }
1517 }
041b39d2 1518 Ok(ret)
8bb4bdeb
XL
1519 }
1520
1521 fn parse_opt(&self,
1522 val: Option<&OsStr>,
1523 opt: &OptBuilder<'a, 'b>,
041b39d2 1524 had_eq: bool,
8bb4bdeb 1525 matcher: &mut ArgMatcher<'a>)
041b39d2
XL
1526 -> ClapResult<ParseResult<'a>> {
1527 debugln!("Parser::parse_opt; opt={}, val={:?}", opt.b.name, val);
1528 debugln!("Parser::parse_opt; opt.settings={:?}", opt.b.settings);
8bb4bdeb 1529 let mut has_eq = false;
ea8adc8c
XL
1530 let no_val = val.is_none();
1531 let empty_vals = opt.is_set(ArgSettings::EmptyValues);
1532 let min_vals_zero = opt.v.min_vals.unwrap_or(1) == 0;
1533 let needs_eq = opt.is_set(ArgSettings::RequireEquals);
8bb4bdeb 1534
041b39d2 1535 debug!("Parser::parse_opt; Checking for val...");
8bb4bdeb 1536 if let Some(fv) = val {
041b39d2 1537 has_eq = fv.starts_with(&[b'=']) || had_eq;
8bb4bdeb 1538 let v = fv.trim_left_matches(b'=');
ea8adc8c
XL
1539 if !empty_vals &&
1540 (v.len_() == 0 || (needs_eq && !has_eq)) {
8bb4bdeb
XL
1541 sdebugln!("Found Empty - Error");
1542 return Err(Error::empty_value(opt,
041b39d2 1543 &*usage::create_error_usage(self, matcher, None),
8bb4bdeb
XL
1544 self.color()));
1545 }
1546 sdebugln!("Found - {:?}, len: {}", v, v.len_());
041b39d2
XL
1547 debugln!("Parser::parse_opt: {:?} contains '='...{:?}",
1548 fv,
1549 fv.starts_with(&[b'=']));
3b2f2976 1550 self.add_val_to_arg(opt, v, matcher)?;
ea8adc8c 1551 } else if needs_eq && !(empty_vals || min_vals_zero) {
041b39d2
XL
1552 sdebugln!("None, but requires equals...Error");
1553 return Err(Error::empty_value(opt,
1554 &*usage::create_error_usage(self, matcher, None),
1555 self.color()));
1556
8bb4bdeb
XL
1557 } else {
1558 sdebugln!("None");
1559 }
1560
1561 matcher.inc_occurrence_of(opt.b.name);
1562 // Increment or create the group "args"
041b39d2
XL
1563 self.groups_for_arg(opt.b.name)
1564 .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
8bb4bdeb 1565
ea8adc8c
XL
1566 let needs_delim = opt.is_set(ArgSettings::RequireDelimiter);
1567 let mult = opt.is_set(ArgSettings::Multiple);
1568 if no_val && min_vals_zero && !has_eq && needs_eq {
1569 debugln!("Parser::parse_opt: More arg vals not required...");
1570 return Ok(ParseResult::ValuesDone);
1571 } else if no_val || (mult && !needs_delim) && !has_eq && matcher.needs_more_vals(opt) {
041b39d2
XL
1572 debugln!("Parser::parse_opt: More arg vals required...");
1573 return Ok(ParseResult::Opt(opt.b.name));
8bb4bdeb 1574 }
041b39d2
XL
1575 debugln!("Parser::parse_opt: More arg vals not required...");
1576 Ok(ParseResult::ValuesDone)
8bb4bdeb
XL
1577 }
1578
1579 fn add_val_to_arg<A>(&self,
1580 arg: &A,
1581 val: &OsStr,
1582 matcher: &mut ArgMatcher<'a>)
041b39d2 1583 -> ClapResult<ParseResult<'a>>
8bb4bdeb
XL
1584 where A: AnyArg<'a, 'b> + Display
1585 {
041b39d2
XL
1586 debugln!("Parser::add_val_to_arg; arg={}, val={:?}", arg.name(), val);
1587 debugln!("Parser::add_val_to_arg; trailing_vals={:?}, DontDelimTrailingVals={:?}",
1588 self.is_set(AS::TrailingValues),
1589 self.is_set(AS::DontDelimitTrailingValues));
1590 if !(self.is_set(AS::TrailingValues) && self.is_set(AS::DontDelimitTrailingValues)) {
8bb4bdeb
XL
1591 if let Some(delim) = arg.val_delim() {
1592 if val.is_empty_() {
3b2f2976 1593 Ok(self.add_single_val_to_arg(arg, val, matcher)?)
8bb4bdeb 1594 } else {
041b39d2 1595 let mut iret = ParseResult::ValuesDone;
8bb4bdeb 1596 for v in val.split(delim as u32 as u8) {
3b2f2976 1597 iret = self.add_single_val_to_arg(arg, v, matcher)?;
8bb4bdeb
XL
1598 }
1599 // If there was a delimiter used, we're not looking for more values
1600 if val.contains_byte(delim as u32 as u8) ||
041b39d2
XL
1601 arg.is_set(ArgSettings::RequireDelimiter) {
1602 iret = ParseResult::ValuesDone;
1603 }
1604 Ok(iret)
8bb4bdeb
XL
1605 }
1606 } else {
041b39d2 1607 self.add_single_val_to_arg(arg, val, matcher)
8bb4bdeb
XL
1608 }
1609 } else {
041b39d2 1610 self.add_single_val_to_arg(arg, val, matcher)
8bb4bdeb 1611 }
8bb4bdeb
XL
1612 }
1613
1614 fn add_single_val_to_arg<A>(&self,
1615 arg: &A,
1616 v: &OsStr,
1617 matcher: &mut ArgMatcher<'a>)
041b39d2 1618 -> ClapResult<ParseResult<'a>>
8bb4bdeb
XL
1619 where A: AnyArg<'a, 'b> + Display
1620 {
041b39d2
XL
1621 debugln!("Parser::add_single_val_to_arg;");
1622 debugln!("Parser::add_single_val_to_arg: adding val...{:?}", v);
1623 if let Some(t) = arg.val_terminator() {
1624 if t == v {
1625 return Ok(ParseResult::ValuesDone);
1626 }
1627 }
8bb4bdeb
XL
1628 matcher.add_val_to(arg.name(), v);
1629
1630 // Increment or create the group "args"
1631 if let Some(grps) = self.groups_for_arg(arg.name()) {
1632 for grp in grps {
1633 matcher.add_val_to(&*grp, v);
1634 }
1635 }
1636
8bb4bdeb 1637 if matcher.needs_more_vals(arg) {
041b39d2 1638 return Ok(ParseResult::Opt(arg.name()));
8bb4bdeb 1639 }
041b39d2 1640 Ok(ParseResult::ValuesDone)
8bb4bdeb
XL
1641 }
1642
041b39d2 1643
8bb4bdeb
XL
1644 fn parse_flag(&self,
1645 flag: &FlagBuilder<'a, 'b>,
1646 matcher: &mut ArgMatcher<'a>)
041b39d2
XL
1647 -> ClapResult<ParseResult<'a>> {
1648 debugln!("Parser::parse_flag;");
8bb4bdeb
XL
1649
1650 matcher.inc_occurrence_of(flag.b.name);
1651 // Increment or create the group "args"
041b39d2
XL
1652 self.groups_for_arg(flag.b.name)
1653 .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
7cac9316 1654
041b39d2 1655 Ok(ParseResult::Flag)
7cac9316
XL
1656 }
1657
8bb4bdeb 1658 fn did_you_mean_error(&self, arg: &str, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
041b39d2
XL
1659
1660 // Didn't match a flag or option
8bb4bdeb 1661 let suffix =
041b39d2 1662 suggestions::did_you_mean_flag_suffix(arg, longs!(self), &self.subcommands);
8bb4bdeb
XL
1663
1664 // Add the arg to the matches to build a proper usage string
1665 if let Some(name) = suffix.1 {
041b39d2 1666 if let Some(opt) = find_opt_by_long!(self, name) {
8bb4bdeb
XL
1667 self.groups_for_arg(&*opt.b.name)
1668 .and_then(|grps| Some(matcher.inc_occurrences_of(&*grps)));
1669 matcher.insert(&*opt.b.name);
041b39d2 1670 } else if let Some(flg) = find_flag_by_long!(self, name) {
8bb4bdeb
XL
1671 self.groups_for_arg(&*flg.b.name)
1672 .and_then(|grps| Some(matcher.inc_occurrences_of(&*grps)));
1673 matcher.insert(&*flg.b.name);
1674 }
1675 }
1676
1677 let used_arg = format!("--{}", arg);
1678 Err(Error::unknown_argument(&*used_arg,
1679 &*suffix.0,
041b39d2 1680 &*usage::create_error_usage(self, matcher, None),
8bb4bdeb
XL
1681 self.color()))
1682 }
1683
8bb4bdeb 1684 // Prints the version to the user and exits if quit=true
041b39d2 1685 fn print_version<W: Write>(&self, w: &mut W, use_long: bool) -> ClapResult<()> {
3b2f2976 1686 self.write_version(w, use_long)?;
8bb4bdeb
XL
1687 w.flush().map_err(Error::from)
1688 }
1689
041b39d2
XL
1690 pub fn write_version<W: Write>(&self, w: &mut W, use_long: bool) -> io::Result<()> {
1691 let ver = if use_long {
1692 self.meta
1693 .long_version
1694 .unwrap_or_else(|| self.meta.version.unwrap_or(""))
1695 } else {
1696 self.meta
1697 .version
1698 .unwrap_or_else(|| self.meta.long_version.unwrap_or(""))
1699 };
8bb4bdeb
XL
1700 if let Some(bn) = self.meta.bin_name.as_ref() {
1701 if bn.contains(' ') {
1702 // Incase we're dealing with subcommands i.e. git mv is translated to git-mv
041b39d2 1703 write!(w, "{} {}", bn.replace(" ", "-"), ver)
8bb4bdeb 1704 } else {
041b39d2 1705 write!(w, "{} {}", &self.meta.name[..], ver)
8bb4bdeb
XL
1706 }
1707 } else {
041b39d2 1708 write!(w, "{} {}", &self.meta.name[..], ver)
8bb4bdeb
XL
1709 }
1710 }
1711
1712 pub fn print_help(&self) -> ClapResult<()> {
1713 let out = io::stdout();
1714 let mut buf_w = BufWriter::new(out.lock());
1715 self.write_help(&mut buf_w)
1716 }
1717
1718 pub fn write_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
041b39d2
XL
1719 Help::write_parser_help(w, self, false)
1720 }
1721
1722 pub fn write_long_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
1723 Help::write_parser_help(w, self, true)
8bb4bdeb
XL
1724 }
1725
1726 pub fn write_help_err<W: Write>(&self, w: &mut W) -> ClapResult<()> {
1727 Help::write_parser_help_to_stderr(w, self)
1728 }
1729
041b39d2 1730 pub fn add_defaults(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
8bb4bdeb 1731 macro_rules! add_val {
041b39d2
XL
1732 (@default $_self:ident, $a:ident, $m:ident) => {
1733 if let Some(ref val) = $a.v.default_val {
ea8adc8c
XL
1734 if $m.get($a.b.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) {
1735 $_self.add_val_to_arg($a, OsStr::new(val), $m)?;
1736
1737 if $_self.cache.map_or(true, |name| name != $a.name()) {
1738 arg_post_processing!($_self, $a, $m);
1739 $_self.cache = Some($a.name());
1740 }
1741 } else {
3b2f2976 1742 $_self.add_val_to_arg($a, OsStr::new(val), $m)?;
041b39d2
XL
1743
1744 if $_self.cache.map_or(true, |name| name != $a.name()) {
1745 arg_post_processing!($_self, $a, $m);
1746 $_self.cache = Some($a.name());
1747 }
1748 }
1749 }
1750 };
8bb4bdeb 1751 ($_self:ident, $a:ident, $m:ident) => {
041b39d2
XL
1752 if let Some(ref vm) = $a.v.default_vals_ifs {
1753 let mut done = false;
1754 if $m.get($a.b.name).is_none() {
1755 for &(arg, val, default) in vm.values() {
1756 let add = if let Some(a) = $m.get(arg) {
1757 if let Some(v) = val {
1758 a.vals.iter().any(|value| v == value)
1759 } else {
1760 true
1761 }
1762 } else {
1763 false
1764 };
1765 if add {
3b2f2976 1766 $_self.add_val_to_arg($a, OsStr::new(default), $m)?;
041b39d2
XL
1767 if $_self.cache.map_or(true, |name| name != $a.name()) {
1768 arg_post_processing!($_self, $a, $m);
1769 $_self.cache = Some($a.name());
1770 }
1771 done = true;
1772 break;
1773 }
1774 }
1775 }
1776
1777 if done {
1778 continue; // outer loop (outside macro)
1779 }
8bb4bdeb 1780 }
041b39d2 1781 add_val!(@default $_self, $a, $m)
8bb4bdeb
XL
1782 };
1783 }
041b39d2
XL
1784
1785 for o in &self.opts {
8bb4bdeb
XL
1786 add_val!(self, o, matcher);
1787 }
041b39d2 1788 for p in self.positionals.values() {
8bb4bdeb
XL
1789 add_val!(self, p, matcher);
1790 }
1791 Ok(())
1792 }
1793
1794 pub fn flags(&self) -> Iter<FlagBuilder<'a, 'b>> { self.flags.iter() }
1795
1796 pub fn opts(&self) -> Iter<OptBuilder<'a, 'b>> { self.opts.iter() }
1797
1798 pub fn positionals(&self) -> vec_map::Values<PosBuilder<'a, 'b>> { self.positionals.values() }
1799
1800 pub fn subcommands(&self) -> Iter<App> { self.subcommands.iter() }
1801
1802 // Should we color the output? None=determined by output location, true=yes, false=no
1803 #[doc(hidden)]
1804 pub fn color(&self) -> ColorWhen {
041b39d2
XL
1805 debugln!("Parser::color;");
1806 debug!("Parser::color: Color setting...");
1807 if self.is_set(AS::ColorNever) {
8bb4bdeb
XL
1808 sdebugln!("Never");
1809 ColorWhen::Never
041b39d2 1810 } else if self.is_set(AS::ColorAlways) {
8bb4bdeb
XL
1811 sdebugln!("Always");
1812 ColorWhen::Always
1813 } else {
1814 sdebugln!("Auto");
1815 ColorWhen::Auto
1816 }
1817 }
1818
1819 pub fn find_any_arg(&self, name: &str) -> Option<&AnyArg> {
041b39d2 1820 if let Some(f) = find_by_name!(self, name, flags, iter) {
8bb4bdeb
XL
1821 return Some(f);
1822 }
041b39d2 1823 if let Some(o) = find_by_name!(self, name, opts, iter) {
8bb4bdeb
XL
1824 return Some(o);
1825 }
041b39d2 1826 if let Some(p) = find_by_name!(self, name, positionals, values) {
8bb4bdeb
XL
1827 return Some(p);
1828 }
1829 None
1830 }
1831
041b39d2
XL
1832 /// Check is a given string matches the binary name for this parser
1833 fn is_bin_name(&self, value: &str) -> bool {
1834 self.meta.bin_name
1835 .as_ref()
1836 .and_then(|name| Some(value == name))
1837 .unwrap_or(false)
1838 }
1839
1840 /// Check is a given string is an alias for this parser
1841 fn is_alias(&self, value: &str) -> bool {
1842 self.meta.aliases
1843 .as_ref()
1844 .and_then(|aliases| {
1845 for alias in aliases {
1846 if alias.0 == value {
1847 return Some(true);
1848 }
1849 }
1850 Some(false)
1851 })
1852 .unwrap_or(false)
1853 }
1854
1855 // Only used for completion scripts due to bin_name messiness
1856 #[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))]
8bb4bdeb 1857 pub fn find_subcommand(&'b self, sc: &str) -> Option<&'b App<'a, 'b>> {
041b39d2
XL
1858 debugln!("Parser::find_subcommand: sc={}", sc);
1859 debugln!("Parser::find_subcommand: Currently in Parser...{}",
1860 self.meta.bin_name.as_ref().unwrap());
1861 for s in &self.subcommands {
1862 if s.p.is_bin_name(sc) {
1863 return Some(s);
1864 }
1865 // XXX: why do we split here?
1866 // isn't `sc` supposed to be single word already?
1867 let last = sc.split(' ').rev().next().expect(INTERNAL_ERROR_MSG);
1868 if s.p.is_alias(last) {
8bb4bdeb
XL
1869 return Some(s);
1870 }
041b39d2 1871
8bb4bdeb
XL
1872 if let Some(app) = s.p.find_subcommand(sc) {
1873 return Some(app);
1874 }
1875 }
1876 None
1877 }
8bb4bdeb 1878
041b39d2
XL
1879 #[inline]
1880 fn contains_long(&self, l: &str) -> bool { longs!(self).any(|al| al == &l) }
1881
1882 #[inline]
1883 fn contains_short(&self, s: char) -> bool { shorts!(self).any(|arg_s| arg_s == &s) }
8bb4bdeb 1884}