@@ -3,6 +3,8 @@ pub use crate::commands::Command;
33use anyhow::{anyhow, Error, Result};
44use helix_core::hashmap;
55use helix_view::document::Mode;
6+use helix_view::input::{KeyCode, KeyEvent, KeyModifiers};
7+use serde::Deserialize;
68use std::{
79 collections::HashMap,
810 fmt::Display,
@@ -99,14 +101,6 @@ use std::{
99101// D] = last diagnostic
100102// }
101103
102−// #[cfg(feature = "term")]
103−pub use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
104−
105−#[derive(Clone, Debug)]
106−pub struct Keymap(pub HashMap<KeyEvent, Command>);
107−#[derive(Clone, Debug)]
108−pub struct Keymaps(pub HashMap<Mode, Keymap>);
109−
110104#[macro_export]
111105macro_rules! key {
112106 ($key:ident) => {
@@ -141,9 +135,21 @@ macro_rules! alt {
141135 };
142136}
143137
138+#[derive(Debug, PartialEq, Deserialize)]
139+#[serde(transparent)]
140+pub struct Keymaps(pub HashMap<Mode, HashMap<KeyEvent, Command>>);
141+
142+impl Deref for Keymaps {
143+ type Target = HashMap<Mode, HashMap<KeyEvent, Command>>;
144+
145+ fn deref(&self) -> &Self::Target {
146+ &self.0
147+ }
148+}
149+
144150impl Default for Keymaps {
145− fn default() -> Self {
146− let normal = Keymap(hashmap!(
151+ fn default() -> Keymaps {
152+ let normal = hashmap!(
147153 key!('h') => Command::move_char_left,
148154 key!('j') => Command::move_line_down,
149155 key!('k') => Command::move_line_up,
@@ -277,12 +283,12 @@ impl Default for Keymaps {
277283 key!('z') => Command::view_mode,
278284
279285 key!('"') => Command::select_register,
280− ));
286+ );
281287 // TODO: decide whether we want normal mode to also be select mode (kakoune-like), or whether
282288 // we keep this separate select mode. More keys can fit into normal mode then, but it's weird
283289 // because some selection operations can now be done from normal mode, some from select mode.
284290 let mut select = normal.clone();
285− select.0.extend(
291+ select.extend(
286292 hashmap!(
287293 key!('h') => Command::extend_char_left,
288294 key!('j') => Command::extend_line_down,
@@ -315,7 +321,7 @@ impl Default for Keymaps {
315321 // TODO: select could be normal mode with some bindings merged over
316322 Mode::Normal => normal,
317323 Mode::Select => select,
318− Mode::Insert => Keymap(hashmap!(
324+ Mode::Insert => hashmap!(
319325 key!(Esc) => Command::normal_mode as Command,
320326 key!(Backspace) => Command::delete_char_backward,
321327 key!(Delete) => Command::delete_char_forward,
@@ -329,309 +335,7 @@ impl Default for Keymaps {
329335 key!(PageDown) => Command::page_down,
330336 ctrl!('x') => Command::completion,
331337 ctrl!('w') => Command::delete_word_backward,
332− )),
338+ ),
333339 ))
334340 }
335341}
336−
337−// Newtype wrapper over keys to allow toml serialization/parsing
338−#[derive(Debug, PartialEq, PartialOrd, Clone, Copy, Hash)]
339−pub struct RepresentableKeyEvent(pub KeyEvent);
340−impl Display for RepresentableKeyEvent {
341− fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
342− let Self(key) = self;
343− f.write_fmt(format_args!(
344− "{}{}{}",
345− if key.modifiers.contains(KeyModifiers::SHIFT) {
346− "S-"
347− } else {
348− ""
349− },
350− if key.modifiers.contains(KeyModifiers::ALT) {
351− "A-"
352− } else {
353− ""
354− },
355− if key.modifiers.contains(KeyModifiers::CONTROL) {
356− "C-"
357− } else {
358− ""
359− },
360− ))?;
361− match key.code {
362− KeyCode::Backspace => f.write_str("backspace")?,
363− KeyCode::Enter => f.write_str("ret")?,
364− KeyCode::Left => f.write_str("left")?,
365− KeyCode::Right => f.write_str("right")?,
366− KeyCode::Up => f.write_str("up")?,
367− KeyCode::Down => f.write_str("down")?,
368− KeyCode::Home => f.write_str("home")?,
369− KeyCode::End => f.write_str("end")?,
370− KeyCode::PageUp => f.write_str("pageup")?,
371− KeyCode::PageDown => f.write_str("pagedown")?,
372− KeyCode::Tab => f.write_str("tab")?,
373− KeyCode::BackTab => f.write_str("backtab")?,
374− KeyCode::Delete => f.write_str("del")?,
375− KeyCode::Insert => f.write_str("ins")?,
376− KeyCode::Null => f.write_str("null")?,
377− KeyCode::Esc => f.write_str("esc")?,
378− KeyCode::Char('<') => f.write_str("lt")?,
379− KeyCode::Char('>') => f.write_str("gt")?,
380− KeyCode::Char('+') => f.write_str("plus")?,
381− KeyCode::Char('-') => f.write_str("minus")?,
382− KeyCode::Char(';') => f.write_str("semicolon")?,
383− KeyCode::Char('%') => f.write_str("percent")?,
384− KeyCode::F(i) => f.write_fmt(format_args!("F{}", i))?,
385− KeyCode::Char(c) => f.write_fmt(format_args!("{}", c))?,
386− };
387− Ok(())
388− }
389−}
390−
391−impl FromStr for RepresentableKeyEvent {
392− type Err = Error;
393−
394− fn from_str(s: &str) -> Result<Self, Self::Err> {
395− let mut tokens: Vec<_> = s.split('-').collect();
396− let code = match tokens.pop().ok_or_else(|| anyhow!("Missing key code"))? {
397− "backspace" => KeyCode::Backspace,
398− "space" => KeyCode::Char(' '),
399− "ret" => KeyCode::Enter,
400− "lt" => KeyCode::Char('<'),
401− "gt" => KeyCode::Char('>'),
402− "plus" => KeyCode::Char('+'),
403− "minus" => KeyCode::Char('-'),
404− "semicolon" => KeyCode::Char(';'),
405− "percent" => KeyCode::Char('%'),
406− "left" => KeyCode::Left,
407− "right" => KeyCode::Right,
408− "up" => KeyCode::Down,
409− "home" => KeyCode::Home,
410− "end" => KeyCode::End,
411− "pageup" => KeyCode::PageUp,
412− "pagedown" => KeyCode::PageDown,
413− "tab" => KeyCode::Tab,
414− "backtab" => KeyCode::BackTab,
415− "del" => KeyCode::Delete,
416− "ins" => KeyCode::Insert,
417− "null" => KeyCode::Null,
418− "esc" => KeyCode::Esc,
419− single if single.len() == 1 => KeyCode::Char(single.chars().next().unwrap()),
420− function if function.len() > 1 && function.starts_with('F') => {
421− let function: String = function.chars().skip(1).collect();
422− let function = str::parse::<u8>(&function)?;
423− (function > 0 && function < 13)
424− .then(|| KeyCode::F(function))
425− .ok_or_else(|| anyhow!("Invalid function key '{}'", function))?
426− }
427− invalid => return Err(anyhow!("Invalid key code '{}'", invalid)),
428− };
429−
430− let mut modifiers = KeyModifiers::empty();
431− for token in tokens {
432− let flag = match token {
433− "S" => KeyModifiers::SHIFT,
434− "A" => KeyModifiers::ALT,
435− "C" => KeyModifiers::CONTROL,
436− _ => return Err(anyhow!("Invalid key modifier '{}-'", token)),
437− };
438−
439− if modifiers.contains(flag) {
440− return Err(anyhow!("Repeated key modifier '{}-'", token));
441− }
442− modifiers.insert(flag);
443− }
444−
445− Ok(RepresentableKeyEvent(KeyEvent { code, modifiers }))
446− }
447−}
448−
449−pub fn parse_keymaps(toml_keymaps: &HashMap<String, HashMap<String, String>>) -> Result<Keymaps> {
450− let mut keymaps = Keymaps::default();
451−
452− for (mode, map) in toml_keymaps {
453− let mode = Mode::from_str(&mode)?;
454− for (key, command) in map {
455− let key = str::parse::<RepresentableKeyEvent>(&key)?;
456− let command = str::parse::<Command>(&command)?;
457− keymaps.0.get_mut(&mode).unwrap().0.insert(key.0, command);
458− }
459− }
460− Ok(keymaps)
461−}
462−
463−impl Deref for Keymap {
464− type Target = HashMap<KeyEvent, Command>;
465− fn deref(&self) -> &Self::Target {
466− &self.0
467− }
468−}
469−
470−impl Deref for Keymaps {
471− type Target = HashMap<Mode, Keymap>;
472− fn deref(&self) -> &Self::Target {
473− &self.0
474− }
475−}
476−
477−impl DerefMut for Keymap {
478− fn deref_mut(&mut self) -> &mut Self::Target {
479− &mut self.0
480− }
481−}
482−
483−impl DerefMut for Keymaps {
484− fn deref_mut(&mut self) -> &mut Self::Target {
485− &mut self.0
486− }
487−}
488−
489−#[cfg(test)]
490−mod test {
491− use crate::config::Config;
492−
493− use super::*;
494−
495− impl PartialEq for Command {
496− fn eq(&self, other: &Self) -> bool {
497− self.name() == other.name()
498− }
499− }
500−
501− #[test]
502− fn parsing_keymaps_config_file() {
503− let sample_keymaps = r#"
504− [keys.insert]
505− y = "move_line_down"
506− S-C-a = "delete_selection"
507−
508− [keys.normal]
509− A-F12 = "move_next_word_end"
510− "#;
511−
512− let config: Config = toml::from_str(sample_keymaps).unwrap();
513− assert_eq!(
514− *config
515− .keymaps
516− .0
517− .get(&Mode::Insert)
518− .unwrap()
519− .0
520− .get(&KeyEvent {
521− code: KeyCode::Char('y'),
522− modifiers: KeyModifiers::NONE
523− })
524− .unwrap(),
525− Command::move_line_down
526− );
527− assert_eq!(
528− *config
529− .keymaps
530− .0
531− .get(&Mode::Insert)
532− .unwrap()
533− .0
534− .get(&KeyEvent {
535− code: KeyCode::Char('a'),
536− modifiers: KeyModifiers::SHIFT | KeyModifiers::CONTROL
537− })
538− .unwrap(),
539− Command::delete_selection
540− );
541− assert_eq!(
542− *config
543− .keymaps
544− .0
545− .get(&Mode::Normal)
546− .unwrap()
547− .0
548− .get(&KeyEvent {
549− code: KeyCode::F(12),
550− modifiers: KeyModifiers::ALT
551− })
552− .unwrap(),
553− Command::move_next_word_end
554− );
555− }
556−
557− #[test]
558− fn parsing_unmodified_keys() {
559− assert_eq!(
560− str::parse::<RepresentableKeyEvent>("backspace").unwrap(),
561− RepresentableKeyEvent(KeyEvent {
562− code: KeyCode::Backspace,
563− modifiers: KeyModifiers::NONE
564− })
565− );
566−
567− assert_eq!(
568− str::parse::<RepresentableKeyEvent>("left").unwrap(),
569− RepresentableKeyEvent(KeyEvent {
570− code: KeyCode::Left,
571− modifiers: KeyModifiers::NONE
572− })
573− );
574−
575− assert_eq!(
576− str::parse::<RepresentableKeyEvent>(",").unwrap(),
577− RepresentableKeyEvent(KeyEvent {
578− code: KeyCode::Char(','),
579− modifiers: KeyModifiers::NONE
580− })
581− );
582−
583− assert_eq!(
584− str::parse::<RepresentableKeyEvent>("w").unwrap(),
585− RepresentableKeyEvent(KeyEvent {
586− code: KeyCode::Char('w'),
587− modifiers: KeyModifiers::NONE
588− })
589− );
590−
591− assert_eq!(
592− str::parse::<RepresentableKeyEvent>("F12").unwrap(),
593− RepresentableKeyEvent(KeyEvent {
594− code: KeyCode::F(12),
595− modifiers: KeyModifiers::NONE
596− })
597− );
598− }
599−
600− fn parsing_modified_keys() {
601− assert_eq!(
602− str::parse::<RepresentableKeyEvent>("S-minus").unwrap(),
603− RepresentableKeyEvent(KeyEvent {
604− code: KeyCode::Char('-'),
605− modifiers: KeyModifiers::SHIFT
606− })
607− );
608−
609− assert_eq!(
610− str::parse::<RepresentableKeyEvent>("C-A-S-F12").unwrap(),
611− RepresentableKeyEvent(KeyEvent {
612− code: KeyCode::F(12),
613− modifiers: KeyModifiers::SHIFT | KeyModifiers::CONTROL | KeyModifiers::ALT
614− })
615− );
616−
617− assert_eq!(
618− str::parse::<RepresentableKeyEvent>("S-C-2").unwrap(),
619− RepresentableKeyEvent(KeyEvent {
620− code: KeyCode::F(2),
621− modifiers: KeyModifiers::SHIFT | KeyModifiers::CONTROL
622− })
623− );
624− }
625−
626− #[test]
627− fn parsing_nonsensical_keys_fails() {
628− assert!(str::parse::<RepresentableKeyEvent>("F13").is_err());
629− assert!(str::parse::<RepresentableKeyEvent>("F0").is_err());
630− assert!(str::parse::<RepresentableKeyEvent>("aaa").is_err());
631− assert!(str::parse::<RepresentableKeyEvent>("S-S-a").is_err());
632− assert!(str::parse::<RepresentableKeyEvent>("C-A-S-C-1").is_err());
633− assert!(str::parse::<RepresentableKeyEvent>("FU").is_err());
634− assert!(str::parse::<RepresentableKeyEvent>("123").is_err());
635− assert!(str::parse::<RepresentableKeyEvent>("S--").is_err());
636− }
637−}