Move more watching code into watch.rs

This commit is contained in:
Laurenz 2023-07-02 19:06:40 +02:00
parent 46fb49aed3
commit 3ab1918509
2 changed files with 41 additions and 46 deletions

View File

@ -1,12 +1,13 @@
use std::collections::HashSet;
use std::io::{self, IsTerminal, Write};
use std::path::Path;
use std::path::{Path, PathBuf};
use codespan_reporting::term::{self, termcolor};
use notify::{RecommendedWatcher, Watcher};
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use same_file::is_same_file;
use termcolor::WriteColor;
use typst::diag::StrResult;
use typst::eval::eco_format;
use crate::args::CompileCommand;
use crate::color_stream;
@ -27,7 +28,7 @@ pub fn watch(mut command: CompileCommand) -> StrResult<()> {
.map_err(|_| "failed to setup file watching")?;
// Watch all the files that are used by the input file and its dependencies.
world.watch(&mut watcher, HashSet::new())?;
watch_dependencies(&mut world, &mut watcher, HashSet::new())?;
// Handle events.
let timeout = std::time::Duration::from_millis(100);
@ -45,18 +46,47 @@ pub fn watch(mut command: CompileCommand) -> StrResult<()> {
if recompile {
// Retrieve the dependencies of the last compilation.
let dependencies = world.dependencies();
let previous: HashSet<PathBuf> =
world.dependencies().map(ToOwned::to_owned).collect();
// Recompile.
compile_once(&mut world, &mut command, true)?;
comemo::evict(10);
// Adjust the watching.
world.watch(&mut watcher, dependencies)?;
watch_dependencies(&mut world, &mut watcher, previous)?;
}
}
}
/// Adjust the file watching. Watches all new dependencies and unwatches
/// all `previous` dependencies that are not relevant anymore.
#[tracing::instrument(skip_all)]
fn watch_dependencies(
world: &mut SystemWorld,
watcher: &mut dyn Watcher,
mut previous: HashSet<PathBuf>,
) -> StrResult<()> {
// Watch new paths that weren't watched yet.
for path in world.dependencies() {
let watched = previous.remove(path);
if path.exists() && !watched {
tracing::info!("Watching {}", path.display());
watcher
.watch(path, RecursiveMode::NonRecursive)
.map_err(|_| eco_format!("failed to watch {path:?}"))?;
}
}
// Unwatch old paths that don't need to be watched anymore.
for path in previous {
tracing::info!("Unwatching {}", path.display());
watcher.unwatch(&path).ok();
}
Ok(())
}
/// Whether a watch event is relevant for compilation.
fn is_event_relevant(event: &notify::Event, output: &Path) -> bool {
// Never recompile because the output file changed.

View File

@ -1,12 +1,11 @@
use std::cell::{OnceCell, RefCell, RefMut};
use std::collections::{HashMap, HashSet};
use std::collections::HashMap;
use std::fs;
use std::hash::Hash;
use std::path::{Path, PathBuf};
use chrono::Datelike;
use comemo::Prehashed;
use notify::{RecursiveMode, Watcher};
use same_file::Handle;
use siphasher::sip128::{Hasher128, SipHasher13};
use typst::diag::{FileError, FileResult, StrResult};
@ -45,6 +44,7 @@ pub struct SystemWorld {
}
impl SystemWorld {
/// Create a new system world.
pub fn new(command: &CompileCommand) -> StrResult<Self> {
let mut searcher = FontSearcher::new();
searcher.search(&command.font_paths);
@ -89,47 +89,12 @@ impl SystemWorld {
self.main
}
/// Adjust the file watching. Watches all new dependencies and unwatches
/// all `previous` dependencies that are not relevant anymore.
#[tracing::instrument(skip_all)]
pub fn watch(
&self,
watcher: &mut dyn Watcher,
mut previous: HashSet<PathBuf>,
) -> StrResult<()> {
// Watch new paths that weren't watched yet.
for slot in self.paths.borrow().values() {
let path = &slot.system_path;
let watched = previous.remove(path);
if path.exists() && !watched {
tracing::info!("Watching {}", path.display());
watcher
.watch(path, RecursiveMode::NonRecursive)
.map_err(|_| eco_format!("failed to watch {path:?}"))?;
}
}
// Unwatch old paths that don't need to be watched anymore.
for path in previous {
tracing::info!("Unwatching {}", path.display());
watcher.unwatch(&path).ok();
}
Ok(())
/// Return all paths the last compilation depended on.
pub fn dependencies(&mut self) -> impl Iterator<Item = &Path> {
self.paths.get_mut().values().map(|slot| slot.system_path.as_path())
}
/// Collect all paths the last compilation depended on.
#[tracing::instrument(skip_all)]
pub fn dependencies(&self) -> HashSet<PathBuf> {
self.paths
.borrow()
.values()
.map(|slot| slot.system_path.clone())
.collect()
}
/// Reset th compilation state in preparation of a new compilation.
#[tracing::instrument(skip_all)]
/// Reset the compilation state in preparation of a new compilation.
pub fn reset(&mut self) {
self.hashes.borrow_mut().clear();
self.paths.borrow_mut().clear();