use super::declaration::{Flag, Style, Verb, WrappedCommand};
use super::parse::{Call, Item};
pub(crate) struct Rendered {
pub(crate) argv: Vec<String>,
pub(crate) item_argv_index: Vec<usize>,
}
pub(crate) fn render(declaration: &WrappedCommand, verb: &Verb, call: &Call) -> Rendered {
let mut argv: Vec<String> = Vec::new();
argv.extend(declaration.lead.iter().cloned());
for step in verb_chain(declaration, &call.verb_path) {
if !step.omit_name
&& let Some(name) = &step.name
{
argv.push(name.clone());
}
argv.extend(step.lead.iter().cloned());
}
let mut item_argv_index = Vec::with_capacity(call.items.len());
for item in &call.items {
item_argv_index.push(argv.len());
match item {
Item::Positional { value, .. } => argv.push(value.clone()),
Item::Flag(use_index) => {
if let Some(use_) = call.flags.get(*use_index)
&& let Some(flag) = verb.flags.get(use_.flag_index)
{
render_flag(flag, use_.value.as_deref(), &mut argv);
}
}
Item::DashDash => argv.push("--".to_string()),
Item::Undeclared(word) => argv.push(word.clone()),
}
}
Rendered {
argv,
item_argv_index,
}
}
fn verb_chain<'d>(declaration: &'d WrappedCommand, path: &[usize]) -> Vec<&'d Verb> {
let Some((&first, rest)) = path.split_first() else {
return declaration.root.iter().collect();
};
let mut chain = Vec::with_capacity(rest.len() + 1);
let mut verb = &declaration.verbs[first];
chain.push(verb);
for &index in rest {
verb = &verb.verbs[index];
chain.push(verb);
}
chain
}
fn render_flag(flag: &Flag, value: Option<&str>, argv: &mut Vec<String>) {
let name = flag.written_name();
match value {
None => argv.push(name),
Some(value) => match flag.effective_style() {
Style::Equals => argv.push(format!("{name}={value}")),
Style::Separate => {
argv.push(name);
argv.push(value.to_string());
}
},
}
}