ad_editor/mode/
mod.rs

1//! Modal editing support.
2use crate::{
3    editor::Actions,
4    key::Input,
5    term::CurShape,
6    trie::{QueryResult, Trie},
7};
8use std::fmt;
9
10mod insert;
11mod normal;
12
13pub(crate) use normal::normal_mode;
14
15/// The modes available for ad
16pub(crate) fn modes() -> Vec<Mode> {
17    vec![normal::normal_mode(), insert::insert_mode()]
18}
19
20#[derive(Debug)]
21pub(crate) struct Mode {
22    pub(crate) name: String,
23    pub(crate) cur_shape: CurShape,
24    pub(crate) keymap: Trie<Input, Actions>,
25    handle_expired_pending: fn(&[Input]) -> QueryResult<Actions>,
26}
27
28impl fmt::Display for Mode {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        write!(f, "{}", self.name)
31    }
32}
33
34impl Mode {
35    pub(crate) fn ephemeral_mode(name: &str) -> Self {
36        Mode {
37            name: name.to_string(),
38            cur_shape: CurShape::Block,
39            keymap: Trie::from_pairs(Vec::new()).unwrap(),
40            handle_expired_pending: |_| QueryResult::Missing,
41        }
42    }
43
44    pub fn handle_keys(&self, keys: &mut Vec<Input>) -> Option<Actions> {
45        match self.keymap.get(keys) {
46            QueryResult::Val(outcome) => {
47                keys.clear();
48                Some(outcome)
49            }
50            QueryResult::Partial => None,
51            QueryResult::Missing => {
52                let res = (self.handle_expired_pending)(keys);
53                match res {
54                    QueryResult::Val(outcome) => {
55                        keys.clear();
56                        Some(outcome)
57                    }
58                    QueryResult::Missing => {
59                        keys.clear();
60                        None
61                    }
62                    QueryResult::Partial => None,
63                }
64            }
65        }
66    }
67}
68
69/// Construct a new [Trie] based keymap
70#[macro_export]
71macro_rules! keymap {
72    ($([$($k:expr),+] => [ $($v:expr),+ ]),+,) => {
73        {
74            let mut pairs = Vec::new();
75
76            $(
77                let key = vec![$($k),+];
78                let value = $crate::keymap!(@action $($v),+);
79                pairs.push((key, value));
80            )+
81
82            $crate::trie::Trie::from_pairs(pairs).unwrap()
83        }
84    };
85
86    (@action $v:expr) => { $crate::editor::Actions::Single($v) };
87    (@action $($v:expr),+) => { $crate::editor::Actions::Multi(vec![$($v),+]) };
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    // This test will panic if any of the default keymaps end up with mappings that
95    // collide internally. The Trie struct rejects overlapping or duplicate keys on
96    // creation which will just panic the editor if this happens so it's worthwhile
97    // making sure we've not messed anything up.
98    #[test]
99    fn mode_keymaps_have_no_collisions() {
100        _ = modes();
101    }
102}