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`
This commit is contained in:
Omnikar 2021-11-10 23:44:50 -05:00 committed by GitHub
parent bf70cfd050
commit d131a9dd0e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 3 deletions

View file

@ -15,6 +15,7 @@ a = "move_char_left" # Maps the 'a' key to the move_char_left command
w = "move_line_up" # Maps the 'w' key move_line_up
"C-S-esc" = "extend_line" # Maps Control-Shift-Escape to extend_line
g = { a = "code_action" } # Maps `ga` to show possible code actions
"ret" = ["open_below", "normal_mode"] # Maps the enter key to open_below then re-enter normal mode
[keys.insert]
"A-x" = "normal_mode" # Maps Alt-X to enter normal mode

View file

@ -85,6 +85,10 @@ macro_rules! keymap {
keymap!({ $label $(sticky=$sticky)? $($($key)|+ => $value,)+ })
};
(@trie [$($cmd:ident),* $(,)?]) => {
$crate::keymap::KeyTrie::Sequence(vec![$($crate::commands::Command::$cmd),*])
};
(
{ $label:literal $(sticky=$sticky:literal)? $($($key:literal)|+ => $value:tt,)+ }
) => {
@ -180,6 +184,7 @@ impl KeyTrieNode {
cmd.doc()
}
KeyTrie::Node(n) => n.name(),
KeyTrie::Sequence(_) => "[Multiple commands]",
};
match body.iter().position(|(d, _)| d == &desc) {
Some(pos) => {
@ -240,6 +245,7 @@ impl DerefMut for KeyTrieNode {
#[serde(untagged)]
pub enum KeyTrie {
Leaf(Command),
Sequence(Vec<Command>),
Node(KeyTrieNode),
}
@ -247,14 +253,14 @@ impl KeyTrie {
pub fn node(&self) -> Option<&KeyTrieNode> {
match *self {
KeyTrie::Node(ref node) => Some(node),
KeyTrie::Leaf(_) => None,
KeyTrie::Leaf(_) | KeyTrie::Sequence(_) => None,
}
}
pub fn node_mut(&mut self) -> Option<&mut KeyTrieNode> {
match *self {
KeyTrie::Node(ref mut node) => Some(node),
KeyTrie::Leaf(_) => None,
KeyTrie::Leaf(_) | KeyTrie::Sequence(_) => None,
}
}
@ -271,7 +277,7 @@ impl KeyTrie {
trie = match trie {
KeyTrie::Node(map) => map.get(key),
// leaf encountered while keys left to process
KeyTrie::Leaf(_) => None,
KeyTrie::Leaf(_) | KeyTrie::Sequence(_) => None,
}?
}
Some(trie)
@ -283,6 +289,8 @@ pub enum KeymapResultKind {
/// Needs more keys to execute a command. Contains valid keys for next keystroke.
Pending(KeyTrieNode),
Matched(Command),
/// Matched a sequence of commands to execute.
MatchedSequence(Vec<Command>),
/// Key was not found in the root keymap
NotFound,
/// Key is invalid in combination with previous keys. Contains keys leading upto
@ -365,6 +373,12 @@ impl Keymap {
Some(&KeyTrie::Leaf(cmd)) => {
return KeymapResult::new(KeymapResultKind::Matched(cmd), self.sticky())
}
Some(&KeyTrie::Sequence(ref cmds)) => {
return KeymapResult::new(
KeymapResultKind::MatchedSequence(cmds.clone()),
self.sticky(),
)
}
None => return KeymapResult::new(KeymapResultKind::NotFound, self.sticky()),
Some(t) => t,
};
@ -382,6 +396,13 @@ impl Keymap {
self.state.clear();
return KeymapResult::new(KeymapResultKind::Matched(cmd), self.sticky());
}
Some(&KeyTrie::Sequence(ref cmds)) => {
self.state.clear();
KeymapResult::new(
KeymapResultKind::MatchedSequence(cmds.clone()),
self.sticky(),
)
}
None => KeymapResult::new(
KeymapResultKind::Cancelled(self.state.drain(..).collect()),
self.sticky(),

View file

@ -695,6 +695,11 @@ impl EditorView {
match &key_result.kind {
KeymapResultKind::Matched(command) => command.execute(cxt),
KeymapResultKind::Pending(node) => self.autoinfo = Some(node.infobox()),
KeymapResultKind::MatchedSequence(commands) => {
for command in commands {
command.execute(cxt);
}
}
KeymapResultKind::NotFound | KeymapResultKind::Cancelled(_) => return Some(key_result),
}
None