mirror of
https://github.com/exoticorn/microw8.git
synced 2026-01-20 11:16:42 +01:00
implement more robust file watcher
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1524,6 +1524,7 @@ dependencies = [
|
||||
"minifb",
|
||||
"notify",
|
||||
"pico-args",
|
||||
"same-file",
|
||||
"uw8-tool",
|
||||
"wasmtime",
|
||||
"wat",
|
||||
|
||||
@@ -13,4 +13,5 @@ notify = "4"
|
||||
pico-args = "0.4"
|
||||
curlywas = { git = "https://github.com/exoticorn/curlywas.git", rev = "196719b" }
|
||||
wat = "1"
|
||||
uw8-tool = { path = "uw8-tool" }
|
||||
uw8-tool = { path = "uw8-tool" }
|
||||
same-file = "1"
|
||||
@@ -1,102 +1,21 @@
|
||||
import "env.memory" memory(4);
|
||||
|
||||
import "env.cls" fn cls(i32);
|
||||
import "env.setPixel" fn setPixel(i32, i32, i32);
|
||||
import "env.time" fn time() -> f32;
|
||||
import "env.line" fn line(f32, f32, f32, f32, i32);
|
||||
import "env.sin" fn sin(f32) -> f32;
|
||||
import "env.cos" fn cos(f32) -> f32;
|
||||
|
||||
fn line(x1: f32, y1: f32, x2: f32, y2: f32, col: i32) {
|
||||
let swapTmp: f32;
|
||||
if x1 > x2 {
|
||||
swapTmp = x1;
|
||||
x1 = x2;
|
||||
x2 = swapTmp;
|
||||
swapTmp = y1;
|
||||
y1 = y2;
|
||||
y2 = swapTmp;
|
||||
}
|
||||
if x1 < 0 as f32 & x2 >= 0 as f32 {
|
||||
y1 = y1 + (y2 - y1) * -x1 / (x2 - x1);
|
||||
x1 = 0 as f32;
|
||||
}
|
||||
if x1 < 320 as f32 & x2 >= 320 as f32 {
|
||||
y2 = y2 + (y2 - y1) * (320 as f32 - x2) / (x2 - x1);
|
||||
x2 = 320 as f32;
|
||||
}
|
||||
|
||||
if y1 > y2 {
|
||||
swapTmp = x1;
|
||||
x1 = x2;
|
||||
x2 = swapTmp;
|
||||
swapTmp = y1;
|
||||
y1 = y2;
|
||||
y2 = swapTmp;
|
||||
}
|
||||
if y1 < 0 as f32 & y2 >= 0 as f32 {
|
||||
x1 = x1 + (x2 - x1) * -y1 / (y2 - y1);
|
||||
y1 = 0 as f32;
|
||||
}
|
||||
if y1 < 240 as f32 & y2 >= 240 as f32 {
|
||||
x2 = x2 + (x2 - x1) * (240 as f32 - y2) / (y2 - y1);
|
||||
y2 = 240 as f32;
|
||||
}
|
||||
|
||||
let lazy dx = x2 - x1;
|
||||
let lazy dy = y2 - y1;
|
||||
let max_axis: f32;
|
||||
let p: f32;
|
||||
if abs(dx) >= dy {
|
||||
max_axis = dx;
|
||||
p = x1;
|
||||
} else {
|
||||
max_axis = dy;
|
||||
p = y1;
|
||||
}
|
||||
|
||||
let steps = floor(p + max_axis) as i32 - floor(p) as i32;
|
||||
p = floor(p) + 0.5 - p;
|
||||
if max_axis < 0 as f32 {
|
||||
steps = -steps;
|
||||
p = -p;
|
||||
max_axis = -max_axis;
|
||||
}
|
||||
dx = dx / max_axis;
|
||||
dy = dy / max_axis;
|
||||
|
||||
let f = min(max_axis, max(0 as f32, p));
|
||||
setPixel((x1 + f * dx) as i32, (y1 + f * dy) as i32, col);
|
||||
|
||||
if !steps {
|
||||
return;
|
||||
}
|
||||
|
||||
x1 = x1 + (1 as f32 + p) * dx;
|
||||
y1 = y1 + (1 as f32 + p) * dy;
|
||||
|
||||
p = p + steps as f32;
|
||||
|
||||
loop pixels {
|
||||
if steps := steps - 1 {
|
||||
setPixel(x1 as i32, y1 as i32, col);
|
||||
x1 = x1 + dx;
|
||||
y1 = y1 + dy;
|
||||
branch pixels;
|
||||
}
|
||||
}
|
||||
|
||||
f = min(max_axis, p) - p;
|
||||
setPixel((x1 + f * dx) as i32, (y1 + f * dy) as i32, col);
|
||||
}
|
||||
|
||||
export fn upd() {
|
||||
cls(0);
|
||||
// line(0.0, 4.0, 7.0, -2.0, 15);
|
||||
// return;
|
||||
let i: i32;
|
||||
loop lines {
|
||||
let angle = i as f32 * (3.1415 / 25.0) + time() * 0.1;
|
||||
line(160.0, 120.0, 160.0 + sin(angle) * 100.0, 120.0 + cos(angle) * 100.0, 47);
|
||||
let angle = i as f32 * (3.1415 / 25.0) + time() * 0.125;
|
||||
line(
|
||||
160 as f32, 120 as f32,
|
||||
160 as f32 + sin(angle) * 100 as f32,
|
||||
120 as f32 + cos(angle) * 100 as f32,
|
||||
47);
|
||||
branch_if (i := i + 1) < 50: lines;
|
||||
}
|
||||
}
|
||||
|
||||
70
src/filewatcher.rs
Normal file
70
src/filewatcher.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
use anyhow::{bail, Result};
|
||||
use notify::{DebouncedEvent, Watcher, RecommendedWatcher};
|
||||
use std::{
|
||||
collections::BTreeSet,
|
||||
path::{Path, PathBuf},
|
||||
sync::mpsc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
pub struct FileWatcher {
|
||||
_watcher: RecommendedWatcher,
|
||||
watched_files: BTreeSet<PathBuf>,
|
||||
rx: mpsc::Receiver<DebouncedEvent>,
|
||||
}
|
||||
|
||||
pub struct FileWatcherBuilder(BTreeSet<PathBuf>);
|
||||
|
||||
impl FileWatcher {
|
||||
pub fn builder() -> FileWatcherBuilder {
|
||||
FileWatcherBuilder(BTreeSet::new())
|
||||
}
|
||||
|
||||
pub fn poll_changed_file(&self) -> Result<Option<PathBuf>> {
|
||||
let event = self.rx.try_recv();
|
||||
match event {
|
||||
Ok(DebouncedEvent::Create(path) | DebouncedEvent::Write(path)) => {
|
||||
let handle = same_file::Handle::from_path(&path)?;
|
||||
for file in &self.watched_files {
|
||||
if handle == same_file::Handle::from_path(file)? {
|
||||
return Ok(Some(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(mpsc::TryRecvError::Disconnected) => bail!("File watcher disconnected"),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileWatcherBuilder {
|
||||
pub fn add_file<P: Into<PathBuf>>(&mut self, path: P) -> &mut Self {
|
||||
self.0.insert(path.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<FileWatcher> {
|
||||
let mut directories: BTreeSet<&Path> = BTreeSet::new();
|
||||
|
||||
for file in &self.0 {
|
||||
if let Some(directory) = file.parent() {
|
||||
directories.insert(directory);
|
||||
}
|
||||
}
|
||||
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let mut watcher = notify::watcher(tx, Duration::from_millis(100))?;
|
||||
|
||||
for directory in directories {
|
||||
watcher.watch(directory, notify::RecursiveMode::NonRecursive)?;
|
||||
}
|
||||
|
||||
Ok(FileWatcher {
|
||||
_watcher: watcher,
|
||||
watched_files: self.0,
|
||||
rx,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,10 @@ use wasmtime::{
|
||||
Engine, GlobalType, Memory, MemoryType, Module, Mutability, Store, TypedFunc, ValType,
|
||||
};
|
||||
|
||||
mod filewatcher;
|
||||
|
||||
pub use filewatcher::FileWatcher;
|
||||
|
||||
static GAMEPAD_KEYS: &'static [Key] = &[
|
||||
Key::Up,
|
||||
Key::Down,
|
||||
|
||||
24
src/main.rs
24
src/main.rs
@@ -1,17 +1,14 @@
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::process;
|
||||
use std::sync::mpsc;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
process::exit,
|
||||
};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use notify::{DebouncedEvent, Watcher};
|
||||
use anyhow::Result;
|
||||
use pico_args::Arguments;
|
||||
use uw8::MicroW8;
|
||||
use uw8::{FileWatcher, MicroW8};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let mut args = Arguments::from_env();
|
||||
@@ -72,13 +69,14 @@ fn run(mut args: Arguments) -> Result<()> {
|
||||
uw8.set_timeout(timeout);
|
||||
}
|
||||
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let mut watcher = notify::watcher(tx, Duration::from_millis(100))?;
|
||||
let mut watcher = FileWatcher::builder();
|
||||
|
||||
if watch_mode {
|
||||
watcher.watch(&filename, notify::RecursiveMode::NonRecursive)?;
|
||||
watcher.add_file(&filename);
|
||||
}
|
||||
|
||||
let watcher = watcher.build()?;
|
||||
|
||||
if let Err(err) = start_cart(&filename, &mut uw8, &config) {
|
||||
eprintln!("Load error: {}", err);
|
||||
if !watch_mode {
|
||||
@@ -87,14 +85,10 @@ fn run(mut args: Arguments) -> Result<()> {
|
||||
}
|
||||
|
||||
while uw8.is_open() {
|
||||
match rx.try_recv() {
|
||||
Ok(DebouncedEvent::Create(_) | DebouncedEvent::Write(_)) => {
|
||||
if let Err(err) = start_cart(&filename, &mut uw8, &config) {
|
||||
eprintln!("Load error: {}", err);
|
||||
}
|
||||
if watcher.poll_changed_file()?.is_some() {
|
||||
if let Err(err) = start_cart(&filename, &mut uw8, &config) {
|
||||
eprintln!("Load error: {}", err);
|
||||
}
|
||||
Err(mpsc::TryRecvError::Disconnected) => bail!("File watcher disconnected"),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if let Err(err) = uw8.run_frame() {
|
||||
|
||||
Reference in New Issue
Block a user