Files
ElyOffice/apps/ely-tree/src/watch.rs
T
ZacharyZhang-NY b7fca0146d Ely Office: six offline-first desktop apps in Rust and GPUI
ElyDoc, ElyTable, ElyShow (LibreOfficeKit), ElyPDF (MuPDF), ElyTree (Git),
ElyMark (Milkdown and CodeMirror in CEF). ElyMail and ElyAgent follow.
2026-10-08 21:20:08 -04:00

48 lines
1.6 KiB
Rust

//! Rereads after outside changes (TREE-02, §13.3).
use std::time::Duration;
use futures::{StreamExt as _, channel::mpsc};
use gpui::Context;
use notify::{RecommendedWatcher, RecursiveMode, Watcher as _};
use crate::{repo::Repo, tree::Tree};
/// Bursts, such as a checkout, settle into one read.
const SETTLE: Duration = Duration::from_millis(250);
/// Watches work tree and Git directory until dropped.
pub fn start(id: u64, repo: &Repo, cx: &mut Context<Tree>) -> notify::Result<RecommendedWatcher> {
let (sender, mut changes) = mpsc::unbounded();
let root = repo.root.display().to_string();
let mut watcher =
notify::recommended_watcher(move |event: notify::Result<notify::Event>| match event {
Ok(_) => {
let _ = sender.unbounded_send(());
}
Err(error) => log::warn!("tree: watching {root} failed: {error}"),
})?;
let mut watched = vec![repo.root.clone()];
// A linked worktree's Git directories lie elsewhere.
for dir in [&repo.common_dir, &repo.git_dir] {
if !watched.iter().any(|top| dir.starts_with(top)) {
watched.push(dir.clone());
}
}
for dir in &watched {
watcher.watch(dir, RecursiveMode::Recursive)?;
}
cx.spawn(async move |this, cx| {
while changes.next().await.is_some() {
cx.background_executor().timer(SETTLE).await;
while changes.try_recv().is_ok() {}
if this.update(cx, |tree, cx| tree.read(id, cx)).is_err() {
break;
}
}
})
.detach();
log::info!("tree: watching {}", repo.root.display());
Ok(watcher)
}