diff --git a/crates/owlry-core/Cargo.toml b/crates/owlry-core/Cargo.toml index c9c8c04..2646444 100644 --- a/crates/owlry-core/Cargo.toml +++ b/crates/owlry-core/Cargo.toml @@ -48,15 +48,17 @@ log = "0.4" env_logger = "0.11" notify-rust = "4" +# Built-in providers +meval = "0.2" +reqwest = { version = "0.13", default-features = false, features = ["rustls", "json", "blocking"] } + # Optional: embedded Lua runtime mlua = { version = "0.11", features = ["lua54", "vendored", "send", "serialize"], optional = true } -meval = { version = "0.2", optional = true } -reqwest = { version = "0.13", default-features = false, features = ["rustls", "json", "blocking"], optional = true } [dev-dependencies] tempfile = "3" [features] default = [] -lua = ["dep:mlua", "dep:meval", "dep:reqwest"] +lua = ["dep:mlua"] dev-logging = [] diff --git a/crates/owlry-core/src/providers/mod.rs b/crates/owlry-core/src/providers/mod.rs index f4a36f2..8194b25 100644 --- a/crates/owlry-core/src/providers/mod.rs +++ b/crates/owlry-core/src/providers/mod.rs @@ -104,10 +104,24 @@ pub trait Provider: Send + Sync { fn items(&self) -> &[LaunchItem]; } +/// Trait for built-in providers that produce results per-keystroke. +/// Unlike static `Provider`s which cache items via `refresh()`/`items()`, +/// dynamic providers generate results on every query. +pub(crate) trait DynamicProvider: Send + Sync { + #[allow(dead_code)] + fn name(&self) -> &str; + fn provider_type(&self) -> ProviderType; + fn query(&self, query: &str) -> Vec; + fn priority(&self) -> u32; +} + /// Manages all providers and handles searching pub struct ProviderManager { /// Core static providers (apps, commands, dmenu) providers: Vec>, + /// Built-in dynamic providers (calculator, converter) + /// These are queried per-keystroke, like native dynamic plugins + builtin_dynamic: Vec>, /// Static native plugin providers (need query() for submenu support) static_native_providers: Vec, /// Dynamic providers from native plugins (calculator, websearch, filesearch) @@ -136,6 +150,7 @@ impl ProviderManager { ) -> Self { let mut manager = Self { providers: core_providers, + builtin_dynamic: Vec::new(), static_native_providers: Vec::new(), dynamic_providers: Vec::new(), widget_providers: Vec::new(), @@ -618,6 +633,28 @@ impl ProviderManager { results.push((item, base_score + grouping_bonus - idx as i64)); } } + + // Built-in dynamic providers (calculator, converter) + for provider in &self.builtin_dynamic { + if !filter.is_active(provider.provider_type()) { + continue; + } + let dynamic_results = provider.query(query); + let base_score = provider.priority() as i64; + + let grouping_bonus: i64 = match provider.provider_type() { + ProviderType::Plugin(ref id) + if matches!(id.as_str(), "calc" | "conv") => + { + 10_000 + } + _ => 0, + }; + + for (idx, item) in dynamic_results.into_iter().enumerate() { + results.push((item, base_score + grouping_bonus - idx as i64)); + } + } } // Empty query (after checking special providers) - return frecency-sorted items