summaryrefslogtreecommitdiff
path: root/src/watch.rs
blob: 967f98c186bef7b212786b4c1ccbacd6c2355481 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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(())
}