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