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:
parent
bf70cfd050
commit
d131a9dd0e
3 changed files with 30 additions and 3 deletions
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue