use crate::config::Config;
use anyhow::Result;
use notify_debouncer_mini::{new_debouncer, notify::RecursiveMode};
use std::path::{Path, PathBuf};
use std::sync::mpsc;
use std::time::{Duration, Instant};
const DEBOUNCE: Duration = Duration::from_millis(150);
pub fn run() -> Result<()> {
let _ = rebuild();
watch_loop(|_| {})
}
pub fn watch_loop<F>(mut on_rebuild: F) -> Result<()>
where
F: FnMut(&Result<()>),
{
let (config, _) = Config::load_with_theme(Path::new("config.yaml"))?;
let (tx, rx) = mpsc::channel();
let mut debouncer = new_debouncer(DEBOUNCE, tx)?;
let mut dirs: Vec<PathBuf> = vec![config.content_dir.clone(), config.data_dir.clone()];
dirs.extend(config.template_roots());
dirs.extend(config.archive_roots());
dirs.extend(config.static_roots());
for dir in &dirs {
if dir.exists() {
debouncer.watcher().watch(dir, RecursiveMode::Recursive)?;
}
}
let config_path = Path::new("config.yaml");
if config_path.exists() {
debouncer
.watcher()
.watch(config_path, RecursiveMode::NonRecursive)?;
}
eprintln!("watching for changes…");
for batch in rx {
match batch {
Ok(_) => {
let result = rebuild();
on_rebuild(&result);
}
Err(e) => eprintln!("watch error: {e}"),
}
}
Ok(())
}
fn rebuild() -> Result<()> {
let start = Instant::now();
let result = crate::build::run(true);
match &result {
Ok(()) => eprintln!("rebuilt in {:?}", start.elapsed()),
Err(e) => eprintln!("build failed: {e:#}"),
}
result
}