use super::r_completer::RCompleter;
use reedline::{Completer, Suggestion};
pub use super::meta::MetaCommandCompleter;
pub struct CombinedCompleter {
r_completer: RCompleter,
meta_completer: MetaCommandCompleter,
}
impl CombinedCompleter {
pub fn new() -> Self {
Self::with_settings(50, 100, 50)
}
pub fn with_settings(timeout_ms: u64, debounce_ms: u64, auto_paren_limit: usize) -> Self {
Self::with_settings_and_rig(timeout_ms, debounce_ms, auto_paren_limit, true)
}
pub fn with_settings_and_rig(
timeout_ms: u64,
debounce_ms: u64,
auto_paren_limit: usize,
rig_enabled: bool,
) -> Self {
Self::with_settings_full(
timeout_ms,
debounce_ms,
auto_paren_limit,
rig_enabled,
false,
vec!["library".to_string(), "require".to_string()],
)
}
pub fn with_settings_full(
timeout_ms: u64,
debounce_ms: u64,
auto_paren_limit: usize,
rig_enabled: bool,
fuzzy_namespace: bool,
package_functions: Vec<String>,
) -> Self {
let mut exclusions: Vec<&'static str> = vec!["r"];
if !rig_enabled {
exclusions.push("switch");
}
CombinedCompleter {
r_completer: RCompleter::with_settings_full(
timeout_ms,
debounce_ms,
auto_paren_limit,
fuzzy_namespace,
package_functions,
),
meta_completer: MetaCommandCompleter::with_exclusions(exclusions),
}
}
}
impl Default for CombinedCompleter {
fn default() -> Self {
Self::new()
}
}
impl Completer for CombinedCompleter {
fn complete(&mut self, line: &str, pos: usize) -> Vec<Suggestion> {
if line.trim_start().starts_with(':') {
self.meta_completer.complete(line, pos)
} else {
self.r_completer.complete(line, pos)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_combined_completer_delegates_to_meta() {
let mut completer = CombinedCompleter::new();
let suggestions = completer.complete(":rep", 4);
assert_eq!(suggestions.len(), 1);
assert_eq!(suggestions[0].value, "reprex");
}
#[test]
fn test_combined_completer_with_leading_whitespace() {
let mut completer = CombinedCompleter::new();
let suggestions = completer.complete(" :rep", 6);
assert_eq!(suggestions.len(), 1);
assert_eq!(suggestions[0].value, "reprex");
}
#[test]
fn test_combined_completer_excludes_r_command() {
let mut completer = CombinedCompleter::new();
let suggestions = completer.complete(":", 1);
let values: Vec<&str> = suggestions.iter().map(|s| s.value.as_str()).collect();
assert!(
!values.contains(&"r"),
"`:r` should be excluded in CombinedCompleter (R mode)"
);
assert!(
values.contains(&"shell"),
"`:shell` should be present in R mode"
);
}
}