@@ -6,6 +6,7 @@ use clap::{Parser, Subcommand};
6
6
use console:: Emoji ;
7
7
use notify_debouncer_mini:: notify:: { self , RecursiveMode } ;
8
8
use notify_debouncer_mini:: { new_debouncer, DebouncedEventKind } ;
9
+ use shlex:: Shlex ;
9
10
use std:: ffi:: OsStr ;
10
11
use std:: fs;
11
12
use std:: io:: { self , prelude:: * } ;
@@ -25,6 +26,16 @@ mod project;
25
26
mod run;
26
27
mod verify;
27
28
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
+
28
39
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
29
40
#[ derive( Parser ) ]
30
41
#[ command( version) ]
@@ -246,47 +257,49 @@ fn main() {
246
257
}
247
258
248
259
fn spawn_watch_shell (
249
- failed_exercise_hint : & Arc < Mutex < Option < String > > > ,
260
+ failed_exercise_hint : Arc < Mutex < Option < String > > > ,
250
261
should_quit : Arc < AtomicBool > ,
251
262
) {
252
- let failed_exercise_hint = Arc :: clone ( failed_exercise_hint) ;
253
263
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 || {
255
266
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}" ) ;
287
281
}
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}" ) ;
288
302
}
289
- Err ( error) => println ! ( "error reading command: {error}" ) ,
290
303
}
291
304
} ) ;
292
305
}
@@ -348,7 +361,7 @@ fn watch(
348
361
Ok ( _) => return Ok ( WatchStatus :: Finished ) ,
349
362
Err ( exercise) => Arc :: new ( Mutex :: new ( Some ( to_owned_hint ( exercise) ) ) ) ,
350
363
} ;
351
- spawn_watch_shell ( & failed_exercise_hint, Arc :: clone ( & should_quit) ) ;
364
+ spawn_watch_shell ( Arc :: clone ( & failed_exercise_hint) , Arc :: clone ( & should_quit) ) ;
352
365
loop {
353
366
match rx. recv_timeout ( Duration :: from_secs ( 1 ) ) {
354
367
Ok ( event) => match event {
0 commit comments