gravel_provider_program/
lib.rsuse glob::{glob, Paths};
use gravel_ffi::prelude::*;
use itertools::Itertools;
use serde::Deserialize;
use std::{path::PathBuf, time::Duration};
#[cfg_attr(target_os = "linux", path = "linux.rs")]
#[cfg_attr(windows, path = "windows.rs")]
mod implementation;
const DEFAULT_CONFIG: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/config.yml"));
struct ProgramProvider {
program_paths: Vec<PathBuf>,
cache: HitCache,
}
#[gravel_provider("program")]
impl Provider for ProgramProvider {
fn new(config: &PluginConfigAdapter<'_>) -> Self {
let config = config.get::<Config>(DEFAULT_CONFIG);
let program_paths = implementation::get_program_paths(&config).collect_vec();
log::debug!("determined program paths: {program_paths:?}");
Self {
program_paths,
cache: HitCache::default().max_age(Duration::from_secs(10)),
}
}
fn query(&self, _query: &str) -> ProviderResult {
fn inner(program_paths: &[PathBuf]) -> impl Iterator<Item = SimpleHit> + '_ {
program_paths
.iter()
.filter_map(expand_glob)
.flatten()
.filter_map(Result::ok)
.unique_by(|p| p.file_name().map(ToOwned::to_owned))
.filter_map(|p| implementation::get_program(&p))
}
let cached = self.cache.get_or(|| inner(&self.program_paths));
ProviderResult::from_cached(cached.get())
}
fn clear_caches(&self) {
self.cache.clear();
}
}
fn expand_glob(pattern: &PathBuf) -> Option<Paths> {
glob(&pattern.to_string_lossy())
.inspect_err(|e| log::error!("unable to expand glob {pattern:?}: {e}"))
.ok()
}
#[derive(Deserialize, Debug)]
struct Config {
#[cfg(windows)]
pub windows: WindowsConfig,
}
#[cfg(windows)]
#[derive(Deserialize, Debug)]
struct WindowsConfig {
shortcut_paths: Vec<String>,
}