diff --git a/src/main.rs b/src/main.rs index 504c02dc..fc83e0fd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,9 +16,11 @@ mod watch; use self::{ consts::WELCOME, exercise::{Exercise, InfoFile}, + list::list, run::run, state_file::StateFile, verify::{verify, VerifyState}, + watch::{watch, WatchExit}, }; /// Rustlings is a collection of small exercises to get you used to writing and reading Rust code @@ -52,8 +54,6 @@ enum Subcommands { /// The name of the exercise name: String, }, - /// List the exercises available in Rustlings - List, } fn find_exercise(name: &str, exercises: &'static [Exercise]) -> Result<(usize, &'static Exercise)> { @@ -112,14 +112,17 @@ If you are just starting with Rustlings, run the command `rustlings init` to ini let mut state_file = StateFile::read_or_default(exercises); match args.command { - None | Some(Subcommands::Watch) => { - watch::watch(&state_file, exercises)?; - } + None | Some(Subcommands::Watch) => loop { + match watch(&mut state_file, exercises)? { + WatchExit::Shutdown => break, + // It is much easier to exit the watch mode, launch the list mode and then restart + // the watch mode instead of trying to pause the watch threads and correct the + // watch state. + WatchExit::List => list(&mut state_file, exercises)?, + } + }, // `Init` is handled above. Some(Subcommands::Init) => (), - Some(Subcommands::List) => { - list::list(&mut state_file, exercises)?; - } Some(Subcommands::Run { name }) => { let (_, exercise) = find_exercise(&name, exercises)?; run(exercise).unwrap_or_else(|_| exit(1)); diff --git a/src/watch.rs b/src/watch.rs index 6324eb36..004a13f6 100644 --- a/src/watch.rs +++ b/src/watch.rs @@ -18,9 +18,19 @@ use crate::{exercise::Exercise, state_file::StateFile}; use self::state::WatchState; +/// Returned by the watch mode to indicate what to do afterwards. +pub enum WatchExit { + /// Exit the program. + Shutdown, + /// Enter the list mode and restart the watch mode afterwards. + List, +} + +#[derive(Copy, Clone)] enum InputEvent { Hint, Clear, + List, Quit, Unrecognized, } @@ -86,20 +96,26 @@ fn input_handler(tx: Sender) { let event = match stdin_buf.trim() { "h" | "hint" => InputEvent::Hint, "c" | "clear" => InputEvent::Clear, + "l" | "list" => InputEvent::List, "q" | "quit" => InputEvent::Quit, _ => InputEvent::Unrecognized, }; - stdin_buf.clear(); - if tx.send(WatchEvent::Input(event)).is_err() { // The receiver was dropped. return; } + + match event { + InputEvent::List | InputEvent::Quit => return, + _ => (), + } + + stdin_buf.clear(); } } -pub fn watch(state_file: &StateFile, exercises: &'static [Exercise]) -> Result<()> { +pub fn watch(state_file: &mut StateFile, exercises: &'static [Exercise]) -> Result { let (tx, rx) = channel(); let mut debouncer = new_debouncer( Duration::from_secs(1), @@ -125,6 +141,9 @@ pub fn watch(state_file: &StateFile, exercises: &'static [Exercise]) -> Result<( WatchEvent::Input(InputEvent::Hint) => { watch_state.show_hint()?; } + WatchEvent::Input(InputEvent::List) => { + return Ok(WatchExit::List); + } WatchEvent::Input(InputEvent::Clear) | WatchEvent::TerminalResize => { watch_state.render()?; } @@ -147,5 +166,5 @@ 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(()) + Ok(WatchExit::Shutdown) } diff --git a/src/watch/state.rs b/src/watch/state.rs index 4db9440b..393ea02c 100644 --- a/src/watch/state.rs +++ b/src/watch/state.rs @@ -36,10 +36,11 @@ impl<'a> WatchState<'a> { let writer = io::stdout().lock(); let prompt = format!( - "\n\n{}int/{}lear/{}uit? ", + "\n\n{}int/{}lear/{}ist/{}uit? ", "h".bold(), "c".bold(), - "q".bold() + "l".bold(), + "q".bold(), ) .into_bytes();