diff --git a/Cargo.lock b/Cargo.lock index dafbbe2..7775e59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2960,6 +2960,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "nucleo-matcher" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf33f538733d1a5a3494b836ba913207f14d9d4a1d3cd67030c5061bdd2cac85" +dependencies = [ + "memchr", + "unicode-segmentation", +] + [[package]] name = "num-bigint" version = "0.4.8" @@ -4292,6 +4302,7 @@ dependencies = [ "libc", "log", "minreq", + "nucleo-matcher", "objc2 0.6.4", "objc2-app-kit 0.3.2", "objc2-application-services", diff --git a/Cargo.toml b/Cargo.toml index 7bb7ed1..a1a3eb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ image = { version = "0.25.9", features = ["tiff"] } libc = "0.2.180" log = "0.4.29" minreq = { version = "2.14.1", features = ["https"] } +nucleo-matcher = "0.3.1" objc2 = "0.6.3" objc2-app-kit = { version = "0.3.2", features = ["NSImage", "NSScreen"] } objc2-application-services = { version = "0.3.2", default-features = false, features = ["HIServices", "Processes"] } diff --git a/src/app/tile.rs b/src/app/tile.rs index b81f2e2..7e340d7 100644 --- a/src/app/tile.rs +++ b/src/app/tile.rs @@ -25,6 +25,8 @@ use iced::{ use iced::{event, window}; use log::{info, warn}; +use nucleo_matcher::pattern::{CaseMatching, Normalization, Pattern}; +use nucleo_matcher::{Matcher, Utf32Str}; use objc2::rc::Retained; use objc2_app_kit::NSRunningApplication; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; @@ -34,6 +36,7 @@ use tokio::io::{AsyncBufReadExt, AsyncRead}; use tray_icon::TrayIcon; use url::Url; +use std::cell::RefCell; use std::collections::HashMap; use std::fmt::Debug; use std::time::Duration; @@ -56,15 +59,22 @@ struct AppIndex { impl AppIndex { /// Search for an element in the index that starts with the provided prefix fn search_prefix<'a>(&'a self, prefix: &'a str) -> impl ParallelIterator + 'a { + let pattern = Pattern::parse(prefix, CaseMatching::Ignore, Normalization::Smart); + self.by_name.par_iter().filter_map(move |(name, app)| { - if name.starts_with(prefix) - || name.contains(format!(" {prefix}").as_str()) - || name.contains(format!("-{prefix}").as_str()) - { - Some(app) - } else { - None + thread_local! { + static MATCHER: RefCell = RefCell::new( + Matcher::new(nucleo_matcher::Config::DEFAULT.match_paths()) + ); } + + MATCHER.with(|m| { + let mut buf = Vec::new(); + let haystack = Utf32Str::new(name, &mut buf); + pattern + .score(haystack, &mut m.borrow_mut()) + .map(|_score| app) + }) }) } @@ -706,7 +716,11 @@ mod tests { .map(|app| app.display_name.clone()) .collect(); - assert_eq!(prefix_results, vec!["Safari".to_string()]); + assert!( + prefix_results.contains(&"Visual Studio Code".to_string()) + && prefix_results.contains(&"Signal Desktop".to_string()) + && prefix_results.contains(&"Safari".to_string()), + ); assert_eq!(spaced_results, vec!["Visual Studio Code".to_string()]); assert_eq!(hyphen_results, vec!["Signal Desktop".to_string()]); } diff --git a/src/app/tile/elm.rs b/src/app/tile/elm.rs index 34ba6c8..dd8fab1 100644 --- a/src/app/tile/elm.rs +++ b/src/app/tile/elm.rs @@ -21,7 +21,6 @@ use crate::app::pages::settings::settings_page; use crate::app::tile::{AppIndex, Hotkeys}; use crate::app::{DEFAULT_WINDOW_HEIGHT, HotkeyCapture, SettingsTab, ToApp, ToApps}; use crate::config::Theme; -use crate::database::load_clipboard; use crate::debounce::Debouncer; use crate::platform::macos::events::Event; use crate::styles::{ diff --git a/src/clipboard.rs b/src/clipboard.rs index 98eb11e..f215d78 100644 --- a/src/clipboard.rs +++ b/src/clipboard.rs @@ -109,16 +109,4 @@ mod tests { ClipBoardContentType::Text("world".to_string()) ); } - - #[test] - fn clipboard_to_app_truncates_and_uses_first_line_for_display() { - let item = - ClipBoardContentType::Text("abcdefghijklmnopqrstuvwxyz\nsecond line".to_string()); - - // let app = item.to_app(); - - // assert_eq!(app.display_name, "abcdefghijklmnopqrstuvwxy"); - // assert_eq!(app.search_name, "abcdefghijklmnopqrstuvwxy"); - // assert_eq!(app.desc, "Clipboard Item"); - } } diff --git a/src/platform/mod.rs b/src/platform.rs similarity index 100% rename from src/platform/mod.rs rename to src/platform.rs