use crate::completions::{CompletionOptions, SortBy}; use nu_protocol::{engine::StateWorkingSet, levenshtein_distance, Span}; use reedline::Suggestion; // Completer trait represents the three stages of the completion // fetch, filter and sort pub trait Completer { fn fetch( &mut self, working_set: &StateWorkingSet, prefix: Vec, span: Span, offset: usize, pos: usize, ) -> (Vec, CompletionOptions); // Filter results using the completion options fn filter( &self, prefix: Vec, items: Vec, options: CompletionOptions, ) -> Vec { items .into_iter() .filter(|it| { // Minimise clones for new functionality match (options.case_sensitive, options.positional) { (true, true) => it.value.as_bytes().starts_with(&prefix), (true, false) => it .value .contains(std::str::from_utf8(&prefix).unwrap_or("")), (false, positional) => { let value = it.value.to_lowercase(); let prefix = std::str::from_utf8(&prefix).unwrap_or("").to_lowercase(); if positional { value.starts_with(&prefix) } else { value.contains(&prefix) } } } }) .collect() } // Sort results using the completion options fn sort( &self, items: Vec, prefix: Vec, options: CompletionOptions, ) -> Vec { let prefix_str = String::from_utf8_lossy(&prefix).to_string(); let mut filtered_items = items; // Sort items match options.sort_by { SortBy::LevenshteinDistance => { filtered_items.sort_by(|a, b| { let a_distance = levenshtein_distance(&prefix_str, &a.value); let b_distance = levenshtein_distance(&prefix_str, &b.value); a_distance.cmp(&b_distance) }); } SortBy::Ascending => { filtered_items.sort_by(|a, b| a.value.cmp(&b.value)); } SortBy::None => {} }; filtered_items } }