diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 59204889..088b3b6d 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -144,14 +144,70 @@ impl DerefMut for KeyTrieNode { } } -#[derive(Debug, Clone, PartialEq, Deserialize)] -#[serde(untagged)] +#[derive(Debug, Clone, PartialEq)] pub enum KeyTrie { Leaf(MappableCommand), Sequence(Vec), Node(KeyTrieNode), } +impl<'de> Deserialize<'de> for KeyTrie { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_any(KeyTrieVisitor) + } +} + +struct KeyTrieVisitor; + +impl<'de> serde::de::Visitor<'de> for KeyTrieVisitor { + type Value = KeyTrie; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "a command, list of commands, or sub-keymap") + } + + fn visit_str(self, command: &str) -> Result + where + E: serde::de::Error, + { + command + .parse::() + .map(KeyTrie::Leaf) + .map_err(E::custom) + } + + fn visit_seq(self, mut seq: S) -> Result + where + S: serde::de::SeqAccess<'de>, + { + let mut commands = Vec::new(); + while let Some(command) = seq.next_element::<&str>()? { + commands.push( + command + .parse::() + .map_err(serde::de::Error::custom)?, + ) + } + Ok(KeyTrie::Sequence(commands)) + } + + fn visit_map(self, mut map: M) -> Result + where + M: serde::de::MapAccess<'de>, + { + let mut mapping = HashMap::new(); + let mut order = Vec::new(); + while let Some((key, value)) = map.next_entry::()? { + mapping.insert(key, value); + order.push(key); + } + Ok(KeyTrie::Node(KeyTrieNode::new("", mapping, order))) + } +} + impl KeyTrie { pub fn node(&self) -> Option<&KeyTrieNode> { match *self {