use rustyline::completion::Pair;
impl super::SqlCompleter {
pub(super) fn complete_describe(&self, text_before_cursor: &str) -> Option<Vec<Pair>> {
let trimmed = text_before_cursor.trim_start();
let after_describe = if let Some(after) = trimmed.strip_prefix(r"\d+ ") {
Some(after)
} else if let Some(after) = trimmed.strip_prefix(r"\d! ") {
Some(after)
} else if let Some(after) = trimmed.strip_prefix(r"\d+! ") {
Some(after)
} else if let Some(after) = trimmed.strip_prefix(r"\d!+ ") {
Some(after)
} else {
trimmed.strip_prefix(r"\d ")
};
if let Some(partial) = after_describe {
let partial_lower = partial.to_lowercase();
let mut completions = Vec::new();
if let Some(cache) = &self.schema_cache {
let cache = cache.read().unwrap();
for table in cache.all_tables() {
if table.to_lowercase().starts_with(&partial_lower) {
completions.push(Pair {
display: table.clone(),
replacement: table,
});
}
}
for view in cache.all_views() {
if view.to_lowercase().starts_with(&partial_lower) {
completions.push(Pair {
display: view.clone(),
replacement: view,
});
}
}
for func in &cache.functions {
if func.to_lowercase().starts_with(&partial_lower) {
completions.push(Pair {
display: func.clone(),
replacement: func.clone(),
});
}
}
for index in cache.all_indexes() {
if index.to_lowercase().starts_with(&partial_lower) {
completions.push(Pair {
display: index.clone(),
replacement: index,
});
}
}
}
completions.sort_by(|a, b| {
let a_key = a.display.replace('_', "~");
let b_key = b.display.replace('_', "~");
a_key.cmp(&b_key)
});
completions.dedup_by(|a, b| a.display == b.display);
return Some(completions);
}
None
}
}
#[cfg(test)]
mod tests {
use crate::{completer::*, theme::Theme};
#[test]
fn test_describe_command_completion() {
let completer = SqlCompleter::new(Theme::Dark);
let completions = completer.find_completions("\\", 1);
assert!(completions.iter().any(|c| c.display == "\\d"));
assert!(completions.iter().any(|c| c.display == "\\d+"));
}
}