Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-view/src/input.rs')
-rw-r--r--helix-view/src/input.rs826
1 files changed, 35 insertions, 791 deletions
diff --git a/helix-view/src/input.rs b/helix-view/src/input.rs
index 539680a6..1e0ddfe2 100644
--- a/helix-view/src/input.rs
+++ b/helix-view/src/input.rs
@@ -1,71 +1,17 @@
-//! Input event handling, currently backed by termina.
+//! Input event handling, currently backed by crossterm.
use anyhow::{anyhow, Error};
-use helix_core::unicode::{segmentation::UnicodeSegmentation, width::UnicodeWidthStr};
+use helix_core::unicode::width::UnicodeWidthStr;
use serde::de::{self, Deserialize, Deserializer};
use std::fmt;
-pub use crate::keyboard::{KeyCode, KeyModifiers, MediaKeyCode, ModifierKeyCode};
+use crate::keyboard::{KeyCode, KeyModifiers};
-#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Hash)]
-pub enum Event {
- FocusGained,
- FocusLost,
- Key(KeyEvent),
- Mouse(MouseEvent),
- Paste(String),
- Resize(u16, u16),
- IdleTimeout,
-}
-
-#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
-pub struct MouseEvent {
- /// The kind of mouse event that was caused.
- pub kind: MouseEventKind,
- /// The column that the event occurred on.
- pub column: u16,
- /// The row that the event occurred on.
- pub row: u16,
- /// The key modifiers active when the event occurred.
- pub modifiers: KeyModifiers,
-}
-
-#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
-pub enum MouseEventKind {
- /// Pressed mouse button. Contains the button that was pressed.
- Down(MouseButton),
- /// Released mouse button. Contains the button that was released.
- Up(MouseButton),
- /// Moved the mouse cursor while pressing the contained mouse button.
- Drag(MouseButton),
- /// Moved the mouse cursor while not pressing a mouse button.
- Moved,
- /// Scrolled mouse wheel downwards (towards the user).
- ScrollDown,
- /// Scrolled mouse wheel upwards (away from the user).
- ScrollUp,
- /// Scrolled mouse wheel leftwards.
- ScrollLeft,
- /// Scrolled mouse wheel rightwards.
- ScrollRight,
-}
-
-/// Represents a mouse button.
-#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
-pub enum MouseButton {
- /// Left mouse button.
- Left,
- /// Right mouse button.
- Right,
- /// Middle mouse button.
- Middle,
-}
/// Represents a key event.
// We use a newtype here because we want to customize Deserialize and Display.
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy, Hash)]
pub struct KeyEvent {
pub code: KeyCode,
pub modifiers: KeyModifiers,
- // TODO: termina now supports kind & state if terminal supports kitty's extended protocol
}
impl KeyEvent {
@@ -76,31 +22,6 @@ impl KeyEvent {
_ => None,
}
}
-
- /// Format the key in such a way that a concatenated sequence
- /// of keys can be read easily.
- ///
- /// ```
- /// # use std::str::FromStr;
- /// # use helix_view::input::KeyEvent;
- ///
- /// let k = KeyEvent::from_str("w").unwrap().key_sequence_format();
- /// assert_eq!(k, "w");
- ///
- /// let k = KeyEvent::from_str("C-w").unwrap().key_sequence_format();
- /// assert_eq!(k, "<C-w>");
- ///
- /// let k = KeyEvent::from_str(" ").unwrap().key_sequence_format();
- /// assert_eq!(k, "<space>");
- /// ```
- pub fn key_sequence_format(&self) -> String {
- let s = self.to_string();
- if s.graphemes(true).count() > 1 {
- format!("<{}>", s)
- } else {
- s
- }
- }
}
pub(crate) mod keys {
@@ -115,59 +36,24 @@ pub(crate) mod keys {
pub(crate) const PAGEUP: &str = "pageup";
pub(crate) const PAGEDOWN: &str = "pagedown";
pub(crate) const TAB: &str = "tab";
+ pub(crate) const BACKTAB: &str = "backtab";
pub(crate) const DELETE: &str = "del";
pub(crate) const INSERT: &str = "ins";
pub(crate) const NULL: &str = "null";
pub(crate) const ESC: &str = "esc";
pub(crate) const SPACE: &str = "space";
- pub(crate) const MINUS: &str = "minus";
pub(crate) const LESS_THAN: &str = "lt";
pub(crate) const GREATER_THAN: &str = "gt";
- pub(crate) const CAPS_LOCK: &str = "capslock";
- pub(crate) const SCROLL_LOCK: &str = "scrolllock";
- pub(crate) const NUM_LOCK: &str = "numlock";
- pub(crate) const PRINT_SCREEN: &str = "printscreen";
- pub(crate) const PAUSE: &str = "pause";
- pub(crate) const MENU: &str = "menu";
- pub(crate) const KEYPAD_BEGIN: &str = "keypadbegin";
- pub(crate) const PLAY: &str = "play";
- pub(crate) const PAUSE_MEDIA: &str = "pausemedia";
- pub(crate) const PLAY_PAUSE: &str = "playpause";
- pub(crate) const REVERSE: &str = "reverse";
- pub(crate) const STOP: &str = "stop";
- pub(crate) const FAST_FORWARD: &str = "fastforward";
- pub(crate) const REWIND: &str = "rewind";
- pub(crate) const TRACK_NEXT: &str = "tracknext";
- pub(crate) const TRACK_PREVIOUS: &str = "trackprevious";
- pub(crate) const RECORD: &str = "record";
- pub(crate) const LOWER_VOLUME: &str = "lowervolume";
- pub(crate) const RAISE_VOLUME: &str = "raisevolume";
- pub(crate) const MUTE_VOLUME: &str = "mutevolume";
- pub(crate) const LEFT_SHIFT: &str = "leftshift";
- pub(crate) const LEFT_CONTROL: &str = "leftcontrol";
- pub(crate) const LEFT_ALT: &str = "leftalt";
- pub(crate) const LEFT_SUPER: &str = "leftsuper";
- pub(crate) const LEFT_HYPER: &str = "lefthyper";
- pub(crate) const LEFT_META: &str = "leftmeta";
- pub(crate) const RIGHT_SHIFT: &str = "rightshift";
- pub(crate) const RIGHT_CONTROL: &str = "rightcontrol";
- pub(crate) const RIGHT_ALT: &str = "rightalt";
- pub(crate) const RIGHT_SUPER: &str = "rightsuper";
- pub(crate) const RIGHT_HYPER: &str = "righthyper";
- pub(crate) const RIGHT_META: &str = "rightmeta";
- pub(crate) const ISO_LEVEL_3_SHIFT: &str = "isolevel3shift";
- pub(crate) const ISO_LEVEL_5_SHIFT: &str = "isolevel5shift";
+ pub(crate) const PLUS: &str = "plus";
+ pub(crate) const MINUS: &str = "minus";
+ pub(crate) const SEMICOLON: &str = "semicolon";
+ pub(crate) const PERCENT: &str = "percent";
}
impl fmt::Display for KeyEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
- "{}{}{}{}",
- if self.modifiers.contains(KeyModifiers::SUPER) {
- "Meta-"
- } else {
- ""
- },
+ "{}{}{}",
if self.modifiers.contains(KeyModifiers::SHIFT) {
"S-"
} else {
@@ -196,54 +82,20 @@ impl fmt::Display for KeyEvent {
KeyCode::PageUp => f.write_str(keys::PAGEUP)?,
KeyCode::PageDown => f.write_str(keys::PAGEDOWN)?,
KeyCode::Tab => f.write_str(keys::TAB)?,
+ KeyCode::BackTab => f.write_str(keys::BACKTAB)?,
KeyCode::Delete => f.write_str(keys::DELETE)?,
KeyCode::Insert => f.write_str(keys::INSERT)?,
KeyCode::Null => f.write_str(keys::NULL)?,
KeyCode::Esc => f.write_str(keys::ESC)?,
KeyCode::Char(' ') => f.write_str(keys::SPACE)?,
- KeyCode::Char('-') => f.write_str(keys::MINUS)?,
KeyCode::Char('<') => f.write_str(keys::LESS_THAN)?,
KeyCode::Char('>') => f.write_str(keys::GREATER_THAN)?,
+ KeyCode::Char('+') => f.write_str(keys::PLUS)?,
+ KeyCode::Char('-') => f.write_str(keys::MINUS)?,
+ KeyCode::Char(';') => f.write_str(keys::SEMICOLON)?,
+ KeyCode::Char('%') => f.write_str(keys::PERCENT)?,
KeyCode::F(i) => f.write_fmt(format_args!("F{}", i))?,
KeyCode::Char(c) => f.write_fmt(format_args!("{}", c))?,
- KeyCode::CapsLock => f.write_str(keys::CAPS_LOCK)?,
- KeyCode::ScrollLock => f.write_str(keys::SCROLL_LOCK)?,
- KeyCode::NumLock => f.write_str(keys::NUM_LOCK)?,
- KeyCode::PrintScreen => f.write_str(keys::PRINT_SCREEN)?,
- KeyCode::Pause => f.write_str(keys::PAUSE)?,
- KeyCode::Menu => f.write_str(keys::MENU)?,
- KeyCode::KeypadBegin => f.write_str(keys::KEYPAD_BEGIN)?,
- KeyCode::Media(MediaKeyCode::Play) => f.write_str(keys::PLAY)?,
- KeyCode::Media(MediaKeyCode::Pause) => f.write_str(keys::PAUSE_MEDIA)?,
- KeyCode::Media(MediaKeyCode::PlayPause) => f.write_str(keys::PLAY_PAUSE)?,
- KeyCode::Media(MediaKeyCode::Stop) => f.write_str(keys::STOP)?,
- KeyCode::Media(MediaKeyCode::Reverse) => f.write_str(keys::REVERSE)?,
- KeyCode::Media(MediaKeyCode::FastForward) => f.write_str(keys::FAST_FORWARD)?,
- KeyCode::Media(MediaKeyCode::Rewind) => f.write_str(keys::REWIND)?,
- KeyCode::Media(MediaKeyCode::TrackNext) => f.write_str(keys::TRACK_NEXT)?,
- KeyCode::Media(MediaKeyCode::TrackPrevious) => f.write_str(keys::TRACK_PREVIOUS)?,
- KeyCode::Media(MediaKeyCode::Record) => f.write_str(keys::RECORD)?,
- KeyCode::Media(MediaKeyCode::LowerVolume) => f.write_str(keys::LOWER_VOLUME)?,
- KeyCode::Media(MediaKeyCode::RaiseVolume) => f.write_str(keys::RAISE_VOLUME)?,
- KeyCode::Media(MediaKeyCode::MuteVolume) => f.write_str(keys::MUTE_VOLUME)?,
- KeyCode::Modifier(ModifierKeyCode::LeftShift) => f.write_str(keys::LEFT_SHIFT)?,
- KeyCode::Modifier(ModifierKeyCode::LeftControl) => f.write_str(keys::LEFT_CONTROL)?,
- KeyCode::Modifier(ModifierKeyCode::LeftAlt) => f.write_str(keys::LEFT_ALT)?,
- KeyCode::Modifier(ModifierKeyCode::LeftSuper) => f.write_str(keys::LEFT_SUPER)?,
- KeyCode::Modifier(ModifierKeyCode::LeftHyper) => f.write_str(keys::LEFT_HYPER)?,
- KeyCode::Modifier(ModifierKeyCode::LeftMeta) => f.write_str(keys::LEFT_META)?,
- KeyCode::Modifier(ModifierKeyCode::RightShift) => f.write_str(keys::RIGHT_SHIFT)?,
- KeyCode::Modifier(ModifierKeyCode::RightControl) => f.write_str(keys::RIGHT_CONTROL)?,
- KeyCode::Modifier(ModifierKeyCode::RightAlt) => f.write_str(keys::RIGHT_ALT)?,
- KeyCode::Modifier(ModifierKeyCode::RightSuper) => f.write_str(keys::RIGHT_SUPER)?,
- KeyCode::Modifier(ModifierKeyCode::RightHyper) => f.write_str(keys::RIGHT_HYPER)?,
- KeyCode::Modifier(ModifierKeyCode::RightMeta) => f.write_str(keys::RIGHT_META)?,
- KeyCode::Modifier(ModifierKeyCode::IsoLevel3Shift) => {
- f.write_str(keys::ISO_LEVEL_3_SHIFT)?
- }
- KeyCode::Modifier(ModifierKeyCode::IsoLevel5Shift) => {
- f.write_str(keys::ISO_LEVEL_5_SHIFT)?
- }
};
Ok(())
}
@@ -264,49 +116,21 @@ impl UnicodeWidthStr for KeyEvent {
KeyCode::PageUp => keys::PAGEUP.len(),
KeyCode::PageDown => keys::PAGEDOWN.len(),
KeyCode::Tab => keys::TAB.len(),
+ KeyCode::BackTab => keys::BACKTAB.len(),
KeyCode::Delete => keys::DELETE.len(),
KeyCode::Insert => keys::INSERT.len(),
KeyCode::Null => keys::NULL.len(),
KeyCode::Esc => keys::ESC.len(),
KeyCode::Char(' ') => keys::SPACE.len(),
+ KeyCode::Char('<') => keys::LESS_THAN.len(),
+ KeyCode::Char('>') => keys::GREATER_THAN.len(),
+ KeyCode::Char('+') => keys::PLUS.len(),
KeyCode::Char('-') => keys::MINUS.len(),
+ KeyCode::Char(';') => keys::SEMICOLON.len(),
+ KeyCode::Char('%') => keys::PERCENT.len(),
KeyCode::F(1..=9) => 2,
KeyCode::F(_) => 3,
KeyCode::Char(c) => c.width().unwrap_or(0),
- KeyCode::CapsLock => keys::CAPS_LOCK.len(),
- KeyCode::ScrollLock => keys::SCROLL_LOCK.len(),
- KeyCode::NumLock => keys::NUM_LOCK.len(),
- KeyCode::PrintScreen => keys::PRINT_SCREEN.len(),
- KeyCode::Pause => keys::PAUSE.len(),
- KeyCode::Menu => keys::MENU.len(),
- KeyCode::KeypadBegin => keys::KEYPAD_BEGIN.len(),
- KeyCode::Media(MediaKeyCode::Play) => keys::PLAY.len(),
- KeyCode::Media(MediaKeyCode::Pause) => keys::PAUSE_MEDIA.len(),
- KeyCode::Media(MediaKeyCode::PlayPause) => keys::PLAY_PAUSE.len(),
- KeyCode::Media(MediaKeyCode::Stop) => keys::STOP.len(),
- KeyCode::Media(MediaKeyCode::Reverse) => keys::REVERSE.len(),
- KeyCode::Media(MediaKeyCode::FastForward) => keys::FAST_FORWARD.len(),
- KeyCode::Media(MediaKeyCode::Rewind) => keys::REWIND.len(),
- KeyCode::Media(MediaKeyCode::TrackNext) => keys::TRACK_NEXT.len(),
- KeyCode::Media(MediaKeyCode::TrackPrevious) => keys::TRACK_PREVIOUS.len(),
- KeyCode::Media(MediaKeyCode::Record) => keys::RECORD.len(),
- KeyCode::Media(MediaKeyCode::LowerVolume) => keys::LOWER_VOLUME.len(),
- KeyCode::Media(MediaKeyCode::RaiseVolume) => keys::RAISE_VOLUME.len(),
- KeyCode::Media(MediaKeyCode::MuteVolume) => keys::MUTE_VOLUME.len(),
- KeyCode::Modifier(ModifierKeyCode::LeftShift) => keys::LEFT_SHIFT.len(),
- KeyCode::Modifier(ModifierKeyCode::LeftControl) => keys::LEFT_CONTROL.len(),
- KeyCode::Modifier(ModifierKeyCode::LeftAlt) => keys::LEFT_ALT.len(),
- KeyCode::Modifier(ModifierKeyCode::LeftSuper) => keys::LEFT_SUPER.len(),
- KeyCode::Modifier(ModifierKeyCode::LeftHyper) => keys::LEFT_HYPER.len(),
- KeyCode::Modifier(ModifierKeyCode::LeftMeta) => keys::LEFT_META.len(),
- KeyCode::Modifier(ModifierKeyCode::RightShift) => keys::RIGHT_SHIFT.len(),
- KeyCode::Modifier(ModifierKeyCode::RightControl) => keys::RIGHT_CONTROL.len(),
- KeyCode::Modifier(ModifierKeyCode::RightAlt) => keys::RIGHT_ALT.len(),
- KeyCode::Modifier(ModifierKeyCode::RightSuper) => keys::RIGHT_SUPER.len(),
- KeyCode::Modifier(ModifierKeyCode::RightHyper) => keys::RIGHT_HYPER.len(),
- KeyCode::Modifier(ModifierKeyCode::RightMeta) => keys::RIGHT_META.len(),
- KeyCode::Modifier(ModifierKeyCode::IsoLevel3Shift) => keys::ISO_LEVEL_3_SHIFT.len(),
- KeyCode::Modifier(ModifierKeyCode::IsoLevel5Shift) => keys::ISO_LEVEL_5_SHIFT.len(),
};
if self.modifiers.contains(KeyModifiers::SHIFT) {
width += 2;
@@ -317,10 +141,6 @@ impl UnicodeWidthStr for KeyEvent {
if self.modifiers.contains(KeyModifiers::CONTROL) {
width += 2;
}
- if self.modifiers.contains(KeyModifiers::SUPER) {
- // "-Meta"
- width += 5;
- }
width
}
@@ -334,7 +154,7 @@ impl std::str::FromStr for KeyEvent {
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut tokens: Vec<_> = s.split('-').collect();
- let mut code = match tokens.pop().ok_or_else(|| anyhow!("Missing key code"))? {
+ let code = match tokens.pop().ok_or_else(|| anyhow!("Missing key code"))? {
keys::BACKSPACE => KeyCode::Backspace,
keys::ENTER => KeyCode::Enter,
keys::LEFT => KeyCode::Left,
@@ -346,73 +166,26 @@ impl std::str::FromStr for KeyEvent {
keys::PAGEUP => KeyCode::PageUp,
keys::PAGEDOWN => KeyCode::PageDown,
keys::TAB => KeyCode::Tab,
+ keys::BACKTAB => KeyCode::BackTab,
keys::DELETE => KeyCode::Delete,
keys::INSERT => KeyCode::Insert,
keys::NULL => KeyCode::Null,
keys::ESC => KeyCode::Esc,
keys::SPACE => KeyCode::Char(' '),
- keys::MINUS => KeyCode::Char('-'),
keys::LESS_THAN => KeyCode::Char('<'),
keys::GREATER_THAN => KeyCode::Char('>'),
- keys::CAPS_LOCK => KeyCode::CapsLock,
- keys::SCROLL_LOCK => KeyCode::ScrollLock,
- keys::NUM_LOCK => KeyCode::NumLock,
- keys::PRINT_SCREEN => KeyCode::PrintScreen,
- keys::PAUSE => KeyCode::Pause,
- keys::MENU => KeyCode::Menu,
- keys::KEYPAD_BEGIN => KeyCode::KeypadBegin,
- keys::PLAY => KeyCode::Media(MediaKeyCode::Play),
- keys::PAUSE_MEDIA => KeyCode::Media(MediaKeyCode::Pause),
- keys::PLAY_PAUSE => KeyCode::Media(MediaKeyCode::PlayPause),
- keys::STOP => KeyCode::Media(MediaKeyCode::Stop),
- keys::REVERSE => KeyCode::Media(MediaKeyCode::Reverse),
- keys::FAST_FORWARD => KeyCode::Media(MediaKeyCode::FastForward),
- keys::REWIND => KeyCode::Media(MediaKeyCode::Rewind),
- keys::TRACK_NEXT => KeyCode::Media(MediaKeyCode::TrackNext),
- keys::TRACK_PREVIOUS => KeyCode::Media(MediaKeyCode::TrackPrevious),
- keys::RECORD => KeyCode::Media(MediaKeyCode::Record),
- keys::LOWER_VOLUME => KeyCode::Media(MediaKeyCode::LowerVolume),
- keys::RAISE_VOLUME => KeyCode::Media(MediaKeyCode::RaiseVolume),
- keys::MUTE_VOLUME => KeyCode::Media(MediaKeyCode::MuteVolume),
- keys::LEFT_SHIFT => KeyCode::Modifier(ModifierKeyCode::LeftShift),
- keys::LEFT_CONTROL => KeyCode::Modifier(ModifierKeyCode::LeftControl),
- keys::LEFT_ALT => KeyCode::Modifier(ModifierKeyCode::LeftAlt),
- keys::LEFT_SUPER => KeyCode::Modifier(ModifierKeyCode::LeftSuper),
- keys::LEFT_HYPER => KeyCode::Modifier(ModifierKeyCode::LeftHyper),
- keys::LEFT_META => KeyCode::Modifier(ModifierKeyCode::LeftMeta),
- keys::RIGHT_SHIFT => KeyCode::Modifier(ModifierKeyCode::RightShift),
- keys::RIGHT_CONTROL => KeyCode::Modifier(ModifierKeyCode::RightControl),
- keys::RIGHT_ALT => KeyCode::Modifier(ModifierKeyCode::RightAlt),
- keys::RIGHT_SUPER => KeyCode::Modifier(ModifierKeyCode::RightSuper),
- keys::RIGHT_HYPER => KeyCode::Modifier(ModifierKeyCode::RightHyper),
- keys::RIGHT_META => KeyCode::Modifier(ModifierKeyCode::RightMeta),
- keys::ISO_LEVEL_3_SHIFT => KeyCode::Modifier(ModifierKeyCode::IsoLevel3Shift),
- keys::ISO_LEVEL_5_SHIFT => KeyCode::Modifier(ModifierKeyCode::IsoLevel5Shift),
+ keys::PLUS => KeyCode::Char('+'),
+ keys::MINUS => KeyCode::Char('-'),
+ keys::SEMICOLON => KeyCode::Char(';'),
+ keys::PERCENT => KeyCode::Char('%'),
single if single.chars().count() == 1 => KeyCode::Char(single.chars().next().unwrap()),
function if function.len() > 1 && function.starts_with('F') => {
let function: String = function.chars().skip(1).collect();
let function = str::parse::<u8>(&function)?;
- (function > 0 && function < 25)
- .then_some(KeyCode::F(function))
+ (function > 0 && function < 13)
+ .then(|| KeyCode::F(function))
.ok_or_else(|| anyhow!("Invalid function key '{}'", function))?
}
- // Checking that the last token is empty ensures that this branch is only taken if
- // `-` is used as a code. For example this branch will not be taken for `S-` (which is
- // missing a code).
- _ if s.ends_with('-') && tokens.last().is_some_and(|t| t.is_empty()) => {
- if s == "-" {
- return Ok(KeyEvent {
- code: KeyCode::Char('-'),
- modifiers: KeyModifiers::empty(),
- });
- } else {
- let suggestion = format!("{}-{}", s.trim_end_matches('-'), keys::MINUS);
- return Err(anyhow!(
- "Key '-' cannot be used with modifiers, use '{}' instead",
- suggestion
- ));
- }
- }
invalid => return Err(anyhow!("Invalid key code '{}'", invalid)),
};
@@ -422,7 +195,6 @@ impl std::str::FromStr for KeyEvent {
"S" => KeyModifiers::SHIFT,
"A" => KeyModifiers::ALT,
"C" => KeyModifiers::CONTROL,
- "Meta" | "Cmd" | "Win" => KeyModifiers::SUPER,
_ => return Err(anyhow!("Invalid key modifier '{}-'", token)),
};
@@ -432,18 +204,6 @@ impl std::str::FromStr for KeyEvent {
modifiers.insert(flag);
}
- // Normalize character keys so that characters like C-S-r and C-R
- // are represented by equal KeyEvents.
- match code {
- KeyCode::Char(ch)
- if ch.is_ascii_lowercase() && modifiers.contains(KeyModifiers::SHIFT) =>
- {
- code = KeyCode::Char(ch.to_ascii_uppercase());
- modifiers.remove(KeyModifiers::SHIFT);
- }
- _ => (),
- }
-
Ok(KeyEvent { code, modifiers })
}
}
@@ -459,258 +219,15 @@ impl<'de> Deserialize<'de> for KeyEvent {
}
#[cfg(feature = "term")]
-impl From<termina::event::Event> for Event {
- fn from(event: termina::event::Event) -> Self {
- match event {
- termina::event::Event::Key(key) => Self::Key(key.into()),
- termina::event::Event::Mouse(mouse) => Self::Mouse(mouse.into()),
- termina::event::Event::WindowResized(termina::WindowSize { rows, cols, .. }) => {
- Self::Resize(cols, rows)
- }
- termina::event::Event::FocusIn => Self::FocusGained,
- termina::event::Event::FocusOut => Self::FocusLost,
- termina::event::Event::Paste(s) => Self::Paste(s),
- _ => unreachable!(),
- }
- }
-}
-
-#[cfg(feature = "term")]
-impl From<termina::event::MouseEvent> for MouseEvent {
- fn from(
- termina::event::MouseEvent {
- kind,
- column,
- row,
- modifiers,
- }: termina::event::MouseEvent,
- ) -> Self {
- Self {
- kind: kind.into(),
- column,
- row,
- modifiers: modifiers.into(),
- }
- }
-}
-
-#[cfg(feature = "term")]
-impl From<termina::event::MouseEventKind> for MouseEventKind {
- fn from(kind: termina::event::MouseEventKind) -> Self {
- match kind {
- termina::event::MouseEventKind::Down(button) => Self::Down(button.into()),
- termina::event::MouseEventKind::Up(button) => Self::Up(button.into()),
- termina::event::MouseEventKind::Drag(button) => Self::Drag(button.into()),
- termina::event::MouseEventKind::Moved => Self::Moved,
- termina::event::MouseEventKind::ScrollDown => Self::ScrollDown,
- termina::event::MouseEventKind::ScrollUp => Self::ScrollUp,
- termina::event::MouseEventKind::ScrollLeft => Self::ScrollLeft,
- termina::event::MouseEventKind::ScrollRight => Self::ScrollRight,
- }
- }
-}
-
-#[cfg(feature = "term")]
-impl From<termina::event::MouseButton> for MouseButton {
- fn from(button: termina::event::MouseButton) -> Self {
- match button {
- termina::event::MouseButton::Left => MouseButton::Left,
- termina::event::MouseButton::Right => MouseButton::Right,
- termina::event::MouseButton::Middle => MouseButton::Middle,
- }
- }
-}
-
-#[cfg(feature = "term")]
-impl From<termina::event::KeyEvent> for KeyEvent {
- fn from(
- termina::event::KeyEvent {
- code, modifiers, ..
- }: termina::event::KeyEvent,
- ) -> Self {
- if code == termina::event::KeyCode::BackTab {
- // special case for BackTab -> Shift-Tab
- let mut modifiers: KeyModifiers = modifiers.into();
- modifiers.insert(KeyModifiers::SHIFT);
- Self {
- code: KeyCode::Tab,
- modifiers,
- }
- } else {
- Self {
- code: code.into(),
- modifiers: modifiers.into(),
- }
- }
- }
-}
-
-#[cfg(feature = "term")]
-impl From<KeyEvent> for termina::event::KeyEvent {
- fn from(KeyEvent { code, modifiers }: KeyEvent) -> Self {
- if code == KeyCode::Tab && modifiers.contains(KeyModifiers::SHIFT) {
- // special case for Shift-Tab -> BackTab
- let mut modifiers = modifiers;
- modifiers.remove(KeyModifiers::SHIFT);
- termina::event::KeyEvent {
- code: termina::event::KeyCode::BackTab,
- modifiers: modifiers.into(),
- kind: termina::event::KeyEventKind::Press,
- state: termina::event::KeyEventState::NONE,
- }
- } else {
- termina::event::KeyEvent {
- code: code.into(),
- modifiers: modifiers.into(),
- kind: termina::event::KeyEventKind::Press,
- state: termina::event::KeyEventState::NONE,
- }
- }
- }
-}
-
-#[cfg(all(feature = "term", windows))]
-impl From<crossterm::event::Event> for Event {
- fn from(event: crossterm::event::Event) -> Self {
- match event {
- crossterm::event::Event::Key(key) => Self::Key(key.into()),
- crossterm::event::Event::Mouse(mouse) => Self::Mouse(mouse.into()),
- crossterm::event::Event::Resize(w, h) => Self::Resize(w, h),
- crossterm::event::Event::FocusGained => Self::FocusGained,
- crossterm::event::Event::FocusLost => Self::FocusLost,
- crossterm::event::Event::Paste(s) => Self::Paste(s),
- }
- }
-}
-
-#[cfg(all(feature = "term", windows))]
-impl From<crossterm::event::MouseEvent> for MouseEvent {
- fn from(
- crossterm::event::MouseEvent {
- kind,
- column,
- row,
- modifiers,
- }: crossterm::event::MouseEvent,
- ) -> Self {
- Self {
- kind: kind.into(),
- column,
- row,
- modifiers: modifiers.into(),
- }
- }
-}
-
-#[cfg(all(feature = "term", windows))]
-impl From<crossterm::event::MouseEventKind> for MouseEventKind {
- fn from(kind: crossterm::event::MouseEventKind) -> Self {
- match kind {
- crossterm::event::MouseEventKind::Down(button) => Self::Down(button.into()),
- crossterm::event::MouseEventKind::Up(button) => Self::Up(button.into()),
- crossterm::event::MouseEventKind::Drag(button) => Self::Drag(button.into()),
- crossterm::event::MouseEventKind::Moved => Self::Moved,
- crossterm::event::MouseEventKind::ScrollDown => Self::ScrollDown,
- crossterm::event::MouseEventKind::ScrollUp => Self::ScrollUp,
- crossterm::event::MouseEventKind::ScrollLeft => Self::ScrollLeft,
- crossterm::event::MouseEventKind::ScrollRight => Self::ScrollRight,
- }
- }
-}
-
-#[cfg(all(feature = "term", windows))]
-impl From<crossterm::event::MouseButton> for MouseButton {
- fn from(button: crossterm::event::MouseButton) -> Self {
- match button {
- crossterm::event::MouseButton::Left => MouseButton::Left,
- crossterm::event::MouseButton::Right => MouseButton::Right,
- crossterm::event::MouseButton::Middle => MouseButton::Middle,
- }
- }
-}
-
-#[cfg(all(feature = "term", windows))]
impl From<crossterm::event::KeyEvent> for KeyEvent {
fn from(
- crossterm::event::KeyEvent {
- code, modifiers, ..
- }: crossterm::event::KeyEvent,
- ) -> Self {
- if code == crossterm::event::KeyCode::BackTab {
- // special case for BackTab -> Shift-Tab
- let mut modifiers: KeyModifiers = modifiers.into();
- modifiers.insert(KeyModifiers::SHIFT);
- Self {
- code: KeyCode::Tab,
- modifiers,
- }
- } else {
- Self {
- code: code.into(),
- modifiers: modifiers.into(),
- }
- }
- }
-}
-
-#[cfg(all(feature = "term", windows))]
-impl From<KeyEvent> for crossterm::event::KeyEvent {
- fn from(KeyEvent { code, modifiers }: KeyEvent) -> Self {
- if code == KeyCode::Tab && modifiers.contains(KeyModifiers::SHIFT) {
- // special case for Shift-Tab -> BackTab
- let mut modifiers = modifiers;
- modifiers.remove(KeyModifiers::SHIFT);
- crossterm::event::KeyEvent {
- code: crossterm::event::KeyCode::BackTab,
- modifiers: modifiers.into(),
- kind: crossterm::event::KeyEventKind::Press,
- state: crossterm::event::KeyEventState::NONE,
- }
- } else {
- crossterm::event::KeyEvent {
- code: code.into(),
- modifiers: modifiers.into(),
- kind: crossterm::event::KeyEventKind::Press,
- state: crossterm::event::KeyEventState::NONE,
- }
- }
- }
-}
-pub fn parse_macro(keys_str: &str) -> anyhow::Result<Vec<KeyEvent>> {
- use anyhow::Context;
- let mut keys_res: anyhow::Result<_> = Ok(Vec::new());
- let mut i = 0;
- while let Ok(keys) = &mut keys_res {
- if i >= keys_str.len() {
- break;
- }
- if !keys_str.is_char_boundary(i) {
- i += 1;
- continue;
- }
-
- let s = &keys_str[i..];
- let mut end_i = 1;
- while !s.is_char_boundary(end_i) {
- end_i += 1;
- }
- let c = &s[..end_i];
- if c == ">" {
- keys_res = Err(anyhow!("Unmatched '>'"));
- } else if c != "<" {
- keys.push(if c == "-" { keys::MINUS } else { c });
- i += end_i;
- } else {
- match s.find('>').context("'>' expected") {
- Ok(end_i) => {
- keys.push(&s[1..end_i]);
- i += end_i + 1;
- }
- Err(err) => keys_res = Err(err),
- }
+ crossterm::event::KeyEvent { code, modifiers }: crossterm::event::KeyEvent,
+ ) -> KeyEvent {
+ KeyEvent {
+ code: code.into(),
+ modifiers: modifiers.into(),
}
}
- keys_res.and_then(|keys| keys.into_iter().map(str::parse).collect())
}
#[cfg(test)]
@@ -758,53 +275,6 @@ mod test {
modifiers: KeyModifiers::NONE
}
);
-
- assert_eq!(
- str::parse::<KeyEvent>("%").unwrap(),
- KeyEvent {
- code: KeyCode::Char('%'),
- modifiers: KeyModifiers::NONE
- }
- );
-
- assert_eq!(
- str::parse::<KeyEvent>(";").unwrap(),
- KeyEvent {
- code: KeyCode::Char(';'),
- modifiers: KeyModifiers::NONE
- }
- );
-
- assert_eq!(
- str::parse::<KeyEvent>(">").unwrap(),
- KeyEvent {
- code: KeyCode::Char('>'),
- modifiers: KeyModifiers::NONE
- }
- );
-
- assert_eq!(
- str::parse::<KeyEvent>("<").unwrap(),
- KeyEvent {
- code: KeyCode::Char('<'),
- modifiers: KeyModifiers::NONE
- }
- );
-
- assert_eq!(
- str::parse::<KeyEvent>("+").unwrap(),
- KeyEvent {
- code: KeyCode::Char('+'),
- modifiers: KeyModifiers::NONE
- }
- );
- assert_eq!(
- str::parse::<KeyEvent>("-").unwrap(),
- KeyEvent {
- code: KeyCode::Char('-'),
- modifiers: KeyModifiers::NONE,
- }
- );
}
#[test]
@@ -832,54 +302,11 @@ mod test {
modifiers: KeyModifiers::SHIFT | KeyModifiers::CONTROL
}
);
-
- assert_eq!(
- str::parse::<KeyEvent>("A-C-+").unwrap(),
- KeyEvent {
- code: KeyCode::Char('+'),
- modifiers: KeyModifiers::ALT | KeyModifiers::CONTROL
- }
- );
-
- assert_eq!(
- str::parse::<KeyEvent>("C-S-r").unwrap(),
- str::parse::<KeyEvent>("C-R").unwrap(),
- );
-
- assert_eq!(
- str::parse::<KeyEvent>("S-w").unwrap(),
- KeyEvent {
- code: KeyCode::Char('W'),
- modifiers: KeyModifiers::NONE
- }
- );
-
- assert_eq!(
- str::parse::<KeyEvent>("Meta-c").unwrap(),
- KeyEvent {
- code: KeyCode::Char('c'),
- modifiers: KeyModifiers::SUPER
- }
- );
- assert_eq!(
- str::parse::<KeyEvent>("Win-s").unwrap(),
- KeyEvent {
- code: KeyCode::Char('s'),
- modifiers: KeyModifiers::SUPER
- }
- );
- assert_eq!(
- str::parse::<KeyEvent>("Cmd-d").unwrap(),
- KeyEvent {
- code: KeyCode::Char('d'),
- modifiers: KeyModifiers::SUPER
- }
- );
}
#[test]
fn parsing_nonsensical_keys_fails() {
- assert!(str::parse::<KeyEvent>("F25").is_err());
+ assert!(str::parse::<KeyEvent>("F13").is_err());
assert!(str::parse::<KeyEvent>("F0").is_err());
assert!(str::parse::<KeyEvent>("aaa").is_err());
assert!(str::parse::<KeyEvent>("S-S-a").is_err());
@@ -887,188 +314,5 @@ mod test {
assert!(str::parse::<KeyEvent>("FU").is_err());
assert!(str::parse::<KeyEvent>("123").is_err());
assert!(str::parse::<KeyEvent>("S--").is_err());
- assert!(str::parse::<KeyEvent>("S-").is_err());
- assert!(str::parse::<KeyEvent>("S-percent").is_err());
- }
-
- #[test]
- fn parsing_unsupported_named_keys() {
- assert!(str::parse::<KeyEvent>("plus").is_err());
- assert!(str::parse::<KeyEvent>("percent").is_err());
- assert!(str::parse::<KeyEvent>("semicolon").is_err());
- }
-
- #[test]
- fn parsing_valid_macros() {
- assert_eq!(
- parse_macro("xdo").ok(),
- Some(vec![
- KeyEvent {
- code: KeyCode::Char('x'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('d'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('o'),
- modifiers: KeyModifiers::NONE,
- },
- ]),
- );
-
- assert_eq!(
- parse_macro("<C-w>v<C-w>h<C-o>xx<A-s>").ok(),
- Some(vec![
- KeyEvent {
- code: KeyCode::Char('w'),
- modifiers: KeyModifiers::CONTROL,
- },
- KeyEvent {
- code: KeyCode::Char('v'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('w'),
- modifiers: KeyModifiers::CONTROL,
- },
- KeyEvent {
- code: KeyCode::Char('h'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('o'),
- modifiers: KeyModifiers::CONTROL,
- },
- KeyEvent {
- code: KeyCode::Char('x'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('x'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('s'),
- modifiers: KeyModifiers::ALT,
- },
- ])
- );
-
- assert_eq!(
- parse_macro(":o foo.bar<ret>").ok(),
- Some(vec![
- KeyEvent {
- code: KeyCode::Char(':'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('o'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char(' '),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('f'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('o'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('o'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('.'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('b'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('a'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('r'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Enter,
- modifiers: KeyModifiers::NONE,
- },
- ])
- );
-
- assert_eq!(
- parse_macro(":w aa-bb.txt<ret>").ok(),
- Some(vec![
- KeyEvent {
- code: KeyCode::Char(':'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('w'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char(' '),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('a'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('a'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('-'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('b'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('b'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('.'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('t'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('x'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Char('t'),
- modifiers: KeyModifiers::NONE,
- },
- KeyEvent {
- code: KeyCode::Enter,
- modifiers: KeyModifiers::NONE,
- },
- ])
- );
- }
-
- #[test]
- fn parsing_invalid_macros_fails() {
- assert!(parse_macro("abc<C-").is_err());
- assert!(parse_macro("abc>123").is_err());
- assert!(parse_macro("wd<foo>").is_err());
}
}