@@ -1,8 +1,11 @@
1use crate::commands;
1use crate::commands;
2pub use crate::commands::Command;
2pub use crate::commands::Command;
3+use crate::config::Config;
3use anyhow::{anyhow, Error, Result};
4use anyhow::{anyhow, Error, Result};
4use helix_core::hashmap;
5use helix_core::hashmap;
5use helix_view::document::Mode;
6use helix_view::document::Mode;
7+use helix_view::input::{KeyCode, KeyEvent, KeyModifiers};
8+use serde::Deserialize;
7 collections::HashMap,
10 collections::HashMap,
8 fmt::Display,
11 fmt::Display,
@@ -99,14 +102,6 @@ use std::{
99// D] = last diagnostic
102// D] = last diagnostic
102−// #[cfg(feature = "term")]
103−pub use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
105−#[derive(Clone, Debug)]
106−pub struct Keymap(pub HashMap<KeyEvent, Command>);
107−#[derive(Clone, Debug)]
108−pub struct Keymaps(pub HashMap<Mode, Keymap>);
110#[macro_export]
105#[macro_export]
111macro_rules! key {
106macro_rules! key {
112 ($key:ident) => {
107 ($key:ident) => {
@@ -141,9 +136,27 @@ macro_rules! alt {
139+#[derive(Debug, Clone, PartialEq, Deserialize)]
140+#[serde(transparent)]
141+pub struct Keymaps(pub HashMap<Mode, HashMap<KeyEvent, Command>>);
143+impl Deref for Keymaps {
144+ type Target = HashMap<Mode, HashMap<KeyEvent, Command>>;
146+ fn deref(&self) -> &Self::Target {
151+impl DerefMut for Keymaps {
152+ fn deref_mut(&mut self) -> &mut Self::Target {
144impl Default for Keymaps {
157impl Default for Keymaps {
145− fn default() -> Self {
158+ fn default() -> Keymaps {
146− let normal = Keymap(hashmap!(
159+ let normal = hashmap!(
147 key!('h') => Command::move_char_left,
160 key!('h') => Command::move_char_left,
148 key!('j') => Command::move_line_down,
161 key!('j') => Command::move_line_down,
149 key!('k') => Command::move_line_up,
162 key!('k') => Command::move_line_up,
@@ -265,12 +278,12 @@ impl Default for Keymaps {
265 key!('z') => Command::view_mode,
278 key!('z') => Command::view_mode,
267 key!('"') => Command::select_register,
280 key!('"') => Command::select_register,
269 // TODO: decide whether we want normal mode to also be select mode (kakoune-like), or whether
282 // TODO: decide whether we want normal mode to also be select mode (kakoune-like), or whether
270 // we keep this separate select mode. More keys can fit into normal mode then, but it's weird
283 // we keep this separate select mode. More keys can fit into normal mode then, but it's weird
271 // because some selection operations can now be done from normal mode, some from select mode.
284 // because some selection operations can now be done from normal mode, some from select mode.
272 let mut select = normal.clone();
285 let mut select = normal.clone();
273− select.0.extend(
286+ select.extend(
274 hashmap!(
287 hashmap!(
275 key!('h') => Command::extend_char_left,
288 key!('h') => Command::extend_char_left,
276 key!('j') => Command::extend_line_down,
289 key!('j') => Command::extend_line_down,
@@ -303,7 +316,7 @@ impl Default for Keymaps {
303 // TODO: select could be normal mode with some bindings merged over
316 // TODO: select could be normal mode with some bindings merged over
304 Mode::Normal => normal,
317 Mode::Normal => normal,
305 Mode::Select => select,
318 Mode::Select => select,
306− Mode::Insert => Keymap(hashmap!(
319+ Mode::Insert => hashmap!(
307 key!(Esc) => Command::normal_mode as Command,
320 key!(Esc) => Command::normal_mode as Command,
308 key!(Backspace) => Command::delete_char_backward,
321 key!(Backspace) => Command::delete_char_backward,
309 key!(Delete) => Command::delete_char_forward,
322 key!(Delete) => Command::delete_char_forward,
@@ -319,309 +332,66 @@ impl Default for Keymaps {
319 key!(End) => Command::move_line_end,
332 key!(End) => Command::move_line_end,
320 ctrl!('x') => Command::completion,
333 ctrl!('x') => Command::completion,
321 ctrl!('w') => Command::delete_word_backward,
334 ctrl!('w') => Command::delete_word_backward,
327−// Newtype wrapper over keys to allow toml serialization/parsing
340+/// Merge default config keys with user overwritten keys for custom
328−#[derive(Debug, PartialEq, PartialOrd, Clone, Copy, Hash)]
341+/// user config.
329−pub struct RepresentableKeyEvent(pub KeyEvent);
342+pub fn merge_keys(mut config: Config) -> Config {
330−impl Display for RepresentableKeyEvent {
343+ let mut delta = std::mem::take(&mut config.keys);
331− fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
344+ for (mode, keys) in &mut *config.keys {
332− let Self(key) = self;
345+ keys.extend(delta.remove(mode).unwrap_or_default());
333− f.write_fmt(format_args!(
335− if key.modifiers.contains(KeyModifiers::SHIFT) {
340− if key.modifiers.contains(KeyModifiers::ALT) {
345− if key.modifiers.contains(KeyModifiers::CONTROL) {
352− KeyCode::Backspace => f.write_str("backspace")?,
353− KeyCode::Enter => f.write_str("ret")?,
354− KeyCode::Left => f.write_str("left")?,
355− KeyCode::Right => f.write_str("right")?,
356− KeyCode::Up => f.write_str("up")?,
357− KeyCode::Down => f.write_str("down")?,
358− KeyCode::Home => f.write_str("home")?,
359− KeyCode::End => f.write_str("end")?,
360− KeyCode::PageUp => f.write_str("pageup")?,
361− KeyCode::PageDown => f.write_str("pagedown")?,
362− KeyCode::Tab => f.write_str("tab")?,
363− KeyCode::BackTab => f.write_str("backtab")?,
364− KeyCode::Delete => f.write_str("del")?,
365− KeyCode::Insert => f.write_str("ins")?,
366− KeyCode::Null => f.write_str("null")?,
367− KeyCode::Esc => f.write_str("esc")?,
368− KeyCode::Char('<') => f.write_str("lt")?,
369− KeyCode::Char('>') => f.write_str("gt")?,
370− KeyCode::Char('+') => f.write_str("plus")?,
371− KeyCode::Char('-') => f.write_str("minus")?,
372− KeyCode::Char(';') => f.write_str("semicolon")?,
373− KeyCode::Char('%') => f.write_str("percent")?,
374− KeyCode::F(i) => f.write_fmt(format_args!("F{}", i))?,
375− KeyCode::Char(c) => f.write_fmt(format_args!("{}", c))?,
381−impl FromStr for RepresentableKeyEvent {
384− fn from_str(s: &str) -> Result<Self, Self::Err> {
385− let mut tokens: Vec<_> = s.split('-').collect();
386− let code = match tokens.pop().ok_or_else(|| anyhow!("Missing key code"))? {
387− "backspace" => KeyCode::Backspace,
388− "space" => KeyCode::Char(' '),
389− "ret" => KeyCode::Enter,
390− "lt" => KeyCode::Char('<'),
391− "gt" => KeyCode::Char('>'),
392− "plus" => KeyCode::Char('+'),
393− "minus" => KeyCode::Char('-'),
394− "semicolon" => KeyCode::Char(';'),
395− "percent" => KeyCode::Char('%'),
396− "left" => KeyCode::Left,
397− "right" => KeyCode::Right,
398− "up" => KeyCode::Down,
399− "home" => KeyCode::Home,
400− "end" => KeyCode::End,
401− "pageup" => KeyCode::PageUp,
402− "pagedown" => KeyCode::PageDown,
403− "tab" => KeyCode::Tab,
404− "backtab" => KeyCode::BackTab,
405− "del" => KeyCode::Delete,
406− "ins" => KeyCode::Insert,
407− "null" => KeyCode::Null,
408− "esc" => KeyCode::Esc,
409− single if single.len() == 1 => KeyCode::Char(single.chars().next().unwrap()),
410− function if function.len() > 1 && function.starts_with('F') => {
411− let function: String = function.chars().skip(1).collect();
412− let function = str::parse::<u8>(&function)?;
413− (function > 0 && function < 13)
414− .then(|| KeyCode::F(function))
415− .ok_or_else(|| anyhow!("Invalid function key '{}'", function))?
417− invalid => return Err(anyhow!("Invalid key code '{}'", invalid)),
420− let mut modifiers = KeyModifiers::empty();
421− for token in tokens {
422− let flag = match token {
423− "S" => KeyModifiers::SHIFT,
424− "A" => KeyModifiers::ALT,
425− "C" => KeyModifiers::CONTROL,
426− _ => return Err(anyhow!("Invalid key modifier '{}-'", token)),
429− if modifiers.contains(flag) {
430− return Err(anyhow!("Repeated key modifier '{}-'", token));
432− modifiers.insert(flag);
435− Ok(RepresentableKeyEvent(KeyEvent { code, modifiers }))
439−pub fn parse_keymaps(toml_keymaps: &HashMap<String, HashMap<String, String>>) -> Result<Keymaps> {
440− let mut keymaps = Keymaps::default();
442− for (mode, map) in toml_keymaps {
443− let mode = Mode::from_str(&mode)?;
444− for (key, command) in map {
445− let key = str::parse::<RepresentableKeyEvent>(&key)?;
446− let command = str::parse::<Command>(&command)?;
447− keymaps.0.get_mut(&mode).unwrap().0.insert(key.0, command);
453−impl Deref for Keymap {
454− type Target = HashMap<KeyEvent, Command>;
455− fn deref(&self) -> &Self::Target {
460−impl Deref for Keymaps {
461− type Target = HashMap<Mode, Keymap>;
462− fn deref(&self) -> &Self::Target {
467−impl DerefMut for Keymap {
468− fn deref_mut(&mut self) -> &mut Self::Target {
473−impl DerefMut for Keymaps {
474− fn deref_mut(&mut self) -> &mut Self::Target {
481− use crate::config::Config;
485− impl PartialEq for Command {
486− fn eq(&self, other: &Self) -> bool {
487− self.name() == other.name()
492− fn parsing_keymaps_config_file() {
493− let sample_keymaps = r#"
495− y = "move_line_down"
496− S-C-a = "delete_selection"
499− A-F12 = "move_next_word_end"
502− let config: Config = toml::from_str(sample_keymaps).unwrap();
511− code: KeyCode::Char('y'),
512− modifiers: KeyModifiers::NONE
515− Command::move_line_down
525− code: KeyCode::Char('a'),
526− modifiers: KeyModifiers::SHIFT | KeyModifiers::CONTROL
529− Command::delete_selection
539− code: KeyCode::F(12),
540− modifiers: KeyModifiers::ALT
543− Command::move_next_word_end
548− fn parsing_unmodified_keys() {
351+fn merge_partial_keys() {
549− assert_eq!(
352+ let config = Config {
550− str::parse::<RepresentableKeyEvent>("backspace").unwrap(),
353+ keys: Keymaps(hashmap! {
354+ Mode::Normal => hashmap! {
551− RepresentableKeyEvent(KeyEvent {
355+ KeyEvent {
552− code: KeyCode::Backspace,
356+ code: KeyCode::Char('i'),
553− modifiers: KeyModifiers::NONE
357+ modifiers: KeyModifiers::NONE,
554− })
358+ } => Command::normal_mode,
555− );
359+ KeyEvent { // key that does not exist
558− str::parse::<RepresentableKeyEvent>("left").unwrap(),
559− RepresentableKeyEvent(KeyEvent {
560− code: KeyCode::Left,
360+ code: KeyCode::Char('无'),
561− modifiers: KeyModifiers::NONE
361+ modifiers: KeyModifiers::NONE,
362+ } => Command::insert_mode,
564−
365+ ..Default::default()
566− str::parse::<RepresentableKeyEvent>(",").unwrap(),
367+ let merged_config = merge_keys(config.clone());
567− RepresentableKeyEvent(KeyEvent {
368+ assert_ne!(config, merged_config);
568− code: KeyCode::Char(','),
569− modifiers: KeyModifiers::NONE
573− assert_eq!(
369+ assert_eq!(
574− str::parse::<RepresentableKeyEvent>("w").unwrap(),
370+ *merged_config
575− RepresentableKeyEvent(KeyEvent {
375+ .get(&KeyEvent {
576− code: KeyCode::Char('w'),
376+ code: KeyCode::Char('i'),
577 modifiers: KeyModifiers::NONE
377 modifiers: KeyModifiers::NONE
380+ Command::normal_mode
581− assert_eq!(
382+ assert_eq!(
582− str::parse::<RepresentableKeyEvent>("F12").unwrap(),
383+ *merged_config
583− RepresentableKeyEvent(KeyEvent {
388+ .get(&KeyEvent {
584− code: KeyCode::F(12),
389+ code: KeyCode::Char('无'),
585 modifiers: KeyModifiers::NONE
390 modifiers: KeyModifiers::NONE
588− }
393+ Command::insert_mode
590− fn parsing_modified_keys() {
592− str::parse::<RepresentableKeyEvent>("S-minus").unwrap(),
593− RepresentableKeyEvent(KeyEvent {
594− code: KeyCode::Char('-'),
595− modifiers: KeyModifiers::SHIFT
600− str::parse::<RepresentableKeyEvent>("C-A-S-F12").unwrap(),
601− RepresentableKeyEvent(KeyEvent {
602− code: KeyCode::F(12),
603− modifiers: KeyModifiers::SHIFT | KeyModifiers::CONTROL | KeyModifiers::ALT
608− str::parse::<RepresentableKeyEvent>("S-C-2").unwrap(),
609− RepresentableKeyEvent(KeyEvent {
610− code: KeyCode::F(2),
611− modifiers: KeyModifiers::SHIFT | KeyModifiers::CONTROL
614− }
395+ assert!(merged_config.keys.0.get(&Mode::Normal).unwrap().len() > 1);
615−
396+ assert!(merged_config.keys.0.get(&Mode::Insert).unwrap().len() > 0);
617− fn parsing_nonsensical_keys_fails() {
618− assert!(str::parse::<RepresentableKeyEvent>("F13").is_err());
619− assert!(str::parse::<RepresentableKeyEvent>("F0").is_err());
620− assert!(str::parse::<RepresentableKeyEvent>("aaa").is_err());
621− assert!(str::parse::<RepresentableKeyEvent>("S-S-a").is_err());
622− assert!(str::parse::<RepresentableKeyEvent>("C-A-S-C-1").is_err());
623− assert!(str::parse::<RepresentableKeyEvent>("FU").is_err());
624− assert!(str::parse::<RepresentableKeyEvent>("123").is_err());
625− assert!(str::parse::<RepresentableKeyEvent>("S--").is_err());