keymap: Store pending/sticky on the root level

pull/1850/head
Blaž Hrastnik 3 years ago
parent cfd992b151
commit 7909d6f05e
No known key found for this signature in database
GPG Key ID: 1238B9C4AD889640

@ -2105,7 +2105,7 @@ pub fn command_palette(cx: &mut Context) {
move |compositor: &mut Compositor, cx: &mut compositor::Context| { move |compositor: &mut Compositor, cx: &mut compositor::Context| {
let doc = doc_mut!(cx.editor); let doc = doc_mut!(cx.editor);
let keymap = let keymap =
compositor.find::<ui::EditorView>().unwrap().keymaps[&doc.mode].reverse_map(); compositor.find::<ui::EditorView>().unwrap().keymaps.map[&doc.mode].reverse_map();
let mut commands: Vec<MappableCommand> = MappableCommand::STATIC_COMMAND_LIST.into(); let mut commands: Vec<MappableCommand> = MappableCommand::STATIC_COMMAND_LIST.into();
commands.extend(typed::TYPABLE_COMMAND_LIST.iter().map(|cmd| { commands.extend(typed::TYPABLE_COMMAND_LIST.iter().map(|cmd| {

@ -43,7 +43,7 @@ mod tests {
assert_eq!( assert_eq!(
toml::from_str::<Config>(sample_keymaps).unwrap(), toml::from_str::<Config>(sample_keymaps).unwrap(),
Config { Config {
keys: Keymaps(hashmap! { keys: Keymaps::new(hashmap! {
Mode::Insert => Keymap::new(keymap!({ "Insert mode" Mode::Insert => Keymap::new(keymap!({ "Insert mode"
"y" => move_line_down, "y" => move_line_down,
"S-C-a" => delete_selection, "S-C-a" => delete_selection,

@ -328,26 +328,15 @@ impl<'a> KeymapResult<'a> {
} }
#[derive(Debug, Clone, PartialEq, Deserialize)] #[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(transparent)]
pub struct Keymap { pub struct Keymap {
/// Always a Node /// Always a Node
#[serde(flatten)]
root: KeyTrie, root: KeyTrie,
/// Stores pending keys waiting for the next key. This is relative to a
/// sticky node if one is in use.
#[serde(skip)]
state: Vec<KeyEvent>,
/// Stores the sticky node if one is activated.
#[serde(skip)]
sticky: Option<KeyTrieNode>,
} }
impl Keymap { impl Keymap {
pub fn new(root: KeyTrie) -> Self { pub fn new(root: KeyTrie) -> Self {
Keymap { Keymap { root }
root,
state: Vec::new(),
sticky: None,
}
} }
pub fn reverse_map(&self) -> HashMap<String, Vec<Vec<KeyEvent>>> { pub fn reverse_map(&self) -> HashMap<String, Vec<Vec<KeyEvent>>> {
@ -387,19 +376,65 @@ impl Keymap {
&self.root &self.root
} }
pub fn sticky(&self) -> Option<&KeyTrieNode> { pub fn merge(&mut self, other: Self) {
self.sticky.as_ref() self.root.merge_nodes(other.root);
}
}
impl Deref for Keymap {
type Target = KeyTrieNode;
fn deref(&self) -> &Self::Target {
self.root.node().unwrap()
} }
}
/// Returns list of keys waiting to be disambiguated. impl Default for Keymap {
fn default() -> Self {
Self::new(KeyTrie::Node(KeyTrieNode::default()))
}
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct Keymaps {
#[serde(flatten)]
pub map: HashMap<Mode, Keymap>,
/// Stores pending keys waiting for the next key. This is relative to a
/// sticky node if one is in use.
#[serde(skip)]
state: Vec<KeyEvent>,
/// Stores the sticky node if one is activated.
#[serde(skip)]
pub sticky: Option<KeyTrieNode>,
}
impl Keymaps {
pub fn new(map: HashMap<Mode, Keymap>) -> Self {
Self {
map,
state: Vec::new(),
sticky: None,
}
}
/// Returns list of keys waiting to be disambiguated in current mode.
pub fn pending(&self) -> &[KeyEvent] { pub fn pending(&self) -> &[KeyEvent] {
&self.state &self.state
} }
pub fn sticky(&self) -> Option<&KeyTrieNode> {
self.sticky.as_ref()
}
/// Lookup `key` in the keymap to try and find a command to execute. Escape /// Lookup `key` in the keymap to try and find a command to execute. Escape
/// key cancels pending keystrokes. If there are no pending keystrokes but a /// key cancels pending keystrokes. If there are no pending keystrokes but a
/// sticky node is in use, it will be cleared. /// sticky node is in use, it will be cleared.
pub fn get(&mut self, key: KeyEvent) -> KeymapResult { pub fn get(&mut self, mode: Mode, key: KeyEvent) -> KeymapResult {
// TODO: remove the sticky part and look up manually
let keymap = &self.map[&mode];
if key!(Esc) == key { if key!(Esc) == key {
if !self.state.is_empty() { if !self.state.is_empty() {
return KeymapResult::new( return KeymapResult::new(
@ -414,7 +449,7 @@ impl Keymap {
let first = self.state.get(0).unwrap_or(&key); let first = self.state.get(0).unwrap_or(&key);
let trie_node = match self.sticky { let trie_node = match self.sticky {
Some(ref trie) => Cow::Owned(KeyTrie::Node(trie.clone())), Some(ref trie) => Cow::Owned(KeyTrie::Node(trie.clone())),
None => Cow::Borrowed(&self.root), None => Cow::Borrowed(&keymap.root),
}; };
let trie = match trie_node.search(&[*first]) { let trie = match trie_node.search(&[*first]) {
@ -457,55 +492,6 @@ impl Keymap {
), ),
} }
} }
pub fn merge(&mut self, other: Self) {
self.root.merge_nodes(other.root);
}
}
impl Deref for Keymap {
type Target = KeyTrieNode;
fn deref(&self) -> &Self::Target {
self.root.node().unwrap()
}
}
impl Default for Keymap {
fn default() -> Self {
Self::new(KeyTrie::Node(KeyTrieNode::default()))
}
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(transparent)]
pub struct Keymaps(pub HashMap<Mode, Keymap>);
impl Keymaps {
/// Returns list of keys waiting to be disambiguated in current mode.
pub fn pending(&self) -> &[KeyEvent] {
self.0
.values()
.find_map(|keymap| match keymap.pending().is_empty() {
true => None,
false => Some(keymap.pending()),
})
.unwrap_or_default()
}
}
impl Deref for Keymaps {
type Target = HashMap<Mode, Keymap>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Keymaps {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
} }
impl Default for Keymaps { impl Default for Keymaps {
@ -856,7 +842,7 @@ impl Default for Keymaps {
"C-x" => completion, "C-x" => completion,
"C-r" => insert_register, "C-r" => insert_register,
}); });
Self(hashmap!( Self::new(hashmap!(
Mode::Normal => Keymap::new(normal), Mode::Normal => Keymap::new(normal),
Mode::Select => Keymap::new(select), Mode::Select => Keymap::new(select),
Mode::Insert => Keymap::new(insert), Mode::Insert => Keymap::new(insert),
@ -867,8 +853,8 @@ impl Default for Keymaps {
/// Merge default config keys with user overwritten keys for custom user config. /// Merge default config keys with user overwritten keys for custom user config.
pub fn merge_keys(mut config: Config) -> Config { pub fn merge_keys(mut config: Config) -> Config {
let mut delta = std::mem::take(&mut config.keys); let mut delta = std::mem::take(&mut config.keys);
for (mode, keys) in &mut *config.keys { for (mode, keys) in &mut config.keys.map {
keys.merge(delta.remove(mode).unwrap_or_default()) keys.merge(delta.map.remove(mode).unwrap_or_default())
} }
config config
} }
@ -895,7 +881,7 @@ mod tests {
#[test] #[test]
fn merge_partial_keys() { fn merge_partial_keys() {
let config = Config { let config = Config {
keys: Keymaps(hashmap! { keys: Keymaps::new(hashmap! {
Mode::Normal => Keymap::new( Mode::Normal => Keymap::new(
keymap!({ "Normal mode" keymap!({ "Normal mode"
"i" => normal_mode, "i" => normal_mode,
@ -913,23 +899,25 @@ mod tests {
let mut merged_config = merge_keys(config.clone()); let mut merged_config = merge_keys(config.clone());
assert_ne!(config, merged_config); assert_ne!(config, merged_config);
let keymap = merged_config.keys.0.get_mut(&Mode::Normal).unwrap(); let keymap = &mut merged_config.keys;
assert_eq!( assert_eq!(
keymap.get(key!('i')).kind, keymap.get(Mode::Normal, key!('i')).kind,
KeymapResultKind::Matched(MappableCommand::normal_mode), KeymapResultKind::Matched(MappableCommand::normal_mode),
"Leaf should replace leaf" "Leaf should replace leaf"
); );
assert_eq!( assert_eq!(
keymap.get(key!('无')).kind, keymap.get(Mode::Normal, key!('无')).kind,
KeymapResultKind::Matched(MappableCommand::insert_mode), KeymapResultKind::Matched(MappableCommand::insert_mode),
"New leaf should be present in merged keymap" "New leaf should be present in merged keymap"
); );
// Assumes that z is a node in the default keymap // Assumes that z is a node in the default keymap
assert_eq!( assert_eq!(
keymap.get(key!('z')).kind, keymap.get(Mode::Normal, key!('z')).kind,
KeymapResultKind::Matched(MappableCommand::jump_backward), KeymapResultKind::Matched(MappableCommand::jump_backward),
"Leaf should replace node" "Leaf should replace node"
); );
let keymap = merged_config.keys.map.get_mut(&Mode::Normal).unwrap();
// Assumes that `g` is a node in default keymap // Assumes that `g` is a node in default keymap
assert_eq!( assert_eq!(
keymap.root().search(&[key!('g'), key!('$')]).unwrap(), keymap.root().search(&[key!('g'), key!('$')]).unwrap(),
@ -949,14 +937,14 @@ mod tests {
"Old leaves in subnode should be present in merged node" "Old leaves in subnode should be present in merged node"
); );
assert!(merged_config.keys.0.get(&Mode::Normal).unwrap().len() > 1); assert!(merged_config.keys.map.get(&Mode::Normal).unwrap().len() > 1);
assert!(merged_config.keys.0.get(&Mode::Insert).unwrap().len() > 0); assert!(merged_config.keys.map.get(&Mode::Insert).unwrap().len() > 0);
} }
#[test] #[test]
fn order_should_be_set() { fn order_should_be_set() {
let config = Config { let config = Config {
keys: Keymaps(hashmap! { keys: Keymaps::new(hashmap! {
Mode::Normal => Keymap::new( Mode::Normal => Keymap::new(
keymap!({ "Normal mode" keymap!({ "Normal mode"
"space" => { "" "space" => { ""
@ -972,7 +960,7 @@ mod tests {
}; };
let mut merged_config = merge_keys(config.clone()); let mut merged_config = merge_keys(config.clone());
assert_ne!(config, merged_config); assert_ne!(config, merged_config);
let keymap = merged_config.keys.0.get_mut(&Mode::Normal).unwrap(); let keymap = merged_config.keys.map.get_mut(&Mode::Normal).unwrap();
// Make sure mapping works // Make sure mapping works
assert_eq!( assert_eq!(
keymap keymap
@ -990,7 +978,7 @@ mod tests {
#[test] #[test]
fn aliased_modes_are_same_in_default_keymap() { fn aliased_modes_are_same_in_default_keymap() {
let keymaps = Keymaps::default(); let keymaps = Keymaps::default();
let root = keymaps.get(&Mode::Normal).unwrap().root(); let root = keymaps.map.get(&Mode::Normal).unwrap().root();
assert_eq!( assert_eq!(
root.search(&[key!(' '), key!('w')]).unwrap(), root.search(&[key!(' '), key!('w')]).unwrap(),
root.search(&["C-w".parse::<KeyEvent>().unwrap()]).unwrap(), root.search(&["C-w".parse::<KeyEvent>().unwrap()]).unwrap(),

@ -703,7 +703,7 @@ impl EditorView {
event: KeyEvent, event: KeyEvent,
) -> Option<KeymapResult> { ) -> Option<KeymapResult> {
cxt.editor.autoinfo = None; cxt.editor.autoinfo = None;
let key_result = self.keymaps.get_mut(&mode).unwrap().get(event); let key_result = self.keymaps.get(mode, event);
cxt.editor.autoinfo = key_result.sticky.map(|node| node.infobox()); cxt.editor.autoinfo = key_result.sticky.map(|node| node.infobox());
match &key_result.kind { match &key_result.kind {
@ -733,7 +733,7 @@ impl EditorView {
Some(ch) => commands::insert::insert_char(cx, ch), Some(ch) => commands::insert::insert_char(cx, ch),
None => { None => {
if let KeymapResultKind::Matched(command) = if let KeymapResultKind::Matched(command) =
self.keymaps.get_mut(&Mode::Insert).unwrap().get(ev).kind self.keymaps.get(Mode::Insert, ev).kind
{ {
command.execute(cx); command.execute(cx);
} }
@ -1182,12 +1182,11 @@ impl Component for EditorView {
// how we entered insert mode is important, and we should track that so // how we entered insert mode is important, and we should track that so
// we can repeat the side effect. // we can repeat the side effect.
self.last_insert.0 = self.last_insert.0 = match self.keymaps.get(mode, key).kind {
match self.keymaps.get_mut(&mode).unwrap().get(key).kind { KeymapResultKind::Matched(command) => command,
KeymapResultKind::Matched(command) => command, // FIXME: insert mode can only be entered through single KeyCodes
// FIXME: insert mode can only be entered through single KeyCodes _ => unimplemented!(),
_ => unimplemented!(), };
};
self.last_insert.1.clear(); self.last_insert.1.clear();
} }
(Mode::Insert, Mode::Normal) => { (Mode::Insert, Mode::Normal) => {

Loading…
Cancel
Save