on master help sign in
Allow keys to be mapped to sequences of commands (#589)

* Allow keys to be mapped to sequences of commands * Handle `Sequence` at the start of `Keymap::get` * Use `"[Multiple commands]"` as command sequence doc * Add command sequence example to `remapping.md`

commitd131a9dd0efc5ff271f8b78cd65a8dc30c193af4 authorOmnikar <omnikar5@gmail.com> dateWed 10 Nov 2021, 23:44 (5 years ago) parentbf70cfd
3 files changed+30−3
book/src/remapping.md+1 helix-term/src/keymap.rs+24−3 helix-term/src/ui/editor.rs+5
book/src/remapping.md+1
@@ -15,6 +15,7 @@ a = "move_char_left" # Maps the 'a' key to the move_char_left command
1515w = "move_line_up" # Maps the 'w' key move_line_up
1616"C-S-esc" = "extend_line" # Maps Control-Shift-Escape to extend_line
1717g = { a = "code_action" } # Maps `ga` to show possible code actions
18+"ret" = ["open_below", "normal_mode"] # Maps the enter key to open_below then re-enter normal mode
1819
1920[keys.insert]
2021"A-x" = "normal_mode" # Maps Alt-X to enter normal mode
helix-term/src/keymap.rs+24−3
@@ -85,6 +85,10 @@ macro_rules! keymap {
8585 keymap!({ $label $(sticky=$sticky)? $($($key)|+ => $value,)+ })
8686 };
8787
88+ (@trie [$($cmd:ident),* $(,)?]) => {
89+ $crate::keymap::KeyTrie::Sequence(vec![$($crate::commands::Command::$cmd),*])
90+ };
91+
8892 (
8993 { $label:literal $(sticky=$sticky:literal)? $($($key:literal)|+ => $value:tt,)+ }
9094 ) => {
@@ -180,6 +184,7 @@ impl KeyTrieNode {
180184 cmd.doc()
181185 }
182186 KeyTrie::Node(n) => n.name(),
187+ KeyTrie::Sequence(_) => "[Multiple commands]",
183188 };
184189 match body.iter().position(|(d, _)| d == &desc) {
185190 Some(pos) => {
@@ -240,6 +245,7 @@ impl DerefMut for KeyTrieNode {
240245#[serde(untagged)]
241246pub enum KeyTrie {
242247 Leaf(Command),
248+ Sequence(Vec<Command>),
243249 Node(KeyTrieNode),
244250}
245251
@@ -247,14 +253,14 @@ impl KeyTrie {
247253 pub fn node(&self) -> Option<&KeyTrieNode> {
248254 match *self {
249255 KeyTrie::Node(ref node) => Some(node),
250− KeyTrie::Leaf(_) => None,
256+ KeyTrie::Leaf(_) | KeyTrie::Sequence(_) => None,
251257 }
252258 }
253259
254260 pub fn node_mut(&mut self) -> Option<&mut KeyTrieNode> {
255261 match *self {
256262 KeyTrie::Node(ref mut node) => Some(node),
257− KeyTrie::Leaf(_) => None,
263+ KeyTrie::Leaf(_) | KeyTrie::Sequence(_) => None,
258264 }
259265 }
260266
@@ -271,7 +277,7 @@ impl KeyTrie {
271277 trie = match trie {
272278 KeyTrie::Node(map) => map.get(key),
273279 // leaf encountered while keys left to process
274− KeyTrie::Leaf(_) => None,
280+ KeyTrie::Leaf(_) | KeyTrie::Sequence(_) => None,
275281 }?
276282 }
277283 Some(trie)
@@ -283,6 +289,8 @@ pub enum KeymapResultKind {
283289 /// Needs more keys to execute a command. Contains valid keys for next keystroke.
284290 Pending(KeyTrieNode),
285291 Matched(Command),
292+ /// Matched a sequence of commands to execute.
293+ MatchedSequence(Vec<Command>),
286294 /// Key was not found in the root keymap
287295 NotFound,
288296 /// Key is invalid in combination with previous keys. Contains keys leading upto
@@ -365,6 +373,12 @@ impl Keymap {
365373 Some(&KeyTrie::Leaf(cmd)) => {
366374 return KeymapResult::new(KeymapResultKind::Matched(cmd), self.sticky())
367375 }
376+ Some(&KeyTrie::Sequence(ref cmds)) => {
377+ return KeymapResult::new(
378+ KeymapResultKind::MatchedSequence(cmds.clone()),
379+ self.sticky(),
380+ )
381+ }
368382 None => return KeymapResult::new(KeymapResultKind::NotFound, self.sticky()),
369383 Some(t) => t,
370384 };
@@ -382,6 +396,13 @@ impl Keymap {
382396 self.state.clear();
383397 return KeymapResult::new(KeymapResultKind::Matched(cmd), self.sticky());
384398 }
399+ Some(&KeyTrie::Sequence(ref cmds)) => {
400+ self.state.clear();
401+ KeymapResult::new(
402+ KeymapResultKind::MatchedSequence(cmds.clone()),
403+ self.sticky(),
404+ )
405+ }
385406 None => KeymapResult::new(
386407 KeymapResultKind::Cancelled(self.state.drain(..).collect()),
387408 self.sticky(),
helix-term/src/ui/editor.rs+5
@@ -695,6 +695,11 @@ impl EditorView {
695695 match &key_result.kind {
696696 KeymapResultKind::Matched(command) => command.execute(cxt),
697697 KeymapResultKind::Pending(node) => self.autoinfo = Some(node.infobox()),
698+ KeymapResultKind::MatchedSequence(commands) => {
699+ for command in commands {
700+ command.execute(cxt);
701+ }
702+ }
698703 KeymapResultKind::NotFound | KeymapResultKind::Cancelled(_) => return Some(key_result),
699704 }
700705 None