ui: add Ctrl-* Alt-* and F1..F12 parsers and tests
parent
2199726b2c
commit
81b7195080
|
@ -267,7 +267,8 @@ impl<'de> Deserialize<'de> for Key {
|
||||||
type Value = Key;
|
type Value = Key;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
formatter.write_str("`secs` or `nanos`")
|
formatter
|
||||||
|
.write_str("a valid key value. Please consult the manual for valid key inputs.")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> Result<Key, E>
|
fn visit_str<E>(self, value: &str) -> Result<Key, E>
|
||||||
|
@ -275,20 +276,61 @@ impl<'de> Deserialize<'de> for Key {
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
{
|
{
|
||||||
match value {
|
match value {
|
||||||
"Backspace" => Ok(Key::Backspace),
|
"Backspace" | "backspace" => Ok(Key::Backspace),
|
||||||
"Left" => Ok(Key::Left),
|
"Left" | "left" => Ok(Key::Left),
|
||||||
"Right" => Ok(Key::Right),
|
"Right" | "right" => Ok(Key::Right),
|
||||||
"Up" => Ok(Key::Up),
|
"Up" | "up" => Ok(Key::Up),
|
||||||
"Down" => Ok(Key::Down),
|
"Down" | "down" => Ok(Key::Down),
|
||||||
"Home" => Ok(Key::Home),
|
"Home" | "home" => Ok(Key::Home),
|
||||||
"End" => Ok(Key::End),
|
"End" | "end" => Ok(Key::End),
|
||||||
"PageUp" => Ok(Key::PageUp),
|
"PageUp" | "pageup" => Ok(Key::PageUp),
|
||||||
"PageDown" => Ok(Key::PageDown),
|
"PageDown" | "pagedown" => Ok(Key::PageDown),
|
||||||
"Delete" => Ok(Key::Delete),
|
"Delete" | "delete" => Ok(Key::Delete),
|
||||||
"Insert" => Ok(Key::Insert),
|
"Insert" | "insert" => Ok(Key::Insert),
|
||||||
"Esc" => Ok(Key::Esc),
|
"Enter" | "enter" => Ok(Key::Char('\n')),
|
||||||
|
"Tab" | "tab" => Ok(Key::Char('\t')),
|
||||||
|
"Esc" | "esc" => Ok(Key::Esc),
|
||||||
ref s if s.len() == 1 => Ok(Key::Char(s.chars().nth(0).unwrap())),
|
ref s if s.len() == 1 => Ok(Key::Char(s.chars().nth(0).unwrap())),
|
||||||
_ => Err(de::Error::unknown_field(value, FIELDS)),
|
ref s if s.starts_with("F") && (s.len() == 2 || s.len() == 3) => {
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
if let Ok(n) = u8::from_str(&s[1..]) {
|
||||||
|
if n >= 1 && n <= 12 {
|
||||||
|
return Ok(Key::F(n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(de::Error::custom(format!(
|
||||||
|
"`{}` should be a number 1 <= n <= 12 instead.",
|
||||||
|
&s[1..]
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
ref s if s.starts_with("M-") && s.len() == 3 => {
|
||||||
|
let c = s.as_bytes()[2] as char;
|
||||||
|
|
||||||
|
if c.is_lowercase() || c.is_numeric() {
|
||||||
|
return Ok(Key::Alt(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(de::Error::custom(format!(
|
||||||
|
"`{}` should be a lowercase and alphanumeric character instead.",
|
||||||
|
&s[2..]
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
ref s if s.starts_with("C-") && s.len() == 3 => {
|
||||||
|
let c = s.as_bytes()[2] as char;
|
||||||
|
|
||||||
|
if c.is_lowercase() || c.is_numeric() {
|
||||||
|
return Ok(Key::Ctrl(c));
|
||||||
|
}
|
||||||
|
Err(de::Error::custom(format!(
|
||||||
|
"`{}` should be a lowercase and alphanumeric character instead.",
|
||||||
|
&s[2..]
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
_ => Err(de::Error::custom(format!(
|
||||||
|
"Cannot derive shortcut from `{}`. Please consult the manual for valid key inputs.",
|
||||||
|
value
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,14 +357,65 @@ impl Serialize for Key {
|
||||||
Key::Delete => serializer.serialize_str("Delete"),
|
Key::Delete => serializer.serialize_str("Delete"),
|
||||||
Key::Insert => serializer.serialize_str("Insert"),
|
Key::Insert => serializer.serialize_str("Insert"),
|
||||||
Key::Esc => serializer.serialize_str("Esc"),
|
Key::Esc => serializer.serialize_str("Esc"),
|
||||||
|
Key::Char('\n') => serializer.serialize_str("Enter"),
|
||||||
|
Key::Char('\t') => serializer.serialize_str("Tab"),
|
||||||
Key::Char(c) => serializer.serialize_char(*c),
|
Key::Char(c) => serializer.serialize_char(*c),
|
||||||
Key::F(n) => serializer.serialize_str(&format!("F{}", n)),
|
Key::F(n) => serializer.serialize_str(&format!("F{}", n)),
|
||||||
Key::Alt(c) => serializer.serialize_str(&format!("M-{}", c)),
|
Key::Alt(c) => serializer.serialize_str(&format!("M-{}", c)),
|
||||||
Key::Ctrl(c) => serializer.serialize_str(&format!("C-{}", c)),
|
Key::Ctrl(c) => serializer.serialize_str(&format!("C-{}", c)),
|
||||||
v => Err(serde::ser::Error::custom(format!(
|
Key::Null => serializer.serialize_str("Null"),
|
||||||
"`{}` is not a valid key",
|
Key::Paste(s) => serializer.serialize_str(s),
|
||||||
v
|
|
||||||
))),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_key_serde() {
|
||||||
|
#[derive(Debug, Deserialize, PartialEq)]
|
||||||
|
struct V {
|
||||||
|
k: Key,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! test_key {
|
||||||
|
($s:literal, ok $v:expr) => {
|
||||||
|
assert_eq!(
|
||||||
|
toml::from_str::<V>(std::concat!("k = \"", $s, "\"")),
|
||||||
|
Ok(V { k: $v })
|
||||||
|
);
|
||||||
|
};
|
||||||
|
($s:literal, err $v:literal) => {
|
||||||
|
assert_eq!(
|
||||||
|
toml::from_str::<V>(std::concat!("k = \"", $s, "\""))
|
||||||
|
.unwrap_err()
|
||||||
|
.to_string(),
|
||||||
|
$v.to_string()
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
test_key!("Backspace", ok Key::Backspace);
|
||||||
|
test_key!("Left", ok Key::Left );
|
||||||
|
test_key!("Right", ok Key::Right);
|
||||||
|
test_key!("Up", ok Key::Up );
|
||||||
|
test_key!("Down", ok Key::Down );
|
||||||
|
test_key!("Home", ok Key::Home );
|
||||||
|
test_key!("End", ok Key::End );
|
||||||
|
test_key!("PageUp", ok Key::PageUp );
|
||||||
|
test_key!("PageDown", ok Key::PageDown );
|
||||||
|
test_key!("Delete", ok Key::Delete );
|
||||||
|
test_key!("Insert", ok Key::Insert );
|
||||||
|
test_key!("Enter", ok Key::Char('\n') );
|
||||||
|
test_key!("Tab", ok Key::Char('\t') );
|
||||||
|
test_key!("k", ok Key::Char('k') );
|
||||||
|
test_key!("1", ok Key::Char('1') );
|
||||||
|
test_key!("Esc", ok Key::Esc );
|
||||||
|
test_key!("C-a", ok Key::Ctrl('a') );
|
||||||
|
test_key!("C-1", ok Key::Ctrl('1') );
|
||||||
|
test_key!("M-a", ok Key::Alt('a') );
|
||||||
|
test_key!("F1", ok Key::F(1) );
|
||||||
|
test_key!("F12", ok Key::F(12) );
|
||||||
|
test_key!("C-V", err "`V` should be a lowercase and alphanumeric character instead. for key `k` at line 1 column 5");
|
||||||
|
test_key!("M-V", err "`V` should be a lowercase and alphanumeric character instead. for key `k` at line 1 column 5");
|
||||||
|
test_key!("F13", err "`13` should be a number 1 <= n <= 12 instead. for key `k` at line 1 column 5");
|
||||||
|
test_key!("Fc", err "`c` should be a number 1 <= n <= 12 instead. for key `k` at line 1 column 5");
|
||||||
|
test_key!("adsfsf", err "Cannot derive shortcut from `adsfsf`. Please consult the manual for valid key inputs. for key `k` at line 1 column 5");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue