1use std::collections::VecDeque;
5use std::sync::Arc;
6use std::sync::atomic::{AtomicBool, Ordering};
7use std::sync::mpsc::{self, Receiver, Sender};
8use std::thread::JoinHandle;
9use std::time::{Duration, Instant};
10
11use katui_proto::input::{InputEvent, InputParser};
12
13use crate::app::is_terminal_answer;
14use crate::pane::{self, PaneView};
15use crate::tty::RawInput;
16
17const INPUT_POLL: Duration = Duration::from_millis(50);
20
21const LATE_INPUT_LIMIT: Duration = Duration::from_millis(600);
25const LATE_INPUT_SILENCE: Duration = Duration::from_millis(150);
26
27#[derive(Debug, PartialEq, Eq)]
29pub enum Signal<M> {
30 Input(InputEvent),
32 Message(M),
34 Pane(PaneView),
36}
37
38#[derive(Debug)]
40pub struct Waker<M>(pub(crate) Sender<Signal<M>>);
41
42impl<M> Clone for Waker<M> {
43 fn clone(&self) -> Self {
44 Self(self.0.clone())
45 }
46}
47
48impl<M> Waker<M> {
49 pub fn send(&self, message: M) -> bool {
51 self.0.send(Signal::Message(message)).is_ok()
52 }
53}
54
55impl<M: Send + 'static> Waker<M> {
56 pub fn every(&self, interval: Duration, message: impl Fn() -> M + Send + 'static) {
60 let waker = self.clone();
61 std::thread::spawn(move || {
62 while waker.send(message()) {
63 std::thread::sleep(interval);
64 }
65 });
66 }
67}
68
69#[derive(Debug)]
71pub struct EventPump<M> {
72 sender: Sender<Signal<M>>,
73 receiver: Receiver<Signal<M>>,
74 queued: VecDeque<Signal<M>>,
75 stop: Arc<AtomicBool>,
76 reader: Option<JoinHandle<()>>,
77}
78
79impl<M: Send + 'static> EventPump<M> {
80 #[must_use]
83 pub fn start() -> Self {
84 let (sender, receiver) = mpsc::channel();
85 let stop = Arc::new(AtomicBool::new(false));
86 let reader = RawInput::open().ok().map(|input| {
87 let (sender, stop) = (sender.clone(), stop.clone());
88 std::thread::spawn(move || read_terminal(input, &stop, &sender))
89 });
90 Self {
91 sender,
92 receiver,
93 queued: VecDeque::new(),
94 stop,
95 reader,
96 }
97 }
98
99 pub fn watch_pane_visibility(&self, program: &str) {
101 let sender = self.sender.clone();
102 pane::watch(program.to_owned(), self.stop.clone(), move |view| {
103 sender.send(Signal::Pane(view)).is_ok()
104 });
105 }
106
107 #[must_use]
109 pub fn reads_terminal(&self) -> bool {
110 self.reader.is_some()
111 }
112
113 #[must_use]
115 pub fn waker(&self) -> Waker<M> {
116 Waker(self.sender.clone())
117 }
118
119 pub fn next(&mut self, wait: Duration) -> Option<Signal<M>> {
121 if let Some(signal) = self.queued.pop_front() {
122 return Some(signal);
123 }
124 self.receiver.recv_timeout(wait).ok()
125 }
126
127 pub fn await_answer(&mut self, image: u32, wait: Duration) -> bool {
130 self.await_event(
131 |event| matches!(event, InputEvent::GraphicsAnswer(answered) if *answered == image),
132 wait,
133 )
134 }
135
136 pub fn await_device_attributes(&mut self, wait: Duration) -> bool {
139 self.await_event(|event| *event == InputEvent::DeviceAttributes, wait)
140 }
141
142 fn await_event(&mut self, wanted: impl Fn(&InputEvent) -> bool, wait: Duration) -> bool {
143 let deadline = Instant::now() + wait;
144 while let Ok(signal) = self
145 .receiver
146 .recv_timeout(deadline.saturating_duration_since(Instant::now()))
147 {
148 match signal {
149 Signal::Input(event) if wanted(&event) => return true,
150 Signal::Input(event) if is_terminal_answer(&event) => {}
151 other => self.queued.push_back(other),
152 }
153 }
154 false
155 }
156
157 pub fn finish(self) {
160 let deadline = Instant::now() + LATE_INPUT_LIMIT;
161 while Instant::now() < deadline && self.receiver.recv_timeout(LATE_INPUT_SILENCE).is_ok() {}
162 }
163}
164
165impl<M> Drop for EventPump<M> {
166 fn drop(&mut self) {
167 self.stop.store(true, Ordering::Relaxed);
168 if let Some(handle) = self.reader.take() {
169 let _ = handle.join();
170 }
171 }
172}
173
174fn read_terminal<M>(mut input: RawInput, stop: &AtomicBool, sender: &Sender<Signal<M>>) {
175 let mut parser = InputParser::default();
176 while !stop.load(Ordering::Relaxed) {
177 let events = match input.read_chunk(INPUT_POLL) {
178 Some(bytes) => parser.feed(&bytes),
179 None => parser.idle().into_iter().collect(),
180 };
181 for event in events {
182 let _ = sender.send(Signal::Input(event));
183 }
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use std::time::Duration;
190
191 use katui_proto::input::{InputEvent, Key, Mods};
192
193 use super::{EventPump, Signal};
194
195 const NO_WAIT: Duration = Duration::from_millis(0);
196
197 fn pump() -> EventPump<u32> {
198 let (sender, receiver) = std::sync::mpsc::channel();
199 EventPump {
200 sender,
201 receiver,
202 queued: std::collections::VecDeque::new(),
203 stop: std::sync::Arc::default(),
204 reader: None,
205 }
206 }
207
208 fn answer(image: u32) -> Signal<u32> {
209 Signal::Input(InputEvent::GraphicsAnswer(image))
210 }
211
212 #[test]
213 fn a_waker_delivers_from_another_thread() {
214 let mut events = pump();
215 let waker = events.waker();
216 std::thread::spawn(move || waker.send(7))
217 .join()
218 .expect("the sender thread cannot panic");
219 assert_eq!(events.next(NO_WAIT), Some(Signal::Message(7)));
220 assert_eq!(events.next(NO_WAIT), None);
221 }
222
223 #[test]
224 fn waiting_for_an_answer_keeps_other_events_in_order() {
225 let mut events = pump();
226 let key = InputEvent::Key(Key::Char('x'), Mods::NONE);
227 events
228 .sender
229 .send(Signal::Input(key.clone()))
230 .expect("the receiver is alive");
231 events
232 .sender
233 .send(answer(5))
234 .expect("the receiver is alive");
235 events
236 .sender
237 .send(Signal::Message(9))
238 .expect("the receiver is alive");
239 assert!(events.await_answer(5, NO_WAIT));
240 assert_eq!(events.next(NO_WAIT), Some(Signal::Input(key)));
241 assert_eq!(events.next(NO_WAIT), Some(Signal::Message(9)));
242 }
243
244 #[test]
245 fn unrelated_events_cannot_extend_the_wait_forever() {
246 let mut events = pump();
247 for _ in 0..3 {
248 events
249 .sender
250 .send(Signal::Message(1))
251 .expect("the receiver is alive");
252 }
253 let started = std::time::Instant::now();
254 assert!(!events.await_answer(5, Duration::from_millis(20)));
255 assert!(started.elapsed() < Duration::from_secs(2));
256 assert_eq!(events.queued.len(), 3, "the events wait their turn");
257 }
258
259 #[test]
260 fn a_stale_answer_cannot_stand_in_for_the_awaited_one() {
261 let mut events = pump();
262 events
263 .sender
264 .send(answer(4))
265 .expect("the receiver is alive");
266 assert!(!events.await_answer(5, NO_WAIT));
267 }
268}