use crate::compsys::ported::_description::_description;
use crate::ported::modules::zutil::testforstyle;
use crate::ported::params::{getaparam, getsparam, setaparam, setsparam};
use crate::ported::zle::compcore::get_compstate_str;
use crate::ported::zle::complete::{bin_compadd, bin_compset};
use crate::ported::zsh_h::{options, MAX_OPS};
use std::fs;
fn make_ops() -> options {
options {
ind: [0u8; MAX_OPS],
args: Vec::new(),
argscount: 0,
argsalloc: 0,
}
}
pub fn _extensions() -> i32 {
if bin_compset(
"compset",
&[
"-P".to_string(),
"(#b)([~$][^/]#/|)(*/|)(\\^|)\\*.".to_string(),
],
&make_ops(),
0,
) != 0
{
return 1;
}
let m_arr = getaparam("match").unwrap_or_default();
let dir_prefix = format!(
"{}{}",
m_arr.first().cloned().unwrap_or_default(),
m_arr.get(1).cloned().unwrap_or_default(),
);
let scan_dir = if dir_prefix.is_empty() {
".".to_string()
} else {
dir_prefix.trim_end_matches('/').to_string()
};
let mut files: Vec<String> = Vec::new();
if let Ok(entries) = fs::read_dir(&scan_dir) {
for ent in entries.flatten() {
let name = ent.file_name().to_string_lossy().to_string();
if let Some(dot) = name.rfind('.') {
if dot > 0 {
let ext = format!(".{}", &name[dot + 1..]);
if !files.contains(&ext) {
files.push(ext);
}
}
}
}
}
if files.is_empty() {
return 1;
}
files.retain(|f| !f[1..].chars().next().map(|c| c.is_ascii_digit()).unwrap_or(false));
let curcontext = getsparam("curcontext").unwrap_or_default();
let prefix_hidden = testforstyle(
&format!(":completion:{}:extensions", curcontext),
"prefix-hidden",
) == 0;
if prefix_hidden {
files = files.iter().map(|f| f.trim_start_matches('.').to_string()).collect();
} else {
let prefix = getsparam("PREFIX").unwrap_or_default();
let _ = setsparam("PREFIX", &format!(".{}", prefix));
let iprefix = getsparam("IPREFIX").unwrap_or_default();
let _ = setsparam("IPREFIX", iprefix.trim_end_matches('.'));
}
let add_space = testforstyle(
&format!(":completion:{}:extensions", curcontext),
"add-space",
) == 0;
let suf: Vec<String> = if !add_space {
vec!["-S".to_string(), "".to_string()]
} else {
Vec::new()
};
let _ = _description(&[
"extensions".to_string(),
"expl".to_string(),
"file extension".to_string(),
]);
let expl = getaparam("expl").unwrap_or_default();
setaparam("files", files.clone());
let mut probe: Vec<String> = vec!["-O".to_string(), "mfiles".to_string()];
probe.extend(expl.iter().cloned());
probe.push("-a".to_string());
probe.push("files".to_string());
let _ = bin_compadd("compadd", &probe, &make_ops(), 0);
let mfiles = getaparam("mfiles").unwrap_or_default();
let prefix = getsparam("PREFIX").unwrap_or_default();
if mfiles.len() > 1 || mfiles.first().map(|m| m != &prefix).unwrap_or(true) {
let mut argv = expl;
argv.extend(suf);
argv.push("-a".to_string());
argv.push("files".to_string());
let _ = bin_compadd("compadd", &argv, &make_ops(), 0);
if get_compstate_str("exact_string").unwrap_or_default().is_empty() {
return 0;
}
}
1
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn returns_one_when_compset_fails() {
let _g = crate::test_util::global_state_lock();
let _ = setsparam("PREFIX", "plain_string");
let _ = setsparam("SUFFIX", "");
let _r = _extensions();
}
}