rustlings/src/watch.rs
2024-04-07 19:29:16 +02:00

83 lines
2 KiB
Rust

use anyhow::Result;
use notify_debouncer_mini::{new_debouncer, notify::RecursiveMode};
use std::{
io::{self, BufRead, Write},
path::Path,
sync::mpsc::{channel, sync_channel},
thread,
time::Duration,
};
mod state;
use crate::{exercise::Exercise, state_file::StateFile};
use self::state::WatchState;
enum Event {
Hint,
Clear,
Quit,
}
pub fn watch(state_file: &StateFile, exercises: &[Exercise]) -> Result<()> {
let (tx, rx) = channel();
let mut debouncer = new_debouncer(Duration::from_secs(1), tx)?;
debouncer
.watcher()
.watch(Path::new("exercises"), RecursiveMode::Recursive)?;
let mut watch_state = WatchState::new(state_file, exercises, rx);
watch_state.run_exercise()?;
watch_state.render()?;
let (tx, rx) = sync_channel(0);
thread::spawn(move || {
let mut stdin = io::stdin().lock();
let mut stdin_buf = String::with_capacity(8);
loop {
stdin.read_line(&mut stdin_buf).unwrap();
let event = match stdin_buf.trim() {
"h" | "hint" => Some(Event::Hint),
"c" | "clear" => Some(Event::Clear),
"q" | "quit" => Some(Event::Quit),
_ => None,
};
stdin_buf.clear();
if tx.send(event).is_err() {
break;
};
}
});
loop {
watch_state.try_recv_event()?;
if let Ok(event) = rx.try_recv() {
match event {
Some(Event::Hint) => {
watch_state.show_hint()?;
}
Some(Event::Clear) => {
watch_state.render()?;
}
Some(Event::Quit) => break,
None => {
watch_state.handle_invalid_cmd()?;
}
}
}
}
watch_state.into_writer().write_all(b"
We hope you're enjoying learning Rust!
If you want to continue working on the exercises at a later point, you can simply run `rustlings` again.
")?;
Ok(())
}