use crate::compsys::ported::_call_program::_call_program;
use crate::ported::modules::zutil::bin_zparseopts;
use crate::ported::params::{getaparam, getsparam, setaparam, setsparam};
use crate::ported::pattern::{patcompile, pattry};
use crate::ported::zsh_h::{options, MAX_OPS};
fn make_ops() -> options {
options {
ind: [0u8; MAX_OPS],
args: Vec::new(),
argscount: 0,
argsalloc: 0,
}
}
fn run_zparseopts_pick_variant(args: &[String]) -> (Vec<String>, Vec<String>) {
let src = "__compsys_argv";
setaparam(src, args.to_vec());
setaparam("opts_flat", Vec::new());
let _ = bin_zparseopts(
"zparseopts",
&[
"-D".to_string(),
"-v".to_string(),
src.to_string(),
"-a".to_string(),
"opts_flat".to_string(),
"b:".to_string(),
"c:".to_string(),
"r:".to_string(),
],
&make_ops(),
0,
);
let opts_flat = getaparam("opts_flat").unwrap_or_default();
let remaining = getaparam(src).unwrap_or_default();
(remaining, opts_flat)
}
fn opt(opts_flat: &[String], key: &str) -> Option<String> {
let mut i = 0;
while i + 1 < opts_flat.len() {
if opts_flat[i] == key {
return Some(opts_flat[i + 1].clone());
}
i += 2;
}
None
}
pub fn _pick_variant(args: &[String]) -> i32 {
let (argv, opts_flat) = run_zparseopts_pick_variant(args);
let cmd_name = match opt(&opts_flat, "-c") {
Some(v) => v,
None => getaparam("words").unwrap_or_default().first().cloned().unwrap_or_default(),
};
let mut var: Vec<(String, String)> = Vec::new();
let mut argv = argv;
while let Some(first) = argv.first() {
if let Some(eq) = first.find('=') {
let (n, p) = first.split_at(eq);
var.push((n.to_string(), p[1..].to_string()));
argv.remove(0);
} else {
break;
}
}
let cmd_variant_arr = getaparam("_cmd_variant").unwrap_or_default();
let cached: Option<String> = cmd_variant_arr
.chunks(2)
.find(|kv| kv.first().map(|k| k == &cmd_name).unwrap_or(false))
.and_then(|kv| kv.get(1).cloned());
if let Some(cached_v) = cached {
if let Some(r) = opt(&opts_flat, "-r") {
let _ = setsparam(&r, &cached_v);
}
let dflt = argv.first().cloned().unwrap_or_default();
if cached_v == dflt {
return 1;
}
return 0;
}
let mut call_args: Vec<String> = vec!["variant".to_string(), cmd_name.clone()];
if argv.len() > 1 {
call_args.extend(argv[1..].iter().cloned());
}
let _ = _call_program(&call_args);
let output = getsparam("REPLY").unwrap_or_default();
for (name, pat) in &var {
let matched = match patcompile(pat, 0, None) {
Some(prog) => pattry(&prog, &output),
None => output.contains(pat),
};
if matched {
if let Some(r) = opt(&opts_flat, "-r") {
let _ = setsparam(&r, name);
}
let mut arr = getaparam("_cmd_variant").unwrap_or_default();
arr.push(cmd_name.clone());
arr.push(name.clone());
setaparam("_cmd_variant", arr);
return 0;
}
}
let dflt = argv.first().cloned().unwrap_or_default();
if let Some(r) = opt(&opts_flat, "-r") {
let _ = setsparam(&r, &dflt);
}
let mut arr = getaparam("_cmd_variant").unwrap_or_default();
arr.push(cmd_name);
arr.push(dflt);
setaparam("_cmd_variant", arr);
1
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_args_returns_one() {
let _g = crate::test_util::global_state_lock();
setaparam("_cmd_variant", Vec::new());
assert_eq!(_pick_variant(&[]), 1);
}
}