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