1use std::{any::TypeId, sync::LazyLock};
2
3use crossterm::event::KeyEvent;
4use parking_lot::Mutex;
5
6pub use self::global::*;
7use super::Mode;
8use crate::{
9 context,
10 data::RwData,
11 mode,
12 text::{Key, Tag, text},
13 ui::Ui,
14 widgets::Widget,
15};
16
17mod global {
18 use std::str::Chars;
19
20 use crossterm::event::{KeyCode, KeyEvent, KeyModifiers as KeyMod};
21 use parking_lot::Mutex;
22
23 use super::{Gives, Remapper};
24 use crate::{
25 data::DataMap,
26 mode::Mode,
27 text::{Text, text},
28 ui::Ui,
29 };
30
31 static REMAPPER: Remapper = Remapper::new();
32 static SEND_KEY: Mutex<fn(KeyEvent)> = Mutex::new(empty);
33
34 pub fn map<M: Mode<U>, U: Ui>(take: &str, give: impl AsGives<U>) {
71 REMAPPER.remap::<M, U>(str_to_keys(take), give.into_gives(), false);
72 }
73
74 pub fn alias<M: Mode<U>, U: Ui>(take: &str, give: impl AsGives<U>) {
98 REMAPPER.remap::<M, U>(str_to_keys(take), give.into_gives(), true);
99 }
100
101 pub fn cur_sequence() -> DataMap<(Vec<KeyEvent>, bool), (Vec<KeyEvent>, bool)> {
102 REMAPPER.cur_seq.map(|seq| seq.clone())
103 }
104
105 pub fn keys_to_text(keys: &[KeyEvent]) -> Text {
107 use crossterm::event::KeyCode::*;
108 let mut seq = Text::builder();
109
110 for key in keys {
111 match key.code {
112 Backspace => text!(seq, [SeqSpecialKey] "BS"),
113 Enter => text!(seq, [SeqSpecialKey] "Enter"),
114 Left => text!(seq, [SeqSpecialKey] "Left"),
115 Right => text!(seq, [SeqSpecialKey] "Right"),
116 Up => text!(seq, [SeqSpecialKey] "Up"),
117 Down => text!(seq, [SeqSpecialKey] "Down"),
118 Home => text!(seq, [SeqSpecialKey] "Home"),
119 End => text!(seq, [SeqSpecialKey] "End"),
120 PageUp => text!(seq, [SeqSpecialKey] "PageU"),
121 PageDown => text!(seq, [SeqSpecialKey] "PageD"),
122 Tab => text!(seq, [SeqSpecialKey] "Tab"),
123 BackTab => text!(seq, [SeqSpecialKey] "BTab"),
124 Delete => text!(seq, [SeqSpecialKey] "Del"),
125 Insert => text!(seq, [SeqSpecialKey] "Ins"),
126 F(num) => text!(seq, [SeqSpecialKey] "F" num),
127 Char(char) => text!(seq, [SeqCharKey] char),
128 Null => text!(seq, [SeqSpecialKey] "Null"),
129 Esc => text!(seq, [SeqSpecialKey] "Esc"),
130 CapsLock => text!(seq, [SeqSpecialKey] "CapsL"),
131 ScrollLock => text!(seq, [SeqSpecialKey] "ScrollL"),
132 NumLock => text!(seq, [SeqSpecialKey] "NumL"),
133 PrintScreen => text!(seq, [SeqSpecialKey] "PrSc"),
134 Pause => text!(seq, [SeqSpecialKey] "Pause"),
135 Menu => text!(seq, [SeqSpecialKey] "Menu"),
136 KeypadBegin => text!(seq, [SeqSpecialKey] "KeypadBeg"),
137 Media(m_code) => text!(seq, [SeqSpecialKey] "Media" m_code),
138 Modifier(m_code) => text!(seq, [SeqSpecialKey] "Mod" m_code),
139 }
140 }
141
142 seq.finish()
143 }
144
145 pub fn keys_to_string(keys: &[KeyEvent]) -> String {
147 use std::fmt::Write;
148
149 use crossterm::event::KeyCode::*;
150 let mut seq = String::new();
151
152 for key in keys {
153 match key.code {
154 Backspace => seq.push_str("<BS>"),
155 Enter => seq.push_str("<Enter>"),
156 Left => seq.push_str("<Left>"),
157 Right => seq.push_str("<Right>"),
158 Up => seq.push_str("<Up>"),
159 Down => seq.push_str("<Down>"),
160 Home => seq.push_str("<Home>"),
161 End => seq.push_str("<End>"),
162 PageUp => seq.push_str("<PageU>"),
163 PageDown => seq.push_str("<PageD>"),
164 Tab => seq.push_str("<Tab>"),
165 BackTab => seq.push_str("<BTab>"),
166 Delete => seq.push_str("<Del>"),
167 Insert => seq.push_str("<Ins>"),
168 F(num) => write!(seq, "<F{num}>").unwrap(),
169 Char(char) => write!(seq, "{char}").unwrap(),
170 Null => seq.push_str("<Null>"),
171 Esc => seq.push_str("<Esc>"),
172 CapsLock => seq.push_str("<CapsL>"),
173 ScrollLock => seq.push_str("<ScrollL>"),
174 NumLock => seq.push_str("<NumL>"),
175 PrintScreen => seq.push_str("<PrSc>"),
176 Pause => seq.push_str("<Pause>"),
177 Menu => seq.push_str("<Menu>"),
178 KeypadBegin => seq.push_str("<KeypadBeg>"),
179 Media(m_code) => write!(seq, "<Media{m_code}>").unwrap(),
180 Modifier(m_code) => write!(seq, "<Mod{m_code}>").unwrap(),
181 }
182 }
183
184 seq
185 }
186
187 pub fn str_to_keys(str: &str) -> Vec<KeyEvent> {
192 const SPECIAL: &[(&str, KeyCode)] = &[
193 ("Enter", KeyCode::Enter),
194 ("Tab", KeyCode::Tab),
195 ("Bspc", KeyCode::Backspace),
196 ("Del", KeyCode::Delete),
197 ("Esc", KeyCode::Esc),
198 ("Up", KeyCode::Up),
199 ("Down", KeyCode::Down),
200 ("Left", KeyCode::Left),
201 ("Right", KeyCode::Right),
202 ("PageU", KeyCode::PageUp),
203 ("PageD", KeyCode::PageDown),
204 ("Home", KeyCode::Home),
205 ("End", KeyCode::End),
206 ("Ins", KeyCode::Insert),
207 ("F1", KeyCode::F(1)),
208 ("F2", KeyCode::F(2)),
209 ("F3", KeyCode::F(3)),
210 ("F4", KeyCode::F(4)),
211 ("F5", KeyCode::F(5)),
212 ("F6", KeyCode::F(6)),
213 ("F7", KeyCode::F(7)),
214 ("F8", KeyCode::F(8)),
215 ("F9", KeyCode::F(9)),
216 ("F10", KeyCode::F(10)),
217 ("F11", KeyCode::F(11)),
218 ("F12", KeyCode::F(12)),
219 ];
220 const MODS: &[(&str, KeyMod)] = &[
221 ("C", KeyMod::CONTROL),
222 ("A", KeyMod::ALT),
223 ("S", KeyMod::SHIFT),
224 ("M", KeyMod::META),
225 ("super", KeyMod::SUPER),
226 ("hyper", KeyMod::HYPER),
227 ];
228 fn match_key(chars: Chars) -> Option<(KeyEvent, Chars)> {
229 let matched_mods = {
230 let mut chars = chars.clone();
231 let mut mods = KeyMod::empty();
232 let mut seq = String::new();
233
234 loop {
235 let char = chars.next()?;
236 if char == '-' {
237 if mods.is_empty() {
238 break None;
239 } else {
240 break Some((mods, chars));
241 }
242 }
243
244 seq.push(char);
245
246 if let Some((_, m)) = MODS.iter().find(|(str, _)| str == &seq)
247 && !mods.contains(*m)
248 {
249 mods = mods.union(*m);
250 seq.clear();
251 } else if !MODS[4..6].iter().any(|(str, _)| str.starts_with(&seq)) {
252 break None;
253 }
254 }
255 };
256
257 let (mut mods, mut chars) = match matched_mods {
258 Some((mods, chars)) => (mods, chars),
259 None => (KeyMod::empty(), chars),
260 };
261
262 let mut code = Some(chars.next().map(KeyCode::Char)?);
263 let mut seq = code.unwrap().to_string();
264
265 loop {
266 if let Some(c) = code.take() {
267 match chars.next()? {
268 '>' if seq.len() > 1 || !mods.is_empty() => {
269 if let KeyCode::Char(_) = c {
271 mods.remove(KeyMod::SHIFT);
272 }
273 break Some((KeyEvent::new(c, mods), chars));
274 }
275 _ if seq.len() > 1 => break None,
276 char => seq.push(char),
277 }
278 }
279
280 if let Some((str, c)) = SPECIAL.iter().find(|(str, _)| str.starts_with(&seq)) {
281 if str == &seq {
282 code = Some(*c);
283 } else {
284 seq.push(chars.next()?);
285 }
286 } else {
287 break None;
288 }
289 }
290 }
291
292 let mut keys = Vec::new();
293 let mut chars = str.chars();
294 let mut next = chars.next();
295
296 while let Some(char) = next {
297 if char == '<'
298 && let Some((key, ahead)) = match_key(chars.clone())
299 {
300 keys.push(key);
301 chars = ahead;
302 } else {
303 keys.push(KeyEvent::from(KeyCode::Char(char)));
304 }
305
306 next = chars.next();
307 }
308
309 keys
310 }
311
312 pub trait AsGives<U> {
313 fn into_gives(self) -> Gives;
314 }
315
316 impl<M: Mode<U>, U: Ui> AsGives<U> for M {
317 fn into_gives(self) -> Gives {
318 if let Some(keys) = self.just_keys() {
319 Gives::Keys(str_to_keys(keys))
320 } else {
321 Gives::Mode(Box::new(move || crate::mode::set(self.clone())))
322 }
323 }
324 }
325
326 pub(crate) fn send_key(mut key: KeyEvent) {
328 if let KeyCode::Char(_) = key.code {
330 key.modifiers.remove(KeyMod::SHIFT);
331 }
332 let f = { *SEND_KEY.lock() };
333 f(key)
334 }
335
336 pub(in crate::mode) fn set_send_key<M: Mode<U>, U: Ui>() {
338 *SEND_KEY.lock() = send_key_fn::<M, U>;
339 }
340
341 fn send_key_fn<M: Mode<U>, U: Ui>(key: KeyEvent) {
343 REMAPPER.send_key::<M, U>(key);
344 }
345
346 fn empty(_: KeyEvent) {}
348}
349
350struct Remapper {
352 remaps: Mutex<Vec<(TypeId, Vec<Remap>)>>,
353 cur_seq: LazyLock<RwData<(Vec<KeyEvent>, bool)>>,
354}
355
356impl Remapper {
357 const fn new() -> Self {
359 Remapper {
360 remaps: Mutex::new(Vec::new()),
361 cur_seq: LazyLock::new(RwData::default),
362 }
363 }
364
365 fn remap<M: Mode<U>, U: Ui>(&self, take: Vec<KeyEvent>, give: Gives, is_alias: bool) {
367 fn remap_inner(
368 remapper: &Remapper,
369 type_id: TypeId,
370 take: Vec<KeyEvent>,
371 give: Gives,
372 is_alias: bool,
373 ) {
374 let remap = Remap::new(take, give, is_alias);
375
376 let mut remaps = remapper.remaps.lock();
377
378 if let Some((_, remaps)) = remaps.iter_mut().find(|(m, _)| type_id == *m) {
379 if remaps.iter().all(|r| {
380 !(r.takes.starts_with(&remap.takes) || remap.takes.starts_with(&r.takes))
381 }) {
382 remaps.push(remap);
383 }
384 } else {
385 remaps.push((type_id, vec![remap]));
386 }
387 }
388
389 remap_inner(self, TypeId::of::<M>(), take, give, is_alias);
390 }
391
392 fn send_key<M: Mode<U>, U: Ui>(&self, key: KeyEvent) {
394 fn send_key_inner<U: Ui>(remapper: &Remapper, type_id: TypeId, key: KeyEvent) {
395 let remaps = remapper.remaps.lock();
396 let Some((_, remaps)) = remaps.iter().find(|(m, _)| type_id == *m) else {
397 mode::send_keys_to(vec![key]);
398 return;
399 };
400
401 let mut cur_seq = remapper.cur_seq.write();
402 let (cur_seq, is_alias) = &mut *cur_seq;
403 cur_seq.push(key);
404
405 if let Some(remap) = remaps.iter().find(|r| r.takes.starts_with(cur_seq)) {
406 *is_alias = remap.is_alias;
407 if remap.takes.len() == cur_seq.len() {
408 if remap.is_alias {
409 remove_alias_and::<U>(|_, _, _| {});
410 }
411
412 *is_alias = false;
413
414 cur_seq.clear();
415 match &remap.gives {
416 Gives::Keys(keys) => mode::send_keys_to(keys.clone()),
417 Gives::Mode(f) => f(),
418 }
419 } else if *is_alias {
420 remove_alias_and::<U>(|widget, area, main| {
421 widget.text_mut().insert_tag(
422 Key::for_alias(),
423 Tag::Ghost(main, text!([Alias] { keys_to_string(cur_seq) })),
424 );
425
426 let cfg = widget.print_cfg();
427 widget.text_mut().add_cursors(area, cfg);
428 widget.update(area);
429 widget.print(area);
430 })
431 }
432 } else if *is_alias {
433 remove_alias_and::<U>(|_, _, _| {});
434 *is_alias = false;
435 mode::send_keys_to(std::mem::take(cur_seq));
436 } else {
437 mode::send_keys_to(std::mem::take(cur_seq));
438 }
439 }
440
441 send_key_inner::<U>(self, TypeId::of::<M>(), key);
442 }
443}
444
445struct Remap {
448 takes: Vec<KeyEvent>,
449 gives: Gives,
450 is_alias: bool,
451}
452
453impl Remap {
454 pub fn new(takes: Vec<KeyEvent>, gives: Gives, is_alias: bool) -> Self {
455 Self { takes, gives, is_alias }
456 }
457}
458
459pub enum Gives {
460 Keys(Vec<KeyEvent>),
461 Mode(Box<dyn Fn() + Send>),
462}
463
464fn remove_alias_and<U: Ui>(f: impl FnOnce(&mut dyn Widget<U>, &U::Area, usize)) {
465 let widget = context::cur_widget::<U>().unwrap();
466 widget.mutate_data(|widget, area, _| {
467 let mut widget = widget.write();
468 let cfg = widget.print_cfg();
469 widget.text_mut().remove_cursors(area, cfg);
470
471 if let Some(main) = widget.cursors().unwrap().get_main() {
472 let main = main.byte();
473 widget.text_mut().remove_tags(main, Key::for_alias());
474 f(&mut *widget, area, main)
475 }
476 })
477}