From fdd7de00bd37e43a4e464d1cb5cc10c3753b3688 Mon Sep 17 00:00:00 2001
From: mo8it <mo8it@proton.me>
Date: Mon, 1 Apr 2024 18:21:56 +0200
Subject: [PATCH] Improvements to `verify`

---
 src/main.rs   | 37 ++++++++++++++++---------------------
 src/verify.rs | 17 ++++++-----------
 2 files changed, 22 insertions(+), 32 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index f9e0f830..7b7b1655 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,7 +8,6 @@ use console::Emoji;
 use notify_debouncer_mini::notify::{self, RecursiveMode};
 use notify_debouncer_mini::{new_debouncer, DebouncedEventKind};
 use shlex::Shlex;
-use std::ffi::OsStr;
 use std::io::{BufRead, Write};
 use std::path::Path;
 use std::process::{exit, Command};
@@ -344,44 +343,40 @@ fn watch(
         Ok(_) => return Ok(WatchStatus::Finished),
         Err(exercise) => Arc::new(Mutex::new(Some(exercise.hint.clone()))),
     };
+
     spawn_watch_shell(Arc::clone(&failed_exercise_hint), Arc::clone(&should_quit));
+
+    let mut pending_exercises = Vec::with_capacity(exercises.len());
     loop {
         match rx.recv_timeout(Duration::from_secs(1)) {
             Ok(event) => match event {
                 Ok(events) => {
                     for event in events {
-                        let event_path = event.path;
                         if event.kind == DebouncedEventKind::Any
-                            && event_path.extension() == Some(OsStr::new("rs"))
-                            && event_path.exists()
+                            && event.path.extension().is_some_and(|ext| ext == "rs")
                         {
-                            let filepath = event_path.as_path().canonicalize().unwrap();
-                            // TODO: Remove unwrap
-                            let pending_exercises = exercises
-                                .iter()
-                                .find(|e| filepath.ends_with(&e.path))
-                                .into_iter()
-                                .chain(exercises.iter().filter(|e| {
-                                    !e.looks_done().unwrap() && !filepath.ends_with(&e.path)
-                                }));
-                            let num_done = exercises
-                                .iter()
-                                .filter(|e| e.looks_done().unwrap() && !filepath.ends_with(&e.path))
-                                .count();
+                            pending_exercises.extend(exercises.iter().filter(|exercise| {
+                                !exercise.looks_done().unwrap_or(false)
+                                    || event.path.ends_with(&exercise.path)
+                            }));
+                            let num_done = exercises.len() - pending_exercises.len();
+
                             clear_screen();
+
                             match verify(
-                                pending_exercises,
+                                pending_exercises.iter().copied(),
                                 (num_done, exercises.len()),
                                 verbose,
                                 success_hints,
                             ) {
                                 Ok(_) => return Ok(WatchStatus::Finished),
                                 Err(exercise) => {
-                                    let mut failed_exercise_hint =
-                                        failed_exercise_hint.lock().unwrap();
-                                    *failed_exercise_hint = Some(exercise.hint.clone());
+                                    let hint = exercise.hint.clone();
+                                    *failed_exercise_hint.lock().unwrap() = Some(hint);
                                 }
                             }
+
+                            pending_exercises.clear();
                         }
                     }
                 }
diff --git a/src/verify.rs b/src/verify.rs
index adfd3b26..6e048a19 100644
--- a/src/verify.rs
+++ b/src/verify.rs
@@ -16,7 +16,7 @@ use crate::exercise::{Exercise, Mode, State};
 // If the Exercise being verified is a test, the verbose boolean
 // determines whether or not the test harness outputs are displayed.
 pub fn verify<'a>(
-    exercises: impl IntoIterator<Item = &'a Exercise>,
+    pending_exercises: impl IntoIterator<Item = &'a Exercise>,
     progress: (usize, usize),
     verbose: bool,
     success_hints: bool,
@@ -33,7 +33,7 @@ pub fn verify<'a>(
     bar.set_position(num_done as u64);
     bar.set_message(format!("({percentage:.1} %)"));
 
-    for exercise in exercises {
+    for exercise in pending_exercises {
         let compile_result = match exercise.mode {
             Mode::Test => compile_and_test(exercise, RunMode::Interactive, verbose, success_hints),
             Mode::Compile => compile_and_run_interactively(exercise, success_hints),
@@ -45,16 +45,11 @@ pub fn verify<'a>(
         percentage += 100.0 / total as f32;
         bar.inc(1);
         bar.set_message(format!("({percentage:.1} %)"));
-        if bar.position() == total as u64 {
-            println!(
-                "Progress: You completed {} / {} exercises ({:.1} %).",
-                bar.position(),
-                total,
-                percentage
-            );
-            bar.finish();
-        }
     }
+
+    bar.finish();
+    println!("You completed all exercises!");
+
     Ok(())
 }