feat(core): add DynamicProvider trait and builtin_dynamic support
Foundation for built-in calculator, converter, and system providers. DynamicProvider trait for per-keystroke providers. ProviderManager iterates builtin_dynamic alongside native dynamic plugins in search.
This commit is contained in:
@@ -48,15 +48,17 @@ log = "0.4"
|
|||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
notify-rust = "4"
|
notify-rust = "4"
|
||||||
|
|
||||||
|
# Built-in providers
|
||||||
|
meval = "0.2"
|
||||||
|
reqwest = { version = "0.13", default-features = false, features = ["rustls", "json", "blocking"] }
|
||||||
|
|
||||||
# Optional: embedded Lua runtime
|
# Optional: embedded Lua runtime
|
||||||
mlua = { version = "0.11", features = ["lua54", "vendored", "send", "serialize"], optional = true }
|
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]
|
[dev-dependencies]
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
lua = ["dep:mlua", "dep:meval", "dep:reqwest"]
|
lua = ["dep:mlua"]
|
||||||
dev-logging = []
|
dev-logging = []
|
||||||
|
|||||||
@@ -104,10 +104,24 @@ pub trait Provider: Send + Sync {
|
|||||||
fn items(&self) -> &[LaunchItem];
|
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<LaunchItem>;
|
||||||
|
fn priority(&self) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
/// Manages all providers and handles searching
|
/// Manages all providers and handles searching
|
||||||
pub struct ProviderManager {
|
pub struct ProviderManager {
|
||||||
/// Core static providers (apps, commands, dmenu)
|
/// Core static providers (apps, commands, dmenu)
|
||||||
providers: Vec<Box<dyn Provider>>,
|
providers: Vec<Box<dyn Provider>>,
|
||||||
|
/// Built-in dynamic providers (calculator, converter)
|
||||||
|
/// These are queried per-keystroke, like native dynamic plugins
|
||||||
|
builtin_dynamic: Vec<Box<dyn DynamicProvider>>,
|
||||||
/// Static native plugin providers (need query() for submenu support)
|
/// Static native plugin providers (need query() for submenu support)
|
||||||
static_native_providers: Vec<NativeProvider>,
|
static_native_providers: Vec<NativeProvider>,
|
||||||
/// Dynamic providers from native plugins (calculator, websearch, filesearch)
|
/// Dynamic providers from native plugins (calculator, websearch, filesearch)
|
||||||
@@ -136,6 +150,7 @@ impl ProviderManager {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let mut manager = Self {
|
let mut manager = Self {
|
||||||
providers: core_providers,
|
providers: core_providers,
|
||||||
|
builtin_dynamic: Vec::new(),
|
||||||
static_native_providers: Vec::new(),
|
static_native_providers: Vec::new(),
|
||||||
dynamic_providers: Vec::new(),
|
dynamic_providers: Vec::new(),
|
||||||
widget_providers: Vec::new(),
|
widget_providers: Vec::new(),
|
||||||
@@ -618,6 +633,28 @@ impl ProviderManager {
|
|||||||
results.push((item, base_score + grouping_bonus - idx as i64));
|
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
|
// Empty query (after checking special providers) - return frecency-sorted items
|
||||||
|
|||||||
Reference in New Issue
Block a user