Skip to main content

modalkit/env/
keyparse.rs

1use nom::{
2    branch::alt,
3    bytes::complete::tag,
4    character::complete::{char, digit1},
5    combinator::{eof, map_res, opt, value},
6    multi::many1,
7    IResult,
8};
9
10use super::{CommonEdgeEvent, CommonEdgePath, CommonEdgePathPart, CommonKeyClass};
11
12use crate::keybindings::{EdgeEvent, EdgeRepeat};
13
14fn parse_base10_usize(input: &str) -> Result<usize, std::num::ParseIntError> {
15    input.parse::<usize>()
16}
17
18fn parse_special(input: &str) -> IResult<&str, CommonEdgePathPart> {
19    let (input, k) = crate::key::parse::parse_special(input)?;
20    let ret = (EdgeRepeat::Once, EdgeEvent::Key(k));
21
22    return Ok((input, ret));
23}
24
25fn parse_count(input: &str) -> IResult<&str, CommonEdgePathPart> {
26    let (input, _) = tag("{count}")(input)?;
27
28    let rep = EdgeRepeat::Min(1);
29    let evt = EdgeEvent::Class(CommonKeyClass::Count);
30
31    Ok((input, (rep, evt)))
32}
33
34fn parse_repetition_min(input: &str) -> IResult<&str, EdgeRepeat> {
35    let (input, _) = tag(">=")(input)?;
36    let (input, n) = map_res(digit1, parse_base10_usize)(input)?;
37
38    Ok((input, EdgeRepeat::Min(n)))
39}
40
41fn parse_repetition_max(input: &str) -> IResult<&str, EdgeRepeat> {
42    let (input, _) = tag("<=")(input)?;
43    let (input, n) = map_res(digit1, parse_base10_usize)(input)?;
44
45    Ok((input, EdgeRepeat::Max(n)))
46}
47
48fn parse_repetition(input: &str) -> IResult<&str, EdgeRepeat> {
49    alt((
50        value(EdgeRepeat::Min(0), tag("*")),
51        value(EdgeRepeat::Min(1), tag("+")),
52        parse_repetition_min,
53        parse_repetition_max,
54    ))(input)
55}
56
57fn parse_edgename(input: &str) -> IResult<&str, CommonEdgePathPart> {
58    let (input, _) = char('{')(input)?;
59    let (input, e) = alt((
60        value(EdgeEvent::Any, tag("any")),
61        value(EdgeEvent::Class(CommonKeyClass::Count), tag("count")),
62        value(EdgeEvent::Class(CommonKeyClass::Register), tag("register")),
63        value(EdgeEvent::Class(CommonKeyClass::Mark), tag("mark")),
64        value(EdgeEvent::Class(CommonKeyClass::Octal), tag("oct")),
65        value(EdgeEvent::Class(CommonKeyClass::Decimal), tag("dec")),
66        value(EdgeEvent::Class(CommonKeyClass::Hexadecimal), tag("hex")),
67        value(EdgeEvent::Class(CommonKeyClass::Digraph1), tag("digraph1")),
68        value(EdgeEvent::Class(CommonKeyClass::Digraph2), tag("digraph2")),
69    ))(input)?;
70    let (input, rep) = opt(parse_repetition)(input)?;
71    let (input, _) = char('}')(input)?;
72
73    let rep = rep.unwrap_or(EdgeRepeat::Once);
74
75    Ok((input, (rep, e)))
76}
77
78fn parse_key_simple(input: &str) -> IResult<&str, CommonEdgePathPart> {
79    let (input, k) = crate::key::parse::parse_simple(input)?;
80    let rep = EdgeRepeat::Once;
81    let key = EdgeEvent::Key(k);
82
83    Ok((input, (rep, key)))
84}
85
86fn parse_key(input: &str) -> IResult<&str, (EdgeRepeat, CommonEdgeEvent)> {
87    alt((parse_special, parse_count, parse_edgename, parse_key_simple))(input)
88}
89
90pub fn parse(input: &str) -> IResult<&str, CommonEdgePath> {
91    let (input, res) = many1(parse_key)(input)?;
92    let (input, _) = eof(input)?;
93
94    Ok((input, res))
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100    use crate::key::TerminalKey;
101    use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
102
103    macro_rules! once {
104        ($ev: expr) => {
105            (EdgeRepeat::Once, $ev)
106        };
107    }
108
109    macro_rules! evkey {
110        ($k: expr) => {
111            once!(EdgeEvent::Key(key!($k)))
112        };
113        ($k: expr, $km: expr) => {
114            once!(EdgeEvent::Key(key!($k, $km)))
115        };
116    }
117
118    macro_rules! evalt {
119        ($c: literal) => {
120            once!(EdgeEvent::Key(key!($c, KeyModifiers::ALT)))
121        };
122    }
123
124    macro_rules! evctl {
125        ($c: literal) => {
126            once!(EdgeEvent::Key(ctl!($c)))
127        };
128    }
129
130    macro_rules! evclass {
131        ($k: expr) => {
132            once!(EdgeEvent::Class($k))
133        };
134    }
135
136    macro_rules! count {
137        () => {
138            (EdgeRepeat::Min(1), EdgeEvent::Class(CommonKeyClass::Count))
139        };
140    }
141
142    macro_rules! res {
143        ( $( $x: expr ),* ) => {
144            Ok(("", vec![ $( $x, )* ]))
145        };
146    }
147
148    #[test]
149    fn test_ctl_uppercase() {
150        assert_eq!(parse("<C-A>"), res![evctl!('a')]);
151        assert_eq!(parse("<C-B>"), res![evctl!('b')]);
152    }
153
154    #[test]
155    fn test_ctl_lowercase() {
156        assert_eq!(parse("<C-a>"), res![evctl!('a')]);
157        assert_eq!(parse("<C-b>"), res![evctl!('b')]);
158    }
159
160    #[test]
161    fn test_shift_lowercase() {
162        let mods = KeyModifiers::SHIFT;
163
164        assert_eq!(parse("<S-a>"), res![evkey!(KeyCode::Char('A'), mods)]);
165        assert_eq!(parse("<S-q>"), res![evkey!(KeyCode::Char('Q'), mods)]);
166        assert_eq!(parse("<S-1>"), res![evkey!(KeyCode::Char('1'), mods)]);
167        assert_eq!(parse("<S-^>"), res![evkey!(KeyCode::Char('^'), mods)]);
168    }
169
170    #[test]
171    fn test_shift_uppercase() {
172        let mods = KeyModifiers::SHIFT;
173
174        assert_eq!(parse("<S-A>"), res![evkey!(KeyCode::Char('A'), mods)]);
175        assert_eq!(parse("<S-Q>"), res![evkey!(KeyCode::Char('Q'), mods)]);
176        assert_eq!(parse("<S-1>"), res![evkey!(KeyCode::Char('1'), mods)]);
177        assert_eq!(parse("<S-^>"), res![evkey!(KeyCode::Char('^'), mods)]);
178    }
179
180    #[test]
181    fn test_shift_alt() {
182        let mods = KeyModifiers::ALT | KeyModifiers::SHIFT;
183
184        assert_eq!(parse("<S-A-a>"), res![evkey!(KeyCode::Char('A'), mods)]);
185        assert_eq!(parse("<S-A-A>"), res![evkey!(KeyCode::Char('A'), mods)]);
186        assert_eq!(parse("<S-A-q>"), res![evkey!(KeyCode::Char('Q'), mods)]);
187        assert_eq!(parse("<S-A-Q>"), res![evkey!(KeyCode::Char('Q'), mods)]);
188    }
189
190    #[test]
191    fn test_alt_lowercase() {
192        let mods = KeyModifiers::ALT;
193
194        assert_eq!(parse("<A-a>"), res![evkey!(KeyCode::Char('a'), mods)]);
195        assert_eq!(parse("<A-b>"), res![evkey!(KeyCode::Char('b'), mods)]);
196        assert_eq!(parse("<M-a>"), res![evkey!(KeyCode::Char('a'), mods)]);
197        assert_eq!(parse("<M-b>"), res![evkey!(KeyCode::Char('b'), mods)]);
198    }
199
200    #[test]
201    fn test_alt_uppercase() {
202        let mods = KeyModifiers::ALT | KeyModifiers::SHIFT;
203
204        assert_eq!(parse("<A-A>"), res![evkey!(KeyCode::Char('A'), mods)]);
205        assert_eq!(parse("<A-B>"), res![evkey!(KeyCode::Char('B'), mods)]);
206        assert_eq!(parse("<M-A>"), res![evkey!(KeyCode::Char('A'), mods)]);
207        assert_eq!(parse("<M-B>"), res![evkey!(KeyCode::Char('B'), mods)]);
208    }
209
210    #[test]
211    fn test_ctl_no_collision() {
212        // These characters are sometimes be the same keypresses, but we should
213        // allow them to be mapped separately for environments that support it.
214        assert_eq!(parse("<C-?>"), res![evctl!('?')]);
215        assert_eq!(parse("<BS>"), res![evkey!(KeyCode::Backspace)]);
216        assert_eq!(parse("<C-I>"), res![evctl!('i')]);
217        assert_eq!(parse("<Tab>"), res![evkey!(KeyCode::Tab)]);
218        assert_eq!(parse("<C-M>"), res![evctl!('m')]);
219        assert_eq!(parse("<Enter>"), res![evkey!(KeyCode::Enter)]);
220        assert_eq!(parse("<C-@>"), res![evctl!('@')]);
221        assert_eq!(parse("<C-Space>"), res![evctl!(' ')]);
222        assert_eq!(parse("<C-[>"), res![evctl!('[')]);
223        assert_eq!(parse("<Esc>"), res![evkey!(KeyCode::Esc)]);
224    }
225
226    #[test]
227    fn test_named_ascii() {
228        assert_eq!(parse("<Space>"), res![evkey!(' ')]);
229        assert_eq!(parse("<Bar>"), res![evkey!('|')]);
230        assert_eq!(parse("<Bslash>"), res![evkey!('\\')]);
231        assert_eq!(parse("<lt>"), res![evkey!('<')]);
232    }
233
234    #[test]
235    fn test_arrow_key() {
236        assert_eq!(parse("<Left>"), res![evkey!(KeyCode::Left)]);
237        assert_eq!(parse("<Right>"), res![evkey!(KeyCode::Right)]);
238        assert_eq!(parse("<Up>"), res![evkey!(KeyCode::Up)]);
239        assert_eq!(parse("<Down>"), res![evkey!(KeyCode::Down)]);
240    }
241
242    #[test]
243    fn test_named_ctl() {
244        // <C-?>
245        assert_eq!(parse("<BS>"), res![evkey!(KeyCode::Backspace)]);
246        assert_eq!(parse("<BackSpace>"), res![evkey!(KeyCode::Backspace)]);
247
248        // <C-J>
249        assert_eq!(parse("<NL>"), res![evkey!('\n')]);
250        assert_eq!(parse("<NewLine>"), res![evkey!('\n')]);
251        assert_eq!(parse("<LineFeed>"), res![evkey!('\n')]);
252        assert_eq!(parse("<LF>"), res![evkey!('\n')]);
253
254        // <C-M>
255        assert_eq!(parse("<CR>"), res![evkey!(KeyCode::Enter)]);
256        assert_eq!(parse("<Return>"), res![evkey!(KeyCode::Enter)]);
257        assert_eq!(parse("<Enter>"), res![evkey!(KeyCode::Enter)]);
258
259        assert_eq!(parse("<Esc>"), res![evkey!(KeyCode::Esc)]);
260        assert_eq!(parse("<Tab>"), res![evkey!(KeyCode::Tab)]);
261        assert_eq!(parse("<Nul>"), res![evkey!(KeyCode::Null)]);
262    }
263
264    #[test]
265    fn test_function_key() {
266        assert_eq!(parse("<F1>"), res![evkey!(KeyCode::F(1))]);
267        assert_eq!(parse("<F2>"), res![evkey!(KeyCode::F(2))]);
268        assert_eq!(parse("<F10>"), res![evkey!(KeyCode::F(10))]);
269    }
270
271    #[test]
272    fn test_special_key() {
273        assert_eq!(parse("<PageUp>"), res![evkey!(KeyCode::PageUp)]);
274        assert_eq!(parse("<PageDown>"), res![evkey!(KeyCode::PageDown)]);
275        assert_eq!(parse("<Home>"), res![evkey!(KeyCode::Home)]);
276        assert_eq!(parse("<End>"), res![evkey!(KeyCode::End)]);
277        assert_eq!(parse("<Insert>"), res![evkey!(KeyCode::Insert)]);
278        assert_eq!(parse("<Del>"), res![evkey!(KeyCode::Delete)]);
279        assert_eq!(parse("<Delete>"), res![evkey!(KeyCode::Delete)]);
280        assert_eq!(parse("<Undo>"), res![evkey!(KeyCode::F(14))]);
281        assert_eq!(parse("<Help>"), res![evkey!(KeyCode::F(15))]);
282        assert_eq!(parse("<S-Tab>"), res![evkey!(KeyCode::BackTab, KeyModifiers::SHIFT)]);
283    }
284
285    #[test]
286    fn test_edges() {
287        assert_eq!(parse("{any}"), res![once!(EdgeEvent::Any)]);
288        assert_eq!(parse("{count}"), res![count!()]);
289        assert_eq!(parse("{mark}"), res![evclass!(CommonKeyClass::Mark)]);
290        assert_eq!(parse("{register}"), res![evclass!(CommonKeyClass::Register)]);
291        assert_eq!(parse("{digraph1}"), res![evclass!(CommonKeyClass::Digraph1)]);
292        assert_eq!(parse("{digraph2}"), res![evclass!(CommonKeyClass::Digraph2)]);
293    }
294
295    #[test]
296    fn test_sequence() {
297        assert_eq!(parse("\"{register}"), res![evkey!('"'), evclass!(CommonKeyClass::Register)]);
298        assert_eq!(parse("<C-R>{register}"), res![evctl!('r'), evclass!(CommonKeyClass::Register)]);
299        assert_eq!(parse("r{any}"), res![evkey!('r'), once!(EdgeEvent::Any)]);
300        assert_eq!(parse("gwgw"), res![evkey!('g'), evkey!('w'), evkey!('g'), evkey!('w')]);
301        assert_eq!(parse("<C-K>{digraph1}{digraph2}"), res![
302            evctl!('k'),
303            evclass!(CommonKeyClass::Digraph1),
304            evclass!(CommonKeyClass::Digraph2)
305        ]);
306    }
307
308    #[test]
309    fn test_multiple_modifiers() {
310        assert_eq!(parse("<C-M-X>"), res![evkey!('x', KeyModifiers::CONTROL | KeyModifiers::ALT)]);
311    }
312
313    #[test]
314    fn test_angle_bracket() {
315        assert_eq!(parse("<C-X>>"), res![evctl!('x'), evkey!('>')]);
316        assert_eq!(parse("<C-X><"), res![evctl!('x'), evkey!('<')]);
317        assert_eq!(parse("<M->>"), res![evalt!('>')]);
318        assert_eq!(parse("<M-<>"), res![evalt!('<')]);
319    }
320}