@@ -10,7 +10,8 @@ use std::fs;
10
10
use std:: io:: { self , prelude:: * } ;
11
11
use std:: path:: Path ;
12
12
use std:: process:: { Command , Stdio } ;
13
- use std:: sync:: mpsc:: channel;
13
+ use std:: sync:: atomic:: { AtomicBool , Ordering } ;
14
+ use std:: sync:: mpsc:: { RecvTimeoutError , channel} ;
14
15
use std:: sync:: { Arc , Mutex } ;
15
16
use std:: thread;
16
17
use std:: time:: Duration ;
@@ -217,68 +218,76 @@ fn main() {
217
218
}
218
219
219
220
Subcommands :: Watch ( _subargs) => {
220
- if let Err ( e) = watch ( & exercises, verbose) {
221
- println ! (
222
- "Error: Could not watch your progress. Error message was {:?}." ,
223
- e
224
- ) ;
225
- println ! ( "Most likely you've run out of disk space or your 'inotify limit' has been reached." ) ;
226
- std:: process:: exit ( 1 ) ;
221
+ match watch ( & exercises, verbose) {
222
+ Err ( e) => {
223
+ println ! (
224
+ "Error: Could not watch your progress. Error message was {:?}." ,
225
+ e
226
+ ) ;
227
+ println ! ( "Most likely you've run out of disk space or your 'inotify limit' has been reached." ) ;
228
+ std:: process:: exit ( 1 ) ;
229
+ }
230
+ Ok ( WatchStatus :: Finished ) => {
231
+ println ! (
232
+ "{emoji} All exercises completed! {emoji}" ,
233
+ emoji = Emoji ( "🎉" , "★" )
234
+ ) ;
235
+ println ! ( ) ;
236
+ println ! ( "+----------------------------------------------------+" ) ;
237
+ println ! ( "| You made it to the Fe-nish line! |" ) ;
238
+ println ! ( "+-------------------------- ------------------------+" ) ;
239
+ println ! ( " \\ / " ) ;
240
+ println ! ( " ▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒ " ) ;
241
+ println ! ( " ▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒ " ) ;
242
+ println ! ( " ▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒ " ) ;
243
+ println ! ( " ░░▒▒▒▒░░▒▒ ▒▒ ▒▒ ▒▒ ▒▒░░▒▒▒▒ " ) ;
244
+ println ! ( " ▓▓▓▓▓▓▓▓ ▓▓ ▓▓██ ▓▓ ▓▓██ ▓▓ ▓▓▓▓▓▓▓▓ " ) ;
245
+ println ! ( " ▒▒▒▒ ▒▒ ████ ▒▒ ████ ▒▒░░ ▒▒▒▒ " ) ;
246
+ println ! ( " ▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒ " ) ;
247
+ println ! ( " ▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒▒▒▒▒▒▒▒▓▓▒▒▓▓▒▒▒▒▒▒▒▒ " ) ;
248
+ println ! ( " ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ " ) ;
249
+ println ! ( " ▒▒▒▒▒▒▒▒▒▒██▒▒▒▒▒▒██▒▒▒▒▒▒▒▒▒▒ " ) ;
250
+ println ! ( " ▒▒ ▒▒▒▒▒▒▒▒▒▒██████▒▒▒▒▒▒▒▒▒▒ ▒▒ " ) ;
251
+ println ! ( " ▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒ " ) ;
252
+ println ! ( " ▒▒ ▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒ ▒▒ " ) ;
253
+ println ! ( " ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ " ) ;
254
+ println ! ( " ▒▒ ▒▒ ▒▒ ▒▒ " ) ;
255
+ println ! ( ) ;
256
+ println ! ( "We hope you enjoyed learning about the various aspects of Rust!" ) ;
257
+ println ! (
258
+ "If you noticed any issues, please don't hesitate to report them to our repo."
259
+ ) ;
260
+ println ! ( "You can also contribute your own exercises to help the greater community!" ) ;
261
+ println ! ( ) ;
262
+ println ! ( "Before reporting an issue or contributing, please read our guidelines:" ) ;
263
+ println ! ( "https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md" ) ;
264
+ }
265
+ Ok ( WatchStatus :: Unfinished ) => {
266
+ println ! ( "We hope you're enjoying learning about Rust!" ) ;
267
+ println ! ( "If you want to continue working on the exercises at a later point, you can simply run `rustlings watch` again" ) ;
268
+ }
227
269
}
228
- println ! (
229
- "{emoji} All exercises completed! {emoji}" ,
230
- emoji = Emoji ( "🎉" , "★" )
231
- ) ;
232
- println ! ( ) ;
233
- println ! ( "+----------------------------------------------------+" ) ;
234
- println ! ( "| You made it to the Fe-nish line! |" ) ;
235
- println ! ( "+-------------------------- ------------------------+" ) ;
236
- println ! ( " \\ / " ) ;
237
- println ! ( " ▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒ " ) ;
238
- println ! ( " ▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒ " ) ;
239
- println ! ( " ▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒ " ) ;
240
- println ! ( " ░░▒▒▒▒░░▒▒ ▒▒ ▒▒ ▒▒ ▒▒░░▒▒▒▒ " ) ;
241
- println ! ( " ▓▓▓▓▓▓▓▓ ▓▓ ▓▓██ ▓▓ ▓▓██ ▓▓ ▓▓▓▓▓▓▓▓ " ) ;
242
- println ! ( " ▒▒▒▒ ▒▒ ████ ▒▒ ████ ▒▒░░ ▒▒▒▒ " ) ;
243
- println ! ( " ▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒ " ) ;
244
- println ! ( " ▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒▒▒▒▒▒▒▒▓▓▒▒▓▓▒▒▒▒▒▒▒▒ " ) ;
245
- println ! ( " ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ " ) ;
246
- println ! ( " ▒▒▒▒▒▒▒▒▒▒██▒▒▒▒▒▒██▒▒▒▒▒▒▒▒▒▒ " ) ;
247
- println ! ( " ▒▒ ▒▒▒▒▒▒▒▒▒▒██████▒▒▒▒▒▒▒▒▒▒ ▒▒ " ) ;
248
- println ! ( " ▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒ " ) ;
249
- println ! ( " ▒▒ ▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒ ▒▒ " ) ;
250
- println ! ( " ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ " ) ;
251
- println ! ( " ▒▒ ▒▒ ▒▒ ▒▒ " ) ;
252
- println ! ( ) ;
253
- println ! ( "We hope you enjoyed learning about the various aspects of Rust!" ) ;
254
- println ! (
255
- "If you noticed any issues, please don't hesitate to report them to our repo."
256
- ) ;
257
- println ! ( "You can also contribute your own exercises to help the greater community!" ) ;
258
- println ! ( ) ;
259
- println ! ( "Before reporting an issue or contributing, please read our guidelines:" ) ;
260
- println ! ( "https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md" ) ;
261
270
}
262
271
}
263
272
}
264
273
265
- fn spawn_watch_shell ( failed_exercise_hint : & Arc < Mutex < Option < String > > > ) {
274
+ fn spawn_watch_shell ( failed_exercise_hint : & Arc < Mutex < Option < String > > > , should_quit : Arc < AtomicBool > ) {
266
275
let failed_exercise_hint = Arc :: clone ( failed_exercise_hint) ;
267
276
println ! ( "Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here." ) ;
268
277
thread:: spawn ( move || loop {
269
278
let mut input = String :: new ( ) ;
270
279
match io:: stdin ( ) . read_line ( & mut input) {
271
280
Ok ( _) => {
272
281
let input = input. trim ( ) ;
273
- if input. eq ( "hint" ) {
282
+ if input == "hint" {
274
283
if let Some ( hint) = & * failed_exercise_hint. lock ( ) . unwrap ( ) {
275
284
println ! ( "{}" , hint) ;
276
285
}
277
- } else if input. eq ( "clear" ) {
286
+ } else if input == "clear" {
278
287
println ! ( "\x1B [2J\x1B [1;1H" ) ;
279
288
} else if input. eq ( "quit" ) {
289
+ should_quit. store ( true , Ordering :: SeqCst ) ;
280
290
println ! ( "Bye!" ) ;
281
- std:: process:: exit ( 0 ) ;
282
291
} else if input. eq ( "help" ) {
283
292
println ! ( "Commands available to you in watch mode:" ) ;
284
293
println ! ( " hint - prints the current exercise's hint" ) ;
@@ -318,14 +327,20 @@ fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise {
318
327
}
319
328
}
320
329
321
- fn watch ( exercises : & [ Exercise ] , verbose : bool ) -> notify:: Result < ( ) > {
330
+ enum WatchStatus {
331
+ Finished ,
332
+ Unfinished ,
333
+ }
334
+
335
+ fn watch ( exercises : & [ Exercise ] , verbose : bool ) -> notify:: Result < WatchStatus > {
322
336
/* Clears the terminal with an ANSI escape code.
323
337
Works in UNIX and newer Windows terminals. */
324
338
fn clear_screen ( ) {
325
339
println ! ( "\x1B c" ) ;
326
340
}
327
341
328
342
let ( tx, rx) = channel ( ) ;
343
+ let should_quit = Arc :: new ( AtomicBool :: new ( false ) ) ;
329
344
330
345
let mut watcher: RecommendedWatcher = Watcher :: new ( tx, Duration :: from_secs ( 2 ) ) ?;
331
346
watcher. watch ( Path :: new ( "./exercises" ) , RecursiveMode :: Recursive ) ?;
@@ -334,12 +349,12 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> {
334
349
335
350
let to_owned_hint = |t : & Exercise | t. hint . to_owned ( ) ;
336
351
let failed_exercise_hint = match verify ( exercises. iter ( ) , verbose) {
337
- Ok ( _) => return Ok ( ( ) ) ,
352
+ Ok ( _) => return Ok ( WatchStatus :: Finished ) ,
338
353
Err ( exercise) => Arc :: new ( Mutex :: new ( Some ( to_owned_hint ( exercise) ) ) ) ,
339
354
} ;
340
- spawn_watch_shell ( & failed_exercise_hint) ;
355
+ spawn_watch_shell ( & failed_exercise_hint, Arc :: clone ( & should_quit ) ) ;
341
356
loop {
342
- match rx. recv ( ) {
357
+ match rx. recv_timeout ( Duration :: from_secs ( 1 ) ) {
343
358
Ok ( event) => match event {
344
359
DebouncedEvent :: Create ( b) | DebouncedEvent :: Chmod ( b) | DebouncedEvent :: Write ( b) => {
345
360
if b. extension ( ) == Some ( OsStr :: new ( "rs" ) ) && b. exists ( ) {
@@ -355,7 +370,7 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> {
355
370
) ;
356
371
clear_screen ( ) ;
357
372
match verify ( pending_exercises, verbose) {
358
- Ok ( _) => return Ok ( ( ) ) ,
373
+ Ok ( _) => return Ok ( WatchStatus :: Finished ) ,
359
374
Err ( exercise) => {
360
375
let mut failed_exercise_hint = failed_exercise_hint. lock ( ) . unwrap ( ) ;
361
376
* failed_exercise_hint = Some ( to_owned_hint ( exercise) ) ;
@@ -365,8 +380,15 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> {
365
380
}
366
381
_ => { }
367
382
} ,
383
+ Err ( RecvTimeoutError :: Timeout ) => {
384
+ // the timeout expired, just check the `should_quit` variable below then loop again
385
+ }
368
386
Err ( e) => println ! ( "watch error: {:?}" , e) ,
369
387
}
388
+ // Check if we need to exit
389
+ if should_quit. load ( Ordering :: SeqCst ) {
390
+ return Ok ( WatchStatus :: Unfinished ) ;
391
+ }
370
392
}
371
393
}
372
394
0 commit comments