1 /// Custom event handlers 2 use crate::{ 3 Cmd, EditMode, InputMode, InputState, KeyCode, KeyEvent, Modifiers, Refresher, RepeatCount, 4 }; 5 6 use radix_trie::TrieKey; 7 use smallvec::{smallvec, SmallVec}; 8 9 /// Input event 10 #[derive(Debug, Clone, PartialEq, Eq, Hash)] 11 pub enum Event { 12 /// Wildcard. 13 /// Useful if you want to filter out some keys. 14 Any, 15 /// Key sequence 16 // TODO Validate 2 ? 17 KeySeq(SmallVec<[KeyEvent; 2]>), 18 /// TODO Mouse event 19 Mouse(), 20 } 21 22 impl Event { 23 /// See [`KeyEvent::normalize`] normalize(mut self) -> Self24 pub(crate) fn normalize(mut self) -> Self { 25 if let Event::KeySeq(ref mut keys) = self { 26 for key in keys.iter_mut() { 27 *key = KeyEvent::normalize(*key); 28 } 29 } 30 self 31 } 32 33 /// Return `i`th key event get(&self, i: usize) -> Option<&KeyEvent>34 pub fn get(&self, i: usize) -> Option<&KeyEvent> { 35 if let Event::KeySeq(ref ks) = self { 36 ks.get(i) 37 } else { 38 None 39 } 40 } 41 } 42 43 impl From<KeyEvent> for Event { from(k: KeyEvent) -> Event44 fn from(k: KeyEvent) -> Event { 45 Event::KeySeq(smallvec![k]) 46 } 47 } 48 49 const BASE: u32 = 0x0010ffff + 1; 50 const BASE_CONTROL: u32 = 0x02000000; 51 const BASE_META: u32 = 0x04000000; 52 const BASE_SHIFT: u32 = 0x01000000; 53 const ESCAPE: u32 = 27; 54 const PAGE_UP: u32 = BASE + 1; 55 const PAGE_DOWN: u32 = PAGE_UP + 1; 56 const DOWN: u32 = PAGE_DOWN + 1; 57 const UP: u32 = DOWN + 1; 58 const LEFT: u32 = UP + 1; 59 const RIGHT: u32 = LEFT + 1; 60 const HOME: u32 = RIGHT + 1; 61 const END: u32 = HOME + 1; 62 const DELETE: u32 = END + 1; 63 const INSERT: u32 = DELETE + 1; 64 //const F1: u32 = INSERT + 1; 65 const MOUSE: u32 = /* F24 + 1 */ INSERT + 25; 66 const PASTE_START: u32 = MOUSE + 1; 67 const PASTE_FINISH: u32 = PASTE_START + 1; 68 const ANY: u32 = PASTE_FINISH + 1; 69 70 impl KeyEvent { encode(&self) -> u3271 fn encode(&self) -> u32 { 72 let mut u = match self.0 { 73 KeyCode::UnknownEscSeq => 0, 74 KeyCode::Backspace => u32::from('\x7f'), 75 KeyCode::BackTab => u32::from('\t') | BASE_SHIFT, 76 KeyCode::BracketedPasteStart => PASTE_START, 77 KeyCode::BracketedPasteEnd => PASTE_FINISH, 78 KeyCode::Char(c) => u32::from(c), 79 KeyCode::Delete => DELETE, 80 KeyCode::Down => DOWN, 81 KeyCode::End => END, 82 KeyCode::Enter => u32::from('\r'), 83 KeyCode::F(i) => INSERT + i as u32, 84 KeyCode::Esc => ESCAPE, 85 KeyCode::Home => HOME, 86 KeyCode::Insert => INSERT, 87 KeyCode::Left => LEFT, 88 KeyCode::Null => 0, 89 KeyCode::PageDown => PAGE_DOWN, 90 KeyCode::PageUp => PAGE_UP, 91 KeyCode::Right => RIGHT, 92 KeyCode::Tab => u32::from('\t'), 93 KeyCode::Up => UP, 94 }; 95 if self.1.contains(Modifiers::CTRL) { 96 u |= BASE_CONTROL; 97 } 98 if self.1.contains(Modifiers::ALT) { 99 u |= BASE_META; 100 } 101 if self.1.contains(Modifiers::SHIFT) { 102 u |= BASE_SHIFT; 103 } 104 u 105 } 106 } 107 108 impl TrieKey for Event { encode_bytes(&self) -> Vec<u8>109 fn encode_bytes(&self) -> Vec<u8> { 110 match self { 111 Event::Any => ANY.to_be_bytes().to_vec(), 112 Event::KeySeq(keys) => { 113 let mut dst = Vec::with_capacity(keys.len() * 4); 114 for key in keys { 115 dst.extend_from_slice(&key.encode().to_be_bytes()); 116 } 117 dst 118 } 119 Event::Mouse() => MOUSE.to_be_bytes().to_vec(), 120 } 121 } 122 } 123 124 /// Event handler 125 pub enum EventHandler { 126 /// unconditional command 127 Simple(Cmd), 128 /// handler behaviour depends on input state 129 Conditional(Box<dyn ConditionalEventHandler>), 130 /* invoke multiple actions 131 * TODO Macro(), */ 132 } 133 134 impl From<Cmd> for EventHandler { from(c: Cmd) -> EventHandler135 fn from(c: Cmd) -> EventHandler { 136 EventHandler::Simple(c) 137 } 138 } 139 140 /// Give access to user input. 141 pub struct EventContext<'r> { 142 mode: EditMode, 143 input_mode: InputMode, 144 wrt: &'r dyn Refresher, 145 } 146 147 impl<'r> EventContext<'r> { new(is: &InputState, wrt: &'r dyn Refresher) -> Self148 pub(crate) fn new(is: &InputState, wrt: &'r dyn Refresher) -> Self { 149 EventContext { 150 mode: is.mode, 151 input_mode: is.input_mode, 152 wrt, 153 } 154 } 155 156 /// emacs or vi mode mode(&self) -> EditMode157 pub fn mode(&self) -> EditMode { 158 self.mode 159 } 160 161 /// vi input mode input_mode(&self) -> InputMode162 pub fn input_mode(&self) -> InputMode { 163 self.input_mode 164 } 165 166 /// Returns `true` if there is a hint displayed. has_hint(&self) -> bool167 pub fn has_hint(&self) -> bool { 168 self.wrt.has_hint() 169 } 170 171 /// Returns the hint text that is shown after the current cursor position. hint_text(&self) -> Option<&str>172 pub fn hint_text(&self) -> Option<&str> { 173 self.wrt.hint_text() 174 } 175 176 /// currently edited line line(&self) -> &str177 pub fn line(&self) -> &str { 178 self.wrt.line() 179 } 180 181 /// Current cursor position (byte position) pos(&self) -> usize182 pub fn pos(&self) -> usize { 183 self.wrt.pos() 184 } 185 } 186 187 /// May behave differently depending on: 188 /// * edit mode (emacs vs vi) 189 /// * vi input mode (insert vs replace vs command modes) 190 /// * empty line 191 /// * cursor position 192 /// * repeat count 193 /// * original key pressed (when same command is bound to different key) 194 /// * hint 195 /// * ... 196 pub trait ConditionalEventHandler: Send + Sync { 197 /// Takes the current input state and 198 /// returns the command to be performed or `None` to perform the default 199 /// one. handle( &self, evt: &Event, n: RepeatCount, positive: bool, ctx: &EventContext, ) -> Option<Cmd>200 fn handle( 201 &self, 202 evt: &Event, 203 n: RepeatCount, 204 positive: bool, 205 ctx: &EventContext, 206 ) -> Option<Cmd>; 207 } 208 209 #[cfg(test)] 210 mod test { 211 use super::{Event, EventHandler}; 212 use crate::{Cmd, KeyCode, KeyEvent, Modifiers}; 213 use radix_trie::Trie; 214 use smallvec::smallvec; 215 216 #[test] encode()217 fn encode() { 218 let mut trie = Trie::new(); 219 let evt = Event::KeySeq(smallvec![KeyEvent::ctrl('X'), KeyEvent::ctrl('E')]); 220 trie.insert(evt.clone(), EventHandler::from(Cmd::Noop)); 221 let prefix = Event::from(KeyEvent::ctrl('X')); 222 let subtrie = trie.get_raw_descendant(&prefix); 223 assert!(subtrie.is_some()); 224 let subtrie = subtrie.unwrap(); 225 let sub_result = subtrie.get(&evt); 226 assert!(sub_result.is_ok()); 227 assert!(sub_result.unwrap().is_some()); 228 let prefix = Event::from(KeyEvent::ctrl('O')); 229 let subtrie = trie.get_raw_descendant(&prefix); 230 assert!(subtrie.is_none()) 231 } 232 233 #[test] no_collision()234 fn no_collision() { 235 use {Event as E, EventHandler as H, KeyCode as C, KeyEvent as K, Modifiers as M}; 236 let mut trie = Trie::new(); 237 trie.insert(E::from(K(C::Backspace, M::NONE)), H::from(Cmd::Noop)); 238 trie.insert(E::from(K(C::Enter, M::NONE)), H::from(Cmd::Noop)); 239 trie.insert(E::from(K(C::Tab, M::NONE)), H::from(Cmd::Noop)); 240 trie.insert(E::from(K(C::Backspace, M::CTRL)), H::from(Cmd::Noop)); 241 trie.insert(E::from(K(C::Enter, M::CTRL)), H::from(Cmd::Noop)); 242 trie.insert(E::from(K(C::Tab, M::CTRL)), H::from(Cmd::Noop)); 243 } 244 } 245