use crate::compsys::ported::_description::_description;
use crate::compsys::ported::_message::_message;
use crate::compsys::ported::_next_label::_next_label;
use crate::compsys::ported::_requested::_requested;
use crate::compsys::ported::_tags::_tags;
use crate::ported::exec_hooks::dispatch_function_call;
use crate::ported::params::{getaparam, getsparam, setaparam, setsparam};
use crate::ported::zle::compcore::get_compstate_str;
use crate::ported::zle::complete::bin_compadd;
use crate::ported::zsh_h::{options, MAX_OPS};
fn make_ops() -> options {
options {
ind: [0u8; MAX_OPS],
args: Vec::new(),
argscount: 0,
argsalloc: 0,
}
}
pub fn _alternative(args: &[String]) -> i32 {
let saved_curcontext = getsparam("curcontext").unwrap_or_default();
let mut subopts: Vec<String> = Vec::new();
let mut curcontext = saved_curcontext.clone();
let mut idx = 0usize;
while idx < args.len() {
let a = &args[idx];
if a == "-O" && idx + 1 < args.len() {
subopts = getaparam(&args[idx + 1]).unwrap_or_default();
idx += 2;
} else if a == "-C" && idx + 1 < args.len() {
if let Some(i) = curcontext.rfind(':') {
curcontext.truncate(i);
}
curcontext.push(':');
curcontext.push_str(&args[idx + 1]);
let _ = setsparam("curcontext", &curcontext);
idx += 2;
} else if a.starts_with('-') && a != "-" && a != "--" {
break;
} else {
break;
}
}
if idx < args.len() && (args[idx] == "-" || args[idx] == "--") {
idx += 1;
}
let defs: Vec<String> = args[idx..].to_vec();
let mut mesgs: Vec<String> = Vec::new();
let tag_names: Vec<String> = defs
.iter()
.map(|d| d.splitn(2, ':').next().unwrap_or("").to_string())
.collect();
let _ = _tags(&tag_names);
let nm_initial: i64 = get_compstate_str("nmatches")
.and_then(|s| s.parse().ok())
.unwrap_or(0);
loop {
if _tags(&[]) != 0 {
break;
}
for def in &defs {
let mut parts = def.splitn(3, ':');
let tag = parts.next().unwrap_or("").to_string();
let descr = parts.next().unwrap_or("").to_string();
let action = parts.next().unwrap_or("").to_string();
if _requested(&[tag.clone()]) != 0 {
continue;
}
let _ = _description(&[tag.clone(), "expl".to_string(), descr.clone()]);
if action.trim().is_empty() {
mesgs.push(format!("{}:{}", tag, descr));
} else if action.starts_with("((") && action.ends_with("))") {
let body = &action[2..action.len() - 2];
let items: Vec<String> =
body.split_whitespace().map(|s| s.to_string()).collect();
setaparam("ws", items);
let mut describe_argv: Vec<String> = vec![
"-t".to_string(),
tag.clone(),
descr.clone(),
"ws".to_string(),
"-M".to_string(),
"r:|[_-]=* r:|=*".to_string(),
];
describe_argv.extend(subopts.iter().cloned());
let _ = dispatch_function_call("_describe", &describe_argv);
} else if action.starts_with('(') && action.ends_with(')') {
let body = &action[1..action.len() - 1];
let items: Vec<String> =
body.split_whitespace().map(|s| s.to_string()).collect();
setaparam("ws", items);
loop {
let mut nl =
vec![tag.clone(), "expl".to_string(), descr.clone()];
if _next_label(&nl) != 0 {
break;
}
nl.clear();
let expl = getaparam("expl").unwrap_or_default();
let mut compadd_argv: Vec<String> = subopts.clone();
compadd_argv.extend(expl);
compadd_argv.push("-a".to_string());
compadd_argv.push("-".to_string());
compadd_argv.push("ws".to_string());
let _ = bin_compadd("compadd", &compadd_argv, &make_ops(), 0);
}
} else if action.starts_with('{') && action.ends_with('}') {
let body = &action[1..action.len() - 1];
loop {
let nl = vec![tag.clone(), "expl".to_string(), descr.clone()];
if _next_label(&nl) != 0 {
break;
}
let _ = crate::ported::exec_hooks::execute_script(body);
}
} else if action.starts_with(' ') {
let parts: Vec<String> = action
.split_whitespace()
.map(|s| s.to_string())
.collect();
loop {
let nl = vec![tag.clone(), "expl".to_string(), descr.clone()];
if _next_label(&nl) != 0 {
break;
}
if let Some(cmd) = parts.first() {
let rest: Vec<String> = parts[1..].to_vec();
let _ = dispatch_function_call(cmd, &rest);
}
}
} else {
let parts: Vec<String> = action
.split_whitespace()
.map(|s| s.to_string())
.collect();
if let Some((cmd, rest)) = parts.split_first() {
loop {
let nl =
vec![tag.clone(), "expl".to_string(), descr.clone()];
if _next_label(&nl) != 0 {
break;
}
let expl = getaparam("expl").unwrap_or_default();
let mut call_argv: Vec<String> = subopts.clone();
call_argv.extend(expl);
call_argv.extend(rest.iter().cloned());
let _ = if cmd == "compadd" {
bin_compadd("compadd", &call_argv, &make_ops(), 0)
} else {
dispatch_function_call(cmd, &call_argv).unwrap_or(1)
};
}
}
}
}
let nm_now: i64 = get_compstate_str("nmatches")
.and_then(|s| s.parse().ok())
.unwrap_or(0);
if nm_now != nm_initial {
let _ = setsparam("curcontext", &saved_curcontext);
return 0;
}
}
for d in &mesgs {
let mut parts = d.splitn(2, ':');
let tag = parts.next().unwrap_or("").to_string();
let desc = parts.next().unwrap_or("").to_string();
let _ = _message(&["-e".to_string(), tag, desc]);
}
let _ = setsparam("curcontext", &saved_curcontext);
1
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn returns_one_for_empty_specs() {
let _g = crate::test_util::global_state_lock();
assert_eq!(_alternative(&[]), 1);
}
#[test]
fn returns_one_when_no_tag_requested() {
let _g = crate::test_util::global_state_lock();
assert_eq!(_alternative(&["foo:desc:_files".to_string()]), 1);
}
}