Trigger check all when an exercise is done but not marked as such

This commit is contained in:
mo8it 2026-08-02 14:18:11 +02:00
parent dd758b79ba
commit 8168c0fced
2 changed files with 35 additions and 23 deletions

View File

@ -43,7 +43,6 @@ enum WatchEvent {
Input(InputEvent), Input(InputEvent),
FileChange { exercise_ind: usize }, FileChange { exercise_ind: usize },
TerminalResize { width: u16 }, TerminalResize { width: u16 },
CheckAll,
NotifyErr(notify::Error), NotifyErr(notify::Error),
TerminalEventErr(io::Error), TerminalEventErr(io::Error),
} }
@ -97,7 +96,20 @@ fn run_watch(
match event { match event {
WatchEvent::Input(InputEvent::Next) => match watch_state.next_exercise(&mut stdout)? { WatchEvent::Input(InputEvent::Next) => match watch_state.next_exercise(&mut stdout)? {
ExercisesProgress::AllDone => break, ExercisesProgress::AllDone => break,
ExercisesProgress::NewPending => watch_state.run_current_exercise(&mut stdout)?, ExercisesProgress::NewPending => {
watch_state.run_current_exercise(&mut stdout)?;
if watch_state.done() {
// An exercise is done although it was not marked as such.
// Trigger check all to fix the state file.
match watch_state.check_all_exercises(&mut stdout)? {
ExercisesProgress::AllDone => break,
ExercisesProgress::NewPending => {
watch_state.run_current_exercise(&mut stdout)?;
}
ExercisesProgress::CurrentPending => watch_state.render(&mut stdout)?,
}
}
}
ExercisesProgress::CurrentPending => (), ExercisesProgress::CurrentPending => (),
}, },
WatchEvent::Input(InputEvent::Run) => watch_state.run_current_exercise(&mut stdout)?, WatchEvent::Input(InputEvent::Run) => watch_state.run_current_exercise(&mut stdout)?,
@ -114,11 +126,6 @@ fn run_watch(
WatchEvent::TerminalResize { width } => { WatchEvent::TerminalResize { width } => {
watch_state.update_term_width(width, &mut stdout)?; watch_state.update_term_width(width, &mut stdout)?;
} }
WatchEvent::CheckAll => match watch_state.check_all_exercises(&mut stdout)? {
ExercisesProgress::AllDone => break,
ExercisesProgress::NewPending => watch_state.run_current_exercise(&mut stdout)?,
ExercisesProgress::CurrentPending => watch_state.render(&mut stdout)?,
},
WatchEvent::NotifyErr(e) => return Err(Error::from(e).context(NOTIFY_ERR)), WatchEvent::NotifyErr(e) => return Err(Error::from(e).context(NOTIFY_ERR)),
WatchEvent::TerminalEventErr(e) => { WatchEvent::TerminalEventErr(e) => {
return Err(Error::from(e).context("Terminal event listener failed")); return Err(Error::from(e).context("Terminal event listener failed"));

View File

@ -24,7 +24,6 @@ const HEADING_ATTRIBUTES: Attributes = Attributes::none()
.with(Attribute::Bold) .with(Attribute::Bold)
.with(Attribute::Underlined); .with(Attribute::Underlined);
#[derive(PartialEq, Eq)]
enum DoneStatus { enum DoneStatus {
DoneWithSolution(String), DoneWithSolution(String),
DoneWithoutSolution, DoneWithoutSolution,
@ -93,19 +92,19 @@ impl<'a> WatchState<'a> {
.current_exercise() .current_exercise()
.run_exercise(Some(&mut self.output), self.app_state.cmd_runner())?; .run_exercise(Some(&mut self.output), self.app_state.cmd_runner())?;
self.output.push(b'\n'); self.output.push(b'\n');
if success {
self.done_status = self.done_status = if success {
if let Some(solution_path) = self.app_state.current_solution_path()? { if let Some(solution_path) = self.app_state.current_solution_path()? {
DoneStatus::DoneWithSolution(solution_path) DoneStatus::DoneWithSolution(solution_path)
} else { } else {
DoneStatus::DoneWithoutSolution DoneStatus::DoneWithoutSolution
}; }
} else { } else {
self.app_state self.app_state
.set_pending(self.app_state.current_exercise_ind())?; .set_pending(self.app_state.current_exercise_ind())?;
self.done_status = DoneStatus::Pending; DoneStatus::Pending
} };
self.app_state.join_editor_handle(editor_handle)?; self.app_state.join_editor_handle(editor_handle)?;
self.render(stdout)?; self.render(stdout)?;
@ -164,18 +163,24 @@ impl<'a> WatchState<'a> {
self.run_current_exercise(stdout) self.run_current_exercise(stdout)
} }
pub fn done(&self) -> bool {
match self.done_status {
DoneStatus::DoneWithSolution(_) | DoneStatus::DoneWithoutSolution => true,
DoneStatus::Pending => false,
}
}
/// Move on to the next exercise if the current one is done. /// Move on to the next exercise if the current one is done.
pub fn next_exercise(&mut self, stdout: &mut StdoutLock) -> Result<ExercisesProgress> { pub fn next_exercise(&mut self, stdout: &mut StdoutLock) -> Result<ExercisesProgress> {
match self.done_status { if self.done() {
DoneStatus::DoneWithSolution(_) | DoneStatus::DoneWithoutSolution => (), return self.app_state.done_current_exercise::<true>(stdout);
DoneStatus::Pending => return Ok(ExercisesProgress::CurrentPending),
} }
self.app_state.done_current_exercise::<true>(stdout) Ok(ExercisesProgress::CurrentPending)
} }
fn show_prompt(&self, stdout: &mut StdoutLock) -> io::Result<()> { fn show_prompt(&self, stdout: &mut StdoutLock) -> io::Result<()> {
if self.done_status != DoneStatus::Pending { if self.done() {
stdout.queue(SetAttribute(Attribute::Bold))?; stdout.queue(SetAttribute(Attribute::Bold))?;
stdout.write_all(b"n")?; stdout.write_all(b"n")?;
stdout.queue(ResetColor)?; stdout.queue(ResetColor)?;
@ -233,7 +238,7 @@ impl<'a> WatchState<'a> {
stdout.write_all(b"\n\n")?; stdout.write_all(b"\n\n")?;
} }
if self.done_status != DoneStatus::Pending { if self.done() {
stdout stdout
.queue(SetAttribute(Attribute::Bold))? .queue(SetAttribute(Attribute::Bold))?
.queue(SetForegroundColor(Color::Green))?; .queue(SetForegroundColor(Color::Green))?;