on master help sign in
Refactor keyevent handling using key, ctrl macros (#1058)
efc2b4cGokul Soumya
helix-term/src/keymap.rs+32
@@ -25,6 +25,38 @@ macro_rules! key {
25 };
25 };
26}
26}
27
27
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+
28/// Macro for defining the root of a `Keymap` object. Example:
60/// Macro for defining the root of a `Keymap` object. Example:
29///
61///
30/// ```
62/// ```
helix-term/src/ui/menu.rs+11−46
@@ -1,5 +1,8 @@
1+use crate::{
1−use crate::compositor::{Component, Compositor, Context, EventResult};
2+ compositor::{Component, Compositor, Context, EventResult},
3+ ctrl, key,
4+};
2−use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
5+use crossterm::event::Event;
3use tui::{buffer::Buffer as Surface, widgets::Table};
6use tui::{buffer::Buffer as Surface, widgets::Table};
4
7
5pub use tui::widgets::{Cell, Row};
8pub use tui::widgets::{Cell, Row};
@@ -192,63 +195,25 @@ impl<T: Item + 'static> Component for Menu<T> {
192 compositor.pop();
195 compositor.pop();
193 })));
196 })));
194
197
195− match event {
198+ match event.into() {
196 // esc or ctrl-c aborts the completion and closes the menu
199 // esc or ctrl-c aborts the completion and closes the menu
197− KeyEvent {
200+ key!(Esc) | ctrl!('c') => {
198− code: KeyCode::Esc, ..
199− }
200− | KeyEvent {
201− code: KeyCode::Char('c'),
202− modifiers: KeyModifiers::CONTROL,
203− } => {
204 (self.callback_fn)(cx.editor, self.selection(), MenuEvent::Abort);
201 (self.callback_fn)(cx.editor, self.selection(), MenuEvent::Abort);
205 return close_fn;
202 return close_fn;
206 }
203 }
207 // arrow up/ctrl-p/shift-tab prev completion choice (including updating the doc)
204 // arrow up/ctrl-p/shift-tab prev completion choice (including updating the doc)
208− KeyEvent {
205+ key!(BackTab) | key!(Up) | ctrl!('p') | ctrl!('k') => {
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− } => {
223 self.move_up();
206 self.move_up();
224 (self.callback_fn)(cx.editor, self.selection(), MenuEvent::Update);
207 (self.callback_fn)(cx.editor, self.selection(), MenuEvent::Update);
225 return EventResult::Consumed(None);
208 return EventResult::Consumed(None);
226 }
209 }
210+ key!(Tab) | key!(Down) | ctrl!('n') | ctrl!('j') => {
227− // arrow down/ctrl-n/tab advances completion choice (including updating the doc)
211+ // 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− } => {
244 self.move_down();
212 self.move_down();
245 (self.callback_fn)(cx.editor, self.selection(), MenuEvent::Update);
213 (self.callback_fn)(cx.editor, self.selection(), MenuEvent::Update);
246 return EventResult::Consumed(None);
214 return EventResult::Consumed(None);
247 }
215 }
248− KeyEvent {
249− code: KeyCode::Enter,
216+ key!(Enter) => {
250− ..
251− } => {
252 if let Some(selection) = self.selection() {
217 if let Some(selection) = self.selection() {
253 (self.callback_fn)(cx.editor, Some(selection), MenuEvent::Validate);
218 (self.callback_fn)(cx.editor, Some(selection), MenuEvent::Validate);
254 }
219 }
helix-term/src/ui/picker.rs+10−55
@@ -1,8 +1,9 @@
1use crate::{
1use crate::{
2 compositor::{Component, Compositor, Context, EventResult},
2 compositor::{Component, Compositor, Context, EventResult},
3+ ctrl, key,
3 ui::EditorView,
4 ui::EditorView,
4};
5};
5−use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
6+use crossterm::event::Event;
6use tui::{
7use tui::{
7 buffer::Buffer as Surface,
8 buffer::Buffer as Surface,
8 widgets::{Block, BorderType, Borders},
9 widgets::{Block, BorderType, Borders},
@@ -402,81 +403,35 @@ impl<T: 'static> Component for Picker<T> {
402 compositor.last_picker = compositor.pop();
403 compositor.last_picker = compositor.pop();
403 })));
404 })));
404
405
405− match key_event {
406+ match key_event.into() {
406− KeyEvent {
407+ key!(BackTab) | key!(Up) | ctrl!('p') | ctrl!('k') => {
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− } => {
421 self.move_up();
408 self.move_up();
422 }
409 }
423− KeyEvent {
410+ key!(Tab) | key!(Down) | ctrl!('n') | ctrl!('j') => {
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− } => {
438 self.move_down();
411 self.move_down();
439 }
412 }
440− KeyEvent {
413+ key!(Esc) | ctrl!('c') => {
441− code: KeyCode::Esc, ..
442− }
443− | KeyEvent {
444− code: KeyCode::Char('c'),
445− modifiers: KeyModifiers::CONTROL,
446− } => {
447 return close_fn;
414 return close_fn;
448 }
415 }
449− KeyEvent {
450− code: KeyCode::Enter,
416+ key!(Enter) => {
451− ..
452− } => {
453 if let Some(option) = self.selection() {
417 if let Some(option) = self.selection() {
454 (self.callback_fn)(&mut cx.editor, option, Action::Replace);
418 (self.callback_fn)(&mut cx.editor, option, Action::Replace);
455 }
419 }
456 return close_fn;
420 return close_fn;
457 }
421 }
458− KeyEvent {
422+ ctrl!('s') => {
459− code: KeyCode::Char('s'),
460− modifiers: KeyModifiers::CONTROL,
461− } => {
462 if let Some(option) = self.selection() {
423 if let Some(option) = self.selection() {
463 (self.callback_fn)(&mut cx.editor, option, Action::HorizontalSplit);
424 (self.callback_fn)(&mut cx.editor, option, Action::HorizontalSplit);
464 }
425 }
465 return close_fn;
426 return close_fn;
466 }
427 }
467− KeyEvent {
428+ ctrl!('v') => {
468− code: KeyCode::Char('v'),
469− modifiers: KeyModifiers::CONTROL,
470− } => {
471 if let Some(option) = self.selection() {
429 if let Some(option) = self.selection() {
472 (self.callback_fn)(&mut cx.editor, option, Action::VerticalSplit);
430 (self.callback_fn)(&mut cx.editor, option, Action::VerticalSplit);
473 }
431 }
474 return close_fn;
432 return close_fn;
475 }
433 }
476− KeyEvent {
434+ ctrl!(' ') => {
477− code: KeyCode::Char(' '),
478− modifiers: KeyModifiers::CONTROL,
479− } => {
480 self.save_filter();
435 self.save_filter();
481 }
436 }
482 _ => {
437 _ => {
helix-term/src/ui/popup.rs+9−19
@@ -1,5 +1,8 @@
1+use crate::{
1−use crate::compositor::{Component, Compositor, Context, EventResult};
2+ compositor::{Component, Compositor, Context, EventResult},
3+ ctrl, key,
4+};
2−use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
5+use crossterm::event::Event;
3use tui::buffer::Buffer as Surface;
6use tui::buffer::Buffer as Surface;
4
7
5use helix_core::Position;
8use helix_core::Position;
@@ -95,27 +98,14 @@ impl<T: Component> Component for Popup<T> {
95 compositor.pop();
98 compositor.pop();
96 })));
99 })));
97
100
98− match key {
101+ match key.into() {
99 // esc or ctrl-c aborts the completion and closes the menu
102 // 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,
103+ key!(Esc) | ctrl!('c') => close_fn,
107−
104+ ctrl!('d') => {
108− KeyEvent {
109− code: KeyCode::Char('d'),
110− modifiers: KeyModifiers::CONTROL,
111− } => {
112 self.scroll(self.size.1 as usize / 2, true);
105 self.scroll(self.size.1 as usize / 2, true);
113 EventResult::Consumed(None)
106 EventResult::Consumed(None)
114 }
107 }
115− KeyEvent {
108+ ctrl!('u') => {
116− code: KeyCode::Char('u'),
117− modifiers: KeyModifiers::CONTROL,
118− } => {
119 self.scroll(self.size.1 as usize / 2, false);
109 self.scroll(self.size.1 as usize / 2, false);
120 EventResult::Consumed(None)
110 EventResult::Consumed(None)
121 }
111 }
helix-term/src/ui/prompt.rs+24−120
@@ -1,6 +1,8 @@
1use crate::compositor::{Component, Compositor, Context, EventResult};
1use crate::compositor::{Component, Compositor, Context, EventResult};
2−use crate::ui;
2+use crate::{alt, ctrl, key, ui};
3−use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
3+use crossterm::event::Event;
4+use helix_view::input::KeyEvent;
5+use helix_view::keyboard::{KeyCode, KeyModifiers};
4use std::{borrow::Cow, ops::RangeFrom};
6use std::{borrow::Cow, ops::RangeFrom};
5use tui::buffer::Buffer as Surface;
7use tui::buffer::Buffer as Surface;
6
8
@@ -421,103 +423,29 @@ impl Component for Prompt {
421 compositor.pop();
423 compositor.pop();
422 })));
424 })));
423
425
424− match event {
426+ match event.into() {
425− KeyEvent {
427+ ctrl!('c') | key!(Esc) => {
426− code: KeyCode::Char('c'),
427− modifiers: KeyModifiers::CONTROL,
428− }
429− | KeyEvent {
430− code: KeyCode::Esc, ..
431− } => {
432 (self.callback_fn)(cx, &self.line, PromptEvent::Abort);
428 (self.callback_fn)(cx, &self.line, PromptEvent::Abort);
433 return close_fn;
429 return close_fn;
434 }
430 }
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)),
431+ alt!('b') | alt!(Left) => 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)),
432+ alt!('f') | alt!(Right) => self.move_cursor(Movement::ForwardWord(1)),
451− KeyEvent {
433+ ctrl!('b') | ctrl!(Left) => self.move_cursor(Movement::BackwardChar(1)),
452− code: KeyCode::Char('f'),
453− modifiers: KeyModifiers::CONTROL,
454− }
455− | KeyEvent {
456− code: KeyCode::Right,
457− ..
458− } => self.move_cursor(Movement::ForwardChar(1)),
434+ ctrl!('f') | ctrl!(Right) => 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(),
435+ ctrl!('e') | key!(End) => 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(),
436+ ctrl!('a') | key!(Home) => self.move_start(),
483− KeyEvent {
484− code: KeyCode::Char('w'),
485− modifiers: KeyModifiers::CONTROL,
486− } => self.delete_word_backwards(),
437+ ctrl!('w') => self.delete_word_backwards(),
487− KeyEvent {
488− code: KeyCode::Char('k'),
489− modifiers: KeyModifiers::CONTROL,
490− } => self.kill_to_end_of_line(),
438+ ctrl!('k') => self.kill_to_end_of_line(),
491− KeyEvent {
492− code: KeyCode::Char('u'),
493− modifiers: KeyModifiers::CONTROL,
494− } => self.kill_to_start_of_line(),
439+ ctrl!('u') => self.kill_to_start_of_line(),
495− KeyEvent {
496− code: KeyCode::Char('h'),
497− modifiers: KeyModifiers::CONTROL,
498− }
499− | KeyEvent {
500− code: KeyCode::Backspace,
440+ ctrl!('h') | key!(Backspace) => {
501− modifiers: KeyModifiers::NONE,
502− } => {
503 self.delete_char_backwards();
441 self.delete_char_backwards();
504 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
442 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
505 }
443 }
506− KeyEvent {
444+ ctrl!('d') | key!(Delete) => {
507− code: KeyCode::Char('d'),
508− modifiers: KeyModifiers::CONTROL,
509− }
510− | KeyEvent {
511− code: KeyCode::Delete,
512− modifiers: KeyModifiers::NONE,
513− } => {
514 self.delete_char_forwards();
445 self.delete_char_forwards();
515 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
446 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
516 }
447 }
517− KeyEvent {
448+ ctrl!('s') => {
518− code: KeyCode::Char('s'),
519− modifiers: KeyModifiers::CONTROL,
520− } => {
521 let (view, doc) = current!(cx.editor);
449 let (view, doc) = current!(cx.editor);
522 let text = doc.text().slice(..);
450 let text = doc.text().slice(..);
523
451
@@ -535,10 +463,7 @@ impl Component for Prompt {
535 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
463 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
536 }
464 }
537 }
465 }
538− KeyEvent {
539− code: KeyCode::Enter,
466+ key!(Enter) => {
540− ..
541− } => {
542 if self.selection.is_some() && self.line.ends_with('/') {
467 if self.selection.is_some() && self.line.ends_with('/') {
543 self.completion = (self.completion_fn)(&self.line);
468 self.completion = (self.completion_fn)(&self.line);
544 self.exit_selection();
469 self.exit_selection();
@@ -553,50 +478,29 @@ impl Component for Prompt {
553 return close_fn;
478 return close_fn;
554 }
479 }
555 }
480 }
556− KeyEvent {
481+ ctrl!('p') | key!(Up) => {
557− code: KeyCode::Char('p'),
558− modifiers: KeyModifiers::CONTROL,
559− }
560− | KeyEvent {
561− code: KeyCode::Up, ..
562− } => {
563 if let Some(register) = self.history_register {
482 if let Some(register) = self.history_register {
564 let register = cx.editor.registers.get_mut(register);
483 let register = cx.editor.registers.get_mut(register);
565 self.change_history(register.read(), CompletionDirection::Backward);
484 self.change_history(register.read(), CompletionDirection::Backward);
566 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
485 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
567 }
486 }
568 }
487 }
569− KeyEvent {
488+ ctrl!('n') | key!(Down) => {
570− code: KeyCode::Char('n'),
571− modifiers: KeyModifiers::CONTROL,
572− }
573− | KeyEvent {
574− code: KeyCode::Down,
575− ..
576− } => {
577 if let Some(register) = self.history_register {
489 if let Some(register) = self.history_register {
578 let register = cx.editor.registers.get_mut(register);
490 let register = cx.editor.registers.get_mut(register);
579 self.change_history(register.read(), CompletionDirection::Forward);
491 self.change_history(register.read(), CompletionDirection::Forward);
580 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
492 (self.callback_fn)(cx, &self.line, PromptEvent::Update);
581 }
493 }
582 }
494 }
583− KeyEvent {
495+ key!(Tab) => {
584− code: KeyCode::Tab, ..
585− } => {
586 self.change_completion_selection(CompletionDirection::Forward);
496 self.change_completion_selection(CompletionDirection::Forward);
587 (self.callback_fn)(cx, &self.line, PromptEvent::Update)
497 (self.callback_fn)(cx, &self.line, PromptEvent::Update)
588 }
498 }
589− KeyEvent {
590− code: KeyCode::BackTab,
499+ key!(BackTab) => {
591− ..
592− } => {
593 self.change_completion_selection(CompletionDirection::Backward);
500 self.change_completion_selection(CompletionDirection::Backward);
594 (self.callback_fn)(cx, &self.line, PromptEvent::Update)
501 (self.callback_fn)(cx, &self.line, PromptEvent::Update)
595 }
502 }
596− KeyEvent {
597− code: KeyCode::Char('q'),
598− modifiers: KeyModifiers::CONTROL,
599− } => self.exit_selection(),
503+ ctrl!('q') => self.exit_selection(),
600 // any char event that's not combined with control or mapped to any other combo
504 // any char event that's not combined with control or mapped to any other combo
601 KeyEvent {
505 KeyEvent {
602 code: KeyCode::Char(c),
506 code: KeyCode::Char(c),