use crate::compsys::ported::_description::_description;
use crate::ported::exec_hooks::dispatch_function_call;
use crate::ported::modules::zutil::lookupstyle;
use crate::ported::params::{getaparam, getiparam, getsparam, setaparam};
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 _user_expand() -> i32 {
if getiparam("_matcher_num") > 1 {
return 1;
}
let iprefix = getsparam("IPREFIX").unwrap_or_default();
let prefix = getsparam("PREFIX").unwrap_or_default();
let suffix = getsparam("SUFFIX").unwrap_or_default();
let isuffix = getsparam("ISUFFIX").unwrap_or_default();
let word = format!("{}{}{}{}", iprefix, prefix, suffix, isuffix);
let curcontext = getsparam("curcontext").unwrap_or_default();
let specs = lookupstyle(&format!(":completion:{}:", curcontext), "user-expand");
if specs.is_empty() {
return 1;
}
let mut exp: Vec<String> = vec![word.clone()];
for spec in &specs {
if let Some(name) = spec.strip_prefix('$') {
let arr = getaparam(name).unwrap_or_default();
let val = arr
.chunks(2)
.find(|kv| kv.first().map(|k| k == &word).unwrap_or(false))
.and_then(|kv| kv.get(1).cloned())
.unwrap_or_default();
if !val.is_empty() {
exp = vec![val];
break;
}
} else if spec.starts_with('_') {
setaparam("reply", Vec::new());
let _ = dispatch_function_call(spec, &[word.clone()]);
let reply = getaparam("reply").unwrap_or_default();
if !reply.is_empty() {
exp = reply;
break;
}
}
}
if exp.len() == 1 && exp[0] == word {
return 1;
}
setaparam("exp", exp);
let _ = _description(&[
"-V".to_string(),
"expansions".to_string(),
"expl".to_string(),
"expansions".to_string(),
format!("o:{}", word),
]);
let expl = getaparam("expl").unwrap_or_default();
let mut compadd_argv: Vec<String> = expl;
compadd_argv.push("-UQ".to_string());
compadd_argv.push("-a".to_string());
compadd_argv.push("exp".to_string());
bin_compadd("compadd", &compadd_argv, &make_ops(), 0)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ported::params::setsparam;
#[test]
fn returns_one_when_user_expand_unset() {
let _g = crate::test_util::global_state_lock();
let _ = setsparam("PREFIX", "");
let _ = setsparam("SUFFIX", "");
let _ = setsparam("IPREFIX", "");
let _ = setsparam("ISUFFIX", "");
crate::ported::params::setiparam("_matcher_num", 1);
assert_eq!(_user_expand(), 1);
}
}