use crate::compsys::ported::_complete::_complete;
use crate::compsys::ported::_description::_description;
use crate::compsys::ported::_requested::_requested;
use crate::compsys::ported::_shadow::{_shadow, _unshadow};
use crate::compsys::ported::_tags::_tags;
use crate::ported::modules::zutil::{lookupstyle, testforstyle};
use crate::ported::params::{getaparam, getiparam, getsparam, setsparam};
use crate::ported::zle::compcore::{get_compstate_str, set_compstate_str};
use crate::ported::zle::complete::{
bin_compadd, clear_compadd_prefix_injector, set_compadd_prefix_injector,
};
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 _approximate(args: &[String]) -> i32 {
if getiparam("_matcher_num") > 1 {
return 1;
}
let prefix = getsparam("PREFIX").unwrap_or_default();
let suffix = getsparam("SUFFIX").unwrap_or_default();
if prefix.len() + suffix.len() <= 1 {
return 1;
}
let curcontext = getsparam("curcontext").unwrap_or_default();
let cfgacc = if let Some(a) = args.first() {
if let Some(rest) = a.strip_prefix("-a") {
if !rest.is_empty() {
rest.to_string()
} else if args.len() > 1 {
args[1].clone()
} else {
"2 numeric".to_string()
}
} else {
lookupstyle(&format!(":completion:{}:", curcontext), "max-errors")
.first()
.cloned()
.unwrap_or_else(|| "2 numeric".to_string())
}
} else {
lookupstyle(&format!(":completion:{}:", curcontext), "max-errors")
.first()
.cloned()
.unwrap_or_else(|| "2 numeric".to_string())
};
let numeric = getiparam("NUMERIC");
let comax: i64 = if cfgacc.contains("numeric") && numeric != 1 {
if cfgacc.contains("not-numeric") {
return 1;
}
if numeric < 1 {
1
} else {
numeric
}
} else {
cfgacc
.chars()
.filter(|c| c.is_ascii_digit())
.collect::<String>()
.parse()
.unwrap_or(0)
};
if comax < 1 {
return 1;
}
let _ = _tags(&["corrections".to_string(), "original".to_string()]);
let opm = get_compstate_str("pattern_match").unwrap_or_default();
if opm.is_empty() {
set_compstate_str("pattern_match", "*");
}
let _ = _shadow(&["-s".to_string(), "_approximate".to_string(), "compadd".to_string()]);
let mut ret: i32 = 1;
let mut comp_correct: i64 = 1;
let oldcontext = curcontext.clone();
while comp_correct <= comax {
let _ = setsparam("_comp_correct", &comp_correct.to_string());
let new_ctx = format!("{}-{}", oldcontext, comp_correct);
let _ = setsparam("curcontext", &new_ctx);
let _ = _description(&[
"corrections".to_string(),
"_correct_expl".to_string(),
"corrections".to_string(),
format!("e:{}", comp_correct),
format!("o:{}{}", prefix, suffix),
]);
set_compadd_prefix_injector(&format!("(#a{})", comp_correct));
let comp_ret = _complete();
clear_compadd_prefix_injector();
if comp_ret == 0 {
let unambig = get_compstate_str("unambiguous").unwrap_or_default();
let pre_suf = format!("{}{}", prefix, suffix);
if testforstyle(&format!(":completion:{}:", new_ctx), "insert-unambiguous") == 0
&& unambig.len() >= pre_suf.len()
{
set_compstate_str("pattern_insert", "unambiguous");
} else if _requested(&["original".to_string()]) == 0 {
let nm: i64 = get_compstate_str("nmatches")
.and_then(|s| s.parse().ok())
.unwrap_or(0);
let orig_on = lookupstyle(&format!(":completion:{}:", new_ctx), "original")
.first()
.map(|v| matches!(v.as_str(), "yes" | "true" | "1" | "on"))
.unwrap_or(false);
if nm > 1 || orig_on {
let _ = _description(&[
"-V".to_string(),
"original".to_string(),
"expl".to_string(),
"original".to_string(),
]);
let expl = getaparam("expl").unwrap_or_default();
let mut compadd_argv = expl;
compadd_argv.push("-U".to_string());
compadd_argv.push("-Q".to_string());
compadd_argv.push("-".to_string());
compadd_argv.push(pre_suf);
let _ = bin_compadd("compadd", &compadd_argv, &make_ops(), 0);
let list = get_compstate_str("list").unwrap_or_default();
if !list.starts_with("list") {
set_compstate_str("list", &format!("{} force", list).trim().to_string());
}
}
}
set_compstate_str("pattern_match", &opm);
ret = 0;
break;
}
comp_correct += 1;
}
let _ = _unshadow();
let _ = setsparam("curcontext", &oldcontext);
ret
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn short_input_returns_one() {
let _g = crate::test_util::global_state_lock();
let _ = setsparam("PREFIX", "a");
let _ = setsparam("SUFFIX", "");
assert_eq!(_approximate(&[]), 1);
}
}