1// Std
2use std::{
3 cell::Cell,
4 ffi::{OsStr, OsString},
5};
6
7use clap_lex::OsStrExt as _;
8
9// Internal
10use crate::builder::{Arg, Command};
11use crate::error::Error as ClapError;
12use crate::error::Result as ClapResult;
13use crate::mkeymap::KeyType;
14use crate::output::Usage;
15use crate::parser::features::suggestions;
16use crate::parser::{ArgMatcher, SubCommand};
17use crate::parser::{Validator, ValueSource};
18use crate::util::AnyValue;
19use crate::util::Id;
20use crate::ArgAction;
21use crate::INTERNAL_ERROR_MSG;
22
23pub(crate) struct Parser<'cmd> {
24 cmd: &'cmd mut Command,
25 cur_idx: Cell<usize>,
26 /// Index of the previous flag subcommand in a group of flags.
27 flag_subcmd_at: Option<usize>,
28 /// Counter indicating the number of items to skip
29 /// when revisiting the group of flags which includes the flag subcommand.
30 flag_subcmd_skip: usize,
31}
32
33// Initializing Methods
34impl<'cmd> Parser<'cmd> {
35 pub(crate) fn new(cmd: &'cmd mut Command) -> Self {
36 Parser {
37 cmd,
38 cur_idx: Cell::new(0),
39 flag_subcmd_at: None,
40 flag_subcmd_skip: 0,
41 }
42 }
43}
44
45// Parsing Methods
46impl<'cmd> Parser<'cmd> {
47 // The actual parsing function
48 #[allow(clippy::cognitive_complexity)]
49 pub(crate) fn get_matches_with(
50 &mut self,
51 matcher: &mut ArgMatcher,
52 raw_args: &mut clap_lex::RawArgs,
53 mut args_cursor: clap_lex::ArgCursor,
54 ) -> ClapResult<()> {
55 debug!("Parser::get_matches_with");
56 // Verify all positional assertions pass
57
58 let mut subcmd_name: Option<String> = None;
59 let mut keep_state = false;
60 let mut parse_state = ParseState::ValuesDone;
61 let mut pos_counter = 1;
62
63 // Already met any valid arg(then we shouldn't expect subcommands after it).
64 let mut valid_arg_found = false;
65 // If the user already passed '--'. Meaning only positional args follow.
66 let mut trailing_values = false;
67
68 // Count of positional args
69 let positional_count = self
70 .cmd
71 .get_keymap()
72 .keys()
73 .filter(|x| x.is_position())
74 .count();
75 // If any arg sets .last(true)
76 let contains_last = self.cmd.get_arguments().any(|x| x.is_last_set());
77
78 while let Some(arg_os) = raw_args.next(&mut args_cursor) {
79 debug!(
80 "Parser::get_matches_with: Begin parsing '{:?}'",
81 arg_os.to_value_os(),
82 );
83
84 // Has the user already passed '--'? Meaning only positional args follow
85 if !trailing_values {
86 if self.cmd.is_subcommand_precedence_over_arg_set()
87 || !matches!(parse_state, ParseState::Opt(_) | ParseState::Pos(_))
88 {
89 // Does the arg match a subcommand name, or any of its aliases (if defined)
90 let sc_name = self.possible_subcommand(arg_os.to_value(), valid_arg_found);
91 debug!("Parser::get_matches_with: sc={sc_name:?}");
92 if let Some(sc_name) = sc_name {
93 if sc_name == "help" && !self.cmd.is_disable_help_subcommand_set() {
94 ok!(self.parse_help_subcommand(raw_args.remaining(&mut args_cursor)));
95 unreachable!("`parse_help_subcommand` always errors");
96 } else {
97 subcmd_name = Some(sc_name.to_owned());
98 }
99 break;
100 }
101 }
102
103 if arg_os.is_escape() {
104 if matches!(&parse_state, ParseState::Opt(opt) | ParseState::Pos(opt) if
105 self.cmd[opt].is_allow_hyphen_values_set())
106 {
107 // ParseResult::MaybeHyphenValue, do nothing
108 } else {
109 debug!("Parser::get_matches_with: setting TrailingVals=true");
110 trailing_values = true;
111 matcher.start_trailing();
112 continue;
113 }
114 } else if let Some((long_arg, long_value)) = arg_os.to_long() {
115 let parse_result = ok!(self.parse_long_arg(
116 matcher,
117 long_arg,
118 long_value,
119 &parse_state,
120 pos_counter,
121 &mut valid_arg_found,
122 ));
123 debug!("Parser::get_matches_with: After parse_long_arg {parse_result:?}");
124 match parse_result {
125 ParseResult::NoArg => {
126 unreachable!("`to_long` always has the flag specified")
127 }
128 ParseResult::ValuesDone => {
129 parse_state = ParseState::ValuesDone;
130 continue;
131 }
132 ParseResult::Opt(id) => {
133 parse_state = ParseState::Opt(id);
134 continue;
135 }
136 ParseResult::FlagSubCommand(name) => {
137 debug!(
138 "Parser::get_matches_with: FlagSubCommand found in long arg {:?}",
139 &name
140 );
141 subcmd_name = Some(name);
142 break;
143 }
144 ParseResult::EqualsNotProvided { arg } => {
145 let _ = self.resolve_pending(matcher);
146 return Err(ClapError::no_equals(
147 self.cmd,
148 arg,
149 Usage::new(self.cmd).create_usage_with_title(&[]),
150 ));
151 }
152 ParseResult::NoMatchingArg { arg } => {
153 let _ = self.resolve_pending(matcher);
154 let remaining_args: Vec<_> =
155 raw_args.remaining(&mut args_cursor).collect();
156 return Err(self.did_you_mean_error(
157 &arg,
158 matcher,
159 &remaining_args,
160 trailing_values,
161 ));
162 }
163 ParseResult::UnneededAttachedValue { rest, used, arg } => {
164 let _ = self.resolve_pending(matcher);
165 return Err(ClapError::too_many_values(
166 self.cmd,
167 rest,
168 arg,
169 Usage::new(self.cmd).create_usage_with_title(&used),
170 ));
171 }
172 ParseResult::MaybeHyphenValue => {
173 // Maybe a hyphen value, do nothing.
174 }
175 ParseResult::AttachedValueNotConsumed => {
176 unreachable!()
177 }
178 }
179 } else if let Some(short_arg) = arg_os.to_short() {
180 // Arg looks like a short flag, and not a possible number
181
182 // Try to parse short args like normal, if allow_hyphen_values or
183 // AllowNegativeNumbers is set, parse_short_arg will *not* throw
184 // an error, and instead return Ok(None)
185 let parse_result = ok!(self.parse_short_arg(
186 matcher,
187 short_arg,
188 &parse_state,
189 pos_counter,
190 &mut valid_arg_found,
191 ));
192 // If it's None, we then check if one of those two AppSettings was set
193 debug!("Parser::get_matches_with: After parse_short_arg {parse_result:?}");
194 match parse_result {
195 ParseResult::NoArg => {
196 // Is a single dash `-`, try positional.
197 }
198 ParseResult::ValuesDone => {
199 parse_state = ParseState::ValuesDone;
200 continue;
201 }
202 ParseResult::Opt(id) => {
203 parse_state = ParseState::Opt(id);
204 continue;
205 }
206 ParseResult::FlagSubCommand(name) => {
207 // If there are more short flags to be processed, we should keep the state, and later
208 // revisit the current group of short flags skipping the subcommand.
209 keep_state = self
210 .flag_subcmd_at
211 .map(|at| {
212 raw_args
213 .seek(&mut args_cursor, clap_lex::SeekFrom::Current(-1));
214 // Since we are now saving the current state, the number of flags to skip during state recovery should
215 // be the current index (`cur_idx`) minus ONE UNIT TO THE LEFT of the starting position.
216 self.flag_subcmd_skip = self.cur_idx.get() - at + 1;
217 })
218 .is_some();
219
220 debug!(
221 "Parser::get_matches_with:FlagSubCommandShort: subcmd_name={}, keep_state={}, flag_subcmd_skip={}",
222 name,
223 keep_state,
224 self.flag_subcmd_skip
225 );
226
227 subcmd_name = Some(name);
228 break;
229 }
230 ParseResult::EqualsNotProvided { arg } => {
231 let _ = self.resolve_pending(matcher);
232 return Err(ClapError::no_equals(
233 self.cmd,
234 arg,
235 Usage::new(self.cmd).create_usage_with_title(&[]),
236 ));
237 }
238 ParseResult::NoMatchingArg { arg } => {
239 let _ = self.resolve_pending(matcher);
240 // We already know it looks like a flag
241 let suggested_trailing_arg =
242 !trailing_values && self.cmd.has_positionals();
243 return Err(ClapError::unknown_argument(
244 self.cmd,
245 arg,
246 None,
247 suggested_trailing_arg,
248 Usage::new(self.cmd).create_usage_with_title(&[]),
249 ));
250 }
251 ParseResult::MaybeHyphenValue => {
252 // Maybe a hyphen value, do nothing.
253 }
254 ParseResult::UnneededAttachedValue { .. }
255 | ParseResult::AttachedValueNotConsumed => unreachable!(),
256 }
257 }
258
259 if let ParseState::Opt(id) = &parse_state {
260 // Assume this is a value of a previous arg.
261
262 // get the option so we can check the settings
263 let arg = &self.cmd[id];
264 let parse_result = if let Some(parse_result) =
265 self.check_terminator(arg, arg_os.to_value_os())
266 {
267 parse_result
268 } else {
269 let trailing_values = false;
270 let arg_values = matcher.pending_values_mut(id, None, trailing_values);
271 arg_values.push(arg_os.to_value_os().to_owned());
272 if matcher.needs_more_vals(arg) {
273 ParseResult::Opt(arg.get_id().clone())
274 } else {
275 ParseResult::ValuesDone
276 }
277 };
278 parse_state = match parse_result {
279 ParseResult::Opt(id) => ParseState::Opt(id),
280 ParseResult::ValuesDone => ParseState::ValuesDone,
281 _ => unreachable!(),
282 };
283 // get the next value from the iterator
284 continue;
285 }
286 }
287
288 // Correct pos_counter.
289 pos_counter = {
290 let is_second_to_last = pos_counter + 1 == positional_count;
291
292 // The last positional argument, or second to last positional
293 // argument may be set to .multiple_values(true) or `.multiple_occurrences(true)`
294 let low_index_mults = is_second_to_last
295 && self.cmd.get_positionals().any(|a| {
296 a.is_multiple() && (positional_count != a.get_index().unwrap_or(0))
297 })
298 && self
299 .cmd
300 .get_positionals()
301 .last()
302 .map(|p_name| !p_name.is_last_set())
303 .unwrap_or_default();
304
305 let is_terminated = self
306 .cmd
307 .get_keymap()
308 .get(&pos_counter)
309 .map(|a| a.get_value_terminator().is_some())
310 .unwrap_or_default();
311
312 let missing_pos = self.cmd.is_allow_missing_positional_set()
313 && is_second_to_last
314 && !trailing_values;
315
316 debug!("Parser::get_matches_with: Positional counter...{pos_counter}");
317 debug!("Parser::get_matches_with: Low index multiples...{low_index_mults:?}");
318
319 if (low_index_mults || missing_pos) && !is_terminated {
320 let skip_current = if let Some(n) = raw_args.peek(&args_cursor) {
321 if let Some(arg) = self
322 .cmd
323 .get_positionals()
324 .find(|a| a.get_index() == Some(pos_counter))
325 {
326 // If next value looks like a new_arg or it's a
327 // subcommand, skip positional argument under current
328 // pos_counter(which means current value cannot be a
329 // positional argument with a value next to it), assume
330 // current value matches the next arg.
331 self.is_new_arg(&n, arg)
332 || self
333 .possible_subcommand(n.to_value(), valid_arg_found)
334 .is_some()
335 } else {
336 true
337 }
338 } else {
339 true
340 };
341
342 if skip_current {
343 debug!("Parser::get_matches_with: Bumping the positional counter...");
344 pos_counter + 1
345 } else {
346 pos_counter
347 }
348 } else if trailing_values
349 && (self.cmd.is_allow_missing_positional_set() || contains_last)
350 {
351 // Came to -- and one positional has .last(true) set, so we go immediately
352 // to the last (highest index) positional
353 debug!("Parser::get_matches_with: .last(true) and --, setting last pos");
354 positional_count
355 } else {
356 pos_counter
357 }
358 };
359
360 if let Some(arg) = self.cmd.get_keymap().get(&pos_counter) {
361 if arg.is_last_set() && !trailing_values {
362 let _ = self.resolve_pending(matcher);
363 // Its already considered a positional, we don't need to suggest turning it
364 // into one
365 let suggested_trailing_arg = false;
366 return Err(ClapError::unknown_argument(
367 self.cmd,
368 arg_os.display().to_string(),
369 None,
370 suggested_trailing_arg,
371 Usage::new(self.cmd).create_usage_with_title(&[]),
372 ));
373 }
374
375 if arg.is_trailing_var_arg_set() {
376 trailing_values = true;
377 }
378
379 if matcher.pending_arg_id() != Some(arg.get_id()) || !arg.is_multiple_values_set() {
380 ok!(self.resolve_pending(matcher));
381 }
382 parse_state =
383 if let Some(parse_result) = self.check_terminator(arg, arg_os.to_value_os()) {
384 debug_assert_eq!(parse_result, ParseResult::ValuesDone);
385 pos_counter += 1;
386 ParseState::ValuesDone
387 } else {
388 let arg_values = matcher.pending_values_mut(
389 arg.get_id(),
390 Some(Identifier::Index),
391 trailing_values,
392 );
393 arg_values.push(arg_os.to_value_os().to_owned());
394
395 // Only increment the positional counter if it doesn't allow multiples
396 if !arg.is_multiple() {
397 pos_counter += 1;
398 ParseState::ValuesDone
399 } else {
400 ParseState::Pos(arg.get_id().clone())
401 }
402 };
403 valid_arg_found = true;
404 } else if let Some(external_parser) =
405 self.cmd.get_external_subcommand_value_parser().cloned()
406 {
407 // Get external subcommand name
408 let sc_name = match arg_os.to_value() {
409 Ok(s) => s.to_owned(),
410 Err(_) => {
411 let _ = self.resolve_pending(matcher);
412 return Err(ClapError::invalid_utf8(
413 self.cmd,
414 Usage::new(self.cmd).create_usage_with_title(&[]),
415 ));
416 }
417 };
418
419 // Collect the external subcommand args
420 let mut sc_m = ArgMatcher::new(self.cmd);
421 sc_m.start_occurrence_of_external(self.cmd);
422
423 for raw_val in raw_args.remaining(&mut args_cursor) {
424 let val = ok!(external_parser.parse_ref(
425 self.cmd,
426 None,
427 raw_val,
428 ValueSource::CommandLine
429 ));
430 let external_id = Id::from_static_ref(Id::EXTERNAL);
431 sc_m.add_val_to(&external_id, val, raw_val.to_os_string());
432 }
433
434 matcher.subcommand(SubCommand {
435 name: sc_name,
436 matches: sc_m.into_inner(),
437 });
438
439 ok!(self.resolve_pending(matcher));
440 #[cfg(feature = "env")]
441 ok!(self.add_env(matcher));
442 ok!(self.add_defaults(matcher));
443 return Validator::new(self.cmd).validate(parse_state, matcher);
444 } else {
445 // Start error processing
446 let _ = self.resolve_pending(matcher);
447 return Err(self.match_arg_error(&arg_os, valid_arg_found, trailing_values));
448 }
449 }
450
451 if let Some(ref pos_sc_name) = subcmd_name {
452 let sc_name = self
453 .cmd
454 .find_subcommand(pos_sc_name)
455 .expect(INTERNAL_ERROR_MSG)
456 .get_name()
457 .to_owned();
458 ok!(self.parse_subcommand(&sc_name, matcher, raw_args, args_cursor, keep_state));
459 }
460
461 ok!(self.resolve_pending(matcher));
462 #[cfg(feature = "env")]
463 ok!(self.add_env(matcher));
464 ok!(self.add_defaults(matcher));
465 Validator::new(self.cmd).validate(parse_state, matcher)
466 }
467
468 fn match_arg_error(
469 &self,
470 arg_os: &clap_lex::ParsedArg<'_>,
471 valid_arg_found: bool,
472 trailing_values: bool,
473 ) -> ClapError {
474 // If argument follows a `--`
475 if trailing_values {
476 // If the arg matches a subcommand name, or any of its aliases (if defined)
477 if self
478 .possible_subcommand(arg_os.to_value(), valid_arg_found)
479 .is_some()
480 {
481 return ClapError::unnecessary_double_dash(
482 self.cmd,
483 arg_os.display().to_string(),
484 Usage::new(self.cmd).create_usage_with_title(&[]),
485 );
486 }
487 }
488
489 let suggested_trailing_arg = !trailing_values
490 && self.cmd.has_positionals()
491 && (arg_os.is_long() || arg_os.is_short());
492
493 if !(self.cmd.is_args_conflicts_with_subcommands_set() && valid_arg_found) {
494 let candidates = suggestions::did_you_mean(
495 &arg_os.display().to_string(),
496 self.cmd.all_subcommand_names(),
497 );
498 // If the argument looks like a subcommand.
499 if !candidates.is_empty() {
500 return ClapError::invalid_subcommand(
501 self.cmd,
502 arg_os.display().to_string(),
503 candidates,
504 self.cmd
505 .get_bin_name()
506 .unwrap_or_else(|| self.cmd.get_name())
507 .to_owned(),
508 suggested_trailing_arg,
509 Usage::new(self.cmd).create_usage_with_title(&[]),
510 );
511 }
512
513 // If the argument must be a subcommand.
514 if self.cmd.has_subcommands()
515 && (!self.cmd.has_positionals() || self.cmd.is_infer_subcommands_set())
516 {
517 return ClapError::unrecognized_subcommand(
518 self.cmd,
519 arg_os.display().to_string(),
520 Usage::new(self.cmd).create_usage_with_title(&[]),
521 );
522 }
523 }
524
525 ClapError::unknown_argument(
526 self.cmd,
527 arg_os.display().to_string(),
528 None,
529 suggested_trailing_arg,
530 Usage::new(self.cmd).create_usage_with_title(&[]),
531 )
532 }
533
534 // Checks if the arg matches a subcommand name, or any of its aliases (if defined)
535 fn possible_subcommand(
536 &self,
537 arg: Result<&str, &OsStr>,
538 valid_arg_found: bool,
539 ) -> Option<&str> {
540 debug!("Parser::possible_subcommand: arg={arg:?}");
541 let arg = some!(arg.ok());
542
543 if !(self.cmd.is_args_conflicts_with_subcommands_set() && valid_arg_found) {
544 if self.cmd.is_infer_subcommands_set() {
545 // For subcommand `test`, we accepts it's prefix: `t`, `te`,
546 // `tes` and `test`.
547 let v = self
548 .cmd
549 .all_subcommand_names()
550 .filter(|s| s.starts_with(arg))
551 .collect::<Vec<_>>();
552
553 if v.len() == 1 {
554 return Some(v[0]);
555 }
556
557 // If there is any ambiguity, fallback to non-infer subcommand
558 // search.
559 }
560 if let Some(sc) = self.cmd.find_subcommand(arg) {
561 return Some(sc.get_name());
562 }
563 }
564 None
565 }
566
567 // Checks if the arg matches a long flag subcommand name, or any of its aliases (if defined)
568 fn possible_long_flag_subcommand(&self, arg: &str) -> Option<&str> {
569 debug!("Parser::possible_long_flag_subcommand: arg={arg:?}");
570 if self.cmd.is_infer_subcommands_set() {
571 let options = self
572 .cmd
573 .get_subcommands()
574 .fold(Vec::new(), |mut options, sc| {
575 if let Some(long) = sc.get_long_flag() {
576 if long.starts_with(arg) {
577 options.push(long);
578 }
579 options.extend(sc.get_all_aliases().filter(|alias| alias.starts_with(arg)))
580 }
581 options
582 });
583 if options.len() == 1 {
584 return Some(options[0]);
585 }
586
587 for sc in options {
588 if sc == arg {
589 return Some(sc);
590 }
591 }
592 } else if let Some(sc_name) = self.cmd.find_long_subcmd(arg) {
593 return Some(sc_name);
594 }
595 None
596 }
597
598 fn parse_help_subcommand(
599 &self,
600 cmds: impl Iterator<Item = &'cmd OsStr>,
601 ) -> ClapResult<std::convert::Infallible> {
602 debug!("Parser::parse_help_subcommand");
603
604 let mut cmd = self.cmd.clone();
605 let sc = {
606 let mut sc = &mut cmd;
607
608 for cmd in cmds {
609 sc = if let Some(sc_name) =
610 sc.find_subcommand(cmd).map(|sc| sc.get_name().to_owned())
611 {
612 sc._build_subcommand(&sc_name).unwrap()
613 } else {
614 return Err(ClapError::unrecognized_subcommand(
615 sc,
616 cmd.to_string_lossy().into_owned(),
617 Usage::new(sc).create_usage_with_title(&[]),
618 ));
619 };
620 }
621
622 sc
623 };
624 let parser = Parser::new(sc);
625
626 Err(parser.help_err(true))
627 }
628
629 fn is_new_arg(&self, next: &clap_lex::ParsedArg<'_>, current_positional: &Arg) -> bool {
630 #![allow(clippy::needless_bool)] // Prefer consistent if/else-if ladder
631
632 debug!(
633 "Parser::is_new_arg: {:?}:{}",
634 next.to_value_os(),
635 current_positional.get_id()
636 );
637
638 if self.cmd[current_positional.get_id()].is_allow_hyphen_values_set()
639 || (self.cmd[current_positional.get_id()].is_allow_negative_numbers_set()
640 && next.is_number())
641 {
642 // If allow hyphen, this isn't a new arg.
643 debug!("Parser::is_new_arg: Allow hyphen");
644 false
645 } else if next.is_long() {
646 // If this is a long flag, this is a new arg.
647 debug!("Parser::is_new_arg: --<something> found");
648 true
649 } else if next.is_short() {
650 // If this is a short flag, this is a new arg. But a singe '-' by
651 // itself is a value and typically means "stdin" on unix systems.
652 debug!("Parser::is_new_arg: -<something> found");
653 true
654 } else {
655 // Nothing special, this is a value.
656 debug!("Parser::is_new_arg: value");
657 false
658 }
659 }
660
661 fn parse_subcommand(
662 &mut self,
663 sc_name: &str,
664 matcher: &mut ArgMatcher,
665 raw_args: &mut clap_lex::RawArgs,
666 args_cursor: clap_lex::ArgCursor,
667 keep_state: bool,
668 ) -> ClapResult<()> {
669 debug!("Parser::parse_subcommand");
670
671 let partial_parsing_enabled = self.cmd.is_ignore_errors_set();
672
673 if let Some(sc) = self.cmd._build_subcommand(sc_name) {
674 let mut sc_matcher = ArgMatcher::new(sc);
675
676 debug!(
677 "Parser::parse_subcommand: About to parse sc={}",
678 sc.get_name()
679 );
680
681 {
682 let mut p = Parser::new(sc);
683 // HACK: maintain indexes between parsers
684 // FlagSubCommand short arg needs to revisit the current short args, but skip the subcommand itself
685 if keep_state {
686 p.cur_idx.set(self.cur_idx.get());
687 p.flag_subcmd_at = self.flag_subcmd_at;
688 p.flag_subcmd_skip = self.flag_subcmd_skip;
689 }
690 if let Err(error) = p.get_matches_with(&mut sc_matcher, raw_args, args_cursor) {
691 if partial_parsing_enabled {
692 debug!("Parser::parse_subcommand: ignored error in subcommand {sc_name}: {error:?}");
693 } else {
694 return Err(error);
695 }
696 }
697 }
698 matcher.subcommand(SubCommand {
699 name: sc.get_name().to_owned(),
700 matches: sc_matcher.into_inner(),
701 });
702 }
703 Ok(())
704 }
705
706 fn parse_long_arg(
707 &mut self,
708 matcher: &mut ArgMatcher,
709 long_arg: Result<&str, &OsStr>,
710 long_value: Option<&OsStr>,
711 parse_state: &ParseState,
712 pos_counter: usize,
713 valid_arg_found: &mut bool,
714 ) -> ClapResult<ParseResult> {
715 // maybe here lifetime should be 'a
716 debug!("Parser::parse_long_arg");
717
718 #[allow(clippy::blocks_in_if_conditions)]
719 if matches!(parse_state, ParseState::Opt(opt) | ParseState::Pos(opt) if
720 self.cmd[opt].is_allow_hyphen_values_set())
721 {
722 debug!("Parser::parse_long_arg: prior arg accepts hyphenated values",);
723 return Ok(ParseResult::MaybeHyphenValue);
724 }
725
726 debug!("Parser::parse_long_arg: Does it contain '='...");
727 let long_arg = match long_arg {
728 Ok(long_arg) => long_arg,
729 Err(long_arg_os) => {
730 return Ok(ParseResult::NoMatchingArg {
731 arg: long_arg_os.to_string_lossy().into_owned(),
732 })
733 }
734 };
735 if long_arg.is_empty() {
736 debug_assert!(
737 long_value.is_some(),
738 "`--` should be filtered out before this point"
739 );
740 }
741
742 let arg = if let Some(arg) = self.cmd.get_keymap().get(long_arg) {
743 debug!("Parser::parse_long_arg: Found valid arg or flag '{arg}'");
744 Some((long_arg, arg))
745 } else if self.cmd.is_infer_long_args_set() {
746 let mut iter = self.cmd.get_arguments().filter_map(|a| {
747 if let Some(long) = a.get_long() {
748 if long.starts_with(long_arg) {
749 return Some((long, a));
750 }
751 }
752 a.aliases
753 .iter()
754 .find_map(|(alias, _)| alias.starts_with(long_arg).then(|| (alias.as_str(), a)))
755 });
756
757 iter.next().filter(|_| iter.next().is_none())
758 } else {
759 None
760 };
761
762 if let Some((_long_arg, arg)) = arg {
763 let ident = Identifier::Long;
764 *valid_arg_found = true;
765 if arg.is_takes_value_set() {
766 debug!(
767 "Parser::parse_long_arg({:?}): Found an arg with value '{:?}'",
768 long_arg, &long_value
769 );
770 let has_eq = long_value.is_some();
771 self.parse_opt_value(ident, long_value, arg, matcher, has_eq)
772 } else if let Some(rest) = long_value {
773 let required = self.cmd.required_graph();
774 debug!("Parser::parse_long_arg({long_arg:?}): Got invalid literal `{rest:?}`");
775 let mut used: Vec<Id> = matcher
776 .arg_ids()
777 .filter(|arg_id| {
778 matcher.check_explicit(arg_id, &crate::builder::ArgPredicate::IsPresent)
779 })
780 .filter(|&n| {
781 self.cmd
782 .find(n)
783 .map(|a| !(a.is_hide_set() || required.contains(a.get_id())))
784 .unwrap_or(true)
785 })
786 .cloned()
787 .collect();
788 used.push(arg.get_id().clone());
789
790 Ok(ParseResult::UnneededAttachedValue {
791 rest: rest.to_string_lossy().into_owned(),
792 used,
793 arg: arg.to_string(),
794 })
795 } else {
796 debug!("Parser::parse_long_arg({long_arg:?}): Presence validated");
797 let trailing_idx = None;
798 self.react(
799 Some(ident),
800 ValueSource::CommandLine,
801 arg,
802 vec![],
803 trailing_idx,
804 matcher,
805 )
806 }
807 } else if let Some(sc_name) = self.possible_long_flag_subcommand(long_arg) {
808 Ok(ParseResult::FlagSubCommand(sc_name.to_string()))
809 } else if self
810 .cmd
811 .get_keymap()
812 .get(&pos_counter)
813 .map(|arg| arg.is_allow_hyphen_values_set() && !arg.is_last_set())
814 .unwrap_or_default()
815 {
816 debug!("Parser::parse_long_args: positional at {pos_counter} allows hyphens");
817 Ok(ParseResult::MaybeHyphenValue)
818 } else {
819 Ok(ParseResult::NoMatchingArg {
820 arg: long_arg.to_owned(),
821 })
822 }
823 }
824
825 fn parse_short_arg(
826 &mut self,
827 matcher: &mut ArgMatcher,
828 mut short_arg: clap_lex::ShortFlags<'_>,
829 parse_state: &ParseState,
830 // change this to possible pos_arg when removing the usage of &mut Parser.
831 pos_counter: usize,
832 valid_arg_found: &mut bool,
833 ) -> ClapResult<ParseResult> {
834 debug!("Parser::parse_short_arg: short_arg={short_arg:?}");
835
836 #[allow(clippy::blocks_in_if_conditions)]
837 if matches!(parse_state, ParseState::Opt(opt) | ParseState::Pos(opt)
838 if self.cmd[opt].is_allow_hyphen_values_set() || (self.cmd[opt].is_allow_negative_numbers_set() && short_arg.is_number()))
839 {
840 debug!("Parser::parse_short_args: prior arg accepts hyphenated values",);
841 return Ok(ParseResult::MaybeHyphenValue);
842 } else if self
843 .cmd
844 .get_keymap()
845 .get(&pos_counter)
846 .map(|arg| arg.is_allow_negative_numbers_set())
847 .unwrap_or_default()
848 && short_arg.is_number()
849 {
850 debug!("Parser::parse_short_arg: negative number");
851 return Ok(ParseResult::MaybeHyphenValue);
852 } else if self
853 .cmd
854 .get_keymap()
855 .get(&pos_counter)
856 .map(|arg| arg.is_allow_hyphen_values_set() && !arg.is_last_set())
857 .unwrap_or_default()
858 && short_arg
859 .clone()
860 .any(|c| !c.map(|c| self.cmd.contains_short(c)).unwrap_or_default())
861 {
862 debug!("Parser::parse_short_args: positional at {pos_counter} allows hyphens");
863 return Ok(ParseResult::MaybeHyphenValue);
864 }
865
866 let mut ret = ParseResult::NoArg;
867
868 let skip = self.flag_subcmd_skip;
869 self.flag_subcmd_skip = 0;
870 let res = short_arg.advance_by(skip);
871 debug_assert_eq!(
872 res,
873 Ok(()),
874 "tracking of `flag_subcmd_skip` is off for `{short_arg:?}`"
875 );
876 while let Some(c) = short_arg.next_flag() {
877 let c = match c {
878 Ok(c) => c,
879 Err(rest) => {
880 return Ok(ParseResult::NoMatchingArg {
881 arg: format!("-{}", rest.to_string_lossy()),
882 });
883 }
884 };
885 debug!("Parser::parse_short_arg:iter:{c}");
886
887 // Check for matching short options, and return the name if there is no trailing
888 // concatenated value: -oval
889 // Option: -o
890 // Value: val
891 if let Some(arg) = self.cmd.get_keymap().get(&c) {
892 let ident = Identifier::Short;
893 debug!("Parser::parse_short_arg:iter:{c}: Found valid opt or flag");
894 *valid_arg_found = true;
895 if !arg.is_takes_value_set() {
896 let arg_values = Vec::new();
897 let trailing_idx = None;
898 ret = ok!(self.react(
899 Some(ident),
900 ValueSource::CommandLine,
901 arg,
902 arg_values,
903 trailing_idx,
904 matcher,
905 ));
906 continue;
907 }
908
909 // Check for trailing concatenated value
910 //
911 // Cloning the iterator, so we rollback if it isn't there.
912 let val = short_arg.clone().next_value_os().unwrap_or_default();
913 debug!("Parser::parse_short_arg:iter:{c}: val={val:?}, short_arg={short_arg:?}");
914 let val = Some(val).filter(|v| !v.is_empty());
915
916 // Default to "we're expecting a value later".
917 //
918 // If attached value is not consumed, we may have more short
919 // flags to parse, continue.
920 //
921 // e.g. `-xvf`, when require_equals && x.min_vals == 0, we don't
922 // consume the `vf`, even if it's provided as value.
923 let (val, has_eq) = if let Some(val) = val.and_then(|v| v.strip_prefix("=")) {
924 (Some(val), true)
925 } else {
926 (val, false)
927 };
928 match ok!(self.parse_opt_value(ident, val, arg, matcher, has_eq)) {
929 ParseResult::AttachedValueNotConsumed => continue,
930 x => return Ok(x),
931 }
932 }
933
934 return if let Some(sc_name) = self.cmd.find_short_subcmd(c) {
935 debug!("Parser::parse_short_arg:iter:{c}: subcommand={sc_name}");
936 // Make sure indices get updated before reading `self.cur_idx`
937 ok!(self.resolve_pending(matcher));
938 self.cur_idx.set(self.cur_idx.get() + 1);
939 debug!("Parser::parse_short_arg: cur_idx:={}", self.cur_idx.get());
940
941 let name = sc_name.to_string();
942 // Get the index of the previously saved flag subcommand in the group of flags (if exists).
943 // If it is a new flag subcommand, then the formentioned index should be the current one
944 // (ie. `cur_idx`), and should be registered.
945 let cur_idx = self.cur_idx.get();
946 self.flag_subcmd_at.get_or_insert(cur_idx);
947 let done_short_args = short_arg.is_empty();
948 if done_short_args {
949 self.flag_subcmd_at = None;
950 }
951 Ok(ParseResult::FlagSubCommand(name))
952 } else {
953 Ok(ParseResult::NoMatchingArg {
954 arg: format!("-{c}"),
955 })
956 };
957 }
958 Ok(ret)
959 }
960
961 fn parse_opt_value(
962 &self,
963 ident: Identifier,
964 attached_value: Option<&OsStr>,
965 arg: &Arg,
966 matcher: &mut ArgMatcher,
967 has_eq: bool,
968 ) -> ClapResult<ParseResult> {
969 debug!(
970 "Parser::parse_opt_value; arg={}, val={:?}, has_eq={:?}",
971 arg.get_id(),
972 attached_value,
973 has_eq
974 );
975 debug!("Parser::parse_opt_value; arg.settings={:?}", arg.settings);
976
977 debug!("Parser::parse_opt_value; Checking for val...");
978 // require_equals is set, but no '=' is provided, try throwing error.
979 if arg.is_require_equals_set() && !has_eq {
980 if arg.get_min_vals() == 0 {
981 debug!("Requires equals, but min_vals == 0");
982 let arg_values = Vec::new();
983 let trailing_idx = None;
984 let react_result = ok!(self.react(
985 Some(ident),
986 ValueSource::CommandLine,
987 arg,
988 arg_values,
989 trailing_idx,
990 matcher,
991 ));
992 debug_assert_eq!(react_result, ParseResult::ValuesDone);
993 if attached_value.is_some() {
994 Ok(ParseResult::AttachedValueNotConsumed)
995 } else {
996 Ok(ParseResult::ValuesDone)
997 }
998 } else {
999 debug!("Requires equals but not provided. Error.");
1000 Ok(ParseResult::EqualsNotProvided {
1001 arg: arg.to_string(),
1002 })
1003 }
1004 } else if let Some(v) = attached_value {
1005 let arg_values = vec![v.to_owned()];
1006 let trailing_idx = None;
1007 let react_result = ok!(self.react(
1008 Some(ident),
1009 ValueSource::CommandLine,
1010 arg,
1011 arg_values,
1012 trailing_idx,
1013 matcher,
1014 ));
1015 debug_assert_eq!(react_result, ParseResult::ValuesDone);
1016 // Attached are always done
1017 Ok(ParseResult::ValuesDone)
1018 } else {
1019 debug!("Parser::parse_opt_value: More arg vals required...");
1020 ok!(self.resolve_pending(matcher));
1021 let trailing_values = false;
1022 matcher.pending_values_mut(arg.get_id(), Some(ident), trailing_values);
1023 Ok(ParseResult::Opt(arg.get_id().clone()))
1024 }
1025 }
1026
1027 fn check_terminator(&self, arg: &Arg, val: &OsStr) -> Option<ParseResult> {
1028 if Some(val) == arg.terminator.as_ref().map(|s| OsStr::new(s.as_str())) {
1029 debug!("Parser::check_terminator: terminator={:?}", arg.terminator);
1030 Some(ParseResult::ValuesDone)
1031 } else {
1032 None
1033 }
1034 }
1035
1036 fn push_arg_values(
1037 &self,
1038 arg: &Arg,
1039 raw_vals: Vec<OsString>,
1040 source: ValueSource,
1041 matcher: &mut ArgMatcher,
1042 ) -> ClapResult<()> {
1043 debug!("Parser::push_arg_values: {raw_vals:?}");
1044
1045 for raw_val in raw_vals {
1046 // update the current index because each value is a distinct index to clap
1047 self.cur_idx.set(self.cur_idx.get() + 1);
1048 debug!(
1049 "Parser::add_single_val_to_arg: cur_idx:={}",
1050 self.cur_idx.get()
1051 );
1052 let value_parser = arg.get_value_parser();
1053 let val = ok!(value_parser.parse_ref(self.cmd, Some(arg), &raw_val, source));
1054
1055 matcher.add_val_to(arg.get_id(), val, raw_val);
1056 matcher.add_index_to(arg.get_id(), self.cur_idx.get());
1057 }
1058
1059 Ok(())
1060 }
1061
1062 fn resolve_pending(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
1063 let pending = match matcher.take_pending() {
1064 Some(pending) => pending,
1065 None => {
1066 return Ok(());
1067 }
1068 };
1069
1070 debug!("Parser::resolve_pending: id={:?}", pending.id);
1071 let arg = self.cmd.find(&pending.id).expect(INTERNAL_ERROR_MSG);
1072 let _ = ok!(self.react(
1073 pending.ident,
1074 ValueSource::CommandLine,
1075 arg,
1076 pending.raw_vals,
1077 pending.trailing_idx,
1078 matcher,
1079 ));
1080
1081 Ok(())
1082 }
1083
1084 fn react(
1085 &self,
1086 ident: Option<Identifier>,
1087 source: ValueSource,
1088 arg: &Arg,
1089 mut raw_vals: Vec<OsString>,
1090 mut trailing_idx: Option<usize>,
1091 matcher: &mut ArgMatcher,
1092 ) -> ClapResult<ParseResult> {
1093 ok!(self.resolve_pending(matcher));
1094
1095 debug!(
1096 "Parser::react action={:?}, identifier={:?}, source={:?}",
1097 arg.get_action(),
1098 ident,
1099 source
1100 );
1101
1102 // Process before `default_missing_values` to avoid it counting as values from the command
1103 // line
1104 if source == ValueSource::CommandLine {
1105 ok!(self.verify_num_args(arg, &raw_vals));
1106 }
1107
1108 if raw_vals.is_empty() {
1109 // We assume this case is valid: require equals, but min_vals == 0.
1110 if !arg.default_missing_vals.is_empty() {
1111 debug!("Parser::react: has default_missing_vals");
1112 trailing_idx = None;
1113 raw_vals.extend(
1114 arg.default_missing_vals
1115 .iter()
1116 .map(|s| s.as_os_str().to_owned()),
1117 );
1118 }
1119 }
1120
1121 if let Some(val_delim) = arg.get_value_delimiter() {
1122 if self.cmd.is_dont_delimit_trailing_values_set() && trailing_idx == Some(0) {
1123 // Nothing to do
1124 } else {
1125 let mut val_delim_buffer = [0; 4];
1126 let val_delim = val_delim.encode_utf8(&mut val_delim_buffer);
1127 let mut split_raw_vals = Vec::with_capacity(raw_vals.len());
1128 for (i, raw_val) in raw_vals.into_iter().enumerate() {
1129 if !raw_val.contains(val_delim)
1130 || (self.cmd.is_dont_delimit_trailing_values_set()
1131 && trailing_idx == Some(i))
1132 {
1133 split_raw_vals.push(raw_val);
1134 } else {
1135 split_raw_vals.extend(raw_val.split(val_delim).map(|x| x.to_owned()));
1136 }
1137 }
1138 raw_vals = split_raw_vals
1139 }
1140 }
1141
1142 match arg.get_action() {
1143 ArgAction::Set => {
1144 if source == ValueSource::CommandLine
1145 && matches!(ident, Some(Identifier::Short) | Some(Identifier::Long))
1146 {
1147 // Record flag's index
1148 self.cur_idx.set(self.cur_idx.get() + 1);
1149 debug!("Parser::react: cur_idx:={}", self.cur_idx.get());
1150 }
1151 if matcher.remove(arg.get_id())
1152 && !(self.cmd.is_args_override_self() || arg.overrides.contains(arg.get_id()))
1153 {
1154 return Err(ClapError::argument_conflict(
1155 self.cmd,
1156 arg.to_string(),
1157 vec![arg.to_string()],
1158 Usage::new(self.cmd).create_usage_with_title(&[]),
1159 ));
1160 }
1161 self.start_custom_arg(matcher, arg, source);
1162 ok!(self.push_arg_values(arg, raw_vals, source, matcher));
1163 if cfg!(debug_assertions) && matcher.needs_more_vals(arg) {
1164 debug!(
1165 "Parser::react not enough values passed in, leaving it to the validator to complain",
1166 );
1167 }
1168 Ok(ParseResult::ValuesDone)
1169 }
1170 ArgAction::Append => {
1171 if source == ValueSource::CommandLine
1172 && matches!(ident, Some(Identifier::Short) | Some(Identifier::Long))
1173 {
1174 // Record flag's index
1175 self.cur_idx.set(self.cur_idx.get() + 1);
1176 debug!("Parser::react: cur_idx:={}", self.cur_idx.get());
1177 }
1178 self.start_custom_arg(matcher, arg, source);
1179 ok!(self.push_arg_values(arg, raw_vals, source, matcher));
1180 if cfg!(debug_assertions) && matcher.needs_more_vals(arg) {
1181 debug!(
1182 "Parser::react not enough values passed in, leaving it to the validator to complain",
1183 );
1184 }
1185 Ok(ParseResult::ValuesDone)
1186 }
1187 ArgAction::SetTrue => {
1188 let raw_vals = if raw_vals.is_empty() {
1189 vec![OsString::from("true")]
1190 } else {
1191 raw_vals
1192 };
1193
1194 if matcher.remove(arg.get_id())
1195 && !(self.cmd.is_args_override_self() || arg.overrides.contains(arg.get_id()))
1196 {
1197 return Err(ClapError::argument_conflict(
1198 self.cmd,
1199 arg.to_string(),
1200 vec![arg.to_string()],
1201 Usage::new(self.cmd).create_usage_with_title(&[]),
1202 ));
1203 }
1204 self.start_custom_arg(matcher, arg, source);
1205 ok!(self.push_arg_values(arg, raw_vals, source, matcher));
1206 Ok(ParseResult::ValuesDone)
1207 }
1208 ArgAction::SetFalse => {
1209 let raw_vals = if raw_vals.is_empty() {
1210 vec![OsString::from("false")]
1211 } else {
1212 raw_vals
1213 };
1214
1215 if matcher.remove(arg.get_id())
1216 && !(self.cmd.is_args_override_self() || arg.overrides.contains(arg.get_id()))
1217 {
1218 return Err(ClapError::argument_conflict(
1219 self.cmd,
1220 arg.to_string(),
1221 vec![arg.to_string()],
1222 Usage::new(self.cmd).create_usage_with_title(&[]),
1223 ));
1224 }
1225 self.start_custom_arg(matcher, arg, source);
1226 ok!(self.push_arg_values(arg, raw_vals, source, matcher));
1227 Ok(ParseResult::ValuesDone)
1228 }
1229 ArgAction::Count => {
1230 let raw_vals = if raw_vals.is_empty() {
1231 let existing_value = *matcher
1232 .get_one::<crate::builder::CountType>(arg.get_id().as_str())
1233 .unwrap_or(&0);
1234 let next_value = existing_value.saturating_add(1);
1235 vec![OsString::from(next_value.to_string())]
1236 } else {
1237 raw_vals
1238 };
1239
1240 matcher.remove(arg.get_id());
1241 self.start_custom_arg(matcher, arg, source);
1242 ok!(self.push_arg_values(arg, raw_vals, source, matcher));
1243 Ok(ParseResult::ValuesDone)
1244 }
1245 ArgAction::Help => {
1246 let use_long = match ident {
1247 Some(Identifier::Long) => true,
1248 Some(Identifier::Short) => false,
1249 Some(Identifier::Index) => true,
1250 None => true,
1251 };
1252 debug!("Help: use_long={use_long}");
1253 Err(self.help_err(use_long))
1254 }
1255 ArgAction::HelpShort => {
1256 let use_long = false;
1257 debug!("Help: use_long={use_long}");
1258 Err(self.help_err(use_long))
1259 }
1260 ArgAction::HelpLong => {
1261 let use_long = true;
1262 debug!("Help: use_long={use_long}");
1263 Err(self.help_err(use_long))
1264 }
1265 ArgAction::Version => {
1266 let use_long = match ident {
1267 Some(Identifier::Long) => true,
1268 Some(Identifier::Short) => false,
1269 Some(Identifier::Index) => true,
1270 None => true,
1271 };
1272 debug!("Version: use_long={use_long}");
1273 Err(self.version_err(use_long))
1274 }
1275 }
1276 }
1277
1278 fn verify_num_args(&self, arg: &Arg, raw_vals: &[OsString]) -> ClapResult<()> {
1279 if self.cmd.is_ignore_errors_set() {
1280 return Ok(());
1281 }
1282
1283 let actual = raw_vals.len();
1284 let expected = arg.get_num_args().expect(INTERNAL_ERROR_MSG);
1285
1286 if 0 < expected.min_values() && actual == 0 {
1287 // Issue 665 (https://github.com/clap-rs/clap/issues/665)
1288 // Issue 1105 (https://github.com/clap-rs/clap/issues/1105)
1289 return Err(ClapError::empty_value(
1290 self.cmd,
1291 &super::get_possible_values_cli(arg)
1292 .iter()
1293 .filter(|pv| !pv.is_hide_set())
1294 .map(|n| n.get_name().to_owned())
1295 .collect::<Vec<_>>(),
1296 arg.to_string(),
1297 ));
1298 } else if let Some(expected) = expected.num_values() {
1299 if expected != actual {
1300 debug!("Validator::validate_arg_num_vals: Sending error WrongNumberOfValues");
1301 return Err(ClapError::wrong_number_of_values(
1302 self.cmd,
1303 arg.to_string(),
1304 expected,
1305 actual,
1306 Usage::new(self.cmd).create_usage_with_title(&[]),
1307 ));
1308 }
1309 } else if actual < expected.min_values() {
1310 return Err(ClapError::too_few_values(
1311 self.cmd,
1312 arg.to_string(),
1313 expected.min_values(),
1314 actual,
1315 Usage::new(self.cmd).create_usage_with_title(&[]),
1316 ));
1317 } else if expected.max_values() < actual {
1318 debug!("Validator::validate_arg_num_vals: Sending error TooManyValues");
1319 return Err(ClapError::too_many_values(
1320 self.cmd,
1321 raw_vals
1322 .last()
1323 .expect(INTERNAL_ERROR_MSG)
1324 .to_string_lossy()
1325 .into_owned(),
1326 arg.to_string(),
1327 Usage::new(self.cmd).create_usage_with_title(&[]),
1328 ));
1329 }
1330
1331 Ok(())
1332 }
1333
1334 fn remove_overrides(&self, arg: &Arg, matcher: &mut ArgMatcher) {
1335 debug!("Parser::remove_overrides: id={:?}", arg.id);
1336 for override_id in &arg.overrides {
1337 debug!("Parser::remove_overrides:iter:{override_id:?}: removing");
1338 matcher.remove(override_id);
1339 }
1340
1341 // Override anything that can override us
1342 let mut transitive = Vec::new();
1343 for arg_id in matcher.arg_ids() {
1344 if let Some(overrider) = self.cmd.find(arg_id) {
1345 if overrider.overrides.contains(arg.get_id()) {
1346 transitive.push(overrider.get_id());
1347 }
1348 }
1349 }
1350 for overrider_id in transitive {
1351 debug!("Parser::remove_overrides:iter:{overrider_id:?}: removing");
1352 matcher.remove(overrider_id);
1353 }
1354 }
1355
1356 #[cfg(feature = "env")]
1357 fn add_env(&mut self, matcher: &mut ArgMatcher) -> ClapResult<()> {
1358 debug!("Parser::add_env");
1359
1360 for arg in self.cmd.get_arguments() {
1361 // Use env only if the arg was absent among command line args,
1362 // early return if this is not the case.
1363 if matcher.contains(&arg.id) {
1364 debug!("Parser::add_env: Skipping existing arg `{arg}`");
1365 continue;
1366 }
1367
1368 debug!("Parser::add_env: Checking arg `{arg}`");
1369 if let Some((_, Some(ref val))) = arg.env {
1370 debug!("Parser::add_env: Found an opt with value={val:?}");
1371 let arg_values = vec![val.to_owned()];
1372 let trailing_idx = None;
1373 let _ = ok!(self.react(
1374 None,
1375 ValueSource::EnvVariable,
1376 arg,
1377 arg_values,
1378 trailing_idx,
1379 matcher,
1380 ));
1381 }
1382 }
1383
1384 Ok(())
1385 }
1386
1387 fn add_defaults(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
1388 debug!("Parser::add_defaults");
1389
1390 for arg in self.cmd.get_arguments() {
1391 debug!("Parser::add_defaults:iter:{}:", arg.get_id());
1392 ok!(self.add_default_value(arg, matcher));
1393 }
1394
1395 Ok(())
1396 }
1397
1398 fn add_default_value(&self, arg: &Arg, matcher: &mut ArgMatcher) -> ClapResult<()> {
1399 if !arg.default_vals_ifs.is_empty() {
1400 debug!("Parser::add_default_value: has conditional defaults");
1401 if !matcher.contains(arg.get_id()) {
1402 for (id, val, default) in arg.default_vals_ifs.iter() {
1403 let add = if let Some(a) = matcher.get(id) {
1404 match val {
1405 crate::builder::ArgPredicate::Equals(v) => {
1406 a.raw_vals_flatten().any(|value| v == value)
1407 }
1408 crate::builder::ArgPredicate::IsPresent => true,
1409 }
1410 } else {
1411 false
1412 };
1413
1414 if add {
1415 if let Some(default) = default {
1416 let arg_values = vec![default.to_os_string()];
1417 let trailing_idx = None;
1418 let _ = ok!(self.react(
1419 None,
1420 ValueSource::DefaultValue,
1421 arg,
1422 arg_values,
1423 trailing_idx,
1424 matcher,
1425 ));
1426 }
1427 return Ok(());
1428 }
1429 }
1430 }
1431 } else {
1432 debug!("Parser::add_default_value: doesn't have conditional defaults");
1433 }
1434
1435 if !arg.default_vals.is_empty() {
1436 debug!(
1437 "Parser::add_default_value:iter:{}: has default vals",
1438 arg.get_id()
1439 );
1440 if matcher.contains(arg.get_id()) {
1441 debug!("Parser::add_default_value:iter:{}: was used", arg.get_id());
1442 // do nothing
1443 } else {
1444 debug!(
1445 "Parser::add_default_value:iter:{}: wasn't used",
1446 arg.get_id()
1447 );
1448 let arg_values: Vec<_> = arg
1449 .default_vals
1450 .iter()
1451 .map(crate::builder::OsStr::to_os_string)
1452 .collect();
1453 let trailing_idx = None;
1454 let _ = ok!(self.react(
1455 None,
1456 ValueSource::DefaultValue,
1457 arg,
1458 arg_values,
1459 trailing_idx,
1460 matcher,
1461 ));
1462 }
1463 } else {
1464 debug!(
1465 "Parser::add_default_value:iter:{}: doesn't have default vals",
1466 arg.get_id()
1467 );
1468
1469 // do nothing
1470 }
1471
1472 Ok(())
1473 }
1474
1475 fn start_custom_arg(&self, matcher: &mut ArgMatcher, arg: &Arg, source: ValueSource) {
1476 if source == ValueSource::CommandLine {
1477 // With each new occurrence, remove overrides from prior occurrences
1478 self.remove_overrides(arg, matcher);
1479 }
1480 matcher.start_custom_arg(arg, source);
1481 if source.is_explicit() {
1482 for group in self.cmd.groups_for_arg(arg.get_id()) {
1483 matcher.start_custom_group(group.clone(), source);
1484 matcher.add_val_to(
1485 &group,
1486 AnyValue::new(arg.get_id().clone()),
1487 OsString::from(arg.get_id().as_str()),
1488 );
1489 }
1490 }
1491 }
1492}
1493
1494// Error, Help, and Version Methods
1495impl<'cmd> Parser<'cmd> {
1496 /// Is only used for the long flag(which is the only one needs fuzzy searching)
1497 fn did_you_mean_error(
1498 &mut self,
1499 arg: &str,
1500 matcher: &mut ArgMatcher,
1501 remaining_args: &[&OsStr],
1502 trailing_values: bool,
1503 ) -> ClapError {
1504 debug!("Parser::did_you_mean_error: arg={arg}");
1505 // Didn't match a flag or option
1506 let longs = self
1507 .cmd
1508 .get_keymap()
1509 .keys()
1510 .filter_map(|x| match x {
1511 KeyType::Long(l) => Some(l.to_string_lossy().into_owned()),
1512 _ => None,
1513 })
1514 .collect::<Vec<_>>();
1515 debug!("Parser::did_you_mean_error: longs={longs:?}");
1516
1517 let did_you_mean = suggestions::did_you_mean_flag(
1518 arg,
1519 remaining_args,
1520 longs.iter().map(|x| &x[..]),
1521 self.cmd.get_subcommands_mut(),
1522 );
1523
1524 // Add the arg to the matches to build a proper usage string
1525 if let Some((name, _)) = did_you_mean.as_ref() {
1526 if let Some(arg) = self.cmd.get_keymap().get(&name.as_ref()) {
1527 self.start_custom_arg(matcher, arg, ValueSource::CommandLine);
1528 }
1529 }
1530 let did_you_mean = did_you_mean.map(|(arg, cmd)| (format!("--{arg}"), cmd));
1531
1532 let required = self.cmd.required_graph();
1533 let used: Vec<Id> = matcher
1534 .arg_ids()
1535 .filter(|arg_id| {
1536 matcher.check_explicit(arg_id, &crate::builder::ArgPredicate::IsPresent)
1537 })
1538 .filter(|n| self.cmd.find(n).map(|a| !a.is_hide_set()).unwrap_or(true))
1539 .cloned()
1540 .collect();
1541
1542 // `did_you_mean` is a lot more likely and should cause us to skip the `--` suggestion
1543 //
1544 // In theory, this is only called for `--long`s, so we don't need to check
1545 let suggested_trailing_arg =
1546 did_you_mean.is_none() && !trailing_values && self.cmd.has_positionals();
1547 ClapError::unknown_argument(
1548 self.cmd,
1549 format!("--{arg}"),
1550 did_you_mean,
1551 suggested_trailing_arg,
1552 Usage::new(self.cmd)
1553 .required(&required)
1554 .create_usage_with_title(&used),
1555 )
1556 }
1557
1558 fn help_err(&self, use_long: bool) -> ClapError {
1559 let styled = self.cmd.write_help_err(use_long);
1560 ClapError::display_help(self.cmd, styled)
1561 }
1562
1563 fn version_err(&self, use_long: bool) -> ClapError {
1564 let styled = self.cmd.write_version_err(use_long);
1565 ClapError::display_version(self.cmd, styled)
1566 }
1567}
1568
1569#[derive(Debug, PartialEq, Eq)]
1570pub(crate) enum ParseState {
1571 ValuesDone,
1572 Opt(Id),
1573 Pos(Id),
1574}
1575
1576/// Recoverable Parsing results.
1577#[derive(Debug, PartialEq, Clone)]
1578#[must_use]
1579enum ParseResult {
1580 FlagSubCommand(String),
1581 Opt(Id),
1582 ValuesDone,
1583 /// Value attached to the short flag is not consumed(e.g. 'u' for `-cu` is
1584 /// not consumed).
1585 AttachedValueNotConsumed,
1586 /// This long flag doesn't need a value but is provided one.
1587 UnneededAttachedValue {
1588 rest: String,
1589 used: Vec<Id>,
1590 arg: String,
1591 },
1592 /// This flag might be an hyphen Value.
1593 MaybeHyphenValue,
1594 /// Equals required but not provided.
1595 EqualsNotProvided {
1596 arg: String,
1597 },
1598 /// Failed to match a Arg.
1599 NoMatchingArg {
1600 arg: String,
1601 },
1602 /// No argument found e.g. parser is given `-` when parsing a flag.
1603 NoArg,
1604}
1605
1606#[derive(Clone, Debug, PartialEq, Eq)]
1607pub(crate) struct PendingArg {
1608 pub(crate) id: Id,
1609 pub(crate) ident: Option<Identifier>,
1610 pub(crate) raw_vals: Vec<OsString>,
1611 pub(crate) trailing_idx: Option<usize>,
1612}
1613
1614#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1615pub(crate) enum Identifier {
1616 Short,
1617 Long,
1618 Index,
1619}
1620