use anyhow::Result; use notify::{Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher}; use std::path::{Path, PathBuf}; use tokio::sync::mpsc; use tracing::debug; pub enum WatchEvent { Changed(PathBuf), Removed(PathBuf), } /// Start a single notify watcher for one or more paths. All events route to the same channel. pub fn start_many(paths: &[PathBuf]) -> Result<(RecommendedWatcher, mpsc::Receiver)> { let (tx, rx) = mpsc::channel::(128); let mut watcher = notify::recommended_watcher(move |res: notify::Result| { let Ok(event) = res else { return }; let kind = event.kind; for path in event.paths { if path.extension().is_none_or(|e| e != "ncl") { continue; } let evt = match &kind { EventKind::Remove(_) => WatchEvent::Removed(path), _ => WatchEvent::Changed(path), }; let _ = tx.try_send(evt); } })?; for p in paths { if p.exists() { watcher.watch(p, RecursiveMode::Recursive)?; debug!("watching: {}", p.display()); } else { debug!("skip watch (not found): {}", p.display()); } } Ok((watcher, rx)) } /// Convenience wrapper for single-path watching (preserves old API for tests/tools). #[allow(dead_code)] pub fn start(watch_path: &Path) -> Result<(RecommendedWatcher, mpsc::Receiver)> { start_many(&[watch_path.to_path_buf()]) }