use std::collections::HashSet;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use async_trait::async_trait;
use tokio::sync::RwLock;
use crate::indexing::facade::IndexFacade;
use crate::watcher::{WatchAction, WatchError, WatchHandler};
pub struct CodeFileHandler {
facade: Arc<RwLock<IndexFacade>>,
cached_paths: RwLock<HashSet<PathBuf>>,
workspace_root: PathBuf,
}
impl CodeFileHandler {
pub fn new(facade: Arc<RwLock<IndexFacade>>, workspace_root: PathBuf) -> Self {
Self {
facade,
cached_paths: RwLock::new(HashSet::new()),
workspace_root,
}
}
pub async fn init_cache(&self) {
let facade = self.facade.read().await;
let paths: HashSet<PathBuf> = facade
.get_all_indexed_paths()
.into_iter()
.map(|p| self.to_absolute(&p))
.collect();
let mut cache = self.cached_paths.write().await;
*cache = paths;
}
fn to_absolute(&self, path: &Path) -> PathBuf {
if path.is_absolute() {
path.to_path_buf()
} else {
self.workspace_root.join(path)
}
}
fn to_relative(&self, path: &Path) -> PathBuf {
path.strip_prefix(&self.workspace_root)
.map(|p| p.to_path_buf())
.unwrap_or_else(|_| path.to_path_buf())
}
}
#[async_trait]
impl WatchHandler for CodeFileHandler {
fn name(&self) -> &str {
"code"
}
fn matches(&self, path: &Path) -> bool {
if let Ok(cache) = self.cached_paths.try_read() {
cache.contains(path)
} else {
false
}
}
async fn tracked_paths(&self) -> Vec<PathBuf> {
let facade = self.facade.read().await;
facade
.get_all_indexed_paths()
.into_iter()
.map(|p| self.to_absolute(&p))
.collect()
}
async fn on_modify(&self, path: &Path) -> Result<WatchAction, WatchError> {
Ok(WatchAction::ReindexCode {
path: self.to_relative(path),
})
}
async fn on_delete(&self, path: &Path) -> Result<WatchAction, WatchError> {
{
let mut cache = self.cached_paths.write().await;
cache.remove(path);
}
Ok(WatchAction::RemoveCode {
path: self.to_relative(path),
})
}
async fn refresh_paths(&self) -> Result<(), WatchError> {
self.init_cache().await;
Ok(())
}
}