#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(
feature = "serialization",
derive(serde::Serialize, serde::Deserialize)
)]
pub struct PaletteItem {
pub id: String,
pub label: String,
pub description: Option<String>,
pub shortcut: Option<String>,
pub category: Option<String>,
}
impl PaletteItem {
pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
Self {
id: id.into(),
label: label.into(),
description: None,
shortcut: None,
category: None,
}
}
pub fn with_description(mut self, desc: impl Into<String>) -> Self {
self.description = Some(desc.into());
self
}
pub fn with_shortcut(mut self, shortcut: impl Into<String>) -> Self {
self.shortcut = Some(shortcut.into());
self
}
pub fn with_category(mut self, category: impl Into<String>) -> Self {
self.category = Some(category.into());
self
}
}
pub fn fuzzy_score(query: &str, text: &str) -> Option<usize> {
if query.is_empty() {
return Some(0);
}
let query_lower = query.to_lowercase();
let text_lower = text.to_lowercase();
if text_lower.starts_with(&query_lower) {
return Some(1000 + text.len().saturating_sub(query.len()));
}
if text_lower.contains(&query_lower) {
return Some(500);
}
let mut text_chars = text_lower.chars();
let mut matched = 0usize;
for qc in query_lower.chars() {
loop {
match text_chars.next() {
Some(tc) if tc == qc => {
matched += 1;
break;
}
Some(_) => {}
None => return None,
}
}
}
Some(matched)
}