1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
#[derive(Debug)]
pub enum Event {
Key(textmode::Key),
Resize((u16, u16)),
ProcessOutput,
ProcessAlternateScreen,
ProcessExit,
ClockTimer,
}
pub struct Reader {
pending: async_std::sync::Mutex<Pending>,
cvar: async_std::sync::Condvar,
}
impl Reader {
pub fn new(
input: async_std::channel::Receiver<Event>,
) -> async_std::sync::Arc<Self> {
let this = std::sync::Arc::new(Self {
pending: async_std::sync::Mutex::new(Pending::new()),
cvar: async_std::sync::Condvar::new(),
});
{
let this = std::sync::Arc::clone(&this);
async_std::task::spawn(async move {
while let Ok(event) = input.recv().await {
this.new_event(Some(event)).await;
}
this.new_event(None).await;
});
}
this
}
pub async fn recv(&self) -> Option<Event> {
let mut pending = self
.cvar
.wait_until(self.pending.lock().await, |pending| {
pending.has_event()
})
.await;
pending.get_event()
}
async fn new_event(&self, event: Option<Event>) {
let mut pending = self.pending.lock().await;
pending.new_event(&event);
self.cvar.notify_one();
}
}
#[derive(Default)]
struct Pending {
key: std::collections::VecDeque<textmode::Key>,
size: Option<(u16, u16)>,
process_output: bool,
process_alternate_screen: bool,
process_exit: bool,
clock_timer: bool,
done: bool,
}
impl Pending {
fn new() -> Self {
Self::default()
}
fn has_event(&self) -> bool {
self.done
|| !self.key.is_empty()
|| self.size.is_some()
|| self.process_output
|| self.process_alternate_screen
|| self.process_exit
|| self.clock_timer
}
fn get_event(&mut self) -> Option<Event> {
if self.done {
return None;
}
if let Some(key) = self.key.pop_front() {
return Some(Event::Key(key));
}
if let Some(size) = self.size.take() {
return Some(Event::Resize(size));
}
if self.process_exit {
self.process_exit = false;
return Some(Event::ProcessExit);
}
if self.process_alternate_screen {
self.process_alternate_screen = false;
return Some(Event::ProcessAlternateScreen);
}
if self.clock_timer {
self.clock_timer = false;
return Some(Event::ClockTimer);
}
// process_output should be last because it will often be the case
// that there is ~always new process output (cat on large files, yes,
// etc) and that shouldn't prevent other events from happening
if self.process_output {
self.process_output = false;
return Some(Event::ProcessOutput);
}
unreachable!()
}
fn new_event(&mut self, event: &Option<Event>) {
match event {
Some(Event::Key(key)) => self.key.push_back(key.clone()),
Some(Event::Resize(size)) => self.size = Some(*size),
Some(Event::ProcessOutput) => self.process_output = true,
Some(Event::ProcessAlternateScreen) => {
self.process_alternate_screen = true;
}
Some(Event::ProcessExit) => self.process_exit = true,
Some(Event::ClockTimer) => self.clock_timer = true,
None => self.done = true,
}
}
}
|