summaryrefslogtreecommitdiff
path: root/src/watch/terminal_event.rs
diff options
context:
space:
mode:
authormo8it <mo8it@proton.me>2024-09-12 17:45:42 +0200
committermo8it <mo8it@proton.me>2024-09-12 17:46:06 +0200
commit3947c4de284cb82945055a0fe802c2755e951bb9 (patch)
tree943146d047f4e3722878df5e2bb3fd5c834886d5 /src/watch/terminal_event.rs
parent664228ef8b910640b353acd7445fa14b9d16ad9f (diff)
Pause input while running an exercise
Diffstat (limited to 'src/watch/terminal_event.rs')
-rw-r--r--src/watch/terminal_event.rs63
1 files changed, 41 insertions, 22 deletions
diff --git a/src/watch/terminal_event.rs b/src/watch/terminal_event.rs
index ca3a846..2a1dfdc 100644
--- a/src/watch/terminal_event.rs
+++ b/src/watch/terminal_event.rs
@@ -1,8 +1,32 @@
use crossterm::event::{self, Event, KeyCode, KeyEventKind};
-use std::sync::mpsc::Sender;
+use std::sync::{
+ atomic::{AtomicBool, Ordering::Relaxed},
+ mpsc::Sender,
+};
use super::WatchEvent;
+static INPUT_PAUSED: AtomicBool = AtomicBool::new(false);
+
+// Private unit type to force using the constructor function.
+#[must_use = "When the guard is dropped, the input is unpaused"]
+pub struct InputPauseGuard(());
+
+impl InputPauseGuard {
+ #[inline]
+ pub fn scoped_pause() -> Self {
+ INPUT_PAUSED.store(true, Relaxed);
+ Self(())
+ }
+}
+
+impl Drop for InputPauseGuard {
+ #[inline]
+ fn drop(&mut self) {
+ INPUT_PAUSED.store(false, Relaxed);
+ }
+}
+
pub enum InputEvent {
Run,
Next,
@@ -11,46 +35,41 @@ pub enum InputEvent {
Quit,
}
-pub fn terminal_event_handler(tx: Sender<WatchEvent>, manual_run: bool) {
- let last_input_event = loop {
- let terminal_event = match event::read() {
- Ok(v) => v,
- Err(e) => {
- // If `send` returns an error, then the receiver is dropped and
- // a shutdown has been already initialized.
- let _ = tx.send(WatchEvent::TerminalEventErr(e));
- return;
- }
- };
-
- match terminal_event {
- Event::Key(key) => {
+pub fn terminal_event_handler(sender: Sender<WatchEvent>, manual_run: bool) {
+ let last_watch_event = loop {
+ match event::read() {
+ Ok(Event::Key(key)) => {
match key.kind {
KeyEventKind::Release | KeyEventKind::Repeat => continue,
KeyEventKind::Press => (),
}
+ if INPUT_PAUSED.load(Relaxed) {
+ continue;
+ }
+
let input_event = match key.code {
KeyCode::Char('n') => InputEvent::Next,
KeyCode::Char('h') => InputEvent::Hint,
- KeyCode::Char('l') => break InputEvent::List,
- KeyCode::Char('q') => break InputEvent::Quit,
+ KeyCode::Char('l') => break WatchEvent::Input(InputEvent::List),
+ KeyCode::Char('q') => break WatchEvent::Input(InputEvent::Quit),
KeyCode::Char('r') if manual_run => InputEvent::Run,
_ => continue,
};
- if tx.send(WatchEvent::Input(input_event)).is_err() {
+ if sender.send(WatchEvent::Input(input_event)).is_err() {
return;
}
}
- Event::Resize(width, _) => {
- if tx.send(WatchEvent::TerminalResize { width }).is_err() {
+ Ok(Event::Resize(width, _)) => {
+ if sender.send(WatchEvent::TerminalResize { width }).is_err() {
return;
}
}
- Event::FocusGained | Event::FocusLost | Event::Mouse(_) => continue,
+ Ok(Event::FocusGained | Event::FocusLost | Event::Mouse(_)) => continue,
+ Err(e) => break WatchEvent::TerminalEventErr(e),
}
};
- let _ = tx.send(WatchEvent::Input(last_input_event));
+ let _ = sender.send(last_watch_event);
}