use crate::ported::params::{getsparam, setaparam};
pub fn _regex_words(args: &[String]) -> i32 {
let _fn_scope = crate::compsys::ported::shared::FnScope::enter("_regex_words");
let mut term = "\0".to_string();
let mut idx = 0usize;
while idx + 1 < args.len() {
if args[idx] == "-t" {
term = args[idx + 1].clone();
idx += 2;
} else {
break;
}
}
if args.len() < idx + 2 {
setaparam("reply", Vec::new());
return 0;
}
let tag = args[idx].clone();
let desc = args[idx + 1].clone();
let words_start = idx + 2;
let word_args: &[String] = &args[words_start..];
if word_args.is_empty() {
setaparam("reply", Vec::new());
return 0;
}
let mut reply: Vec<String> = vec!["(".to_string()];
let (mut matches, end): (String, String) = if term == "\0" {
(format!(":{}:{}:(( ", tag, desc), "))".to_string())
} else {
let q = shell_quote(&term);
let qd = shell_quote(&desc);
(
format!(":{}:{}:_values -s {} {}", tag, desc, q, qd),
String::new(),
)
};
for arg in word_args {
let wds: Vec<&str> = arg.split(':').filter(|f| !f.is_empty()).collect();
let w0 = wds.first().copied().unwrap_or("");
let w1 = wds.get(1).copied().unwrap_or("");
let w2 = wds.get(2).copied().unwrap_or("");
let class = if term == "\0" {
"[^\0]#".to_string()
} else {
format!("[^{}]#", term)
};
let regex = format!("/{}{}/", w0.replace('*', &class), term);
reply.push(regex);
if term == "\0" {
let mut m = w0.replace('*', "");
if !w1.is_empty() {
m.push_str("\\:");
m.push_str(&backslash_escape(w1, &[':', ' ', '(', ')']));
}
m.push(' ');
matches.push_str(&m);
} else {
matches.push_str(&format!(
" {}\\[{}\\]",
shell_quote(&backslash_escape(&w0.replace('*', ""), &[':', '[', ']'])),
shell_quote(&backslash_escape(w1, &[':', '[', ']'])),
));
}
if !w2.is_empty() {
reply.extend(crate::compsys::ported::eval_action_words(w2));
}
reply.push("|".to_string());
}
reply.push("/[]/".to_string());
reply.push(format!("{}{}", matches, end));
reply.push(")".to_string());
setaparam("reply", reply);
0
}
fn backslash_escape(s: &str, chars: &[char]) -> String {
let mut out = String::with_capacity(s.len());
for c in s.chars() {
if chars.contains(&c) {
out.push('\\');
}
out.push(c);
}
out
}
fn shell_quote(s: &str) -> String {
let esc = s.replace('\'', "'\\''");
format!("'{}'", esc)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_args_clears_reply() {
let _g = crate::test_util::global_state_lock();
assert_eq!(_regex_words(&[]), 0);
let reply = crate::ported::params::getaparam("reply").unwrap_or_default();
assert!(reply.is_empty());
}
#[test]
fn emits_reply_for_simple_spec() {
let _g = crate::test_util::global_state_lock();
let _ = _regex_words(&[
"options".to_string(),
"option name".to_string(),
"foo:my foo:".to_string(),
"bar:my bar:".to_string(),
]);
let reply = crate::ported::params::getaparam("reply").unwrap_or_default();
assert!(reply.first().map(|s| s == "(").unwrap_or(false));
assert!(reply.last().map(|s| s == ")").unwrap_or(false));
let _ = getsparam("PREFIX");
}
}