Make the list mode part of the watch mode

This commit is contained in:
mo8it 2024-04-10 02:12:50 +02:00
parent 533a009257
commit d1a965f019
3 changed files with 37 additions and 14 deletions

View file

@ -16,9 +16,11 @@ mod watch;
use self::{ use self::{
consts::WELCOME, consts::WELCOME,
exercise::{Exercise, InfoFile}, exercise::{Exercise, InfoFile},
list::list,
run::run, run::run,
state_file::StateFile, state_file::StateFile,
verify::{verify, VerifyState}, verify::{verify, VerifyState},
watch::{watch, WatchExit},
}; };
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code /// 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 /// The name of the exercise
name: String, name: String,
}, },
/// List the exercises available in Rustlings
List,
} }
fn find_exercise(name: &str, exercises: &'static [Exercise]) -> Result<(usize, &'static Exercise)> { 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); let mut state_file = StateFile::read_or_default(exercises);
match args.command { match args.command {
None | Some(Subcommands::Watch) => { None | Some(Subcommands::Watch) => loop {
watch::watch(&state_file, exercises)?; 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. // `Init` is handled above.
Some(Subcommands::Init) => (), Some(Subcommands::Init) => (),
Some(Subcommands::List) => {
list::list(&mut state_file, exercises)?;
}
Some(Subcommands::Run { name }) => { Some(Subcommands::Run { name }) => {
let (_, exercise) = find_exercise(&name, exercises)?; let (_, exercise) = find_exercise(&name, exercises)?;
run(exercise).unwrap_or_else(|_| exit(1)); run(exercise).unwrap_or_else(|_| exit(1));

View file

@ -18,9 +18,19 @@ use crate::{exercise::Exercise, state_file::StateFile};
use self::state::WatchState; 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 { enum InputEvent {
Hint, Hint,
Clear, Clear,
List,
Quit, Quit,
Unrecognized, Unrecognized,
} }
@ -86,20 +96,26 @@ fn input_handler(tx: Sender<WatchEvent>) {
let event = match stdin_buf.trim() { let event = match stdin_buf.trim() {
"h" | "hint" => InputEvent::Hint, "h" | "hint" => InputEvent::Hint,
"c" | "clear" => InputEvent::Clear, "c" | "clear" => InputEvent::Clear,
"l" | "list" => InputEvent::List,
"q" | "quit" => InputEvent::Quit, "q" | "quit" => InputEvent::Quit,
_ => InputEvent::Unrecognized, _ => InputEvent::Unrecognized,
}; };
stdin_buf.clear();
if tx.send(WatchEvent::Input(event)).is_err() { if tx.send(WatchEvent::Input(event)).is_err() {
// The receiver was dropped. // The receiver was dropped.
return; 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<WatchExit> {
let (tx, rx) = channel(); let (tx, rx) = channel();
let mut debouncer = new_debouncer( let mut debouncer = new_debouncer(
Duration::from_secs(1), Duration::from_secs(1),
@ -125,6 +141,9 @@ pub fn watch(state_file: &StateFile, exercises: &'static [Exercise]) -> Result<(
WatchEvent::Input(InputEvent::Hint) => { WatchEvent::Input(InputEvent::Hint) => {
watch_state.show_hint()?; watch_state.show_hint()?;
} }
WatchEvent::Input(InputEvent::List) => {
return Ok(WatchExit::List);
}
WatchEvent::Input(InputEvent::Clear) | WatchEvent::TerminalResize => { WatchEvent::Input(InputEvent::Clear) | WatchEvent::TerminalResize => {
watch_state.render()?; 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. If you want to continue working on the exercises at a later point, you can simply run `rustlings` again.
")?; ")?;
Ok(()) Ok(WatchExit::Shutdown)
} }

View file

@ -36,10 +36,11 @@ impl<'a> WatchState<'a> {
let writer = io::stdout().lock(); let writer = io::stdout().lock();
let prompt = format!( let prompt = format!(
"\n\n{}int/{}lear/{}uit? ", "\n\n{}int/{}lear/{}ist/{}uit? ",
"h".bold(), "h".bold(),
"c".bold(), "c".bold(),
"q".bold() "l".bold(),
"q".bold(),
) )
.into_bytes(); .into_bytes();