on master help sign in
Refactor keyevent handling using key, ctrl macros (#1058)

Adds ctrl! and alt! macros (which existed before the big keymap refactor) and uses them in event handling of Components. Note that this converts crossterm's KeyEvent to our own KeyEvent on each invocation of handle_event in Components.

commitefc2b4c77be55afad07762cdde9b3b74c8477933 authorGokul Soumya <gokulps15@gmail.com> dateWed 10 Nov 2021, 21:28 (5 years ago) parente863e3b
5 files changed+86−240
helix-term/src/keymap.rs+32 helix-term/src/ui/menu.rs+11−46 helix-term/src/ui/picker.rs+10−55 helix-term/src/ui/popup.rs+9−19 helix-term/src/ui/prompt.rs+24−120
helix-term/src/keymap.rs+32
@@ -25,6 +25,38 @@ macro_rules! key {
2525 };
2626}
2727
28+#[macro_export]
29+macro_rules! ctrl {
30+ ($key:ident) => {
31+ ::helix_view::input::KeyEvent {
32+ code: ::helix_view::keyboard::KeyCode::$key,
33+ modifiers: ::helix_view::keyboard::KeyModifiers::CONTROL,
34+ }
35+ };
36+ ($($ch:tt)*) => {
37+ ::helix_view::input::KeyEvent {
38+ code: ::helix_view::keyboard::KeyCode::Char($($ch)*),
39+ modifiers: ::helix_view::keyboard::KeyModifiers::CONTROL,
40+ }
41+ };
42+}
43+
44+#[macro_export]
45+macro_rules! alt {
46+ ($key:ident) => {
47+ ::helix_view::input::KeyEvent {
48+ code: ::helix_view::keyboard::KeyCode::$key,
49+ modifiers: ::helix_view::keyboard::KeyModifiers::ALT,
50+ }
51+ };
52+ ($($ch:tt)*) => {
53+ ::helix_view::input::KeyEvent {
54+ code: ::helix_view::keyboard::KeyCode::Char($($ch)*),
55+ modifiers: ::helix_view::keyboard::KeyModifiers::ALT,
56+ }
57+ };
58+}
59+
2860/// Macro for defining the root of a `Keymap` object. Example:
2961///
3062/// ```
helix-term/src/ui/menu.rs+11−46
@@ -1,5 +1,8 @@
1−use crate::compositor::{Component, Compositor, Context, EventResult};
2−use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
1+use crate::{
2+ compositor::{Component, Compositor, Context, EventResult},
3+ ctrl, key,
4+};
5+use crossterm::event::Event;
36use tui::{buffer::Buffer as Surface, widgets::Table};
47
58pub use tui::widgets::{Cell, Row};
@@ -192,63 +195,25 @@ impl<T: Item + 'static> Component for Menu<T> {
192195 compositor.pop();
193196 })));
194197
195− match event {
198+ match event.into() {
196199 // esc or ctrl-c aborts the completion and closes the menu
197− KeyEvent {
198− code: KeyCode::Esc, ..
199− }
200− | KeyEvent {
201− code: KeyCode::Char('c'),
202− modifiers: KeyModifiers::CONTROL,
203− } => {
200+ key!(Esc) | ctrl!('c') => {
204201 (self.callback_fn)(cx.editor, self.selection(), MenuEvent::Abort);
205202 return close_fn;
206203 }
207204 // arrow up/ctrl-p/shift-tab prev completion choice (including updating the doc)
208− KeyEvent {
209− code: KeyCode::BackTab,
210− ..
211− }
212− | KeyEvent {
213− code: KeyCode::Up, ..
214− }
215− | KeyEvent {
216− code: KeyCode::Char('p'),
217− modifiers: KeyModifiers::CONTROL,
218− }
219− | KeyEvent {
220− code: KeyCode::Char('k'),
221− modifiers: KeyModifiers::CONTROL,
222− } => {
205+ key!(BackTab) | key!(Up) | ctrl!('p') | ctrl!('k') => {
223206 self.move_up();
224207 (self.callback_fn)(cx.editor, self.selection(), MenuEvent::Update);
225208 return EventResult::Consumed(None);
226209 }
227− // arrow down/ctrl-n/tab advances completion choice (including updating the doc)
228− KeyEvent {
229− code: KeyCode::Tab,
230− modifiers: KeyModifiers::NONE,
231− }
232− | KeyEvent {
233− code: KeyCode::Down,
234− ..
235− }
236− | KeyEvent {
237− code: KeyCode::Char('n'),
238− modifiers: KeyModifiers::CONTROL,
239− }
240− | KeyEvent {
241− code: KeyCode::Char('j'),
242− modifiers: KeyModifiers::CONTROL,
243− } => {
210+ key!(Tab) | key!(Down) | ctrl!('n') | ctrl!('j') => {
211+ // arrow down/ctrl-n/tab advances completion choice (including updating the doc)
244212 self.move_down();
245213 (self.callback_fn)(cx.editor, self.selection(), MenuEvent::Update);
246214 return EventResult::Consumed(None);
247215 }
248− KeyEvent {
249− code: KeyCode::Enter,
250− ..
251− } => {
216+ key!(Enter) => {
252217 if let Some(selection) = self.selection() {
253218 (self.callback_fn)(cx.editor, Some(selection), MenuEvent::Validate);
254219 }
helix-term/src/ui/picker.rs+10−55
@@ -1,8 +1,9 @@
11use crate::{
22 compositor::{Component, Compositor, Context, EventResult},
3+ ctrl, key,
34 ui::EditorView,
45};
5−use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
6+use crossterm::event::Event;
67use tui::{
78 buffer::Buffer as Surface,
89 widgets::{Block, BorderType, Borders},
@@ -402,81 +403,35 @@ impl<T: 'static> Component for Picker<T> {
402403 compositor.last_picker = compositor.pop();
403404 })));
404405
405− match key_event {
406− KeyEvent {
407− code: KeyCode::Up, ..
408− }
409− | KeyEvent {
410− code: KeyCode::BackTab,
411− ..
412− }
413− | KeyEvent {
414− code: KeyCode::Char('k'),
415− modifiers: KeyModifiers::CONTROL,
416− }
417− | KeyEvent {
418− code: KeyCode::Char('p'),
419− modifiers: KeyModifiers::CONTROL,
420− } => {
406+ match key_event.into() {
407+ key!(BackTab) | key!(Up) | ctrl!('p') | ctrl!('k') => {
421408 self.move_up();
422409 }
423− KeyEvent {
424− code: KeyCode::Down,
425− ..
426− }
427− | KeyEvent {
428− code: KeyCode::Tab, ..
429− }
430− | KeyEvent {
431− code: KeyCode::Char('j'),
432− modifiers: KeyModifiers::CONTROL,
433− }
434− | KeyEvent {
435− code: KeyCode::Char('n'),
436− modifiers: KeyModifiers::CONTROL,
437− } => {
410+ key!(Tab) | key!(Down) | ctrl!('n') | ctrl!('j') => {
438411 self.move_down();
439412 }
440− KeyEvent {
441− code: KeyCode::Esc, ..
442− }
443− | KeyEvent {
444− code: KeyCode::Char('c'),
445− modifiers: KeyModifiers::CONTROL,
446− } => {
413+ key!(Esc) | ctrl!('c') => {
447414 return close_fn;
448415 }
449− KeyEvent {
450− code: KeyCode::Enter,
451− ..
452− } => {
416+ key!(Enter) => {
453417 if let Some(option) = self.selection() {
454418 (self.callback_fn)(&mut cx.editor, option, Action::Replace);
455419 }
456420 return close_fn;
457421 }
458− KeyEvent {
459− code: KeyCode::Char('s'),
460− modifiers: KeyModifiers::CONTROL,
461− } => {
422+ ctrl!('s') => {
462423 if let Some(option) = self.selection() {
463424 (self.callback_fn)(&mut cx.editor, option, Action::HorizontalSplit);
464425 }
465426 return close_fn;
466427 }
467− KeyEvent {
468− code: KeyCode::Char('v'),
469− modifiers: KeyModifiers::CONTROL,
470− } => {
428+ ctrl!('v') => {
471429 if let Some(option) = self.selection() {
472430 (self.callback_fn)(&mut cx.editor, option, Action::VerticalSplit);
473431 }
474432 return close_fn;
475433 }
476− KeyEvent {
477− code: KeyCode::Char(' '),
478− modifiers: KeyModifiers::CONTROL,
479− } => {
434+ ctrl!(' ') => {
480435 self.save_filter();
481436 }
482437 _ => {
helix-term/src/ui/popup.rs+9−19
@@ -1,5 +1,8 @@
1−use crate::compositor::{Component, Compositor, Context, EventResult};
2−use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
1+use crate::{
2+ compositor::{Component, Compositor, Context, EventResult},
3+ ctrl, key,
4+};
5+use crossterm::event::Event;
36use tui::buffer::Buffer as Surface;
47
58use helix_core::Position;
@@ -95,27 +98,14 @@ impl<T: Component> Component for Popup<T> {
9598 compositor.pop();
9699 })));
97100
98− match key {
101+ match key.into() {
99102 // esc or ctrl-c aborts the completion and closes the menu
100− KeyEvent {
101− code: KeyCode::Esc, ..
102− }
103− | KeyEvent {
104− code: KeyCode::Char('c'),
105− modifiers: KeyModifiers::CONTROL,
106− } => close_fn,
107−
108− KeyEvent {
109− code: KeyCode::Char('d'),
110− modifiers: KeyModifiers::CONTROL,
111− } => {
103+ key!(Esc) | ctrl!('c') => close_fn,
104+ ctrl!('d') => {
112105 self.scroll(self.size.1 as usize / 2, true);
113106 EventResult::Consumed(None)
114107 }
115− KeyEvent {
116− code: KeyCode::Char('u'),
117− modifiers: KeyModifiers::CONTROL,
118− } => {
108+ ctrl!('u') => {
119109 self.scroll(self.size.1 as usize / 2, false);
120110 EventResult::Consumed(None)
121111 }
helix-term/src/ui/prompt.rs+24−120
@@ -1,6 +1,8 @@
11use crate::compositor::{Component, Compositor, Context, EventResult};
2−use crate::ui;
3−use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
2+use crate::{alt, ctrl, key, ui};
3+use crossterm::event::Event;
4+use helix_view::input::KeyEvent;
5+use helix_view::keyboard::{KeyCode, KeyModifiers};
46use std::{borrow::Cow, ops::RangeFrom};
57use tui::buffer::Buffer as Surface;
68
@@ -421,103 +423,29 @@ impl Component for Prompt {
421423 compositor.pop();
422424 })));
423425
424− match event {
425− KeyEvent {
426− code: KeyCode::Char('c'),
427− modifiers: KeyModifiers::CONTROL,
428− }
429− | KeyEvent {
430− code: KeyCode::Esc, ..
431− } => {
426+ match event.into() {
427+ ctrl!('c') | key!(Esc) => {
432428 (self.callback_fn)(cx, &self.line, PromptEvent::Abort);
433429 return close_fn;
434430 }
435− KeyEvent {
436− code: KeyCode::Left,
437− modifiers: KeyModifiers::ALT,
438− }
439− | KeyEvent {
440− code: KeyCode::Char('b'),
441− modifiers: KeyModifiers::ALT,
442− } => self.move_cursor(Movement::BackwardWord(1)),
443− KeyEvent {
444− code: KeyCode::Right,
445− modifiers: KeyModifiers::ALT,
446− }
447− | KeyEvent {
448− code: KeyCode::Char('f'),
449− modifiers: KeyModifiers::ALT,
450− } => self.move_cursor(Movement::ForwardWord(1)),
451− KeyEvent {
452− code: KeyCode::Char('f'),
453− modifiers: KeyModifiers::CONTROL,
454− }
455− | KeyEvent {
456− code: KeyCode::Right,
457− ..
458− } => self.move_cursor(Movement::ForwardChar(1)),
459− KeyEvent {
460− code: KeyCode::Char('b'),
461− modifiers: KeyModifiers::CONTROL,
462− }
463− | KeyEvent {
464− code: KeyCode::Left,
465− ..
466− } => self.move_cursor(Movement::BackwardChar(1)),
467− KeyEvent {
468− code: KeyCode::End,
469− modifiers: KeyModifiers::NONE,
470− }
471− | KeyEvent {
472− code: KeyCode::Char('e'),
473− modifiers: KeyModifiers::CONTROL,
474− } => self.move_end(),
475− KeyEvent {
476− code: KeyCode::Home,
477− modifiers: KeyModifiers::NONE,
478− }
479− | KeyEvent {
480− code: KeyCode::Char('a'),
481− modifiers: KeyModifiers::CONTROL,
482− } => self.move_start(),
483− KeyEvent {
484− code: KeyCode::Char('w'),
485− modifiers: KeyModifiers::CONTROL,
486− } => self.delete_word_backwards(),
487− KeyEvent {
488− code: KeyCode::Char('k'),
489− modifiers: KeyModifiers::CONTROL,
490− } => self.kill_to_end_of_line(),
491− KeyEvent {
492− code: KeyCode::Char('u'),
493− modifiers: KeyModifiers::CONTROL,
494− } => self.kill_to_start_of_line(),
495− KeyEvent {
496− code: KeyCode::Char('h'),
497− modifiers: KeyModifiers::CONTROL,
498− }
499− | KeyEvent {
500− code: KeyCode::Backspace,
501− modifiers: KeyModifiers::NONE,
502− } => {
431+ alt!('b') | alt!(Left) => self.move_cursor(Movement::BackwardWord(1)),
432+ alt!('f') | alt!(Right) => self.move_cursor(Movement::ForwardWord(1)),
433+ ctrl!('b') | ctrl!(Left) => self.move_cursor(Movement::BackwardChar(1)),
434+ ctrl!('f') | ctrl!(Right) => self.move_cursor(Movement::ForwardChar(1)),
435+ ctrl!('e') | key!(End) => self.move_end(),
436+ ctrl!('a') | key!(Home) => self.move_start(),
437+ ctrl!('w') => self.delete_word_backwards(),
438+ ctrl!('k') => self.kill_to_end_of_line(),
439+ ctrl!('u') => self.kill_to_start_of_line(),
440+ ctrl!('h') | key!(Backspace) => {
503441 self.delete_char_backwards();
504442 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
505443 }
506− KeyEvent {
507− code: KeyCode::Char('d'),
508− modifiers: KeyModifiers::CONTROL,
509− }
510− | KeyEvent {
511− code: KeyCode::Delete,
512− modifiers: KeyModifiers::NONE,
513− } => {
444+ ctrl!('d') | key!(Delete) => {
514445 self.delete_char_forwards();
515446 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
516447 }
517− KeyEvent {
518− code: KeyCode::Char('s'),
519− modifiers: KeyModifiers::CONTROL,
520− } => {
448+ ctrl!('s') => {
521449 let (view, doc) = current!(cx.editor);
522450 let text = doc.text().slice(..);
523451
@@ -535,10 +463,7 @@ impl Component for Prompt {
535463 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
536464 }
537465 }
538− KeyEvent {
539− code: KeyCode::Enter,
540− ..
541− } => {
466+ key!(Enter) => {
542467 if self.selection.is_some() && self.line.ends_with('/') {
543468 self.completion = (self.completion_fn)(&self.line);
544469 self.exit_selection();
@@ -553,50 +478,29 @@ impl Component for Prompt {
553478 return close_fn;
554479 }
555480 }
556− KeyEvent {
557− code: KeyCode::Char('p'),
558− modifiers: KeyModifiers::CONTROL,
559− }
560− | KeyEvent {
561− code: KeyCode::Up, ..
562− } => {
481+ ctrl!('p') | key!(Up) => {
563482 if let Some(register) = self.history_register {
564483 let register = cx.editor.registers.get_mut(register);
565484 self.change_history(register.read(), CompletionDirection::Backward);
566485 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
567486 }
568487 }
569− KeyEvent {
570− code: KeyCode::Char('n'),
571− modifiers: KeyModifiers::CONTROL,
572− }
573− | KeyEvent {
574− code: KeyCode::Down,
575− ..
576− } => {
488+ ctrl!('n') | key!(Down) => {
577489 if let Some(register) = self.history_register {
578490 let register = cx.editor.registers.get_mut(register);
579491 self.change_history(register.read(), CompletionDirection::Forward);
580492 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
581493 }
582494 }
583− KeyEvent {
584− code: KeyCode::Tab, ..
585− } => {
495+ key!(Tab) => {
586496 self.change_completion_selection(CompletionDirection::Forward);
587497 (self.callback_fn)(cx, &self.line, PromptEvent::Update)
588498 }
589− KeyEvent {
590− code: KeyCode::BackTab,
591− ..
592− } => {
499+ key!(BackTab) => {
593500 self.change_completion_selection(CompletionDirection::Backward);
594501 (self.callback_fn)(cx, &self.line, PromptEvent::Update)
595502 }
596− KeyEvent {
597− code: KeyCode::Char('q'),
598− modifiers: KeyModifiers::CONTROL,
599− } => self.exit_selection(),
503+ ctrl!('q') => self.exit_selection(),
600504 // any char event that's not combined with control or mapped to any other combo
601505 KeyEvent {
602506 code: KeyCode::Char(c),