use crate::compsys::ported::_message::_message;
use crate::compsys::ported::_normal::_normal;
use crate::ported::exec::dispatch_function_call;
use crate::ported::params::{getaparam, getsparam, setsparam};
use crate::ported::zle::compcore::{get_compstate_str, set_compstate_str};
fn assoc_get(name: &str, key: &str) -> Option<String> {
crate::ported::params::paramtab_hashed_storage()
.lock()
.ok()?
.get(name)?
.get(key)
.cloned()
}
fn set_ccarray_field(n: usize, value: &str) {
debug_assert!(n >= 1, "ccarray is 1-based");
let cur = getsparam("curcontext").unwrap_or_default();
let mut parts: Vec<&str> = cur.split(':').collect();
while parts.len() < n {
parts.push("");
}
parts[n - 1] = value;
let _ = setsparam("curcontext", &parts.join(":"));
}
pub fn _complete() -> i32 {
let _fn_scope = crate::compsys::ported::shared::FnScope::enter("_complete");
{
use crate::compsys::ported::shared::declare_locals;
declare_locals(&["comp", "name", "oldcontext", "ret", "service"], 0);
}
let mut _cc_scope = crate::compsys::ported::shared::LocalScope::declare(&[], 0);
_cc_scope.also_keeping_value(&["curcontext"]);
let mut ret: i32 = 1;
let oldcontext = getsparam("curcontext").unwrap_or_default();
let compcontext = getsparam("compcontext").unwrap_or_default();
tracing::debug!(
target: "compsys_args",
%compcontext,
compskip = %getsparam("_compskip").unwrap_or_default(),
context = %get_compstate_str("context").unwrap_or_default(),
"_complete ENTER"
);
if !compcontext.is_empty() {
if compcontext.matches(':').count() >= 2 {
let mut parts = compcontext.splitn(3, ':');
let tag = parts
.next()
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.unwrap_or_else(|| "values".to_string());
let descr = parts
.next()
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.unwrap_or_else(|| "value".to_string());
let action = parts.next().unwrap_or("").to_string();
if action.trim().is_empty() {
return _message(&["-e".to_string(), tag, descr]);
}
let parts: Vec<String> = crate::compsys::ported::eval_action_words(&action);
if let Some((cmd, rest)) = parts.split_first() {
return dispatch_function_call(cmd, rest).unwrap_or(1);
}
return 1;
}
set_ccarray_field(3, &compcontext);
let comp = assoc_get("_comps", &compcontext).unwrap_or_default();
if !comp.is_empty() {
return dispatch_function_call(&comp, &[]).unwrap_or(1);
}
return 1;
}
let first_comp = assoc_get("_comps", "-first-").unwrap_or_default();
if !first_comp.is_empty() {
let service = assoc_get("_services", "-first-").unwrap_or_else(|| "-first-".to_string());
let _ = setsparam("service", &service);
set_ccarray_field(3, "-first-");
if dispatch_function_call(&first_comp, &[]).unwrap_or(1) == 0 {
ret = 0;
}
if getsparam("_compskip").as_deref() == Some("all") {
let _ = setsparam("_compskip", "");
return ret;
}
}
let vared = get_compstate_str("vared").unwrap_or_default();
if !vared.is_empty() {
set_compstate_str("context", "vared");
}
let context = get_compstate_str("context").unwrap_or_default();
if context == "command" {
let _ = setsparam("curcontext", &oldcontext);
if _normal(&["-s".to_string()]) == 0 {
ret = 0;
}
} else {
let cname = format!("-{}-", context.replacen('_', "-", 1));
set_ccarray_field(3, &cname);
let mut comp = assoc_get("_comps", &cname).unwrap_or_default();
let service = assoc_get("_services", &cname).unwrap_or_else(|| cname.clone());
let _ = setsparam("service", &service);
if comp.is_empty() {
let cs = getsparam("_compskip").unwrap_or_default();
if cs.contains("default") {
let _ = setsparam("_compskip", "");
return 1;
}
comp = assoc_get("_comps", "-default-").unwrap_or_default();
let default_service =
assoc_get("_services", "-default-").unwrap_or_else(|| "-default-".to_string());
let _ = setsparam("service", &default_service);
}
if !comp.is_empty() {
if dispatch_function_call(&comp, &[]).unwrap_or(1) == 0 {
ret = 0;
}
}
}
let _ = setsparam("_compskip", "");
ret
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn returns_one_without_executor() {
let _g = crate::test_util::global_state_lock();
let _ = setsparam("compcontext", "");
set_compstate_str("context", "command");
crate::ported::params::setaparam("_comps", Vec::new());
let _r = _complete();
}
#[test]
fn ccarray_field_three_is_the_command_field() {
let _g = crate::test_util::global_state_lock();
let _ = setsparam("curcontext", ":megacomplete::");
set_ccarray_field(3, "-subscript-");
assert_eq!(
getsparam("curcontext").as_deref(),
Some(":megacomplete:-subscript-:")
);
}
#[test]
fn ccarray_field_pads_short_context() {
let _g = crate::test_util::global_state_lock();
let _ = setsparam("curcontext", "foo");
set_ccarray_field(3, "bar");
assert_eq!(getsparam("curcontext").as_deref(), Some("foo::bar"));
let _ = setsparam("curcontext", "");
set_ccarray_field(3, "bar");
assert_eq!(getsparam("curcontext").as_deref(), Some("::bar"));
}
#[test]
fn ccarray_field_preserves_trailing_fields() {
let _g = crate::test_util::global_state_lock();
let _ = setsparam("curcontext", ":complete:oldcmd:argfield");
set_ccarray_field(3, "-parameter-");
assert_eq!(
getsparam("curcontext").as_deref(),
Some(":complete:-parameter-:argfield")
);
}
}