const KNOWN_FUNCTIONS: &[&str] = &[
"sin", "cos", "tan", "csc", "sec", "cot", "arcsin", "arccos", "arctan", "sinh", "cosh", "tanh",
"log", "ln", "exp", "sqrt", "abs", "floor", "ceil", "round", "sign", "min", "max", "gcd",
"lcm", "atan2", "cbrt", "pow", "sgn", "lg", "asin", "acos", "atan", "log2",
];
pub fn levenshtein(a: &str, b: &str) -> usize {
let a_chars: Vec<char> = a.chars().collect();
let b_chars: Vec<char> = b.chars().collect();
let a_len = a_chars.len();
let b_len = b_chars.len();
if a_len == 0 {
return b_len;
}
if b_len == 0 {
return a_len;
}
let mut prev_row: Vec<usize> = (0..=b_len).collect();
let mut curr_row: Vec<usize> = vec![0; b_len + 1];
for (i, a_char) in a_chars.iter().enumerate() {
curr_row[0] = i + 1;
for (j, b_char) in b_chars.iter().enumerate() {
let cost = if a_char == b_char { 0 } else { 1 };
curr_row[j + 1] = std::cmp::min(
std::cmp::min(curr_row[j] + 1, prev_row[j + 1] + 1),
prev_row[j] + cost,
);
}
std::mem::swap(&mut prev_row, &mut curr_row);
}
prev_row[b_len]
}
pub fn suggest_function(unknown: &str) -> Option<String> {
KNOWN_FUNCTIONS
.iter()
.filter(|&&f| levenshtein(unknown, f) <= 2)
.min_by_key(|&&f| levenshtein(unknown, f))
.map(|&f| format!("Did you mean '{}'?", f))
}