Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-term/src/config.rs')
-rw-r--r--helix-term/src/config.rs114
1 files changed, 111 insertions, 3 deletions
diff --git a/helix-term/src/config.rs b/helix-term/src/config.rs
index 4407a882..27dcb971 100644
--- a/helix-term/src/config.rs
+++ b/helix-term/src/config.rs
@@ -1,5 +1,5 @@
-use crate::keymap::{default::default, merge_keys, Keymap};
use helix_view::document::Mode;
+use helix_view::keymap::{default::default, Keymap};
use serde::Deserialize;
use std::collections::HashMap;
use std::fmt::Display;
@@ -27,6 +27,15 @@ impl Default for Config {
}
}
+/// Merge default config keys with user overwritten keys for custom user config.
+pub fn merge_keys(mut config: Config) -> Config {
+ let mut delta = std::mem::replace(&mut config.keys, default());
+ for (mode, keys) in &mut config.keys {
+ keys.merge(delta.remove(mode).unwrap_or_default())
+ }
+ config
+}
+
#[derive(Debug)]
pub enum ConfigLoadError {
BadConfig(TomlError),
@@ -63,10 +72,9 @@ mod tests {
#[test]
fn parsing_keymaps_config_file() {
- use crate::keymap;
- use crate::keymap::Keymap;
use helix_core::hashmap;
use helix_view::document::Mode;
+ use helix_view::keymap::{self, Keymap};
let sample_keymaps = r#"
[keys.insert]
@@ -104,4 +112,104 @@ mod tests {
let default_keys = Config::default().keys;
assert_eq!(default_keys, default());
}
+
+ use arc_swap::access::Constant;
+ use helix_core::hashmap;
+
+ #[test]
+ fn merge_partial_keys() {
+ let config = Config {
+ keys: hashmap! {
+ Mode::Normal => Keymap::new(
+ keymap!({ "Normal mode"
+ "i" => normal_mode,
+ "无" => insert_mode,
+ "z" => jump_backward,
+ "g" => { "Merge into goto mode"
+ "$" => goto_line_end,
+ "g" => delete_char_forward,
+ },
+ })
+ )
+ },
+ ..Default::default()
+ };
+ let mut merged_config = merge_keys(config.clone());
+ assert_ne!(config, merged_config);
+
+ let mut keymap = Keymaps::new(Box::new(Constant(merged_config.keys.clone())));
+ assert_eq!(
+ keymap.get(Mode::Normal, key!('i')),
+ KeymapResult::Matched(MappableCommand::normal_mode),
+ "Leaf should replace leaf"
+ );
+ assert_eq!(
+ keymap.get(Mode::Normal, key!('无')),
+ KeymapResult::Matched(MappableCommand::insert_mode),
+ "New leaf should be present in merged keymap"
+ );
+ // Assumes that z is a node in the default keymap
+ assert_eq!(
+ keymap.get(Mode::Normal, key!('z')),
+ KeymapResult::Matched(MappableCommand::jump_backward),
+ "Leaf should replace node"
+ );
+
+ let keymap = merged_config.keys.get_mut(&Mode::Normal).unwrap();
+ // Assumes that `g` is a node in default keymap
+ assert_eq!(
+ keymap.root().search(&[key!('g'), key!('$')]).unwrap(),
+ &KeyTrie::Leaf(MappableCommand::goto_line_end),
+ "Leaf should be present in merged subnode"
+ );
+ // Assumes that `gg` is in default keymap
+ assert_eq!(
+ keymap.root().search(&[key!('g'), key!('g')]).unwrap(),
+ &KeyTrie::Leaf(MappableCommand::delete_char_forward),
+ "Leaf should replace old leaf in merged subnode"
+ );
+ // Assumes that `ge` is in default keymap
+ assert_eq!(
+ keymap.root().search(&[key!('g'), key!('e')]).unwrap(),
+ &KeyTrie::Leaf(MappableCommand::goto_last_line),
+ "Old leaves in subnode should be present in merged node"
+ );
+
+ assert!(merged_config.keys.get(&Mode::Normal).unwrap().len() > 1);
+ assert!(merged_config.keys.get(&Mode::Insert).unwrap().len() > 0);
+ }
+
+ #[test]
+ fn order_should_be_set() {
+ let config = Config {
+ keys: hashmap! {
+ Mode::Normal => Keymap::new(
+ keymap!({ "Normal mode"
+ "space" => { ""
+ "s" => { ""
+ "v" => vsplit,
+ "c" => hsplit,
+ },
+ },
+ })
+ )
+ },
+ ..Default::default()
+ };
+ let mut merged_config = merge_keys(config.clone());
+ assert_ne!(config, merged_config);
+ let keymap = merged_config.keys.get_mut(&Mode::Normal).unwrap();
+ // Make sure mapping works
+ assert_eq!(
+ keymap
+ .root()
+ .search(&[key!(' '), key!('s'), key!('v')])
+ .unwrap(),
+ &KeyTrie::Leaf(MappableCommand::vsplit),
+ "Leaf should be present in merged subnode"
+ );
+ // Make sure an order was set during merge
+ let node = keymap.root().search(&[helix_view::key!(' ')]).unwrap();
+ assert!(!node.node().unwrap().order().is_empty())
+ }
}