1use crate::{
3 Cmd, EditMode, InputMode, InputState, KeyCode, KeyEvent, Modifiers, Refresher, RepeatCount,
4};
5
6use radix_trie::TrieKey;
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10pub enum Event {
11 Any,
14 KeySeq(Vec<KeyEvent>),
16 Mouse(),
18}
19
20impl Event {
21 pub(crate) fn normalize(mut self) -> Self {
23 if let Self::KeySeq(ref mut keys) = self {
24 for key in keys.iter_mut() {
25 *key = KeyEvent::normalize(*key);
26 }
27 }
28 self
29 }
30
31 #[must_use]
33 pub fn get(&self, i: usize) -> Option<&KeyEvent> {
34 if let Self::KeySeq(ref ks) = self {
35 ks.get(i)
36 } else {
37 None
38 }
39 }
40}
41
42impl From<KeyEvent> for Event {
43 fn from(k: KeyEvent) -> Self {
44 Self::KeySeq(vec![k])
45 }
46}
47
48const BASE: u32 = 0x0010_ffff + 1;
49const BASE_CONTROL: u32 = 0x0200_0000;
50const BASE_META: u32 = 0x0400_0000;
51const BASE_SHIFT: u32 = 0x0100_0000;
52const ESCAPE: u32 = 27;
53const PAGE_UP: u32 = BASE + 1;
54const PAGE_DOWN: u32 = PAGE_UP + 1;
55const DOWN: u32 = PAGE_DOWN + 1;
56const UP: u32 = DOWN + 1;
57const LEFT: u32 = UP + 1;
58const RIGHT: u32 = LEFT + 1;
59const HOME: u32 = RIGHT + 1;
60const END: u32 = HOME + 1;
61const DELETE: u32 = END + 1;
62const INSERT: u32 = DELETE + 1;
63const MOUSE: u32 = INSERT + 25;
65const PASTE_START: u32 = MOUSE + 1;
66const PASTE_FINISH: u32 = PASTE_START + 1;
67const ANY: u32 = PASTE_FINISH + 1;
68
69impl KeyEvent {
70 fn encode(&self) -> u32 {
71 let mut u = match self.0 {
72 KeyCode::UnknownEscSeq | KeyCode::Null => 0,
73 KeyCode::Backspace => u32::from('\x7f'),
74 KeyCode::BackTab => u32::from('\t') | BASE_SHIFT,
75 KeyCode::BracketedPasteStart => PASTE_START,
76 KeyCode::BracketedPasteEnd => PASTE_FINISH,
77 KeyCode::Char(c) => u32::from(c),
78 KeyCode::Delete => DELETE,
79 KeyCode::Down => DOWN,
80 KeyCode::End => END,
81 KeyCode::Enter => u32::from('\r'),
82 KeyCode::F(i) => INSERT + u32::from(i),
83 KeyCode::Esc => ESCAPE,
84 KeyCode::Home => HOME,
85 KeyCode::Insert => INSERT,
86 KeyCode::Left => LEFT,
87 KeyCode::PageDown => PAGE_DOWN,
88 KeyCode::PageUp => PAGE_UP,
89 KeyCode::Right => RIGHT,
90 KeyCode::Tab => u32::from('\t'),
91 KeyCode::Up => UP,
92 };
93 if self.1.contains(Modifiers::CTRL) {
94 u |= BASE_CONTROL;
95 }
96 if self.1.contains(Modifiers::ALT) {
97 u |= BASE_META;
98 }
99 if self.1.contains(Modifiers::SHIFT) {
100 u |= BASE_SHIFT;
101 }
102 u
103 }
104}
105
106impl TrieKey for Event {
107 fn encode_bytes(&self) -> Vec<u8> {
108 match self {
109 Self::Any => ANY.to_be_bytes().to_vec(),
110 Self::KeySeq(keys) => {
111 let mut dst = Vec::with_capacity(keys.len() * 4);
112 for key in keys {
113 dst.extend_from_slice(&key.encode().to_be_bytes());
114 }
115 dst
116 }
117 Self::Mouse() => MOUSE.to_be_bytes().to_vec(),
118 }
119 }
120}
121
122pub enum EventHandler {
124 Simple(Cmd),
126 Conditional(Box<dyn ConditionalEventHandler>),
128 }
131
132impl From<Cmd> for EventHandler {
133 fn from(c: Cmd) -> Self {
134 Self::Simple(c)
135 }
136}
137
138pub struct EventContext<'r> {
140 mode: EditMode,
141 input_mode: InputMode,
142 wrt: &'r dyn Refresher,
143}
144
145impl<'r> EventContext<'r> {
146 pub(crate) fn new(is: &InputState, wrt: &'r dyn Refresher) -> Self {
147 Self {
148 mode: is.mode,
149 input_mode: is.input_mode,
150 wrt,
151 }
152 }
153
154 #[must_use]
156 pub fn mode(&self) -> EditMode {
157 self.mode
158 }
159
160 #[must_use]
162 pub fn input_mode(&self) -> InputMode {
163 self.input_mode
164 }
165
166 #[must_use]
168 pub fn has_hint(&self) -> bool {
169 self.wrt.has_hint()
170 }
171
172 #[must_use]
174 pub fn hint_text(&self) -> Option<&str> {
175 self.wrt.hint_text()
176 }
177
178 #[must_use]
180 pub fn line(&self) -> &str {
181 self.wrt.line()
182 }
183
184 #[must_use]
186 pub fn pos(&self) -> usize {
187 self.wrt.pos()
188 }
189}
190
191pub trait ConditionalEventHandler: Send + Sync {
201 fn handle(
205 &self,
206 evt: &Event,
207 n: RepeatCount,
208 positive: bool,
209 ctx: &EventContext,
210 ) -> Option<Cmd>;
211}
212
213#[cfg(test)]
214mod test {
215 use super::{Event, EventHandler};
216 use crate::{Cmd, KeyCode, KeyEvent, Modifiers};
217 use radix_trie::Trie;
218
219 #[test]
220 fn encode() {
221 let mut trie = Trie::new();
222 let evt = Event::KeySeq(vec![KeyEvent::ctrl('X'), KeyEvent::ctrl('E')]);
223 trie.insert(evt.clone(), EventHandler::from(Cmd::Noop));
224 let prefix = Event::from(KeyEvent::ctrl('X'));
225 let subtrie = trie.get_raw_descendant(&prefix);
226 assert!(subtrie.is_some());
227 let subtrie = subtrie.unwrap();
228 let sub_result = subtrie.get(&evt);
229 assert!(sub_result.unwrap().is_some());
230 let prefix = Event::from(KeyEvent::ctrl('O'));
231 let subtrie = trie.get_raw_descendant(&prefix);
232 assert!(subtrie.is_none())
233 }
234
235 #[test]
236 fn no_collision() {
237 use {Event as E, EventHandler as H, KeyCode as C, KeyEvent as K, Modifiers as M};
238 let mut trie = Trie::new();
239 trie.insert(E::from(K(C::Backspace, M::NONE)), H::from(Cmd::Noop));
240 trie.insert(E::from(K(C::Enter, M::NONE)), H::from(Cmd::Noop));
241 trie.insert(E::from(K(C::Tab, M::NONE)), H::from(Cmd::Noop));
242 trie.insert(E::from(K(C::Backspace, M::CTRL)), H::from(Cmd::Noop));
243 trie.insert(E::from(K(C::Enter, M::CTRL)), H::from(Cmd::Noop));
244 trie.insert(E::from(K(C::Tab, M::CTRL)), H::from(Cmd::Noop));
245 }
246
247 #[test]
248 #[ignore]
249 #[cfg(target_arch = "x86_64")]
250 fn size_of_event() {
251 use core::mem::size_of;
252 assert_eq!(size_of::<Event>(), 32);
253 }
254}