diff options
author | Nathan Vegdahl | 2021-06-20 23:09:14 +0000 |
---|---|---|
committer | Nathan Vegdahl | 2021-06-20 23:09:14 +0000 |
commit | e686c3e4626fdafbcc2dab9d381eba83a5f6f974 (patch) | |
tree | a598e3fedc1f2ae78ebc6f132c81b37cedf5415d /helix-view/src/input.rs | |
parent | 4efd6713c5b30b33c497a1f85b77a7b0a7fd17e0 (diff) | |
parent | 985625763addd839a101263ae90cfb2f205830fc (diff) |
Merge branch 'master' of github.com:helix-editor/helix into line_ending_detection
Rebasing was making me manually fix conflicts on every commit, so
merging instead.
Diffstat (limited to 'helix-view/src/input.rs')
-rw-r--r-- | helix-view/src/input.rs | 226 |
1 files changed, 0 insertions, 226 deletions
diff --git a/helix-view/src/input.rs b/helix-view/src/input.rs deleted file mode 100644 index ab417819..00000000 --- a/helix-view/src/input.rs +++ /dev/null @@ -1,226 +0,0 @@ -//! Input event handling, currently backed by crossterm. -use anyhow::{anyhow, Error}; -use crossterm::event; -use serde::de::{self, Deserialize, Deserializer}; -use std::fmt; - -pub use crossterm::event::{KeyCode, KeyModifiers}; - -/// Represents a key event. -// We use a newtype here because we want to customize Deserialize and Display. -#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy, Hash)] -pub struct KeyEvent { - pub code: KeyCode, - pub modifiers: KeyModifiers, -} - -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::SHIFT) { - "S-" - } else { - "" - }, - if self.modifiers.contains(KeyModifiers::ALT) { - "A-" - } else { - "" - }, - if self.modifiers.contains(KeyModifiers::CONTROL) { - "C-" - } else { - "" - }, - ))?; - match self.code { - KeyCode::Backspace => f.write_str("backspace")?, - KeyCode::Enter => f.write_str("ret")?, - KeyCode::Left => f.write_str("left")?, - KeyCode::Right => f.write_str("right")?, - KeyCode::Up => f.write_str("up")?, - KeyCode::Down => f.write_str("down")?, - KeyCode::Home => f.write_str("home")?, - KeyCode::End => f.write_str("end")?, - KeyCode::PageUp => f.write_str("pageup")?, - KeyCode::PageDown => f.write_str("pagedown")?, - KeyCode::Tab => f.write_str("tab")?, - KeyCode::BackTab => f.write_str("backtab")?, - KeyCode::Delete => f.write_str("del")?, - KeyCode::Insert => f.write_str("ins")?, - KeyCode::Null => f.write_str("null")?, - KeyCode::Esc => f.write_str("esc")?, - KeyCode::Char('<') => f.write_str("lt")?, - KeyCode::Char('>') => f.write_str("gt")?, - KeyCode::Char('+') => f.write_str("plus")?, - KeyCode::Char('-') => f.write_str("minus")?, - KeyCode::Char(';') => f.write_str("semicolon")?, - KeyCode::Char('%') => f.write_str("percent")?, - KeyCode::F(i) => f.write_fmt(format_args!("F{}", i))?, - KeyCode::Char(c) => f.write_fmt(format_args!("{}", c))?, - }; - Ok(()) - } -} - -impl std::str::FromStr for KeyEvent { - type Err = Error; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - let mut tokens: Vec<_> = s.split('-').collect(); - let code = match tokens.pop().ok_or_else(|| anyhow!("Missing key code"))? { - "backspace" => KeyCode::Backspace, - "space" => KeyCode::Char(' '), - "ret" => KeyCode::Enter, - "lt" => KeyCode::Char('<'), - "gt" => KeyCode::Char('>'), - "plus" => KeyCode::Char('+'), - "minus" => KeyCode::Char('-'), - "semicolon" => KeyCode::Char(';'), - "percent" => KeyCode::Char('%'), - "left" => KeyCode::Left, - "right" => KeyCode::Right, - "up" => KeyCode::Down, - "home" => KeyCode::Home, - "end" => KeyCode::End, - "pageup" => KeyCode::PageUp, - "pagedown" => KeyCode::PageDown, - "tab" => KeyCode::Tab, - "backtab" => KeyCode::BackTab, - "del" => KeyCode::Delete, - "ins" => KeyCode::Insert, - "null" => KeyCode::Null, - "esc" => KeyCode::Esc, - single if single.len() == 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 < 13) - .then(|| KeyCode::F(function)) - .ok_or_else(|| anyhow!("Invalid function key '{}'", function))? - } - invalid => return Err(anyhow!("Invalid key code '{}'", invalid)), - }; - - let mut modifiers = KeyModifiers::empty(); - for token in tokens { - let flag = match token { - "S" => KeyModifiers::SHIFT, - "A" => KeyModifiers::ALT, - "C" => KeyModifiers::CONTROL, - _ => return Err(anyhow!("Invalid key modifier '{}-'", token)), - }; - - if modifiers.contains(flag) { - return Err(anyhow!("Repeated key modifier '{}-'", token)); - } - modifiers.insert(flag); - } - - Ok(KeyEvent { code, modifiers }) - } -} - -impl<'de> Deserialize<'de> for KeyEvent { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - s.parse().map_err(de::Error::custom) - } -} - -impl From<event::KeyEvent> for KeyEvent { - fn from(event::KeyEvent { code, modifiers }: event::KeyEvent) -> KeyEvent { - KeyEvent { code, modifiers } - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn parsing_unmodified_keys() { - assert_eq!( - str::parse::<KeyEvent>("backspace").unwrap(), - KeyEvent { - code: KeyCode::Backspace, - modifiers: KeyModifiers::NONE - } - ); - - assert_eq!( - str::parse::<KeyEvent>("left").unwrap(), - KeyEvent { - code: KeyCode::Left, - modifiers: KeyModifiers::NONE - } - ); - - assert_eq!( - str::parse::<KeyEvent>(",").unwrap(), - KeyEvent { - code: KeyCode::Char(','), - modifiers: KeyModifiers::NONE - } - ); - - assert_eq!( - str::parse::<KeyEvent>("w").unwrap(), - KeyEvent { - code: KeyCode::Char('w'), - modifiers: KeyModifiers::NONE - } - ); - - assert_eq!( - str::parse::<KeyEvent>("F12").unwrap(), - KeyEvent { - code: KeyCode::F(12), - modifiers: KeyModifiers::NONE - } - ); - } - - #[test] - fn parsing_modified_keys() { - assert_eq!( - str::parse::<KeyEvent>("S-minus").unwrap(), - KeyEvent { - code: KeyCode::Char('-'), - modifiers: KeyModifiers::SHIFT - } - ); - - assert_eq!( - str::parse::<KeyEvent>("C-A-S-F12").unwrap(), - KeyEvent { - code: KeyCode::F(12), - modifiers: KeyModifiers::SHIFT | KeyModifiers::CONTROL | KeyModifiers::ALT - } - ); - - assert_eq!( - str::parse::<KeyEvent>("S-C-2").unwrap(), - KeyEvent { - code: KeyCode::Char('2'), - modifiers: KeyModifiers::SHIFT | KeyModifiers::CONTROL - } - ); - } - - #[test] - fn parsing_nonsensical_keys_fails() { - 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()); - assert!(str::parse::<KeyEvent>("C-A-S-C-1").is_err()); - assert!(str::parse::<KeyEvent>("FU").is_err()); - assert!(str::parse::<KeyEvent>("123").is_err()); - assert!(str::parse::<KeyEvent>("S--").is_err()); - } -} |