11use anyhow:: { bail, Context , Error , Result } ;
2- use crossterm:: {
3- style:: { ResetColor , SetForegroundColor } ,
4- terminal, QueueableCommand ,
5- } ;
2+ use crossterm:: { cursor, terminal, QueueableCommand } ;
63use std:: {
74 env,
85 fs:: { File , OpenOptions } ,
@@ -23,7 +20,7 @@ use crate::{
2320 embedded:: EMBEDDED_FILES ,
2421 exercise:: { Exercise , RunnableExercise } ,
2522 info_file:: ExerciseInfo ,
26- term:: { self , progress_bar_with_success } ,
23+ term:: { self , show_exercises_check_progress } ,
2724} ;
2825
2926const STATE_FILE_NAME : & str = ".rustlings-state.txt" ;
@@ -44,18 +41,12 @@ pub enum StateFileStatus {
4441 NotRead ,
4542}
4643
47- enum ExerciseCheckProgress {
48- Checking ,
49- Done ,
50- Pending ,
51- Error ,
52- }
53-
5444#[ derive( Clone , Copy ) ]
55- enum ExerciseCheckResult {
45+ pub enum ExerciseCheckProgress {
46+ None ,
47+ Checking ,
5648 Done ,
5749 Pending ,
58- Error ,
5950}
6051
6152pub struct AppState {
@@ -417,27 +408,25 @@ impl AppState {
417408 }
418409 }
419410
420- // Return the exercise index of the first pending exercise found.
421- pub fn check_all_exercises ( & mut self , stdout : & mut StdoutLock ) -> Result < Option < usize > > {
411+ fn check_all_exercises_impl ( & mut self , stdout : & mut StdoutLock ) -> Result < Option < usize > > {
422412 stdout. write_all ( "Checking all exercises…\n " . as_bytes ( ) ) ?;
423- let n_exercises = self . exercises . len ( ) as u16 ;
424413 let next_exercise_ind = AtomicUsize :: new ( 0 ) ;
425414 let term_width = terminal:: size ( )
426415 . context ( "Failed to get the terminal size" ) ?
427416 . 0 ;
417+ clear_terminal ( stdout) ?;
428418
429- let mut results = vec ! [ ExerciseCheckResult :: Error ; self . exercises. len( ) ] ;
419+ let mut progresses = vec ! [ ExerciseCheckProgress :: None ; self . exercises. len( ) ] ;
430420 let mut done = 0 ;
431421 let mut pending = 0 ;
432422
433423 thread:: scope ( |s| {
434- let mut checking = 0 ;
435- let ( exercise_result_sender, exercise_result_receiver) = mpsc:: channel ( ) ;
424+ let ( exercise_progress_sender, exercise_progress_receiver) = mpsc:: channel ( ) ;
436425 let n_threads = thread:: available_parallelism ( )
437426 . map_or ( DEFAULT_CHECK_PARALLELISM , |count| count. get ( ) ) ;
438427
439428 for _ in 0 ..n_threads {
440- let exercise_result_sender = exercise_result_sender . clone ( ) ;
429+ let exercise_progress_sender = exercise_progress_sender . clone ( ) ;
441430 let next_exercise_ind = & next_exercise_ind;
442431 let slf = & self ;
443432 thread:: Builder :: new ( )
@@ -449,125 +438,102 @@ impl AppState {
449438 } ;
450439
451440 // Notify the progress bar that this exercise is pending.
452- if exercise_result_sender
441+ if exercise_progress_sender
453442 . send ( ( exercise_ind, ExerciseCheckProgress :: Checking ) )
454443 . is_err ( )
455444 {
456445 break ;
457446 } ;
458447
459448 let success = exercise. run_exercise ( None , & slf. cmd_runner ) ;
460- let result = match success {
449+ let progress = match success {
461450 Ok ( true ) => ExerciseCheckProgress :: Done ,
462451 Ok ( false ) => ExerciseCheckProgress :: Pending ,
463- Err ( _) => ExerciseCheckProgress :: Error ,
452+ Err ( _) => ExerciseCheckProgress :: None ,
464453 } ;
465454
466455 // Notify the progress bar that this exercise is done.
467- if exercise_result_sender. send ( ( exercise_ind, result) ) . is_err ( ) {
456+ if exercise_progress_sender
457+ . send ( ( exercise_ind, progress) )
458+ . is_err ( )
459+ {
468460 break ;
469461 }
470462 } )
471463 . context ( "Failed to spawn a thread to check all exercises" ) ?;
472464 }
473465
474466 // Drop this sender to detect when the last thread is done.
475- drop ( exercise_result_sender) ;
476-
477- // Print the legend.
478- stdout. write_all ( b"Color legend: " ) ?;
479- stdout. queue ( SetForegroundColor ( term:: PROGRESS_FAILED_COLOR ) ) ?;
480- stdout. write_all ( b"Pending" ) ?;
481- stdout. queue ( ResetColor ) ?;
482- stdout. write_all ( b" - " ) ?;
483- stdout. queue ( SetForegroundColor ( term:: PROGRESS_SUCCESS_COLOR ) ) ?;
484- stdout. write_all ( b"Done" ) ?;
485- stdout. queue ( ResetColor ) ?;
486- stdout. write_all ( b" - " ) ?;
487- stdout. queue ( SetForegroundColor ( term:: PROGRESS_PENDING_COLOR ) ) ?;
488- stdout. write_all ( b"Checking" ) ?;
489- stdout. queue ( ResetColor ) ?;
490- stdout. write_all ( b"\n " ) ?;
467+ drop ( exercise_progress_sender) ;
491468
492- while let Ok ( ( exercise_ind, result) ) = exercise_result_receiver. recv ( ) {
493- match result {
494- ExerciseCheckProgress :: Checking => checking += 1 ,
495- ExerciseCheckProgress :: Done => {
496- results[ exercise_ind] = ExerciseCheckResult :: Done ;
497- checking -= 1 ;
498- done += 1 ;
499- }
500- ExerciseCheckProgress :: Pending => {
501- results[ exercise_ind] = ExerciseCheckResult :: Pending ;
502- checking -= 1 ;
503- pending += 1 ;
504- }
505- ExerciseCheckProgress :: Error => checking -= 1 ,
469+ while let Ok ( ( exercise_ind, progress) ) = exercise_progress_receiver. recv ( ) {
470+ progresses[ exercise_ind] = progress;
471+
472+ match progress {
473+ ExerciseCheckProgress :: None | ExerciseCheckProgress :: Checking => ( ) ,
474+ ExerciseCheckProgress :: Done => done += 1 ,
475+ ExerciseCheckProgress :: Pending => pending += 1 ,
506476 }
507477
508- stdout. write_all ( b"\r " ) ?;
509- progress_bar_with_success (
510- stdout,
511- checking,
512- pending,
513- done,
514- n_exercises,
515- term_width,
516- ) ?;
517- stdout. flush ( ) ?;
478+ show_exercises_check_progress ( stdout, & progresses, term_width) ?;
518479 }
519480
520481 Ok :: < _ , Error > ( ( ) )
521482 } ) ?;
522483
523484 let mut first_pending_exercise_ind = None ;
524- for ( exercise_ind, result ) in results . into_iter ( ) . enumerate ( ) {
525- match result {
526- ExerciseCheckResult :: Done => {
485+ for exercise_ind in 0 ..progresses . len ( ) {
486+ match progresses [ exercise_ind ] {
487+ ExerciseCheckProgress :: Done => {
527488 self . set_status ( exercise_ind, true ) ?;
528489 }
529- ExerciseCheckResult :: Pending => {
490+ ExerciseCheckProgress :: Pending => {
530491 self . set_status ( exercise_ind, false ) ?;
531492 if first_pending_exercise_ind. is_none ( ) {
532493 first_pending_exercise_ind = Some ( exercise_ind) ;
533494 }
534495 }
535- ExerciseCheckResult :: Error => {
496+ ExerciseCheckProgress :: None | ExerciseCheckProgress :: Checking => {
536497 // If we got an error while checking all exercises in parallel,
537498 // it could be because we exceeded the limit of open file descriptors.
538499 // Therefore, try running exercises with errors sequentially.
500+ progresses[ exercise_ind] = ExerciseCheckProgress :: Checking ;
501+ show_exercises_check_progress ( stdout, & progresses, term_width) ?;
502+
539503 let exercise = & self . exercises [ exercise_ind] ;
540504 let success = exercise. run_exercise ( None , & self . cmd_runner ) ?;
541505 if success {
542506 done += 1 ;
507+ progresses[ exercise_ind] = ExerciseCheckProgress :: Done ;
543508 } else {
544509 pending += 1 ;
545510 if first_pending_exercise_ind. is_none ( ) {
546511 first_pending_exercise_ind = Some ( exercise_ind) ;
547512 }
513+ progresses[ exercise_ind] = ExerciseCheckProgress :: Pending ;
548514 }
549515 self . set_status ( exercise_ind, success) ?;
550516
551- stdout. write_all ( b"\r " ) ?;
552- progress_bar_with_success (
553- stdout,
554- u16:: from ( pending + done < n_exercises) ,
555- pending,
556- done,
557- n_exercises,
558- term_width,
559- ) ?;
560- stdout. flush ( ) ?;
517+ show_exercises_check_progress ( stdout, & progresses, term_width) ?;
561518 }
562519 }
563520 }
564521
565522 self . write ( ) ?;
566- stdout. write_all ( b"\n \n " ) ?;
523+ stdout. write_all ( b"\n " ) ?;
567524
568525 Ok ( first_pending_exercise_ind)
569526 }
570527
528+ // Return the exercise index of the first pending exercise found.
529+ pub fn check_all_exercises ( & mut self , stdout : & mut StdoutLock ) -> Result < Option < usize > > {
530+ stdout. queue ( cursor:: Hide ) ?;
531+ let res = self . check_all_exercises_impl ( stdout) ;
532+ stdout. queue ( cursor:: Show ) ?;
533+
534+ res
535+ }
536+
571537 /// Mark the current exercise as done and move on to the next pending exercise if one exists.
572538 /// If all exercises are marked as done, run all of them to make sure that they are actually
573539 /// done. If an exercise which is marked as done fails, mark it as pending and continue on it.
0 commit comments