diff options
| author | mo8it <mo8it@proton.me> | 2024-09-12 17:45:42 +0200 |
|---|---|---|
| committer | mo8it <mo8it@proton.me> | 2024-09-12 17:46:06 +0200 |
| commit | 3947c4de284cb82945055a0fe802c2755e951bb9 (patch) | |
| tree | 943146d047f4e3722878df5e2bb3fd5c834886d5 /src/watch/terminal_event.rs | |
| parent | 664228ef8b910640b353acd7445fa14b9d16ad9f (diff) | |
Pause input while running an exercise
Diffstat (limited to 'src/watch/terminal_event.rs')
| -rw-r--r-- | src/watch/terminal_event.rs | 63 |
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); } |
