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.
pull/1069/head
Gokul Soumya 3 years ago committed by GitHub
parent e863e3b62d
commit efc2b4c77b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -25,6 +25,38 @@ macro_rules! key {
};
}
#[macro_export]
macro_rules! ctrl {
($key:ident) => {
::helix_view::input::KeyEvent {
code: ::helix_view::keyboard::KeyCode::$key,
modifiers: ::helix_view::keyboard::KeyModifiers::CONTROL,
}
};
($($ch:tt)*) => {
::helix_view::input::KeyEvent {
code: ::helix_view::keyboard::KeyCode::Char($($ch)*),
modifiers: ::helix_view::keyboard::KeyModifiers::CONTROL,
}
};
}
#[macro_export]
macro_rules! alt {
($key:ident) => {
::helix_view::input::KeyEvent {
code: ::helix_view::keyboard::KeyCode::$key,
modifiers: ::helix_view::keyboard::KeyModifiers::ALT,
}
};
($($ch:tt)*) => {
::helix_view::input::KeyEvent {
code: ::helix_view::keyboard::KeyCode::Char($($ch)*),
modifiers: ::helix_view::keyboard::KeyModifiers::ALT,
}
};
}
/// Macro for defining the root of a `Keymap` object. Example:
///
/// ```

@ -1,5 +1,8 @@
use crate::compositor::{Component, Compositor, Context, EventResult};
use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
use crate::{
compositor::{Component, Compositor, Context, EventResult},
ctrl, key,
};
use crossterm::event::Event;
use tui::{buffer::Buffer as Surface, widgets::Table};
pub use tui::widgets::{Cell, Row};
@ -192,63 +195,25 @@ impl<T: Item + 'static> Component for Menu<T> {
compositor.pop();
})));
match event {
match event.into() {
// esc or ctrl-c aborts the completion and closes the menu
KeyEvent {
code: KeyCode::Esc, ..
}
| KeyEvent {
code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL,
} => {
key!(Esc) | ctrl!('c') => {
(self.callback_fn)(cx.editor, self.selection(), MenuEvent::Abort);
return close_fn;
}
// arrow up/ctrl-p/shift-tab prev completion choice (including updating the doc)
KeyEvent {
code: KeyCode::BackTab,
..
}
| KeyEvent {
code: KeyCode::Up, ..
}
| KeyEvent {
code: KeyCode::Char('p'),
modifiers: KeyModifiers::CONTROL,
}
| KeyEvent {
code: KeyCode::Char('k'),
modifiers: KeyModifiers::CONTROL,
} => {
key!(BackTab) | key!(Up) | ctrl!('p') | ctrl!('k') => {
self.move_up();
(self.callback_fn)(cx.editor, self.selection(), MenuEvent::Update);
return EventResult::Consumed(None);
}
// arrow down/ctrl-n/tab advances completion choice (including updating the doc)
KeyEvent {
code: KeyCode::Tab,
modifiers: KeyModifiers::NONE,
}
| KeyEvent {
code: KeyCode::Down,
..
}
| KeyEvent {
code: KeyCode::Char('n'),
modifiers: KeyModifiers::CONTROL,
}
| KeyEvent {
code: KeyCode::Char('j'),
modifiers: KeyModifiers::CONTROL,
} => {
key!(Tab) | key!(Down) | ctrl!('n') | ctrl!('j') => {
// arrow down/ctrl-n/tab advances completion choice (including updating the doc)
self.move_down();
(self.callback_fn)(cx.editor, self.selection(), MenuEvent::Update);
return EventResult::Consumed(None);
}
KeyEvent {
code: KeyCode::Enter,
..
} => {
key!(Enter) => {
if let Some(selection) = self.selection() {
(self.callback_fn)(cx.editor, Some(selection), MenuEvent::Validate);
}

@ -1,8 +1,9 @@
use crate::{
compositor::{Component, Compositor, Context, EventResult},
ctrl, key,
ui::EditorView,
};
use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
use crossterm::event::Event;
use tui::{
buffer::Buffer as Surface,
widgets::{Block, BorderType, Borders},
@ -402,81 +403,35 @@ impl<T: 'static> Component for Picker<T> {
compositor.last_picker = compositor.pop();
})));
match key_event {
KeyEvent {
code: KeyCode::Up, ..
}
| KeyEvent {
code: KeyCode::BackTab,
..
}
| KeyEvent {
code: KeyCode::Char('k'),
modifiers: KeyModifiers::CONTROL,
}
| KeyEvent {
code: KeyCode::Char('p'),
modifiers: KeyModifiers::CONTROL,
} => {
match key_event.into() {
key!(BackTab) | key!(Up) | ctrl!('p') | ctrl!('k') => {
self.move_up();
}
KeyEvent {
code: KeyCode::Down,
..
}
| KeyEvent {
code: KeyCode::Tab, ..
}
| KeyEvent {
code: KeyCode::Char('j'),
modifiers: KeyModifiers::CONTROL,
}
| KeyEvent {
code: KeyCode::Char('n'),
modifiers: KeyModifiers::CONTROL,
} => {
key!(Tab) | key!(Down) | ctrl!('n') | ctrl!('j') => {
self.move_down();
}
KeyEvent {
code: KeyCode::Esc, ..
}
| KeyEvent {
code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL,
} => {
key!(Esc) | ctrl!('c') => {
return close_fn;
}
KeyEvent {
code: KeyCode::Enter,
..
} => {
key!(Enter) => {
if let Some(option) = self.selection() {
(self.callback_fn)(&mut cx.editor, option, Action::Replace);
}
return close_fn;
}
KeyEvent {
code: KeyCode::Char('s'),
modifiers: KeyModifiers::CONTROL,
} => {
ctrl!('s') => {
if let Some(option) = self.selection() {
(self.callback_fn)(&mut cx.editor, option, Action::HorizontalSplit);
}
return close_fn;
}
KeyEvent {
code: KeyCode::Char('v'),
modifiers: KeyModifiers::CONTROL,
} => {
ctrl!('v') => {
if let Some(option) = self.selection() {
(self.callback_fn)(&mut cx.editor, option, Action::VerticalSplit);
}
return close_fn;
}
KeyEvent {
code: KeyCode::Char(' '),
modifiers: KeyModifiers::CONTROL,
} => {
ctrl!(' ') => {
self.save_filter();
}
_ => {

@ -1,5 +1,8 @@
use crate::compositor::{Component, Compositor, Context, EventResult};
use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
use crate::{
compositor::{Component, Compositor, Context, EventResult},
ctrl, key,
};
use crossterm::event::Event;
use tui::buffer::Buffer as Surface;
use helix_core::Position;
@ -95,27 +98,14 @@ impl<T: Component> Component for Popup<T> {
compositor.pop();
})));
match key {
match key.into() {
// esc or ctrl-c aborts the completion and closes the menu
KeyEvent {
code: KeyCode::Esc, ..
}
| KeyEvent {
code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL,
} => close_fn,
KeyEvent {
code: KeyCode::Char('d'),
modifiers: KeyModifiers::CONTROL,
} => {
key!(Esc) | ctrl!('c') => close_fn,
ctrl!('d') => {
self.scroll(self.size.1 as usize / 2, true);
EventResult::Consumed(None)
}
KeyEvent {
code: KeyCode::Char('u'),
modifiers: KeyModifiers::CONTROL,
} => {
ctrl!('u') => {
self.scroll(self.size.1 as usize / 2, false);
EventResult::Consumed(None)
}

@ -1,6 +1,8 @@
use crate::compositor::{Component, Compositor, Context, EventResult};
use crate::ui;
use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
use crate::{alt, ctrl, key, ui};
use crossterm::event::Event;
use helix_view::input::KeyEvent;
use helix_view::keyboard::{KeyCode, KeyModifiers};
use std::{borrow::Cow, ops::RangeFrom};
use tui::buffer::Buffer as Surface;
@ -421,103 +423,29 @@ impl Component for Prompt {
compositor.pop();
})));
match event {
KeyEvent {
code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL,
}
| KeyEvent {
code: KeyCode::Esc, ..
} => {
match event.into() {
ctrl!('c') | key!(Esc) => {
(self.callback_fn)(cx, &self.line, PromptEvent::Abort);
return close_fn;
}
KeyEvent {
code: KeyCode::Left,
modifiers: KeyModifiers::ALT,
}
| KeyEvent {
code: KeyCode::Char('b'),
modifiers: KeyModifiers::ALT,
} => self.move_cursor(Movement::BackwardWord(1)),
KeyEvent {
code: KeyCode::Right,
modifiers: KeyModifiers::ALT,
}
| KeyEvent {
code: KeyCode::Char('f'),
modifiers: KeyModifiers::ALT,
} => self.move_cursor(Movement::ForwardWord(1)),
KeyEvent {
code: KeyCode::Char('f'),
modifiers: KeyModifiers::CONTROL,
}
| KeyEvent {
code: KeyCode::Right,
..
} => self.move_cursor(Movement::ForwardChar(1)),
KeyEvent {
code: KeyCode::Char('b'),
modifiers: KeyModifiers::CONTROL,
}
| KeyEvent {
code: KeyCode::Left,
..
} => self.move_cursor(Movement::BackwardChar(1)),
KeyEvent {
code: KeyCode::End,
modifiers: KeyModifiers::NONE,
}
| KeyEvent {
code: KeyCode::Char('e'),
modifiers: KeyModifiers::CONTROL,
} => self.move_end(),
KeyEvent {
code: KeyCode::Home,
modifiers: KeyModifiers::NONE,
}
| KeyEvent {
code: KeyCode::Char('a'),
modifiers: KeyModifiers::CONTROL,
} => self.move_start(),
KeyEvent {
code: KeyCode::Char('w'),
modifiers: KeyModifiers::CONTROL,
} => self.delete_word_backwards(),
KeyEvent {
code: KeyCode::Char('k'),
modifiers: KeyModifiers::CONTROL,
} => self.kill_to_end_of_line(),
KeyEvent {
code: KeyCode::Char('u'),
modifiers: KeyModifiers::CONTROL,
} => self.kill_to_start_of_line(),
KeyEvent {
code: KeyCode::Char('h'),
modifiers: KeyModifiers::CONTROL,
}
| KeyEvent {
code: KeyCode::Backspace,
modifiers: KeyModifiers::NONE,
} => {
alt!('b') | alt!(Left) => self.move_cursor(Movement::BackwardWord(1)),
alt!('f') | alt!(Right) => self.move_cursor(Movement::ForwardWord(1)),
ctrl!('b') | ctrl!(Left) => self.move_cursor(Movement::BackwardChar(1)),
ctrl!('f') | ctrl!(Right) => self.move_cursor(Movement::ForwardChar(1)),
ctrl!('e') | key!(End) => self.move_end(),
ctrl!('a') | key!(Home) => self.move_start(),
ctrl!('w') => self.delete_word_backwards(),
ctrl!('k') => self.kill_to_end_of_line(),
ctrl!('u') => self.kill_to_start_of_line(),
ctrl!('h') | key!(Backspace) => {
self.delete_char_backwards();
(self.callback_fn)(cx, &self.line, PromptEvent::Update);
}
KeyEvent {
code: KeyCode::Char('d'),
modifiers: KeyModifiers::CONTROL,
}
| KeyEvent {
code: KeyCode::Delete,
modifiers: KeyModifiers::NONE,
} => {
ctrl!('d') | key!(Delete) => {
self.delete_char_forwards();
(self.callback_fn)(cx, &self.line, PromptEvent::Update);
}
KeyEvent {
code: KeyCode::Char('s'),
modifiers: KeyModifiers::CONTROL,
} => {
ctrl!('s') => {
let (view, doc) = current!(cx.editor);
let text = doc.text().slice(..);
@ -535,10 +463,7 @@ impl Component for Prompt {
(self.callback_fn)(cx, &self.line, PromptEvent::Update);
}
}
KeyEvent {
code: KeyCode::Enter,
..
} => {
key!(Enter) => {
if self.selection.is_some() && self.line.ends_with('/') {
self.completion = (self.completion_fn)(&self.line);
self.exit_selection();
@ -553,50 +478,29 @@ impl Component for Prompt {
return close_fn;
}
}
KeyEvent {
code: KeyCode::Char('p'),
modifiers: KeyModifiers::CONTROL,
}
| KeyEvent {
code: KeyCode::Up, ..
} => {
ctrl!('p') | key!(Up) => {
if let Some(register) = self.history_register {
let register = cx.editor.registers.get_mut(register);
self.change_history(register.read(), CompletionDirection::Backward);
(self.callback_fn)(cx, &self.line, PromptEvent::Update);
}
}
KeyEvent {
code: KeyCode::Char('n'),
modifiers: KeyModifiers::CONTROL,
}
| KeyEvent {
code: KeyCode::Down,
..
} => {
ctrl!('n') | key!(Down) => {
if let Some(register) = self.history_register {
let register = cx.editor.registers.get_mut(register);
self.change_history(register.read(), CompletionDirection::Forward);
(self.callback_fn)(cx, &self.line, PromptEvent::Update);
}
}
KeyEvent {
code: KeyCode::Tab, ..
} => {
key!(Tab) => {
self.change_completion_selection(CompletionDirection::Forward);
(self.callback_fn)(cx, &self.line, PromptEvent::Update)
}
KeyEvent {
code: KeyCode::BackTab,
..
} => {
key!(BackTab) => {
self.change_completion_selection(CompletionDirection::Backward);
(self.callback_fn)(cx, &self.line, PromptEvent::Update)
}
KeyEvent {
code: KeyCode::Char('q'),
modifiers: KeyModifiers::CONTROL,
} => self.exit_selection(),
ctrl!('q') => self.exit_selection(),
// any char event that's not combined with control or mapped to any other combo
KeyEvent {
code: KeyCode::Char(c),

Loading…
Cancel
Save