use crate::active_help::ActiveHelp;
use crate::completion_item::CompletionItem;
use crate::context::Context;
use crate::error::Result;
use std::borrow::Cow;
#[derive(Clone, Debug)]
pub struct CompletionResultOptimized {
pub items: Vec<CompletionItem>,
pub active_help: Vec<ActiveHelp>,
}
impl CompletionResultOptimized {
#[must_use]
pub fn new() -> Self {
Self {
items: Vec::new(),
active_help: Vec::new(),
}
}
#[allow(clippy::should_implement_trait)]
#[must_use]
pub fn add(mut self, value: impl Into<Cow<'static, str>>) -> Self {
self.items.push(CompletionItem::new(value));
self
}
#[must_use]
pub fn add_with_description(
mut self,
value: impl Into<Cow<'static, str>>,
desc: impl Into<Cow<'static, str>>,
) -> Self {
self.items
.push(CompletionItem::with_description(value, desc));
self
}
#[must_use]
pub fn extend<I, S>(mut self, values: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<Cow<'static, str>>,
{
self.items
.extend(values.into_iter().map(|v| CompletionItem::new(v)));
self
}
#[must_use]
pub fn extend_items<I>(mut self, items: I) -> Self
where
I: IntoIterator<Item = CompletionItem>,
{
self.items.extend(items);
self
}
#[must_use]
pub fn add_help(mut self, help: ActiveHelp) -> Self {
self.active_help.push(help);
self
}
#[must_use]
pub fn add_help_text<S: Into<String>>(mut self, message: S) -> Self {
self.active_help.push(ActiveHelp::new(message));
self
}
#[must_use]
pub fn add_conditional_help<S, F>(mut self, message: S, condition: F) -> Self
where
S: Into<String>,
F: Fn(&Context) -> bool + Send + Sync + 'static,
{
self.active_help
.push(ActiveHelp::with_condition(message, condition));
self
}
#[must_use]
pub fn merge(mut self, other: Self) -> Self {
self.items.extend(other.items);
self.active_help.extend(other.active_help);
self
}
#[must_use]
pub fn into_legacy(self) -> crate::completion::CompletionResult {
let mut result = crate::completion::CompletionResult::new();
for item in self.items {
result.values.push(item.value.into_owned());
result
.descriptions
.push(item.description.map_or(String::new(), Cow::into_owned));
}
result.active_help = self.active_help;
result
}
#[must_use]
pub fn from_legacy(legacy: crate::completion::CompletionResult) -> Self {
let items = legacy
.values
.into_iter()
.zip(legacy.descriptions)
.map(|(value, desc)| {
if desc.is_empty() {
CompletionItem::new(value)
} else {
CompletionItem::with_description(value, desc)
}
})
.collect();
Self {
items,
active_help: legacy.active_help,
}
}
}
impl Default for CompletionResultOptimized {
fn default() -> Self {
Self::new()
}
}
pub type CompletionFuncOptimized =
Box<dyn Fn(&Context, &str) -> Result<CompletionResultOptimized> + Send + Sync>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_optimized_completion_result() {
let result = CompletionResultOptimized::new()
.add("option1")
.add_with_description("option2", "Description for option2")
.extend(["option3", "option4"]);
assert_eq!(result.items.len(), 4);
assert_eq!(result.items[0].value, "option1");
assert_eq!(result.items[0].description, None);
assert_eq!(result.items[1].value, "option2");
assert_eq!(
result.items[1].description.as_deref(),
Some("Description for option2")
);
}
#[test]
fn test_memory_efficiency() {
let result = CompletionResultOptimized::new()
.add("static1")
.add_with_description("static2", "static description");
assert!(matches!(result.items[0].value, Cow::Borrowed(_)));
assert!(matches!(
result.items[1].description.as_ref().unwrap(),
Cow::Borrowed(_)
));
}
#[test]
fn test_legacy_conversion() {
let optimized = CompletionResultOptimized::new()
.add("val1")
.add_with_description("val2", "desc2");
let legacy = optimized.clone().into_legacy();
assert_eq!(legacy.values, vec!["val1", "val2"]);
assert_eq!(legacy.descriptions, vec!["", "desc2"]);
let back = CompletionResultOptimized::from_legacy(legacy);
assert_eq!(back.items.len(), optimized.items.len());
assert_eq!(back.items[0].value, optimized.items[0].value);
}
}