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.get_bin_name_fallback().to_owned(),
505 suggested_trailing_arg,
506 Usage::new(self.cmd).create_usage_with_title(&[]),
507 );
508 }
509
510 // If the argument must be a subcommand.
511 if self.cmd.has_subcommands()
512 && (!self.cmd.has_positionals() || self.cmd.is_infer_subcommands_set())
513 {
514 return ClapError::unrecognized_subcommand(
515 self.cmd,
516 arg_os.display().to_string(),
517 Usage::new(self.cmd).create_usage_with_title(&[]),
518 );
519 }
520 }
521
522 ClapError::unknown_argument(
523 self.cmd,
524 arg_os.display().to_string(),
525 None,
526 suggested_trailing_arg,
527 Usage::new(self.cmd).create_usage_with_title(&[]),
528 )
529 }
530
531 // Checks if the arg matches a subcommand name, or any of its aliases (if defined)
532 fn possible_subcommand(
533 &self,
534 arg: Result<&str, &OsStr>,
535 valid_arg_found: bool,
536 ) -> Option<&str> {
537 debug!("Parser::possible_subcommand: arg={arg:?}");
538 let arg = some!(arg.ok());
539
540 if !(self.cmd.is_args_conflicts_with_subcommands_set() && valid_arg_found) {
541 if self.cmd.is_infer_subcommands_set() {
542 // For subcommand `test`, we accepts it's prefix: `t`, `te`,
543 // `tes` and `test`.
544 let mut iter = self.cmd.get_subcommands().filter_map(|s| {
545 if s.get_name().starts_with(arg) {
546 return Some(s.get_name());
547 }
548
549 // Use find here instead of chaining the iterator because we want to accept
550 // conflicts in aliases.
551 s.get_all_aliases().find(|s| s.starts_with(arg))
552 });
553
554 if let name @ Some(_) = iter.next() {
555 if iter.next().is_none() {
556 return name;
557 }
558 }
559 }
560 // Don't use an else here because we want inference to support exact matching even if
561 // there are conflicts.
562 if let Some(sc) = self.cmd.find_subcommand(arg) {
563 return Some(sc.get_name());
564 }
565 }
566 None
567 }
568
569 // Checks if the arg matches a long flag subcommand name, or any of its aliases (if defined)
570 fn possible_long_flag_subcommand(&self, arg: &str) -> Option<&str> {
571 debug!("Parser::possible_long_flag_subcommand: arg={arg:?}");
572 if self.cmd.is_infer_subcommands_set() {
573 let mut iter = self.cmd.get_subcommands().filter_map(|sc| {
574 sc.get_long_flag().and_then(|long| {
575 if long.starts_with(arg) {
576 Some(sc.get_name())
577 } else {
578 sc.get_all_long_flag_aliases().find_map(|alias| {
579 if alias.starts_with(arg) {
580 Some(sc.get_name())
581 } else {
582 None
583 }
584 })
585 }
586 })
587 });
588
589 if let name @ Some(_) = iter.next() {
590 if iter.next().is_none() {
591 return name;
592 }
593 }
594 }
595 if let Some(sc_name) = self.cmd.find_long_subcmd(arg) {
596 return Some(sc_name);
597 }
598 None
599 }
600
601 fn parse_help_subcommand(
602 &self,
603 cmds: impl Iterator<Item = &'cmd OsStr>,
604 ) -> ClapResult<std::convert::Infallible> {
605 debug!("Parser::parse_help_subcommand");
606
607 let mut cmd = self.cmd.clone();
608 let sc = {
609 let mut sc = &mut cmd;
610
611 for cmd in cmds {
612 sc = if let Some(sc_name) =
613 sc.find_subcommand(cmd).map(|sc| sc.get_name().to_owned())
614 {
615 sc._build_subcommand(&sc_name).unwrap()
616 } else {
617 return Err(ClapError::unrecognized_subcommand(
618 sc,
619 cmd.to_string_lossy().into_owned(),
620 Usage::new(sc).create_usage_with_title(&[]),
621 ));
622 };
623 }
624
625 sc
626 };
627 let parser = Parser::new(sc);
628
629 Err(parser.help_err(true))
630 }
631
632 fn is_new_arg(&self, next: &clap_lex::ParsedArg<'_>, current_positional: &Arg) -> bool {
633 #![allow(clippy::needless_bool)] // Prefer consistent if/else-if ladder
634
635 debug!(
636 "Parser::is_new_arg: {:?}:{}",
637 next.to_value_os(),
638 current_positional.get_id()
639 );
640
641 if self.cmd[current_positional.get_id()].is_allow_hyphen_values_set()
642 || (self.cmd[current_positional.get_id()].is_allow_negative_numbers_set()
643 && next.is_negative_number())
644 {
645 // If allow hyphen, this isn't a new arg.
646 debug!("Parser::is_new_arg: Allow hyphen");
647 false
648 } else if next.is_long() {
649 // If this is a long flag, this is a new arg.
650 debug!("Parser::is_new_arg: --<something> found");
651 true
652 } else if next.is_short() {
653 // If this is a short flag, this is a new arg. But a singe '-' by
654 // itself is a value and typically means "stdin" on unix systems.
655 debug!("Parser::is_new_arg: -<something> found");
656 true
657 } else {
658 // Nothing special, this is a value.
659 debug!("Parser::is_new_arg: value");
660 false
661 }
662 }
663
664 fn parse_subcommand(
665 &mut self,
666 sc_name: &str,
667 matcher: &mut ArgMatcher,
668 raw_args: &mut clap_lex::RawArgs,
669 args_cursor: clap_lex::ArgCursor,
670 keep_state: bool,
671 ) -> ClapResult<()> {
672 debug!("Parser::parse_subcommand");
673
674 let partial_parsing_enabled = self.cmd.is_ignore_errors_set();
675
676 if let Some(sc) = self.cmd._build_subcommand(sc_name) {
677 let mut sc_matcher = ArgMatcher::new(sc);
678
679 debug!(
680 "Parser::parse_subcommand: About to parse sc={}",
681 sc.get_name()
682 );
683
684 {
685 let mut p = Parser::new(sc);
686 // HACK: maintain indexes between parsers
687 // FlagSubCommand short arg needs to revisit the current short args, but skip the subcommand itself
688 if keep_state {
689 p.cur_idx.set(self.cur_idx.get());
690 p.flag_subcmd_at = self.flag_subcmd_at;
691 p.flag_subcmd_skip = self.flag_subcmd_skip;
692 }
693 if let Err(error) = p.get_matches_with(&mut sc_matcher, raw_args, args_cursor) {
694 if partial_parsing_enabled {
695 debug!("Parser::parse_subcommand: ignored error in subcommand {sc_name}: {error:?}");
696 } else {
697 return Err(error);
698 }
699 }
700 }
701 matcher.subcommand(SubCommand {
702 name: sc.get_name().to_owned(),
703 matches: sc_matcher.into_inner(),
704 });
705 }
706 Ok(())
707 }
708
709 fn parse_long_arg(
710 &mut self,
711 matcher: &mut ArgMatcher,
712 long_arg: Result<&str, &OsStr>,
713 long_value: Option<&OsStr>,
714 parse_state: &ParseState,
715 pos_counter: usize,
716 valid_arg_found: &mut bool,
717 ) -> ClapResult<ParseResult> {
718 // maybe here lifetime should be 'a
719 debug!("Parser::parse_long_arg");
720
721 #[allow(clippy::blocks_in_if_conditions)]
722 if matches!(parse_state, ParseState::Opt(opt) | ParseState::Pos(opt) if
723 self.cmd[opt].is_allow_hyphen_values_set())
724 {
725 debug!("Parser::parse_long_arg: prior arg accepts hyphenated values",);
726 return Ok(ParseResult::MaybeHyphenValue);
727 }
728
729 debug!("Parser::parse_long_arg: Does it contain '='...");
730 let long_arg = match long_arg {
731 Ok(long_arg) => long_arg,
732 Err(long_arg_os) => {
733 return Ok(ParseResult::NoMatchingArg {
734 arg: long_arg_os.to_string_lossy().into_owned(),
735 })
736 }
737 };
738 if long_arg.is_empty() {
739 debug_assert!(
740 long_value.is_some(),
741 "`--` should be filtered out before this point"
742 );
743 }
744
745 let arg = if let Some(arg) = self.cmd.get_keymap().get(long_arg) {
746 debug!("Parser::parse_long_arg: Found valid arg or flag '{arg}'");
747 Some((long_arg, arg))
748 } else if self.cmd.is_infer_long_args_set() {
749 let mut iter = self.cmd.get_arguments().filter_map(|a| {
750 if let Some(long) = a.get_long() {
751 if long.starts_with(long_arg) {
752 return Some((long, a));
753 }
754 }
755 a.aliases
756 .iter()
757 .find_map(|(alias, _)| alias.starts_with(long_arg).then(|| (alias.as_str(), a)))
758 });
759
760 iter.next().filter(|_| iter.next().is_none())
761 } else {
762 None
763 };
764
765 if let Some((_long_arg, arg)) = arg {
766 let ident = Identifier::Long;
767 *valid_arg_found = true;
768 if arg.is_takes_value_set() {
769 debug!(
770 "Parser::parse_long_arg({:?}): Found an arg with value '{:?}'",
771 long_arg, &long_value
772 );
773 let has_eq = long_value.is_some();
774 self.parse_opt_value(ident, long_value, arg, matcher, has_eq)
775 } else if let Some(rest) = long_value {
776 let required = self.cmd.required_graph();
777 debug!("Parser::parse_long_arg({long_arg:?}): Got invalid literal `{rest:?}`");
778 let mut used: Vec<Id> = matcher
779 .arg_ids()
780 .filter(|arg_id| {
781 matcher.check_explicit(arg_id, &crate::builder::ArgPredicate::IsPresent)
782 })
783 .filter(|&n| {
784 self.cmd
785 .find(n)
786 .map(|a| !(a.is_hide_set() || required.contains(a.get_id())))
787 .unwrap_or(true)
788 })
789 .cloned()
790 .collect();
791 used.push(arg.get_id().clone());
792
793 Ok(ParseResult::UnneededAttachedValue {
794 rest: rest.to_string_lossy().into_owned(),
795 used,
796 arg: arg.to_string(),
797 })
798 } else {
799 debug!("Parser::parse_long_arg({long_arg:?}): Presence validated");
800 let trailing_idx = None;
801 self.react(
802 Some(ident),
803 ValueSource::CommandLine,
804 arg,
805 vec![],
806 trailing_idx,
807 matcher,
808 )
809 }
810 } else if let Some(sc_name) = self.possible_long_flag_subcommand(long_arg) {
811 Ok(ParseResult::FlagSubCommand(sc_name.to_string()))
812 } else if self
813 .cmd
814 .get_keymap()
815 .get(&pos_counter)
816 .map(|arg| arg.is_allow_hyphen_values_set() && !arg.is_last_set())
817 .unwrap_or_default()
818 {
819 debug!("Parser::parse_long_args: positional at {pos_counter} allows hyphens");
820 Ok(ParseResult::MaybeHyphenValue)
821 } else {
822 Ok(ParseResult::NoMatchingArg {
823 arg: long_arg.to_owned(),
824 })
825 }
826 }
827
828 fn parse_short_arg(
829 &mut self,
830 matcher: &mut ArgMatcher,
831 mut short_arg: clap_lex::ShortFlags<'_>,
832 parse_state: &ParseState,
833 // change this to possible pos_arg when removing the usage of &mut Parser.
834 pos_counter: usize,
835 valid_arg_found: &mut bool,
836 ) -> ClapResult<ParseResult> {
837 debug!("Parser::parse_short_arg: short_arg={short_arg:?}");
838
839 #[allow(clippy::blocks_in_if_conditions)]
840 if matches!(parse_state, ParseState::Opt(opt) | ParseState::Pos(opt)
841 if self.cmd[opt].is_allow_hyphen_values_set() || (self.cmd[opt].is_allow_negative_numbers_set() && short_arg.is_negative_number()))
842 {
843 debug!("Parser::parse_short_args: prior arg accepts hyphenated values",);
844 return Ok(ParseResult::MaybeHyphenValue);
845 } else if self
846 .cmd
847 .get_keymap()
848 .get(&pos_counter)
849 .map(|arg| arg.is_allow_negative_numbers_set())
850 .unwrap_or_default()
851 && short_arg.is_negative_number()
852 {
853 debug!("Parser::parse_short_arg: negative number");
854 return Ok(ParseResult::MaybeHyphenValue);
855 } else if self
856 .cmd
857 .get_keymap()
858 .get(&pos_counter)
859 .map(|arg| arg.is_allow_hyphen_values_set() && !arg.is_last_set())
860 .unwrap_or_default()
861 && short_arg
862 .clone()
863 .any(|c| !c.map(|c| self.cmd.contains_short(c)).unwrap_or_default())
864 {
865 debug!("Parser::parse_short_args: positional at {pos_counter} allows hyphens");
866 return Ok(ParseResult::MaybeHyphenValue);
867 }
868
869 let mut ret = ParseResult::NoArg;
870
871 let skip = self.flag_subcmd_skip;
872 self.flag_subcmd_skip = 0;
873 let res = short_arg.advance_by(skip);
874 debug_assert_eq!(
875 res,
876 Ok(()),
877 "tracking of `flag_subcmd_skip` is off for `{short_arg:?}`"
878 );
879 while let Some(c) = short_arg.next_flag() {
880 let c = match c {
881 Ok(c) => c,
882 Err(rest) => {
883 return Ok(ParseResult::NoMatchingArg {
884 arg: format!("-{}", rest.to_string_lossy()),
885 });
886 }
887 };
888 debug!("Parser::parse_short_arg:iter:{c}");
889
890 // Check for matching short options, and return the name if there is no trailing
891 // concatenated value: -oval
892 // Option: -o
893 // Value: val
894 if let Some(arg) = self.cmd.get_keymap().get(&c) {
895 let ident = Identifier::Short;
896 debug!("Parser::parse_short_arg:iter:{c}: Found valid opt or flag");
897 *valid_arg_found = true;
898 if !arg.is_takes_value_set() {
899 let arg_values = Vec::new();
900 let trailing_idx = None;
901 ret = ok!(self.react(
902 Some(ident),
903 ValueSource::CommandLine,
904 arg,
905 arg_values,
906 trailing_idx,
907 matcher,
908 ));
909 continue;
910 }
911
912 // Check for trailing concatenated value
913 //
914 // Cloning the iterator, so we rollback if it isn't there.
915 let val = short_arg.clone().next_value_os().unwrap_or_default();
916 debug!("Parser::parse_short_arg:iter:{c}: val={val:?}, short_arg={short_arg:?}");
917 let val = Some(val).filter(|v| !v.is_empty());
918
919 // Default to "we're expecting a value later".
920 //
921 // If attached value is not consumed, we may have more short
922 // flags to parse, continue.
923 //
924 // e.g. `-xvf`, when require_equals && x.min_vals == 0, we don't
925 // consume the `vf`, even if it's provided as value.
926 let (val, has_eq) = if let Some(val) = val.and_then(|v| v.strip_prefix("=")) {
927 (Some(val), true)
928 } else {
929 (val, false)
930 };
931 match ok!(self.parse_opt_value(ident, val, arg, matcher, has_eq)) {
932 ParseResult::AttachedValueNotConsumed => continue,
933 x => return Ok(x),
934 }
935 }
936
937 return if let Some(sc_name) = self.cmd.find_short_subcmd(c) {
938 debug!("Parser::parse_short_arg:iter:{c}: subcommand={sc_name}");
939 // Make sure indices get updated before reading `self.cur_idx`
940 ok!(self.resolve_pending(matcher));
941 self.cur_idx.set(self.cur_idx.get() + 1);
942 debug!("Parser::parse_short_arg: cur_idx:={}", self.cur_idx.get());
943
944 let name = sc_name.to_string();
945 // Get the index of the previously saved flag subcommand in the group of flags (if exists).
946 // If it is a new flag subcommand, then the formentioned index should be the current one
947 // (ie. `cur_idx`), and should be registered.
948 let cur_idx = self.cur_idx.get();
949 self.flag_subcmd_at.get_or_insert(cur_idx);
950 let done_short_args = short_arg.is_empty();
951 if done_short_args {
952 self.flag_subcmd_at = None;
953 }
954 Ok(ParseResult::FlagSubCommand(name))
955 } else {
956 Ok(ParseResult::NoMatchingArg {
957 arg: format!("-{c}"),
958 })
959 };
960 }
961 Ok(ret)
962 }
963
964 fn parse_opt_value(
965 &self,
966 ident: Identifier,
967 attached_value: Option<&OsStr>,
968 arg: &Arg,
969 matcher: &mut ArgMatcher,
970 has_eq: bool,
971 ) -> ClapResult<ParseResult> {
972 debug!(
973 "Parser::parse_opt_value; arg={}, val={:?}, has_eq={:?}",
974 arg.get_id(),
975 attached_value,
976 has_eq
977 );
978 debug!("Parser::parse_opt_value; arg.settings={:?}", arg.settings);
979
980 debug!("Parser::parse_opt_value; Checking for val...");
981 // require_equals is set, but no '=' is provided, try throwing error.
982 if arg.is_require_equals_set() && !has_eq {
983 if arg.get_min_vals() == 0 {
984 debug!("Requires equals, but min_vals == 0");
985 let arg_values = Vec::new();
986 let trailing_idx = None;
987 let react_result = ok!(self.react(
988 Some(ident),
989 ValueSource::CommandLine,
990 arg,
991 arg_values,
992 trailing_idx,
993 matcher,
994 ));
995 debug_assert_eq!(react_result, ParseResult::ValuesDone);
996 if attached_value.is_some() {
997 Ok(ParseResult::AttachedValueNotConsumed)
998 } else {
999 Ok(ParseResult::ValuesDone)
1000 }
1001 } else {
1002 debug!("Requires equals but not provided. Error.");
1003 Ok(ParseResult::EqualsNotProvided {
1004 arg: arg.to_string(),
1005 })
1006 }
1007 } else if let Some(v) = attached_value {
1008 let arg_values = vec![v.to_owned()];
1009 let trailing_idx = None;
1010 let react_result = ok!(self.react(
1011 Some(ident),
1012 ValueSource::CommandLine,
1013 arg,
1014 arg_values,
1015 trailing_idx,
1016 matcher,
1017 ));
1018 debug_assert_eq!(react_result, ParseResult::ValuesDone);
1019 // Attached are always done
1020 Ok(ParseResult::ValuesDone)
1021 } else {
1022 debug!("Parser::parse_opt_value: More arg vals required...");
1023 ok!(self.resolve_pending(matcher));
1024 let trailing_values = false;
1025 matcher.pending_values_mut(arg.get_id(), Some(ident), trailing_values);
1026 Ok(ParseResult::Opt(arg.get_id().clone()))
1027 }
1028 }
1029
1030 fn check_terminator(&self, arg: &Arg, val: &OsStr) -> Option<ParseResult> {
1031 if Some(val) == arg.terminator.as_ref().map(|s| OsStr::new(s.as_str())) {
1032 debug!("Parser::check_terminator: terminator={:?}", arg.terminator);
1033 Some(ParseResult::ValuesDone)
1034 } else {
1035 None
1036 }
1037 }
1038
1039 fn push_arg_values(
1040 &self,
1041 arg: &Arg,
1042 raw_vals: Vec<OsString>,
1043 source: ValueSource,
1044 matcher: &mut ArgMatcher,
1045 ) -> ClapResult<()> {
1046 debug!("Parser::push_arg_values: {raw_vals:?}");
1047
1048 for raw_val in raw_vals {
1049 // update the current index because each value is a distinct index to clap
1050 self.cur_idx.set(self.cur_idx.get() + 1);
1051 debug!(
1052 "Parser::add_single_val_to_arg: cur_idx:={}",
1053 self.cur_idx.get()
1054 );
1055 let value_parser = arg.get_value_parser();
1056 let val = ok!(value_parser.parse_ref(self.cmd, Some(arg), &raw_val, source));
1057
1058 matcher.add_val_to(arg.get_id(), val, raw_val);
1059 matcher.add_index_to(arg.get_id(), self.cur_idx.get());
1060 }
1061
1062 Ok(())
1063 }
1064
1065 fn resolve_pending(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
1066 let pending = match matcher.take_pending() {
1067 Some(pending) => pending,
1068 None => {
1069 return Ok(());
1070 }
1071 };
1072
1073 debug!("Parser::resolve_pending: id={:?}", pending.id);
1074 let arg = self.cmd.find(&pending.id).expect(INTERNAL_ERROR_MSG);
1075 let _ = ok!(self.react(
1076 pending.ident,
1077 ValueSource::CommandLine,
1078 arg,
1079 pending.raw_vals,
1080 pending.trailing_idx,
1081 matcher,
1082 ));
1083
1084 Ok(())
1085 }
1086
1087 fn react(
1088 &self,
1089 ident: Option<Identifier>,
1090 source: ValueSource,
1091 arg: &Arg,
1092 mut raw_vals: Vec<OsString>,
1093 mut trailing_idx: Option<usize>,
1094 matcher: &mut ArgMatcher,
1095 ) -> ClapResult<ParseResult> {
1096 ok!(self.resolve_pending(matcher));
1097
1098 debug!(
1099 "Parser::react action={:?}, identifier={:?}, source={:?}",
1100 arg.get_action(),
1101 ident,
1102 source
1103 );
1104
1105 // Process before `default_missing_values` to avoid it counting as values from the command
1106 // line
1107 if source == ValueSource::CommandLine {
1108 ok!(self.verify_num_args(arg, &raw_vals));
1109 }
1110
1111 if raw_vals.is_empty() {
1112 // We assume this case is valid: require equals, but min_vals == 0.
1113 if !arg.default_missing_vals.is_empty() {
1114 debug!("Parser::react: has default_missing_vals");
1115 trailing_idx = None;
1116 raw_vals.extend(
1117 arg.default_missing_vals
1118 .iter()
1119 .map(|s| s.as_os_str().to_owned()),
1120 );
1121 }
1122 }
1123
1124 if let Some(val_delim) = arg.get_value_delimiter() {
1125 if self.cmd.is_dont_delimit_trailing_values_set() && trailing_idx == Some(0) {
1126 // Nothing to do
1127 } else {
1128 let mut val_delim_buffer = [0; 4];
1129 let val_delim = val_delim.encode_utf8(&mut val_delim_buffer);
1130 let mut split_raw_vals = Vec::with_capacity(raw_vals.len());
1131 for (i, raw_val) in raw_vals.into_iter().enumerate() {
1132 if !raw_val.contains(val_delim)
1133 || (self.cmd.is_dont_delimit_trailing_values_set()
1134 && trailing_idx == Some(i))
1135 {
1136 split_raw_vals.push(raw_val);
1137 } else {
1138 split_raw_vals.extend(raw_val.split(val_delim).map(|x| x.to_owned()));
1139 }
1140 }
1141 raw_vals = split_raw_vals
1142 }
1143 }
1144
1145 match arg.get_action() {
1146 ArgAction::Set => {
1147 if source == ValueSource::CommandLine
1148 && matches!(ident, Some(Identifier::Short) | Some(Identifier::Long))
1149 {
1150 // Record flag's index
1151 self.cur_idx.set(self.cur_idx.get() + 1);
1152 debug!("Parser::react: cur_idx:={}", self.cur_idx.get());
1153 }
1154 if matcher.remove(arg.get_id())
1155 && !(self.cmd.is_args_override_self() || arg.overrides.contains(arg.get_id()))
1156 {
1157 return Err(ClapError::argument_conflict(
1158 self.cmd,
1159 arg.to_string(),
1160 vec![arg.to_string()],
1161 Usage::new(self.cmd).create_usage_with_title(&[]),
1162 ));
1163 }
1164 self.start_custom_arg(matcher, arg, source);
1165 ok!(self.push_arg_values(arg, raw_vals, source, matcher));
1166 if cfg!(debug_assertions) && matcher.needs_more_vals(arg) {
1167 debug!(
1168 "Parser::react not enough values passed in, leaving it to the validator to complain",
1169 );
1170 }
1171 Ok(ParseResult::ValuesDone)
1172 }
1173 ArgAction::Append => {
1174 if source == ValueSource::CommandLine
1175 && matches!(ident, Some(Identifier::Short) | Some(Identifier::Long))
1176 {
1177 // Record flag's index
1178 self.cur_idx.set(self.cur_idx.get() + 1);
1179 debug!("Parser::react: cur_idx:={}", self.cur_idx.get());
1180 }
1181 self.start_custom_arg(matcher, arg, source);
1182 ok!(self.push_arg_values(arg, raw_vals, source, matcher));
1183 if cfg!(debug_assertions) && matcher.needs_more_vals(arg) {
1184 debug!(
1185 "Parser::react not enough values passed in, leaving it to the validator to complain",
1186 );
1187 }
1188 Ok(ParseResult::ValuesDone)
1189 }
1190 ArgAction::SetTrue => {
1191 let raw_vals = if raw_vals.is_empty() {
1192 vec![OsString::from("true")]
1193 } else {
1194 raw_vals
1195 };
1196
1197 if matcher.remove(arg.get_id())
1198 && !(self.cmd.is_args_override_self() || arg.overrides.contains(arg.get_id()))
1199 {
1200 return Err(ClapError::argument_conflict(
1201 self.cmd,
1202 arg.to_string(),
1203 vec![arg.to_string()],
1204 Usage::new(self.cmd).create_usage_with_title(&[]),
1205 ));
1206 }
1207 self.start_custom_arg(matcher, arg, source);
1208 ok!(self.push_arg_values(arg, raw_vals, source, matcher));
1209 Ok(ParseResult::ValuesDone)
1210 }
1211 ArgAction::SetFalse => {
1212 let raw_vals = if raw_vals.is_empty() {
1213 vec![OsString::from("false")]
1214 } else {
1215 raw_vals
1216 };
1217
1218 if matcher.remove(arg.get_id())
1219 && !(self.cmd.is_args_override_self() || arg.overrides.contains(arg.get_id()))
1220 {
1221 return Err(ClapError::argument_conflict(
1222 self.cmd,
1223 arg.to_string(),
1224 vec![arg.to_string()],
1225 Usage::new(self.cmd).create_usage_with_title(&[]),
1226 ));
1227 }
1228 self.start_custom_arg(matcher, arg, source);
1229 ok!(self.push_arg_values(arg, raw_vals, source, matcher));
1230 Ok(ParseResult::ValuesDone)
1231 }
1232 ArgAction::Count => {
1233 let raw_vals = if raw_vals.is_empty() {
1234 let existing_value = *matcher
1235 .get_one::<crate::builder::CountType>(arg.get_id().as_str())
1236 .unwrap_or(&0);
1237 let next_value = existing_value.saturating_add(1);
1238 vec![OsString::from(next_value.to_string())]
1239 } else {
1240 raw_vals
1241 };
1242
1243 matcher.remove(arg.get_id());
1244 self.start_custom_arg(matcher, arg, source);
1245 ok!(self.push_arg_values(arg, raw_vals, source, matcher));
1246 Ok(ParseResult::ValuesDone)
1247 }
1248 ArgAction::Help => {
1249 let use_long = match ident {
1250 Some(Identifier::Long) => true,
1251 Some(Identifier::Short) => false,
1252 Some(Identifier::Index) => true,
1253 None => true,
1254 };
1255 debug!("Help: use_long={use_long}");
1256 Err(self.help_err(use_long))
1257 }
1258 ArgAction::HelpShort => {
1259 let use_long = false;
1260 debug!("Help: use_long={use_long}");
1261 Err(self.help_err(use_long))
1262 }
1263 ArgAction::HelpLong => {
1264 let use_long = true;
1265 debug!("Help: use_long={use_long}");
1266 Err(self.help_err(use_long))
1267 }
1268 ArgAction::Version => {
1269 let use_long = match ident {
1270 Some(Identifier::Long) => true,
1271 Some(Identifier::Short) => false,
1272 Some(Identifier::Index) => true,
1273 None => true,
1274 };
1275 debug!("Version: use_long={use_long}");
1276 Err(self.version_err(use_long))
1277 }
1278 }
1279 }
1280
1281 fn verify_num_args(&self, arg: &Arg, raw_vals: &[OsString]) -> ClapResult<()> {
1282 if self.cmd.is_ignore_errors_set() {
1283 return Ok(());
1284 }
1285
1286 let actual = raw_vals.len();
1287 let expected = arg.get_num_args().expect(INTERNAL_ERROR_MSG);
1288
1289 if 0 < expected.min_values() && actual == 0 {
1290 // Issue 665 (https://github.com/clap-rs/clap/issues/665)
1291 // Issue 1105 (https://github.com/clap-rs/clap/issues/1105)
1292 return Err(ClapError::empty_value(
1293 self.cmd,
1294 &super::get_possible_values_cli(arg)
1295 .iter()
1296 .filter(|pv| !pv.is_hide_set())
1297 .map(|n| n.get_name().to_owned())
1298 .collect::<Vec<_>>(),
1299 arg.to_string(),
1300 ));
1301 } else if let Some(expected) = expected.num_values() {
1302 if expected != actual {
1303 debug!("Validator::validate_arg_num_vals: Sending error WrongNumberOfValues");
1304 return Err(ClapError::wrong_number_of_values(
1305 self.cmd,
1306 arg.to_string(),
1307 expected,
1308 actual,
1309 Usage::new(self.cmd).create_usage_with_title(&[]),
1310 ));
1311 }
1312 } else if actual < expected.min_values() {
1313 return Err(ClapError::too_few_values(
1314 self.cmd,
1315 arg.to_string(),
1316 expected.min_values(),
1317 actual,
1318 Usage::new(self.cmd).create_usage_with_title(&[]),
1319 ));
1320 } else if expected.max_values() < actual {
1321 debug!("Validator::validate_arg_num_vals: Sending error TooManyValues");
1322 return Err(ClapError::too_many_values(
1323 self.cmd,
1324 raw_vals
1325 .last()
1326 .expect(INTERNAL_ERROR_MSG)
1327 .to_string_lossy()
1328 .into_owned(),
1329 arg.to_string(),
1330 Usage::new(self.cmd).create_usage_with_title(&[]),
1331 ));
1332 }
1333
1334 Ok(())
1335 }
1336
1337 fn remove_overrides(&self, arg: &Arg, matcher: &mut ArgMatcher) {
1338 debug!("Parser::remove_overrides: id={:?}", arg.id);
1339 for override_id in &arg.overrides {
1340 debug!("Parser::remove_overrides:iter:{override_id:?}: removing");
1341 matcher.remove(override_id);
1342 }
1343
1344 // Override anything that can override us
1345 let mut transitive = Vec::new();
1346 for arg_id in matcher.arg_ids() {
1347 if let Some(overrider) = self.cmd.find(arg_id) {
1348 if overrider.overrides.contains(arg.get_id()) {
1349 transitive.push(overrider.get_id());
1350 }
1351 }
1352 }
1353 for overrider_id in transitive {
1354 debug!("Parser::remove_overrides:iter:{overrider_id:?}: removing");
1355 matcher.remove(overrider_id);
1356 }
1357 }
1358
1359 #[cfg(feature = "env")]
1360 fn add_env(&mut self, matcher: &mut ArgMatcher) -> ClapResult<()> {
1361 debug!("Parser::add_env");
1362
1363 for arg in self.cmd.get_arguments() {
1364 // Use env only if the arg was absent among command line args,
1365 // early return if this is not the case.
1366 if matcher.contains(&arg.id) {
1367 debug!("Parser::add_env: Skipping existing arg `{arg}`");
1368 continue;
1369 }
1370
1371 debug!("Parser::add_env: Checking arg `{arg}`");
1372 if let Some((_, Some(ref val))) = arg.env {
1373 debug!("Parser::add_env: Found an opt with value={val:?}");
1374 let arg_values = vec![val.to_owned()];
1375 let trailing_idx = None;
1376 let _ = ok!(self.react(
1377 None,
1378 ValueSource::EnvVariable,
1379 arg,
1380 arg_values,
1381 trailing_idx,
1382 matcher,
1383 ));
1384 }
1385 }
1386
1387 Ok(())
1388 }
1389
1390 fn add_defaults(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
1391 debug!("Parser::add_defaults");
1392
1393 for arg in self.cmd.get_arguments() {
1394 debug!("Parser::add_defaults:iter:{}:", arg.get_id());
1395 ok!(self.add_default_value(arg, matcher));
1396 }
1397
1398 Ok(())
1399 }
1400
1401 fn add_default_value(&self, arg: &Arg, matcher: &mut ArgMatcher) -> ClapResult<()> {
1402 if !arg.default_vals_ifs.is_empty() {
1403 debug!("Parser::add_default_value: has conditional defaults");
1404 if !matcher.contains(arg.get_id()) {
1405 for (id, val, default) in arg.default_vals_ifs.iter() {
1406 let add = if let Some(a) = matcher.get(id) {
1407 match val {
1408 crate::builder::ArgPredicate::Equals(v) => {
1409 a.raw_vals_flatten().any(|value| v == value)
1410 }
1411 crate::builder::ArgPredicate::IsPresent => true,
1412 }
1413 } else {
1414 false
1415 };
1416
1417 if add {
1418 if let Some(default) = default {
1419 let arg_values = vec![default.to_os_string()];
1420 let trailing_idx = None;
1421 let _ = ok!(self.react(
1422 None,
1423 ValueSource::DefaultValue,
1424 arg,
1425 arg_values,
1426 trailing_idx,
1427 matcher,
1428 ));
1429 }
1430 return Ok(());
1431 }
1432 }
1433 }
1434 } else {
1435 debug!("Parser::add_default_value: doesn't have conditional defaults");
1436 }
1437
1438 if !arg.default_vals.is_empty() {
1439 debug!(
1440 "Parser::add_default_value:iter:{}: has default vals",
1441 arg.get_id()
1442 );
1443 if matcher.contains(arg.get_id()) {
1444 debug!("Parser::add_default_value:iter:{}: was used", arg.get_id());
1445 // do nothing
1446 } else {
1447 debug!(
1448 "Parser::add_default_value:iter:{}: wasn't used",
1449 arg.get_id()
1450 );
1451 let arg_values: Vec<_> = arg
1452 .default_vals
1453 .iter()
1454 .map(crate::builder::OsStr::to_os_string)
1455 .collect();
1456 let trailing_idx = None;
1457 let _ = ok!(self.react(
1458 None,
1459 ValueSource::DefaultValue,
1460 arg,
1461 arg_values,
1462 trailing_idx,
1463 matcher,
1464 ));
1465 }
1466 } else {
1467 debug!(
1468 "Parser::add_default_value:iter:{}: doesn't have default vals",
1469 arg.get_id()
1470 );
1471
1472 // do nothing
1473 }
1474
1475 Ok(())
1476 }
1477
1478 fn start_custom_arg(&self, matcher: &mut ArgMatcher, arg: &Arg, source: ValueSource) {
1479 if source == ValueSource::CommandLine {
1480 // With each new occurrence, remove overrides from prior occurrences
1481 self.remove_overrides(arg, matcher);
1482 }
1483 matcher.start_custom_arg(arg, source);
1484 if source.is_explicit() {
1485 for group in self.cmd.groups_for_arg(arg.get_id()) {
1486 matcher.start_custom_group(group.clone(), source);
1487 matcher.add_val_to(
1488 &group,
1489 AnyValue::new(arg.get_id().clone()),
1490 OsString::from(arg.get_id().as_str()),
1491 );
1492 }
1493 }
1494 }
1495}
1496
1497// Error, Help, and Version Methods
1498impl<'cmd> Parser<'cmd> {
1499 /// Is only used for the long flag(which is the only one needs fuzzy searching)
1500 fn did_you_mean_error(
1501 &mut self,
1502 arg: &str,
1503 matcher: &mut ArgMatcher,
1504 remaining_args: &[&OsStr],
1505 trailing_values: bool,
1506 ) -> ClapError {
1507 debug!("Parser::did_you_mean_error: arg={arg}");
1508 // Didn't match a flag or option
1509 let longs = self
1510 .cmd
1511 .get_keymap()
1512 .keys()
1513 .filter_map(|x| match x {
1514 KeyType::Long(l) => Some(l.to_string_lossy().into_owned()),
1515 _ => None,
1516 })
1517 .collect::<Vec<_>>();
1518 debug!("Parser::did_you_mean_error: longs={longs:?}");
1519
1520 let did_you_mean = suggestions::did_you_mean_flag(
1521 arg,
1522 remaining_args,
1523 longs.iter().map(|x| &x[..]),
1524 self.cmd.get_subcommands_mut(),
1525 );
1526
1527 // Add the arg to the matches to build a proper usage string
1528 if let Some((name, _)) = did_you_mean.as_ref() {
1529 if let Some(arg) = self.cmd.get_keymap().get(&name.as_ref()) {
1530 self.start_custom_arg(matcher, arg, ValueSource::CommandLine);
1531 }
1532 }
1533 let did_you_mean = did_you_mean.map(|(arg, cmd)| (format!("--{arg}"), cmd));
1534
1535 let required = self.cmd.required_graph();
1536 let used: Vec<Id> = matcher
1537 .arg_ids()
1538 .filter(|arg_id| {
1539 matcher.check_explicit(arg_id, &crate::builder::ArgPredicate::IsPresent)
1540 })
1541 .filter(|n| self.cmd.find(n).map(|a| !a.is_hide_set()).unwrap_or(true))
1542 .cloned()
1543 .collect();
1544
1545 // `did_you_mean` is a lot more likely and should cause us to skip the `--` suggestion
1546 //
1547 // In theory, this is only called for `--long`s, so we don't need to check
1548 let suggested_trailing_arg =
1549 did_you_mean.is_none() && !trailing_values && self.cmd.has_positionals();
1550 ClapError::unknown_argument(
1551 self.cmd,
1552 format!("--{arg}"),
1553 did_you_mean,
1554 suggested_trailing_arg,
1555 Usage::new(self.cmd)
1556 .required(&required)
1557 .create_usage_with_title(&used),
1558 )
1559 }
1560
1561 fn help_err(&self, use_long: bool) -> ClapError {
1562 let styled = self.cmd.write_help_err(use_long);
1563 ClapError::display_help(self.cmd, styled)
1564 }
1565
1566 fn version_err(&self, use_long: bool) -> ClapError {
1567 let styled = self.cmd.write_version_err(use_long);
1568 ClapError::display_version(self.cmd, styled)
1569 }
1570}
1571
1572#[derive(Debug, PartialEq, Eq)]
1573pub(crate) enum ParseState {
1574 ValuesDone,
1575 Opt(Id),
1576 Pos(Id),
1577}
1578
1579/// Recoverable Parsing results.
1580#[derive(Debug, PartialEq, Clone)]
1581#[must_use]
1582enum ParseResult {
1583 FlagSubCommand(String),
1584 Opt(Id),
1585 ValuesDone,
1586 /// Value attached to the short flag is not consumed(e.g. 'u' for `-cu` is
1587 /// not consumed).
1588 AttachedValueNotConsumed,
1589 /// This long flag doesn't need a value but is provided one.
1590 UnneededAttachedValue {
1591 rest: String,
1592 used: Vec<Id>,
1593 arg: String,
1594 },
1595 /// This flag might be an hyphen Value.
1596 MaybeHyphenValue,
1597 /// Equals required but not provided.
1598 EqualsNotProvided {
1599 arg: String,
1600 },
1601 /// Failed to match a Arg.
1602 NoMatchingArg {
1603 arg: String,
1604 },
1605 /// No argument found e.g. parser is given `-` when parsing a flag.
1606 NoArg,
1607}
1608
1609#[derive(Clone, Debug, PartialEq, Eq)]
1610pub(crate) struct PendingArg {
1611 pub(crate) id: Id,
1612 pub(crate) ident: Option<Identifier>,
1613 pub(crate) raw_vals: Vec<OsString>,
1614 pub(crate) trailing_idx: Option<usize>,
1615}
1616
1617#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1618pub(crate) enum Identifier {
1619 Short,
1620 Long,
1621 Index,
1622}
1623