Skip to content

Commit 3dce7e5

Browse files
committed
Improvements to watch mode
1 parent 9c6f56b commit 3dce7e5

File tree

3 files changed

+57
-36
lines changed

3 files changed

+57
-36
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ notify-debouncer-mini = "0.4.1"
1818
regex = "1.10.3"
1919
serde_json = "1.0.114"
2020
serde = { version = "1.0.197", features = ["derive"] }
21+
shlex = "1.3.0"
2122
toml = "0.8.10"
2223

2324
[[bin]]

src/main.rs

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use clap::{Parser, Subcommand};
66
use console::Emoji;
77
use notify_debouncer_mini::notify::{self, RecursiveMode};
88
use notify_debouncer_mini::{new_debouncer, DebouncedEventKind};
9+
use shlex::Shlex;
910
use std::ffi::OsStr;
1011
use std::fs;
1112
use std::io::{self, prelude::*};
@@ -25,6 +26,16 @@ mod project;
2526
mod run;
2627
mod verify;
2728

29+
const WATCH_MODE_HELP_MESSAGE: &str = "Commands available to you in watch mode:
30+
hint - prints the current exercise's hint
31+
clear - clears the screen
32+
quit - quits watch mode
33+
!<cmd> - executes a command, like `!rustc --explain E0381`
34+
help - displays this help message
35+
36+
Watch mode automatically re-evaluates the current exercise
37+
when you edit a file's contents.";
38+
2839
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
2940
#[derive(Parser)]
3041
#[command(version)]
@@ -246,47 +257,49 @@ fn main() {
246257
}
247258

248259
fn spawn_watch_shell(
249-
failed_exercise_hint: &Arc<Mutex<Option<String>>>,
260+
failed_exercise_hint: Arc<Mutex<Option<String>>>,
250261
should_quit: Arc<AtomicBool>,
251262
) {
252-
let failed_exercise_hint = Arc::clone(failed_exercise_hint);
253263
println!("Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.");
254-
thread::spawn(move || loop {
264+
265+
thread::spawn(move || {
255266
let mut input = String::new();
256-
match io::stdin().read_line(&mut input) {
257-
Ok(_) => {
258-
let input = input.trim();
259-
if input == "hint" {
260-
if let Some(hint) = &*failed_exercise_hint.lock().unwrap() {
261-
println!("{hint}");
262-
}
263-
} else if input == "clear" {
264-
println!("\x1B[2J\x1B[1;1H");
265-
} else if input.eq("quit") {
266-
should_quit.store(true, Ordering::SeqCst);
267-
println!("Bye!");
268-
} else if input.eq("help") {
269-
println!("Commands available to you in watch mode:");
270-
println!(" hint - prints the current exercise's hint");
271-
println!(" clear - clears the screen");
272-
println!(" quit - quits watch mode");
273-
println!(" !<cmd> - executes a command, like `!rustc --explain E0381`");
274-
println!(" help - displays this help message");
275-
println!();
276-
println!("Watch mode automatically re-evaluates the current exercise");
277-
println!("when you edit a file's contents.")
278-
} else if let Some(cmd) = input.strip_prefix('!') {
279-
let parts: Vec<&str> = cmd.split_whitespace().collect();
280-
if parts.is_empty() {
281-
println!("no command provided");
282-
} else if let Err(e) = Command::new(parts[0]).args(&parts[1..]).status() {
283-
println!("failed to execute command `{}`: {}", cmd, e);
284-
}
285-
} else {
286-
println!("unknown command: {input}");
267+
let mut stdin = io::stdin().lock();
268+
269+
loop {
270+
// Recycle input buffer.
271+
input.clear();
272+
273+
if let Err(e) = stdin.read_line(&mut input) {
274+
println!("error reading command: {e}");
275+
}
276+
277+
let input = input.trim();
278+
if input == "hint" {
279+
if let Some(hint) = &*failed_exercise_hint.lock().unwrap() {
280+
println!("{hint}");
287281
}
282+
} else if input == "clear" {
283+
println!("\x1B[2J\x1B[1;1H");
284+
} else if input == "quit" {
285+
should_quit.store(true, Ordering::SeqCst);
286+
println!("Bye!");
287+
} else if input == "help" {
288+
println!("{WATCH_MODE_HELP_MESSAGE}");
289+
} else if let Some(cmd) = input.strip_prefix('!') {
290+
let mut parts = Shlex::new(cmd);
291+
292+
let Some(program) = parts.next() else {
293+
println!("no command provided");
294+
continue;
295+
};
296+
297+
if let Err(e) = Command::new(program).args(parts).status() {
298+
println!("failed to execute command `{cmd}`: {e}");
299+
}
300+
} else {
301+
println!("unknown command: {input}\n{WATCH_MODE_HELP_MESSAGE}");
288302
}
289-
Err(error) => println!("error reading command: {error}"),
290303
}
291304
});
292305
}
@@ -348,7 +361,7 @@ fn watch(
348361
Ok(_) => return Ok(WatchStatus::Finished),
349362
Err(exercise) => Arc::new(Mutex::new(Some(to_owned_hint(exercise)))),
350363
};
351-
spawn_watch_shell(&failed_exercise_hint, Arc::clone(&should_quit));
364+
spawn_watch_shell(Arc::clone(&failed_exercise_hint), Arc::clone(&should_quit));
352365
loop {
353366
match rx.recv_timeout(Duration::from_secs(1)) {
354367
Ok(event) => match event {

0 commit comments

Comments
 (0)