use std::path::PathBuf;
use std::sync::mpsc as std_mpsc;
use std::time::Duration;
use notify::{Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
pub fn spawn_git_watcher(
repo_path: PathBuf,
tx_ui: crossbeam_channel::Sender<crate::tui::message::Message>,
) -> Result<RecommendedWatcher, notify::Error> {
let (tx_fs, rx_fs) = std_mpsc::channel::<notify::Result<Event>>();
let mut watcher = notify::recommended_watcher(move |res| {
let _ = tx_fs.send(res);
})?;
let git_dir = repo_path.join(".git");
if git_dir.exists() {
watcher.watch(&git_dir, RecursiveMode::Recursive)?;
}
std::thread::spawn(move || {
let quiet = Duration::from_millis(200);
let mut pending = false;
loop {
let recv_result = if pending {
rx_fs.recv_timeout(quiet)
} else {
match rx_fs.recv() {
Ok(ev) => Ok(ev),
Err(_) => Err(std_mpsc::RecvTimeoutError::Disconnected),
}
};
match recv_result {
Ok(Ok(event)) => {
if is_meaningful(&event) {
pending = true;
}
}
Ok(Err(_e)) => {
pending = true;
}
Err(std_mpsc::RecvTimeoutError::Timeout) => {
if pending {
let _ = tx_ui.send(crate::tui::message::Message::Refresh);
pending = false;
}
}
Err(std_mpsc::RecvTimeoutError::Disconnected) => break,
}
}
});
Ok(watcher)
}
fn is_meaningful(event: &Event) -> bool {
let has_lock = event.paths.iter().any(|p| {
p.file_name()
.and_then(|n| n.to_str())
.map(|n| n.ends_with(".lock"))
.unwrap_or(false)
});
if has_lock {
return false;
}
matches!(
event.kind,
EventKind::Create(_) | EventKind::Modify(_) | EventKind::Remove(_) | EventKind::Any
)
}