diff --git a/lib/src/parse.rs b/lib/src/parse.rs index 75bedab2..a7b4f87c 100644 --- a/lib/src/parse.rs +++ b/lib/src/parse.rs @@ -3,7 +3,7 @@ use indexmap::IndexMap; use itertools::Itertools; use log::trace; use miette::bail; -use std::collections::{BTreeMap, HashMap, VecDeque}; +use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; use std::fmt::{Debug, Display, Formatter}; use std::sync::Arc; use strum::EnumTryAs; @@ -117,6 +117,15 @@ fn flag_keys(flag: &SpecFlag) -> Vec { keys } +fn unique_flags<'a>( + flags: impl IntoIterator>, +) -> impl Iterator> { + let mut seen = HashSet::new(); + flags + .into_iter() + .filter(move |flag| seen.insert(Arc::as_ptr(flag) as usize)) +} + /// Extract the flag key from a flag word for lookup in available_flags map /// Handles both long flags (--flag, --flag=value) and short flags (-f) fn get_flag_key(word: &str) -> &str { @@ -704,7 +713,7 @@ fn parse_partial_with_env( } } - for flag in out.available_flags.values() { + for flag in unique_flags(out.available_flags.values()) { if out.flags.contains_key(flag) { continue; } diff --git a/lib/tests/parse.rs b/lib/tests/parse.rs index e743deb8..31264941 100644 --- a/lib/tests/parse.rs +++ b/lib/tests/parse.rs @@ -30,6 +30,11 @@ required_flag: args="", expected=r#"Missing required flag: --name "#, +required_flag_with_short_alias: + spec=r#"flag "-n --name " required=#true"#, + args="", + expected=r#"Missing required flag: --name "#, + negate: spec=r#"flag "--force" negate="--no-force""#, args="--no-force",