aboutsummaryrefslogtreecommitdiff
path: root/helix-term/src/keymap.rs
diff options
context:
space:
mode:
authorMatouš Dzivjak2022-02-17 05:03:11 +0000
committerGitHub2022-02-17 05:03:11 +0000
commitafec54485a3be29ff1172f70157a183853273420 (patch)
tree9612658764e105970cba22c2e4c26b0be7be942a /helix-term/src/keymap.rs
parent24f90ba8d8f4a10fb18f71b05c278fe89b71a261 (diff)
feat(commands): command palette (#1400)
* feat(commands): command palette Add new command to display command pallete that can be used to discover and execute available commands. Fixes: https://github.com/helix-editor/helix/issues/559 * Make picker take the whole context, not just editor * Bind command pallete * Typable commands also in the palette * Show key bindings for commands * Fix tests, small refactor * Refactor keymap mapping, fix typo * Ignore sequence key bindings for now * Apply suggestions * Fix lint issues in tests * Fix after rebase Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
Diffstat (limited to 'helix-term/src/keymap.rs')
-rw-r--r--helix-term/src/keymap.rs77
1 files changed, 76 insertions, 1 deletions
diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs
index f414f797..0147f58e 100644
--- a/helix-term/src/keymap.rs
+++ b/helix-term/src/keymap.rs
@@ -343,13 +343,46 @@ pub struct Keymap {
impl Keymap {
pub fn new(root: KeyTrie) -> Self {
- Self {
+ Keymap {
root,
state: Vec::new(),
sticky: None,
}
}
+ pub fn reverse_map(&self) -> HashMap<String, Vec<Vec<KeyEvent>>> {
+ // recursively visit all nodes in keymap
+ fn map_node(
+ cmd_map: &mut HashMap<String, Vec<Vec<KeyEvent>>>,
+ node: &KeyTrie,
+ keys: &mut Vec<KeyEvent>,
+ ) {
+ match node {
+ KeyTrie::Leaf(cmd) => match cmd {
+ MappableCommand::Typable { name, .. } => {
+ cmd_map.entry(name.into()).or_default().push(keys.clone())
+ }
+ MappableCommand::Static { name, .. } => cmd_map
+ .entry(name.to_string())
+ .or_default()
+ .push(keys.clone()),
+ },
+ KeyTrie::Node(next) => {
+ for (key, trie) in &next.map {
+ keys.push(*key);
+ map_node(cmd_map, trie, keys);
+ keys.pop();
+ }
+ }
+ KeyTrie::Sequence(_) => {}
+ };
+ }
+
+ let mut res = HashMap::new();
+ map_node(&mut res, &self.root, &mut Vec::new());
+ res
+ }
+
pub fn root(&self) -> &KeyTrie {
&self.root
}
@@ -706,6 +739,7 @@ impl Default for Keymaps {
"/" => global_search,
"k" => hover,
"r" => rename_symbol,
+ "?" => command_palette,
},
"z" => { "View"
"z" | "c" => align_view_center,
@@ -958,4 +992,45 @@ mod tests {
"Mismatch for view mode on `z` and `Z`"
);
}
+
+ #[test]
+ fn reverse_map() {
+ let normal_mode = keymap!({ "Normal mode"
+ "i" => insert_mode,
+ "g" => { "Goto"
+ "g" => goto_file_start,
+ "e" => goto_file_end,
+ },
+ "j" | "k" => move_line_down,
+ });
+ let keymap = Keymap::new(normal_mode);
+ let mut reverse_map = keymap.reverse_map();
+
+ // sort keybindings in order to have consistent tests
+ // HashMaps can be compared but we can still get different ordering of bindings
+ // for commands that have multiple bindings assigned
+ for v in reverse_map.values_mut() {
+ v.sort()
+ }
+
+ assert_eq!(
+ reverse_map,
+ HashMap::from([
+ ("insert_mode".to_string(), vec![vec![key!('i')]]),
+ (
+ "goto_file_start".to_string(),
+ vec![vec![key!('g'), key!('g')]]
+ ),
+ (
+ "goto_file_end".to_string(),
+ vec![vec![key!('g'), key!('e')]]
+ ),
+ (
+ "move_line_down".to_string(),
+ vec![vec![key!('j')], vec![key!('k')]]
+ ),
+ ]),
+ "Mistmatch"
+ )
+ }
}