fix issue with optional branches having wrong flag insert positions

This commit is contained in:
dawn 2026-01-17 15:40:07 +03:00
parent e2b354aae1
commit c5ce6fb6c0
No known key found for this signature in database
3 changed files with 28 additions and 6 deletions

View file

@ -1,6 +1,7 @@
use std::{
collections::HashSet,
fmt::{Debug, Display},
sync::Arc,
};
use smol_str::SmolStr;
@ -17,6 +18,7 @@ pub struct Command {
pub show_in_suggestions: bool,
pub parse_flags_before: usize,
pub hidden_flags: HashSet<SmolStr>,
pub original: Option<Arc<Command>>,
}
impl Command {
@ -41,6 +43,7 @@ impl Command {
parse_flags_before,
tokens,
hidden_flags: HashSet::new(),
original: None,
}
}

View file

@ -181,15 +181,18 @@ pub fn parse_command(
let mut flags: HashMap<String, Option<ParameterValue>> = HashMap::new();
let mut misplaced_flags: Vec<MatchedFlag> = Vec::new();
let mut invalid_flags: Vec<MatchedFlag> = Vec::new();
for (token_idx, raw_flag) in raw_flags {
let Some(matched_flag) = match_flag(command.flags.iter(), raw_flag.clone()) else {
invalid_flags.push(raw_flag);
continue;
};
if token_idx != command.parse_flags_before {
misplaced_flags.push(raw_flag);
continue;
}
match matched_flag {
// a flag was matched
Ok((name, value)) => {
@ -216,6 +219,8 @@ pub fn parse_command(
}
}
}
let full_cmd = command.original.as_deref().unwrap_or(&command);
if misplaced_flags.is_empty().not() {
let mut error = format!(
"Flag{} ",
@ -230,7 +235,8 @@ pub fn parse_command(
write!(
&mut error,
" in command `{prefix}{input}` {} misplaced. Try reordering to match the command usage `{prefix}{command}`.",
(misplaced_flags.len() > 1).then_some("are").unwrap_or("is")
(misplaced_flags.len() > 1).then_some("are").unwrap_or("is"),
command = full_cmd
).expect("oom");
return Err(error);
}
@ -250,7 +256,8 @@ pub fn parse_command(
" {} seem to be applicable in this command (`{prefix}{command}`).",
(invalid_flags.len() > 1)
.then_some("don't")
.unwrap_or("doesn't")
.unwrap_or("doesn't"),
command = full_cmd
)
.expect("oom");
return Err(error);

View file

@ -1,3 +1,5 @@
use std::sync::Arc;
use ordermap::OrderMap;
use crate::{command::Command, token::Token};
@ -27,10 +29,20 @@ impl TreeBranch {
if matches!(token, Token::Parameter(ref param) if param.is_optional())
&& index < command.tokens.len() - 1
{
current_branch.register_command(Command {
tokens: command.tokens[index + 1..].to_vec(),
..command.clone()
});
let mut new_command = command.clone();
new_command.tokens = command.tokens[index + 1..].to_vec();
new_command.original = command
.original
.clone()
.or_else(|| Some(Arc::new(command.clone())));
// if the optional parameter we're skipping is *before* the flag insertion point,
// we need to shift the index left by 1 to account for the removed token
if new_command.parse_flags_before > index {
new_command.parse_flags_before -= 1;
}
current_branch.register_command(new_command);
}
// recursively get or create a sub-branch for each token
current_branch = current_branch