use logos::Logos;
#[derive(Logos, Debug, PartialEq)]
pub(crate) enum Token {
#[token("Ctrl")]
Ctrl,
#[token("Shift")]
Shift,
#[token("Alt")]
Alt,
#[regex(r"[A-Za-z0-9]", |lex| lex.slice().chars().next().unwrap())]
Char(char),
#[regex(r"F[1-9][0-2]?", |lex| parse_function_key(lex.slice()))]
FKey(u8),
#[token("ArrowUp")]
ArrowUp,
#[token("ArrowDown")]
ArrowDown,
#[token("ArrowLeft")]
ArrowLeft,
#[token("ArrowRight")]
ArrowRight,
#[token("Enter")]
Enter,
#[token("Escape")]
Escape,
#[token("Tab")]
Tab,
#[token("Backspace")]
Backspace,
#[token("Delete")]
Delete,
#[token("+")]
Plus,
}
fn parse_function_key(s: &str) -> Option<u8> {
s.trim_start_matches('F').parse::<u8>().ok()
}
#[cfg(test)]
mod tests {
use logos::Logos as _;
use super::{Token, parse_function_key};
#[test]
fn test_ctrl() {
assert_eq!(Token::lexer("Ctrl").next().unwrap().unwrap(), Token::Ctrl);
}
#[test]
fn test_shift() {
assert_eq!(
Token::lexer("Shift").next().unwrap().unwrap(),
Token::Shift
);
}
#[test]
fn test_alt() {
assert_eq!(Token::lexer("Alt").next().unwrap().unwrap(), Token::Alt);
}
#[test]
fn test_char_lower() {
assert_eq!(Token::lexer("a").next().unwrap().unwrap(), Token::Char('a'));
}
#[test]
fn test_char_upper() {
assert_eq!(Token::lexer("A").next().unwrap().unwrap(), Token::Char('A'));
}
#[test]
fn test_char_digit() {
assert_eq!(Token::lexer("5").next().unwrap().unwrap(), Token::Char('5'));
}
#[test]
fn test_fkey_1() {
assert_eq!(Token::lexer("F1").next().unwrap().unwrap(), Token::FKey(1));
}
#[test]
fn test_fkey_9() {
assert_eq!(Token::lexer("F9").next().unwrap().unwrap(), Token::FKey(9));
}
#[test]
fn test_fkey_10() {
assert_eq!(Token::lexer("F10").next().unwrap().unwrap(), Token::FKey(10));
}
#[test]
fn test_fkey_12() {
assert_eq!(
Token::lexer("F12").next().unwrap().unwrap(),
Token::FKey(12)
);
}
#[test]
fn test_arrow_up() {
assert_eq!(
Token::lexer("ArrowUp").next().unwrap().unwrap(),
Token::ArrowUp
);
}
#[test]
fn test_arrow_down() {
assert_eq!(
Token::lexer("ArrowDown").next().unwrap().unwrap(),
Token::ArrowDown
);
}
#[test]
fn test_arrow_left() {
assert_eq!(
Token::lexer("ArrowLeft").next().unwrap().unwrap(),
Token::ArrowLeft
);
}
#[test]
fn test_arrow_right() {
assert_eq!(
Token::lexer("ArrowRight").next().unwrap().unwrap(),
Token::ArrowRight
);
}
#[test]
fn test_enter() {
assert_eq!(Token::lexer("Enter").next().unwrap().unwrap(), Token::Enter);
}
#[test]
fn test_escape() {
assert_eq!(
Token::lexer("Escape").next().unwrap().unwrap(),
Token::Escape
);
}
#[test]
fn test_tab() {
assert_eq!(Token::lexer("Tab").next().unwrap().unwrap(), Token::Tab);
}
#[test]
fn test_backspace() {
assert_eq!(
Token::lexer("Backspace").next().unwrap().unwrap(),
Token::Backspace
);
}
#[test]
fn test_delete() {
assert_eq!(
Token::lexer("Delete").next().unwrap().unwrap(),
Token::Delete
);
}
#[test]
fn test_plus() {
assert_eq!(Token::lexer("+").next().unwrap().unwrap(), Token::Plus);
}
#[test]
fn test_ctrl_plus_a() {
let mut lexer = Token::lexer("Ctrl+a");
assert_eq!(lexer.next().unwrap().unwrap(), Token::Ctrl);
assert_eq!(lexer.next().unwrap().unwrap(), Token::Plus);
assert_eq!(lexer.next().unwrap().unwrap(), Token::Char('a'));
assert!(lexer.next().is_none());
}
#[test]
fn test_shift_alt_f10() {
let mut lexer = Token::lexer("Shift+Alt+F10");
assert_eq!(lexer.next().unwrap().unwrap(), Token::Shift);
assert_eq!(lexer.next().unwrap().unwrap(), Token::Plus);
assert_eq!(lexer.next().unwrap().unwrap(), Token::Alt);
assert_eq!(lexer.next().unwrap().unwrap(), Token::Plus);
assert_eq!(lexer.next().unwrap().unwrap(), Token::FKey(10));
}
#[test]
fn test_parse_function_key_f1() {
assert_eq!(parse_function_key("F1"), Some(1));
}
#[test]
fn test_parse_function_key_f12() {
assert_eq!(parse_function_key("F12"), Some(12));
}
#[test]
fn test_parse_function_key_invalid() {
assert_eq!(parse_function_key("F256"), None); assert_eq!(parse_function_key("Invalid"), None); }
}