use super::Keystroke;
use crate::parse::is_decimal_digit;
#[must_use]
pub fn af_merge_change(event: &Keystroke) -> String {
event.merged()
}
#[must_use]
pub fn af_extract_nums(s: &str) -> Option<Vec<String>> {
let mut runs: Vec<String> = Vec::new();
let mut run = String::new();
if matches!(s.chars().next(), Some('.' | ',')) {
runs.push("0".to_string());
}
for ch in s.chars() {
if is_decimal_digit(ch) {
run.push(ch);
} else if !run.is_empty() {
runs.push(std::mem::take(&mut run));
}
}
if !run.is_empty() {
runs.push(run);
}
(!runs.is_empty()).then_some(runs)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn merge_change_transcript_lines() {
assert_eq!(af_merge_change(&Keystroke::commit("one")), "one");
assert_eq!(af_merge_change(&Keystroke::insert("one", "A", 0)), "Aone");
}
#[test]
fn a_selection_is_replaced() {
assert_eq!(
af_merge_change(&Keystroke::replace("abcd", "X", 1, 3)),
"aXd"
);
assert_eq!(af_merge_change(&Keystroke::replace("abcd", "", 0, 4)), "");
}
#[test]
fn a_negative_selection_start_keeps_everything() {
let mut event = Keystroke::insert("abc", "X", 0);
event.sel_start = -1;
event.sel_end = -1;
assert_eq!(af_merge_change(&event), "abcX");
}
#[test]
fn a_stale_selection_end_truncates() {
assert_eq!(
af_merge_change(&Keystroke::replace("abc", "X", 1, 99)),
"aX"
);
}
#[test]
fn extract_nums_transcript_line() {
assert_eq!(af_extract_nums("100 200").unwrap(), ["100", "200"]);
}
#[test]
fn a_leading_mark_yields_two_runs_not_one_number() {
assert_eq!(af_extract_nums(".5").unwrap(), ["0", "5"]);
assert_eq!(af_extract_nums(",5").unwrap(), ["0", "5"]);
assert_eq!(af_extract_nums("1.5").unwrap(), ["1", "5"]);
}
#[test]
fn a_string_without_digits_has_no_answer() {
for value in ["", "abc", " ", "-"] {
assert!(af_extract_nums(value).is_none(), "{value:?}");
}
assert_eq!(af_extract_nums("...").unwrap(), ["0"]);
}
#[test]
fn runs_keep_their_leading_zeros_and_their_order() {
assert_eq!(af_extract_nums("a01b002c3").unwrap(), ["01", "002", "3"]);
}
}