use std::time::Duration;
pub const PAUSE: Duration = Duration::from_millis(500);
pub const COUNT: usize = 10;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Step {
Send(String),
Pause,
}
pub fn expand(text: &str, user: &str, password: &str) -> Vec<Step> {
let text = text.replace("{user}", user).replace("{password}", password);
let mut steps = Vec::new();
let mut cur = String::new();
let mut chars = text.chars().peekable();
while let Some(c) = chars.next() {
match c {
'~' => {
if !cur.is_empty() {
steps.push(Step::Send(std::mem::take(&mut cur)));
}
steps.push(Step::Pause);
}
'^' => match chars.peek().copied() {
Some(n @ ('^' | '~')) => {
chars.next();
cur.push(n);
}
Some(n) if n.is_ascii_alphabetic() || "@[\\]_".contains(n) => {
chars.next();
cur.push(char::from(n.to_ascii_uppercase() as u8 & 0x1F));
}
_ => cur.push('^'),
},
_ => cur.push(c),
}
}
if !cur.is_empty() {
steps.push(Step::Send(cur));
}
steps
}
pub fn key_name(i: usize) -> char {
if i == 9 { '0' } else { char::from(b'1' + i as u8) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn expands() {
assert_eq!(
expand("{user}^M~{password}^M", "sysop", "secret"),
vec![Step::Send("sysop\r".into()), Step::Pause, Step::Send("secret\r".into())]
);
assert_eq!(expand("^[[A^^x^~y", "", ""), vec![Step::Send("\x1b[A^x~y".into())]);
assert_eq!(expand("100^%", "", ""), vec![Step::Send("100^%".into())]);
assert_eq!(expand("~~", "", ""), vec![Step::Pause, Step::Pause]);
assert!(expand("", "", "").is_empty());
assert_eq!((key_name(0), key_name(9)), ('1', '0'));
}
}