use crate::parse::Token;
enum FlagKind {
Unknown,
Boolean,
ValuedGlued, ValuedNext, }
pub(super) fn walk_positionals<'a>(
short: &[u8],
valued_short: &[u8],
long: &[&str],
valued_long: &[&str],
numeric_shorthand: bool,
tokens: &'a [Token],
) -> Option<Vec<&'a str>> {
let mut out = Vec::new();
let mut flags_done = false;
let mut i = 1;
while i < tokens.len() {
let t = tokens[i].as_str();
if !flags_done && t == "--" {
flags_done = true;
} else if flags_done || t == "-" || !t.starts_with('-') {
out.push(t);
} else {
match classify_flag(short, valued_short, long, valued_long, numeric_shorthand, t) {
FlagKind::Unknown => return None,
FlagKind::ValuedNext => i += 1, FlagKind::Boolean | FlagKind::ValuedGlued => {}
}
}
i += 1;
}
Some(out)
}
fn classify_flag(
short: &[u8],
valued_short: &[u8],
long: &[&str],
valued_long: &[&str],
numeric_shorthand: bool,
t: &str,
) -> FlagKind {
if let Some(rest) = t.strip_prefix("--") {
let name_len = rest.split('=').next().unwrap_or(rest).len();
let full = &t[..2 + name_len];
let has_eq = t.len() > 2 + name_len;
if valued_long.contains(&full) {
return if has_eq { FlagKind::ValuedGlued } else { FlagKind::ValuedNext };
}
if long.contains(&full) {
return if has_eq { FlagKind::ValuedGlued } else { FlagKind::Boolean };
}
return FlagKind::Unknown;
}
let bytes = t.as_bytes();
if numeric_shorthand && bytes.len() > 1 && bytes[1..].iter().all(|b| b.is_ascii_digit()) {
return FlagKind::Boolean;
}
let mut k = 1;
while k < bytes.len() {
let b = bytes[k];
if valued_short.contains(&b) {
return if k + 1 < bytes.len() { FlagKind::ValuedGlued } else { FlagKind::ValuedNext };
}
if short.contains(&b) {
k += 1;
} else {
return FlagKind::Unknown;
}
}
FlagKind::Boolean
}
pub(super) fn walk_value<'a>(valued_short: &[u8], tokens: &'a [Token], short: u8, long: &str) -> Option<&'a str> {
let mut i = 1;
while i < tokens.len() {
let t = tokens[i].as_str();
if t == "--" {
break;
}
if t.starts_with("--") {
if let Some(v) = t.strip_prefix(long).and_then(|r| r.strip_prefix('=')) {
return Some(v);
}
if t == long {
return tokens.get(i + 1).map(Token::as_str);
}
} else if t.starts_with('-') && t != "-" {
let bytes = t.as_bytes();
let mut k = 1;
while k < bytes.len() {
let b = bytes[k];
if b == short && valued_short.contains(&b) {
let glued = &t[k + 1..];
return if glued.is_empty() { tokens.get(i + 1).map(Token::as_str) } else { Some(glued) };
}
if valued_short.contains(&b) {
break; }
k += 1;
}
}
i += 1;
}
None
}