@@ -6,6 +6,7 @@ use clap::{Parser, Subcommand};
66use console:: Emoji ;
77use notify_debouncer_mini:: notify:: { self , RecursiveMode } ;
88use notify_debouncer_mini:: { new_debouncer, DebouncedEventKind } ;
9+ use shlex:: Shlex ;
910use std:: ffi:: OsStr ;
1011use std:: fs;
1112use std:: io:: { self , prelude:: * } ;
@@ -25,6 +26,16 @@ mod project;
2526mod run;
2627mod 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
248259fn 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