@@ -4,6 +4,7 @@ use helix_core::hashmap;
44use helix_view::{document::Mode, info::Info, input::KeyEvent};
55use serde::Deserialize;
66use std::{
7+ borrow::Cow,
78 collections::HashMap,
89 ops::{Deref, DerefMut},
910};
@@ -47,13 +48,13 @@ macro_rules! keymap {
4748 };
4849
4950 (@trie
50− { $label:literal $($($key:literal)|+ => $value:tt,)+ }
51+ { $label:literal $(sticky=$sticky:literal)? $($($key:literal)|+ => $value:tt,)+ }
5152 ) => {
52− keymap!({ $label $($($key)|+ => $value,)+ })
53+ keymap!({ $label $(sticky=$sticky)? $($($key)|+ => $value,)+ })
5354 };
5455
5556 (
56− { $label:literal $($($key:literal)|+ => $value:tt,)+ }
57+ { $label:literal $(sticky=$sticky:literal)? $($($key:literal)|+ => $value:tt,)+ }
5758 ) => {
5859 // modified from the hashmap! macro
5960 {
@@ -70,7 +71,9 @@ macro_rules! keymap {
7071 _order.push(_key);
7172 )+
7273 )*
73− $crate::keymap::KeyTrie::Node($crate::keymap::KeyTrieNode::new($label, _map, _order))
74+ let mut _node = $crate::keymap::KeyTrieNode::new($label, _map, _order);
75+ $( _node.is_sticky = $sticky; )?
76+ $crate::keymap::KeyTrie::Node(_node)
7477 }
7578 };
7679}
@@ -84,6 +87,8 @@ pub struct KeyTrieNode {
8487 map: HashMap<KeyEvent, KeyTrie>,
8588 #[serde(skip)]
8689 order: Vec<KeyEvent>,
90+ #[serde(skip)]
91+ pub is_sticky: bool,
8792}
8893
8994impl KeyTrieNode {
@@ -92,6 +97,7 @@ impl KeyTrieNode {
9297 name: name.to_string(),
9398 map,
9499 order,
100+ is_sticky: false,
95101 }
96102 }
97103
@@ -119,12 +125,10 @@ impl KeyTrieNode {
119125 }
120126 }
121127 }
122−}
123128
124−impl From<KeyTrieNode> for Info {
125− fn from(node: KeyTrieNode) -> Self {
126− let mut body: Vec<(&str, Vec<KeyEvent>)> = Vec::with_capacity(node.len());
127− for (&key, trie) in node.iter() {
129+ pub fn infobox(&self) -> Info {
130+ let mut body: Vec<(&str, Vec<KeyEvent>)> = Vec::with_capacity(self.len());
131+ for (&key, trie) in self.iter() {
128132 let desc = match trie {
129133 KeyTrie::Leaf(cmd) => cmd.doc(),
130134 KeyTrie::Node(n) => n.name(),
@@ -136,16 +140,16 @@ impl From<KeyTrieNode> for Info {
136140 }
137141 }
138142 body.sort_unstable_by_key(|(_, keys)| {
139− node.order.iter().position(|&k| k == keys[0]).unwrap()
143+ self.order.iter().position(|&k| k == keys[0]).unwrap()
140144 });
141− let prefix = format!("{} ", node.name());
145+ let prefix = format!("{} ", self.name());
142146 if body.iter().all(|(desc, _)| desc.starts_with(&prefix)) {
143147 body = body
144148 .into_iter()
145149 .map(|(desc, keys)| (desc.strip_prefix(&prefix).unwrap(), keys))
146150 .collect();
147151 }
148− Info::new(node.name(), body)
152+ Info::new(self.name(), body)
149153 }
150154}
151155
@@ -218,7 +222,7 @@ impl KeyTrie {
218222}
219223
220224#[derive(Debug, Clone, PartialEq)]
221−pub enum KeymapResult {
225+pub enum KeymapResultKind {
222226 /// Needs more keys to execute a command. Contains valid keys for next keystroke.
223227 Pending(KeyTrieNode),
224228 Matched(Command),
@@ -229,14 +233,31 @@ pub enum KeymapResult {
229233 Cancelled(Vec<KeyEvent>),
230234}
231235
236+/// Returned after looking up a key in [`Keymap`]. The `sticky` field has a
237+/// reference to the sticky node if one is currently active.
238+pub struct KeymapResult<'a> {
239+ pub kind: KeymapResultKind,
240+ pub sticky: Option<&'a KeyTrieNode>,
241+}
242+
243+impl<'a> KeymapResult<'a> {
244+ pub fn new(kind: KeymapResultKind, sticky: Option<&'a KeyTrieNode>) -> Self {
245+ Self { kind, sticky }
246+ }
247+}
248+
232249#[derive(Debug, Clone, PartialEq, Deserialize)]
233250pub struct Keymap {
234251 /// Always a Node
235252 #[serde(flatten)]
236253 root: KeyTrie,
237− /// Stores pending keys waiting for the next key
254+ /// Stores pending keys waiting for the next key. This is relative to a
255+ /// sticky node if one is in use.
238256 #[serde(skip)]
239257 state: Vec<KeyEvent>,
258+ /// Stores the sticky node if one is activated.
259+ #[serde(skip)]
260+ sticky: Option<KeyTrieNode>,
240261}
241262
242263impl Keymap {
@@ -244,6 +265,7 @@ impl Keymap {
244265 Keymap {
245266 root,
246267 state: Vec::new(),
268+ sticky: None,
247269 }
248270 }
249271
@@ -251,27 +273,60 @@ impl Keymap {
251273 &self.root
252274 }
253275
276+ pub fn sticky(&self) -> Option<&KeyTrieNode> {
277+ self.sticky.as_ref()
278+ }
279+
254280 /// Returns list of keys waiting to be disambiguated.
255281 pub fn pending(&self) -> &[KeyEvent] {
256282 &self.state
257283 }
258284
259− /// Lookup `key` in the keymap to try and find a command to execute
285+ /// Lookup `key` in the keymap to try and find a command to execute. Escape
286+ /// key cancels pending keystrokes. If there are no pending keystrokes but a
287+ /// sticky node is in use, it will be cleared.
260288 pub fn get(&mut self, key: KeyEvent) -> KeymapResult {
261− let &first = self.state.get(0).unwrap_or(&key);
262− let trie = match self.root.search(&[first]) {
263− Some(&KeyTrie::Leaf(cmd)) => return KeymapResult::Matched(cmd),
264− None => return KeymapResult::NotFound,
289+ if let key!(Esc) = key {
290+ if self.state.is_empty() {
291+ self.sticky = None;
292+ }
293+ return KeymapResult::new(
294+ KeymapResultKind::Cancelled(self.state.drain(..).collect()),
295+ self.sticky(),
296+ );
297+ }
298+
299+ let first = self.state.get(0).unwrap_or(&key);
300+ let trie_node = match self.sticky {
301+ Some(ref trie) => Cow::Owned(KeyTrie::Node(trie.clone())),
302+ None => Cow::Borrowed(&self.root),
303+ };
304+
305+ let trie = match trie_node.search(&[*first]) {
306+ Some(&KeyTrie::Leaf(cmd)) => {
307+ return KeymapResult::new(KeymapResultKind::Matched(cmd), self.sticky())
308+ }
309+ None => return KeymapResult::new(KeymapResultKind::NotFound, self.sticky()),
265310 Some(t) => t,
266311 };
312+
267313 self.state.push(key);
268314 match trie.search(&self.state[1..]) {
269− Some(&KeyTrie::Node(ref map)) => KeymapResult::Pending(map.clone()),
270− Some(&KeyTrie::Leaf(command)) => {
315+ Some(&KeyTrie::Node(ref map)) => {
316+ if map.is_sticky {
317+ self.state.clear();
318+ self.sticky = Some(map.clone());
319+ }
320+ KeymapResult::new(KeymapResultKind::Pending(map.clone()), self.sticky())
321+ }
322+ Some(&KeyTrie::Leaf(cmd)) => {
271323 self.state.clear();
272− KeymapResult::Matched(command)
324+ return KeymapResult::new(KeymapResultKind::Matched(cmd), self.sticky());
273325 }
274− None => KeymapResult::Cancelled(self.state.drain(..).collect()),
326+ None => KeymapResult::new(
327+ KeymapResultKind::Cancelled(self.state.drain(..).collect()),
328+ self.sticky(),
329+ ),
275330 }
276331 }
277332
@@ -602,19 +657,19 @@ fn merge_partial_keys() {
602657
603658 let keymap = merged_config.keys.0.get_mut(&Mode::Normal).unwrap();
604659 assert_eq!(
605− keymap.get(key!('i')),
606− KeymapResult::Matched(Command::normal_mode),
660+ keymap.get(key!('i')).kind,
661+ KeymapResultKind::Matched(Command::normal_mode),
607662 "Leaf should replace leaf"
608663 );
609664 assert_eq!(
610− keymap.get(key!('无')),
611− KeymapResult::Matched(Command::insert_mode),
665+ keymap.get(key!('无')).kind,
666+ KeymapResultKind::Matched(Command::insert_mode),
612667 "New leaf should be present in merged keymap"
613668 );
614669 // Assumes that z is a node in the default keymap
615670 assert_eq!(
616− keymap.get(key!('z')),
617− KeymapResult::Matched(Command::jump_backward),
671+ keymap.get(key!('z')).kind,
672+ KeymapResultKind::Matched(Command::jump_backward),
618673 "Leaf should replace node"
619674 );
620675 // Assumes that `g` is a node in default keymap