use crate::error::Result;
use crate::project::Project;
use colored::Colorize;
use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Watcher};
use std::sync::mpsc::channel;
use std::time::Duration;
pub fn execute(no_run: bool) -> Result<()> {
let project = Project::find_and_load()?;
println!("{} for changes...", "Watching".cyan().bold());
println!(" Source: {}", project.source_dir().display());
println!(" Assets: {}", project.assets_dir().display());
println!();
println!("Press Ctrl+C to stop");
println!();
if let Err(e) = crate::commands::build::execute(false, false) {
eprintln!("{} Initial build failed: {}", "โ".red().bold(), e);
} else if !no_run {
if let Err(e) = launch_simulator_for_project(&project) {
eprintln!("{} Failed to launch simulator: {}", "โ".red().bold(), e);
}
}
let (tx, rx) = channel();
let mut watcher = RecommendedWatcher::new(
move |res: std::result::Result<Event, notify::Error>| {
if let Ok(event) = res {
let _ = tx.send(event);
}
},
Config::default().with_poll_interval(Duration::from_millis(500)),
)?;
watcher.watch(project.source_dir().as_ref(), RecursiveMode::Recursive)?;
watcher.watch(project.assets_dir().as_ref(), RecursiveMode::Recursive)?;
let mut last_build = std::time::Instant::now();
loop {
match rx.recv() {
Ok(event) => {
if last_build.elapsed() < Duration::from_millis(500) {
continue;
}
if !is_relevant_event(&event) {
continue;
}
println!();
println!("{} Change detected, rebuilding...", "ยป".cyan().bold());
last_build = std::time::Instant::now();
if let Err(e) = crate::commands::build::execute(false, false) {
eprintln!("{} Build failed: {}", "โ".red().bold(), e);
} else {
println!();
}
}
Err(e) => {
eprintln!("Watch error: {:?}", e);
break;
}
}
}
Ok(())
}
fn is_relevant_event(event: &Event) -> bool {
use notify::EventKind;
match event.kind {
EventKind::Create(_) | EventKind::Modify(_) | EventKind::Remove(_) => {
event.paths.iter().any(|p| {
p.extension()
.and_then(|e| e.to_str())
.map(|e| matches!(e, "lua" | "png" | "wav" | "fnt" | "json"))
.unwrap_or(false)
})
}
_ => false,
}
}
fn launch_simulator_for_project(project: &Project) -> Result<()> {
let sdk = crate::sdk::Sdk::detect()?;
let pdx_path = project.pdx_path();
sdk.launch_simulator(&pdx_path)
}