use std::time::{Duration, Instant};
use super::{
file_picker::{FilePaletteMatches, WorkspacePathCache},
types::CommandChoice,
App, ComposerMode,
};
pub(super) const PALETTE_CACHE_TTL: Duration = Duration::from_secs(2);
#[derive(Clone, Debug)]
struct FileMatchCache {
query: String,
matches: FilePaletteMatches,
refreshed_at: Instant,
}
struct SkillMatchCache {
skills: std::sync::Arc<Vec<crate::skills::Skill>>,
refreshed_at: Instant,
}
#[derive(Default)]
pub(super) struct PaletteCaches {
file: Option<FileMatchCache>,
skills: Option<SkillMatchCache>,
workspace: WorkspacePathCache,
}
impl PaletteCaches {
pub(super) fn fresh_file(&self, query: &str, ttl: Duration) -> Option<FilePaletteMatches> {
let cache = self.file.as_ref()?;
(cache.query == query && cache.refreshed_at.elapsed() < ttl).then(|| cache.matches.clone())
}
pub(super) fn store_file(&mut self, query: String, matches: FilePaletteMatches) {
self.file = Some(FileMatchCache {
query,
matches,
refreshed_at: Instant::now(),
});
}
pub(super) fn clear_file(&mut self) {
self.file = None;
}
pub(super) fn workspace_mut(&mut self) -> &mut WorkspacePathCache {
&mut self.workspace
}
pub(super) fn fresh_skills(
&self,
ttl: Duration,
) -> Option<std::sync::Arc<Vec<crate::skills::Skill>>> {
let cache = self.skills.as_ref()?;
(cache.refreshed_at.elapsed() < ttl).then(|| std::sync::Arc::clone(&cache.skills))
}
pub(super) fn store_skills(&mut self, skills: std::sync::Arc<Vec<crate::skills::Skill>>) {
self.skills = Some(SkillMatchCache {
skills,
refreshed_at: Instant::now(),
});
}
#[cfg(test)]
pub(super) fn expire_file(&mut self) {
if let Some(cache) = self.file.as_mut() {
cache.refreshed_at = Instant::now() - PALETTE_CACHE_TTL;
}
}
#[cfg(test)]
pub(super) fn expire_workspace(&mut self) {
self.workspace.expire();
}
}
#[derive(Debug)]
pub(super) enum ActivePalette {
Command(Vec<CommandChoice>),
File(FilePaletteMatches),
}
impl App {
pub(super) fn active_palette(&mut self) -> Option<ActivePalette> {
if !matches!(self.input_ui.composer(), ComposerMode::Input)
|| self.input_ui.shell_mode().is_some()
{
return None;
}
if let Some(matches) = self.visible_command_matches() {
return Some(ActivePalette::Command(matches));
}
if self.input_ui.file_palette_dismissed() {
return None;
}
let matches = self.file_match_list();
(!matches.is_empty()).then_some(ActivePalette::File(matches))
}
#[cfg(test)]
pub(super) fn command_palette_visible(&mut self) -> bool {
matches!(self.active_palette(), Some(ActivePalette::Command(_)))
}
}