summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNahor <nahor.j+github@gmail.com>2024-10-02 13:40:32 -0700
committerNahor <nahor.j+github@gmail.com>2024-10-02 13:40:32 -0700
commitc52867eb8bf69f67e702b87dd2bf12125aa7ab12 (patch)
tree8bd8d22b1de936b279063e0a43c1c740708a7c15
parent26fd97a209d936755aa653ee0110d17d27e47306 (diff)
Add command to check all the exercises
This allows for skipping repeating "next" when multiple exercises are done at once, or when earlier exercises have been updated/changed (and thus must be redone) while still working of the whole set (i.e. the final check_all is not yet available to flag those undone exercises)
-rw-r--r--src/app_state.rs24
-rw-r--r--src/watch.rs7
-rw-r--r--src/watch/state.rs22
-rw-r--r--src/watch/terminal_event.rs2
4 files changed, 51 insertions, 4 deletions
diff --git a/src/app_state.rs b/src/app_state.rs
index de5a382..99772b7 100644
--- a/src/app_state.rs
+++ b/src/app_state.rs
@@ -396,8 +396,16 @@ impl AppState {
}
// Return the exercise index of the first pending exercise found.
- fn check_all_exercises(&mut self, stdout: &mut StdoutLock) -> Result<Option<usize>> {
- stdout.write_all(FINAL_CHECK_MSG)?;
+ pub fn check_all_exercises(
+ &mut self,
+ stdout: &mut StdoutLock,
+ final_check: bool,
+ ) -> Result<Option<usize>> {
+ if !final_check {
+ stdout.write_all(INTERMEDIATE_CHECK_MSG)?;
+ } else {
+ stdout.write_all(FINAL_CHECK_MSG)?;
+ }
let n_exercises = self.exercises.len();
let (mut checked_count, mut results) = thread::scope(|s| {
@@ -513,7 +521,7 @@ impl AppState {
stdout.write_all(b"\n")?;
}
- if let Some(pending_exercise_ind) = self.check_all_exercises(stdout)? {
+ if let Some(pending_exercise_ind) = self.check_all_exercises(stdout, true)? {
stdout.write_all(b"\n\n")?;
self.current_exercise_ind = pending_exercise_ind;
@@ -525,6 +533,12 @@ impl AppState {
// Write that the last exercise is done.
self.write()?;
+ self.render_final_message(stdout)?;
+
+ Ok(ExercisesProgress::AllDone)
+ }
+
+ pub fn render_final_message(&self, stdout: &mut StdoutLock) -> Result<()> {
clear_terminal(stdout)?;
stdout.write_all(FENISH_LINE.as_bytes())?;
@@ -534,12 +548,14 @@ impl AppState {
stdout.write_all(b"\n")?;
}
- Ok(ExercisesProgress::AllDone)
+ Ok(())
}
}
const BAD_INDEX_ERR: &str = "The current exercise index is higher than the number of exercises";
const STATE_FILE_HEADER: &[u8] = b"DON'T EDIT THIS FILE!\n\n";
+const INTERMEDIATE_CHECK_MSG: &[u8] = b"Checking all exercises
+";
const FINAL_CHECK_MSG: &[u8] = b"All exercises seem to be done.
Recompiling and running all exercises to make sure that all of them are actually done.
";
diff --git a/src/watch.rs b/src/watch.rs
index 35533b0..b984675 100644
--- a/src/watch.rs
+++ b/src/watch.rs
@@ -103,6 +103,13 @@ fn run_watch(
WatchEvent::Input(InputEvent::Run) => watch_state.run_current_exercise(&mut stdout)?,
WatchEvent::Input(InputEvent::Hint) => watch_state.show_hint(&mut stdout)?,
WatchEvent::Input(InputEvent::List) => return Ok(WatchExit::List),
+ WatchEvent::Input(InputEvent::CheckAll) => match watch_state
+ .check_all_exercises(&mut stdout)?
+ {
+ ExercisesProgress::AllDone => break,
+ ExercisesProgress::NewPending => watch_state.run_current_exercise(&mut stdout)?,
+ ExercisesProgress::CurrentPending => (),
+ },
WatchEvent::Input(InputEvent::Reset) => watch_state.reset_exercise(&mut stdout)?,
WatchEvent::Input(InputEvent::Quit) => {
stdout.write_all(QUIT_MSG)?;
diff --git a/src/watch/state.rs b/src/watch/state.rs
index 19910f0..67a6357 100644
--- a/src/watch/state.rs
+++ b/src/watch/state.rs
@@ -196,6 +196,11 @@ impl<'a> WatchState<'a> {
stdout.write_all(b":list / ")?;
stdout.queue(SetAttribute(Attribute::Bold))?;
+ stdout.write_all(b"c")?;
+ stdout.queue(ResetColor)?;
+ stdout.write_all(b":check all / ")?;
+
+ stdout.queue(SetAttribute(Attribute::Bold))?;
stdout.write_all(b"x")?;
stdout.queue(ResetColor)?;
stdout.write_all(b":reset / ")?;
@@ -274,6 +279,23 @@ impl<'a> WatchState<'a> {
Ok(())
}
+ pub fn check_all_exercises(&mut self, stdout: &mut StdoutLock) -> Result<ExercisesProgress> {
+ stdout.write_all(b"\n")?;
+
+ if let Some(first_fail) = self.app_state.check_all_exercises(stdout, false)? {
+ // Only change exercise if the current one is done...
+ if self.app_state.current_exercise().done {
+ self.app_state.set_current_exercise_ind(first_fail)?;
+ }
+ // ...but always pretend it's a "new" anyway because that refreshes
+ // the display
+ Ok(ExercisesProgress::NewPending)
+ } else {
+ self.app_state.render_final_message(stdout)?;
+ Ok(ExercisesProgress::AllDone)
+ }
+ }
+
pub fn update_term_width(&mut self, width: u16, stdout: &mut StdoutLock) -> io::Result<()> {
if self.term_width != width {
self.term_width = width;
diff --git a/src/watch/terminal_event.rs b/src/watch/terminal_event.rs
index 1ed681d..48411db 100644
--- a/src/watch/terminal_event.rs
+++ b/src/watch/terminal_event.rs
@@ -11,6 +11,7 @@ pub enum InputEvent {
Run,
Hint,
List,
+ CheckAll,
Reset,
Quit,
}
@@ -37,6 +38,7 @@ pub fn terminal_event_handler(
KeyCode::Char('r') if manual_run => InputEvent::Run,
KeyCode::Char('h') => InputEvent::Hint,
KeyCode::Char('l') => break WatchEvent::Input(InputEvent::List),
+ KeyCode::Char('c') => InputEvent::CheckAll,
KeyCode::Char('x') => {
if sender.send(WatchEvent::Input(InputEvent::Reset)).is_err() {
return;