add tests

This commit is contained in:
Junkui Zhang 2025-08-19 14:45:37 +08:00
parent 345377544b
commit 49278ceec0

View file

@ -5,17 +5,6 @@ use std::{
fmt::{Display, Write},
};
/// TODO:
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct KeystrokeDisplay {
/// TODO:
pub inner: Keystroke,
/// TODO:
pub modifiers: Modifiers,
/// TODO:
pub key: String,
}
/// A keystroke and associated metadata generated by the platform
#[derive(Clone, Debug, Eq, PartialEq, Default, Deserialize, Hash)]
pub struct Keystroke {
@ -35,6 +24,17 @@ pub struct Keystroke {
pub key_char: Option<String>,
}
/// TODO:
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct KeystrokeDisplay {
/// TODO:
pub inner: Keystroke,
/// TODO:
pub modifiers: Modifiers,
/// TODO:
pub key: String,
}
/// Error type for `Keystroke::parse`. This is used instead of `anyhow::Error` so that Zed can use
/// markdown to display it.
#[derive(Debug)]
@ -275,6 +275,34 @@ impl Keystroke {
}
self
}
fn into_shifted(self) -> Self {
let Keystroke {
modifiers,
key,
key_char,
} = self;
let (key, modifiers) = into_shifted_key(key, modifiers);
Self {
key,
modifiers,
key_char,
}
}
}
impl KeystrokeDisplay {
/// TODO:
pub fn parse(source: &str) -> std::result::Result<Self, InvalidKeystrokeError> {
let keystroke = Keystroke::parse(source)?;
let (key, modifiers) = to_unshifted_key(&keystroke.key, &keystroke.modifiers);
let inner = keystroke.into_shifted();
Ok(KeystrokeDisplay {
inner,
key,
modifiers,
})
}
}
fn is_printable_key(key: &str) -> bool {
@ -611,3 +639,227 @@ pub struct Capslock {
#[serde(default)]
pub on: bool,
}
fn to_unshifted_key(key: &str, modifiers: &Modifiers) -> (String, Modifiers) {
let mut modifiers = modifiers.clone();
match key {
"~" => {
modifiers.shift = true;
("`".to_string(), modifiers)
}
"!" => {
modifiers.shift = true;
("1".to_string(), modifiers)
}
"@" => {
modifiers.shift = true;
("2".to_string(), modifiers)
}
"#" => {
modifiers.shift = true;
("3".to_string(), modifiers)
}
"$" => {
modifiers.shift = true;
("4".to_string(), modifiers)
}
"%" => {
modifiers.shift = true;
("5".to_string(), modifiers)
}
"^" => {
modifiers.shift = true;
("6".to_string(), modifiers)
}
"&" => {
modifiers.shift = true;
("7".to_string(), modifiers)
}
"*" => {
modifiers.shift = true;
("8".to_string(), modifiers)
}
"(" => {
modifiers.shift = true;
("9".to_string(), modifiers)
}
")" => {
modifiers.shift = true;
("0".to_string(), modifiers)
}
"_" => {
modifiers.shift = true;
("-".to_string(), modifiers)
}
"+" => {
modifiers.shift = true;
("=".to_string(), modifiers)
}
"{" => {
modifiers.shift = true;
("[".to_string(), modifiers)
}
"}" => {
modifiers.shift = true;
("]".to_string(), modifiers)
}
"|" => {
modifiers.shift = true;
("\\".to_string(), modifiers)
}
":" => {
modifiers.shift = true;
(";".to_string(), modifiers)
}
"\"" => {
modifiers.shift = true;
("'".to_string(), modifiers)
}
"<" => {
modifiers.shift = true;
(",".to_string(), modifiers)
}
">" => {
modifiers.shift = true;
(">".to_string(), modifiers)
}
"?" => {
modifiers.shift = true;
("/".to_string(), modifiers)
}
_ => (key.to_string(), modifiers),
}
}
fn into_shifted_key(key: String, mut modifiers: Modifiers) -> (String, Modifiers) {
if !modifiers.shift {
(key, modifiers)
} else {
match key.as_str() {
"`" => {
modifiers.shift = false;
("~".to_string(), modifiers)
}
"1" => {
modifiers.shift = false;
("!".to_string(), modifiers)
}
"2" => {
modifiers.shift = false;
("@".to_string(), modifiers)
}
"3" => {
modifiers.shift = false;
("#".to_string(), modifiers)
}
"4" => {
modifiers.shift = false;
("$".to_string(), modifiers)
}
"5" => {
modifiers.shift = false;
("%".to_string(), modifiers)
}
"6" => {
modifiers.shift = false;
("^".to_string(), modifiers)
}
"7" => {
modifiers.shift = false;
("&".to_string(), modifiers)
}
"8" => {
modifiers.shift = false;
("*".to_string(), modifiers)
}
"9" => {
modifiers.shift = false;
("(".to_string(), modifiers)
}
"0" => {
modifiers.shift = false;
(")".to_string(), modifiers)
}
"-" => {
modifiers.shift = false;
("_".to_string(), modifiers)
}
"=" => {
modifiers.shift = false;
("+".to_string(), modifiers)
}
"[" => {
modifiers.shift = false;
("{".to_string(), modifiers)
}
"]" => {
modifiers.shift = false;
("}".to_string(), modifiers)
}
"\\" => {
modifiers.shift = false;
("|".to_string(), modifiers)
}
";" => {
modifiers.shift = false;
(":".to_string(), modifiers)
}
"'" => {
modifiers.shift = false;
("\"".to_string(), modifiers)
}
"," => {
modifiers.shift = false;
("<".to_string(), modifiers)
}
"." => {
modifiers.shift = false;
(">".to_string(), modifiers)
}
"/" => {
modifiers.shift = false;
("?".to_string(), modifiers)
}
_ => (key, modifiers),
}
}
}
#[cfg(test)]
mod tests {
use crate::{Keystroke, KeystrokeDisplay, Modifiers};
#[test]
fn test_parsing_keystroke_on_windows() {
// On windows, users prefer to use "ctrl-shift-key", so here we support
// both "ctrl-$" and "ctrl-shift-4"
let source = "ctrl-$";
let keystroke = Keystroke::parse(source).unwrap();
assert_eq!(keystroke.modifiers, Modifiers::control());
assert_eq!(keystroke.key, "$");
assert_eq!(keystroke.key_char, None);
let keystroke_display = KeystrokeDisplay::parse(source).unwrap();
assert_eq!(keystroke_display.inner, keystroke);
assert_eq!(keystroke_display.key, "4");
assert_eq!(keystroke_display.modifiers, Modifiers::control_shift());
let source = "ctrl-shift-4";
let keystroke = Keystroke::parse(source).unwrap();
assert_eq!(keystroke.modifiers, Modifiers::control_shift());
assert_eq!(keystroke.key, "4");
assert_eq!(keystroke.key_char, None);
let keystroke_display = KeystrokeDisplay::parse(source).unwrap();
assert_eq!(
keystroke_display.inner,
Keystroke {
modifiers: Modifiers::control(),
key: "$".to_string(),
key_char: None
}
);
assert_eq!(keystroke_display.key, "4");
assert_eq!(keystroke_display.modifiers, Modifiers::control_shift());
}
}