Skip to main content

strop_core/frontend_input/
notation.rs

1//! Streaming script-token decoding shared by Editor::feed_text and headless.
2//! Tokens retain physical modifiers until the engine selects the input owner.
3//! Unknown tokens stay literal; a lone '<' never fabricates a closing '>'.
4use super::{KeyCode, KeyEvent, Modifiers};
5
6pub fn parse(text: &str) -> Keys<'_> {
7    Keys {
8        remaining: text,
9        literal_bytes: 0,
10    }
11}
12pub struct Keys<'a> {
13    remaining: &'a str,
14    literal_bytes: usize,
15}
16impl Iterator for Keys<'_> {
17    type Item = KeyEvent;
18    fn next(&mut self) -> Option<KeyEvent> {
19        let ch = self.remaining.chars().next()?;
20        if self.literal_bytes > 0 {
21            self.remaining = &self.remaining[ch.len_utf8()..];
22            self.literal_bytes -= ch.len_utf8();
23            return Some(KeyEvent::press(KeyCode::Char(ch)));
24        }
25        if ch == '<' {
26            if let Some(end) = self.remaining.find('>') {
27                if let Some(key) = token(&self.remaining[1..end]) {
28                    self.remaining = &self.remaining[end + 1..];
29                    return Some(key);
30                }
31                self.literal_bytes = end;
32            }
33        }
34        self.remaining = &self.remaining[ch.len_utf8()..];
35        Some(character(ch))
36    }
37}
38
39fn character(ch: char) -> KeyEvent {
40    let code = match ch {
41        '\x1b' => KeyCode::Escape,
42        '\r' | '\n' => KeyCode::Enter,
43        '\x7f' | '\x08' => KeyCode::Backspace,
44        '\t' => KeyCode::Tab,
45        '\0' => KeyCode::Null,
46        '\x01'..='\x1a' => {
47            let mut key = KeyEvent::press(KeyCode::Char(char::from(ch as u8 - 1 + b'a')));
48            key.modifiers.control = true;
49            return key;
50        }
51        '\x1c'..='\x1f' => {
52            let scalar = match ch {
53                '\x1c' => '\\',
54                '\x1d' => ']',
55                '\x1e' => '6',
56                _ => '_',
57            };
58            let mut key = KeyEvent::press(KeyCode::Char(scalar));
59            key.modifiers.control = true;
60            return key;
61        }
62        ch => KeyCode::Char(ch),
63    };
64    KeyEvent::press(code)
65}
66
67fn token(mut text: &str) -> Option<KeyEvent> {
68    let mut modifiers = Modifiers::default();
69    while let Some((modifier, rest)) = text.split_once('-') {
70        if modifier.eq_ignore_ascii_case("c") {
71            modifiers.control = true;
72        } else if modifier.eq_ignore_ascii_case("s") {
73            modifiers.shift = true;
74        } else if modifier.eq_ignore_ascii_case("a") || modifier.eq_ignore_ascii_case("m") {
75            modifiers.alt = true;
76        } else if modifier.eq_ignore_ascii_case("d") || modifier.eq_ignore_ascii_case("super") {
77            modifiers.super_key = true;
78        } else {
79            break;
80        }
81        text = rest;
82    }
83    let mut code = NAMES
84        .iter()
85        .find(|(name, _)| text.eq_ignore_ascii_case(name))
86        .map(|(_, code)| *code);
87    if code.is_none() && text.starts_with(['f', 'F']) {
88        code = text[1..]
89            .parse::<u8>()
90            .ok()
91            .filter(|number| *number != 0)
92            .map(KeyCode::Function);
93    }
94    if code.is_none() {
95        let mut chars = text.chars();
96        if let Some(ch) = chars.next() {
97            if chars.next().is_none() && modifiers != Modifiers::default() {
98                code = Some(KeyCode::Char(ch));
99            }
100        }
101    }
102    let mut code = code?;
103    if code == KeyCode::Tab && modifiers.shift {
104        code = KeyCode::BackTab;
105    }
106    if code == KeyCode::Char('^') && modifiers.control {
107        code = KeyCode::Char('6');
108        modifiers.shift = true;
109    }
110    let mut key = KeyEvent::press(code);
111    key.modifiers = modifiers;
112    Some(key)
113}
114const NAMES: &[(&str, KeyCode)] = &[
115    ("esc", KeyCode::Escape),
116    ("cr", KeyCode::Enter),
117    ("enter", KeyCode::Enter),
118    ("bs", KeyCode::Backspace),
119    ("backspace", KeyCode::Backspace),
120    ("space", KeyCode::Char(' ')),
121    ("lt", KeyCode::Char('<')),
122    ("gt", KeyCode::Char('>')),
123    ("up", KeyCode::Up),
124    ("down", KeyCode::Down),
125    ("left", KeyCode::Left),
126    ("right", KeyCode::Right),
127    ("tab", KeyCode::Tab),
128    ("home", KeyCode::Home),
129    ("end", KeyCode::End),
130    ("pageup", KeyCode::PageUp),
131    ("pagedown", KeyCode::PageDown),
132    ("delete", KeyCode::Delete),
133    ("insert", KeyCode::Insert),
134    ("null", KeyCode::Null),
135];