From 0e8492eac1606edba86748c4de547a2c758cd232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A9vis=20Morvany?= <63788850+tretre91@users.noreply.github.com> Date: Mon, 10 Jul 2023 12:21:59 +0200 Subject: [PATCH] Fix `typst watch` not working with some text editors (#1680) --- crates/typst-cli/src/watch.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/crates/typst-cli/src/watch.rs b/crates/typst-cli/src/watch.rs index 2ad73f858..cf9c05bae 100644 --- a/crates/typst-cli/src/watch.rs +++ b/crates/typst-cli/src/watch.rs @@ -34,6 +34,7 @@ pub fn watch(mut command: CompileCommand) -> StrResult<()> { let timeout = std::time::Duration::from_millis(100); let output = command.output(); loop { + let mut removed = HashSet::new(); let mut recompile = false; for event in rx .recv() @@ -41,13 +42,32 @@ pub fn watch(mut command: CompileCommand) -> StrResult<()> { .chain(std::iter::from_fn(|| rx.recv_timeout(timeout).ok())) { let event = event.map_err(|_| "failed to watch directory")?; + + // Workaround for notify-rs' implicit unwatch on remove/rename + // (triggered by some editors when saving files) with the inotify + // backend. By keeping track of the removed files, we can allow + // those we still depend on to be watched again later on. + if matches!( + event.kind, + notify::EventKind::Remove(notify::event::RemoveKind::File) + ) { + let path = &event.paths[0]; + removed.insert(path.clone()); + + // Remove the watch in case it still exists. + watcher.unwatch(path).ok(); + } + recompile |= is_event_relevant(&event, &output); } if recompile { // Retrieve the dependencies of the last compilation. - let previous: HashSet = - world.dependencies().map(ToOwned::to_owned).collect(); + let previous: HashSet = world + .dependencies() + .filter(|path| !removed.contains(*path)) + .map(ToOwned::to_owned) + .collect(); // Recompile. compile_once(&mut world, &mut command, true)?;