@@ -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:: * } ;
@@ -244,47 +245,49 @@ fn main() {
244
245
}
245
246
246
247
fn spawn_watch_shell (
247
- failed_exercise_hint : & Arc < Mutex < Option < String > > > ,
248
+ failed_exercise_hint : Arc < Mutex < Option < String > > > ,
248
249
should_quit : Arc < AtomicBool > ,
249
250
) {
250
- let failed_exercise_hint = Arc :: clone ( failed_exercise_hint) ;
251
251
println ! ( "Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here." ) ;
252
- thread:: spawn ( move || loop {
253
- let mut input = String :: new ( ) ;
254
- match io:: stdin ( ) . read_line ( & mut input) {
255
- Ok ( _) => {
256
- let input = input. trim ( ) ;
257
- if input == "hint" {
258
- if let Some ( hint) = & * failed_exercise_hint. lock ( ) . unwrap ( ) {
259
- println ! ( "{hint}" ) ;
260
- }
261
- } else if input == "clear" {
262
- println ! ( "\x1B [2J\x1B [1;1H" ) ;
263
- } else if input. eq ( "quit" ) {
264
- should_quit. store ( true , Ordering :: SeqCst ) ;
265
- println ! ( "Bye!" ) ;
266
- } else if input. eq ( "help" ) {
267
- println ! ( "Commands available to you in watch mode:" ) ;
268
- println ! ( " hint - prints the current exercise's hint" ) ;
269
- println ! ( " clear - clears the screen" ) ;
270
- println ! ( " quit - quits watch mode" ) ;
271
- println ! ( " !<cmd> - executes a command, like `!rustc --explain E0381`" ) ;
272
- println ! ( " help - displays this help message" ) ;
273
- println ! ( ) ;
274
- println ! ( "Watch mode automatically re-evaluates the current exercise" ) ;
275
- println ! ( "when you edit a file's contents." )
276
- } else if let Some ( cmd) = input. strip_prefix ( '!' ) {
277
- let parts: Vec < & str > = cmd. split_whitespace ( ) . collect ( ) ;
278
- if parts. is_empty ( ) {
279
- println ! ( "no command provided" ) ;
280
- } else if let Err ( e) = Command :: new ( parts[ 0 ] ) . args ( & parts[ 1 ..] ) . status ( ) {
281
- println ! ( "failed to execute command `{cmd}`: {e}" ) ;
282
- }
283
- } else {
284
- println ! ( "unknown command: {input}" ) ;
252
+
253
+ thread:: spawn ( move || {
254
+ let mut input = String :: with_capacity ( 32 ) ;
255
+ let mut stdin = io:: stdin ( ) . lock ( ) ;
256
+
257
+ loop {
258
+ // Recycle input buffer.
259
+ input. clear ( ) ;
260
+
261
+ if let Err ( e) = stdin. read_line ( & mut input) {
262
+ println ! ( "error reading command: {e}" ) ;
263
+ }
264
+
265
+ let input = input. trim ( ) ;
266
+ if input == "hint" {
267
+ if let Some ( hint) = & * failed_exercise_hint. lock ( ) . unwrap ( ) {
268
+ println ! ( "{hint}" ) ;
269
+ }
270
+ } else if input == "clear" {
271
+ println ! ( "\x1B [2J\x1B [1;1H" ) ;
272
+ } else if input == "quit" {
273
+ should_quit. store ( true , Ordering :: SeqCst ) ;
274
+ println ! ( "Bye!" ) ;
275
+ } else if input == "help" {
276
+ println ! ( "{WATCH_MODE_HELP_MESSAGE}" ) ;
277
+ } else if let Some ( cmd) = input. strip_prefix ( '!' ) {
278
+ let mut parts = Shlex :: new ( cmd) ;
279
+
280
+ let Some ( program) = parts. next ( ) else {
281
+ println ! ( "no command provided" ) ;
282
+ continue ;
283
+ } ;
284
+
285
+ if let Err ( e) = Command :: new ( program) . args ( parts) . status ( ) {
286
+ println ! ( "failed to execute command `{cmd}`: {e}" ) ;
285
287
}
288
+ } else {
289
+ println ! ( "unknown command: {input}\n {WATCH_MODE_HELP_MESSAGE}" ) ;
286
290
}
287
- Err ( error) => println ! ( "error reading command: {error}" ) ,
288
291
}
289
292
} ) ;
290
293
}
@@ -345,7 +348,7 @@ fn watch(
345
348
Ok ( _) => return Ok ( WatchStatus :: Finished ) ,
346
349
Err ( exercise) => Arc :: new ( Mutex :: new ( Some ( exercise. hint . clone ( ) ) ) ) ,
347
350
} ;
348
- spawn_watch_shell ( & failed_exercise_hint, Arc :: clone ( & should_quit) ) ;
351
+ spawn_watch_shell ( Arc :: clone ( & failed_exercise_hint) , Arc :: clone ( & should_quit) ) ;
349
352
loop {
350
353
match rx. recv_timeout ( Duration :: from_secs ( 1 ) ) {
351
354
Ok ( event) => match event {
@@ -462,3 +465,13 @@ const WELCOME: &str = r" welcome to...
462
465
| | | |_| \__ \ |_| | | | | | (_| \__ \
463
466
|_| \__,_|___/\__|_|_|_| |_|\__, |___/
464
467
|___/" ;
468
+
469
+ const WATCH_MODE_HELP_MESSAGE : & str = "Commands available to you in watch mode:
470
+ hint - prints the current exercise's hint
471
+ clear - clears the screen
472
+ quit - quits watch mode
473
+ !<cmd> - executes a command, like `!rustc --explain E0381`
474
+ help - displays this help message
475
+
476
+ Watch mode automatically re-evaluates the current exercise
477
+ when you edit a file's contents." ;
0 commit comments