Skip to content

Commit 2b46c7f

Browse files
authored
feat: Convert from Backend::Key to Node (#10)
1 parent d109777 commit 2b46c7f

File tree

5 files changed

+148
-25
lines changed

5 files changed

+148
-25
lines changed

examples/termion.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ fn main() {
2020
let evt = c.unwrap();
2121

2222
if let Event::Key(key) = evt {
23-
if let Some((k, action)) = bindings.keys.get_key_value(&KeyMap::from(key)) {
23+
if let Some((k, action)) = bindings.0.get_key_value(&KeyMap::from(key)) {
2424
if *action == Action::Quit {
2525
break;
2626
}

src/backend/crossterm.rs

+80-19
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
22
use serde::{de, Deserialize, Deserializer};
33

44
use crate::parser::{self, Key as Keys, Modifier, Node};
5-
use super::Key;
5+
use super::{Key, NodeModifiers};
66

77
pub type KeyMap = Key<KeyEvent>;
88

@@ -12,7 +12,7 @@ pub fn parse(s: &str) -> Result<KeyMap, pom::Error> {
1212

1313
impl From<KeyEvent> for KeyMap {
1414
fn from(value: KeyEvent) -> Self {
15-
Self { event: value, node: None }
15+
Self { event: value, node: Some(Node::from(value)) }
1616
}
1717
}
1818

@@ -25,6 +25,38 @@ impl From<Node> for KeyMap {
2525
}
2626
}
2727

28+
impl From<KeyEvent> for Node {
29+
fn from(value: KeyEvent) -> Self {
30+
match value {
31+
KeyEvent { code, modifiers, .. } => {
32+
let key = match code {
33+
KeyCode::BackTab => Keys::BackTab,
34+
KeyCode::Backspace => Keys::Backspace,
35+
KeyCode::Char(' ') => Keys::Space,
36+
KeyCode::Char(c) => Keys::Char(c),
37+
KeyCode::Delete => Keys::Delete,
38+
KeyCode::Down => Keys::Down,
39+
KeyCode::End => Keys::End,
40+
KeyCode::Enter => Keys::Enter,
41+
KeyCode::Esc => Keys::Esc,
42+
KeyCode::F(n) => Keys::F(n),
43+
KeyCode::Home => Keys::Home,
44+
KeyCode::Insert => Keys::Insert,
45+
KeyCode::Left => Keys::Left,
46+
KeyCode::PageDown => Keys::PageDown,
47+
KeyCode::PageUp => Keys::PageUp,
48+
KeyCode::Right => Keys::Right,
49+
KeyCode::Tab => Keys::Tab,
50+
KeyCode::Up => Keys::Up,
51+
code => panic!("Unsupport KeyEvent {code:?}"),
52+
};
53+
54+
Self { key, modifiers: NodeModifiers::from(modifiers).into() }
55+
}
56+
}
57+
}
58+
}
59+
2860
impl<'a> From<&'a Node> for KeyEvent {
2961
fn from(node: &'a Node) -> Self {
3062
let key = match node.key {
@@ -48,26 +80,37 @@ impl<'a> From<&'a Node> for KeyEvent {
4880
Keys::Up => KeyCode::Up.into(),
4981
};
5082

51-
Self::new(key, modifiers(node.modifiers))
83+
Self::new(key, NodeModifiers::from(node.modifiers).into())
5284
}
5385
}
5486

55-
fn modifiers(m: u8) -> KeyModifiers {
56-
let mut mods = KeyModifiers::NONE;
57-
if m & Modifier::Alt as u8 != 0 {
58-
mods |= KeyModifiers::ALT
59-
}
60-
if m & Modifier::Cmd as u8 != 0 {
61-
mods |= KeyModifiers::META
62-
}
63-
if m & Modifier::Ctrl as u8 != 0 {
64-
mods |= KeyModifiers::CONTROL
65-
}
66-
if m & Modifier::Shift as u8 != 0 {
67-
mods |= KeyModifiers::SHIFT
87+
const MODIFIERS: [(KeyModifiers, parser::Modifier); 4] = [
88+
(KeyModifiers::ALT, Modifier::Alt),
89+
(KeyModifiers::CONTROL, Modifier::Ctrl),
90+
(KeyModifiers::META, Modifier::Cmd),
91+
(KeyModifiers::SHIFT, Modifier::Shift),
92+
];
93+
94+
impl From<KeyModifiers> for NodeModifiers {
95+
fn from(value: KeyModifiers) -> Self {
96+
Self(MODIFIERS.into_iter().fold(0, |mut m, (m1, m2)| {
97+
if value.contains(m1) {
98+
m |= m2 as u8;
99+
}
100+
m
101+
}))
68102
}
103+
}
69104

70-
mods
105+
impl From<NodeModifiers> for KeyModifiers {
106+
fn from(value: NodeModifiers) -> Self {
107+
MODIFIERS.into_iter().fold(KeyModifiers::NONE, |mut m, (m1, m2)| {
108+
if value.0 & m2 as u8 != 0 {
109+
m|= m1
110+
}
111+
m
112+
})
113+
}
71114
}
72115

73116
/// Deserializes into Key
@@ -86,10 +129,10 @@ mod tests {
86129
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
87130
use serde::Deserialize;
88131

89-
use crate::backend::{
132+
use crate::{backend::{
90133
crossterm::{parse, KeyMap},
91134
Key
92-
};
135+
}, parser::{Node, self}};
93136

94137
#[test]
95138
fn test_parse() {
@@ -110,6 +153,24 @@ mod tests {
110153
});
111154
}
112155

156+
#[test]
157+
fn test_from_key_to_node() {
158+
let alt_a = KeyEvent::new(
159+
KeyCode::Char('a'),
160+
KeyModifiers::ALT | KeyModifiers::CONTROL | KeyModifiers::SHIFT,
161+
);
162+
163+
[
164+
(KeyEvent::from(KeyCode::Char('[')), "["),
165+
(KeyEvent::from(KeyCode::Delete), "del"),
166+
(alt_a, "alt-ctrl-shift-a"),
167+
]
168+
.map(|(key, code)| {
169+
let node = parser::parse(code).unwrap();
170+
assert_eq!(Node::from(key), node);
171+
});
172+
}
173+
113174
#[test]
114175
fn test_deserialize() {
115176
use std::collections::HashMap;

src/backend/mod.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ mod termion;
1313
#[cfg(feature = "termion")]
1414
pub use self::termion::{KeyMap, parse};
1515

16-
use crate::parser::Node;
16+
use crate::parser::{Node, Modifiers};
1717

1818
#[derive(Debug, Eq)]
1919
pub struct Key<T> {
@@ -41,3 +41,19 @@ impl Display for KeyMap {
4141
}
4242
}
4343
}
44+
45+
/// A wrapper that allows conversion between backend's modifier
46+
/// and Node's modifier.
47+
struct NodeModifiers(Modifiers);
48+
49+
impl From<NodeModifiers> for Modifiers {
50+
fn from(value: NodeModifiers) -> Self {
51+
value.0
52+
}
53+
}
54+
55+
impl From<Modifiers> for NodeModifiers {
56+
fn from(value: Modifiers) -> Self {
57+
Self(value)
58+
}
59+
}

src/backend/termion.rs

+48-3
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,41 @@ impl From<KeyEvent> for KeyMap {
1616
fn from(value: KeyEvent) -> Self {
1717
Self {
1818
event: value,
19-
node: None,
19+
node: Some(Node::from(value)),
2020
}
2121
}
2222
}
2323

24+
impl From<KeyEvent> for Node {
25+
fn from(value: KeyEvent) -> Self {
26+
let (key, modifiers) = match value {
27+
KeyEvent::BackTab => (Keys::BackTab, 0),
28+
KeyEvent::Backspace => (Keys::Backspace, 0),
29+
KeyEvent::Delete => (Keys::Delete, 0),
30+
KeyEvent::Down => (Keys::Down, 0),
31+
KeyEvent::End => (Keys::End, 0),
32+
KeyEvent::Esc => (Keys::Esc, 0),
33+
KeyEvent::Home => (Keys::Home, 0),
34+
KeyEvent::F(n) => (Keys::F(n), 0),
35+
KeyEvent::Insert => (Keys::Insert, 0),
36+
KeyEvent::Left => (Keys::Left, 0),
37+
KeyEvent::PageDown => (Keys::PageDown, 0),
38+
KeyEvent::PageUp => (Keys::PageUp, 0),
39+
KeyEvent::Right => (Keys::Right, 0),
40+
KeyEvent::Up => (Keys::Up, 0),
41+
KeyEvent::Char(' ') => (Keys::Space, 0),
42+
KeyEvent::Char('\n') => (Keys::Enter, 0),
43+
KeyEvent::Char('\t') => (Keys::Tab, 0),
44+
KeyEvent::Char(c) => (Keys::Char(c), 0),
45+
KeyEvent::Alt(c) => (Keys::Char(c), Modifier::Alt as u8),
46+
KeyEvent::Ctrl(c) => (Keys::Char(c), Modifier::Ctrl as u8),
47+
key => panic!("Unsupport Key {key:?}"),
48+
};
49+
50+
Self { key, modifiers }
51+
}
52+
}
53+
2454
impl From<Node> for KeyMap {
2555
fn from(node: Node) -> Self {
2656
let key = match node.key {
@@ -81,7 +111,7 @@ impl<'s> Deserialize<'s> for KeyMap {
81111

82112
#[cfg(test)]
83113
mod tests {
84-
use crate::{backend::termion::parse, Key};
114+
use crate::{backend::termion::parse, Key, parser::{self, Node}};
85115
use termion::event::Key as KeyEvent;
86116

87117
#[test]
@@ -91,12 +121,27 @@ mod tests {
91121
("del", KeyEvent::Delete),
92122
("alt-a", KeyEvent::Alt('a')),
93123
("shift-a", KeyEvent::Char('A')),
94-
("shift-=", KeyEvent::Char('+')),
124+
("A", KeyEvent::Char('A')),
95125
("enter", KeyEvent::Char('\n')),
96126
("ctrl-a", KeyEvent::Ctrl('a')),
97127
]
98128
.map(|(s, node)| {
99129
assert_eq!(Key::from(node), parse(s).unwrap());
100130
});
101131
}
132+
133+
#[test]
134+
fn test_from_key_to_node() {
135+
let alt_a = KeyEvent::Alt('a');
136+
137+
[
138+
(KeyEvent::Char('['), "["),
139+
(KeyEvent::Delete, "del"),
140+
(alt_a, "alt-a"),
141+
]
142+
.map(|(key, code)| {
143+
let node = parser::parse(code).unwrap();
144+
assert_eq!(Node::from(key), node);
145+
});
146+
}
102147
}

src/parser.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ pub(crate) enum Modifier {
3636
Shift = 0b1000,
3737
}
3838

39-
type Modifiers = u8;
39+
pub(crate) type Modifiers = u8;
40+
4041
const MODIFIERS: [Modifier; 4] = [
4142
Modifier::Alt,
4243
Modifier::Cmd,

0 commit comments

Comments
 (0)