diff --git a/src/trial/history.rs b/src/trial/history.rs index 18344f0..ee314d9 100644 --- a/src/trial/history.rs +++ b/src/trial/history.rs @@ -101,7 +101,7 @@ impl History { } /// Push a typed grapheme cluster to the history. - fn push_typed(&mut self, typed: &str) { + pub fn push_typed(&mut self, typed: &str) { debug_assert_eq!(typed.graphemes(true).count(), 1); // Push the index of the cluster. diff --git a/src/trial/mod.rs b/src/trial/mod.rs index cc22d1b..f4d153e 100644 --- a/src/trial/mod.rs +++ b/src/trial/mod.rs @@ -2,6 +2,8 @@ mod history; use history::History; +use unicode_segmentation::UnicodeSegmentation; + /// The state of a trial. pub struct Trial { /// The history of typed grapheme clusters and reference grapheme clusters. @@ -35,7 +37,9 @@ impl Trial { pub fn process(&mut self, input: Input) { match input { Input::TypeScalar(c) => { - self.working_grapheme_cluster.push(c); + if let Some(finished_cluster) = push_to_working_cluster(&mut self.working_grapheme_cluster, c) { + self.history.push_typed(&finished_cluster); + } } Input::DeleteGraphemeCluster if self.working_grapheme_cluster.is_empty() => { todo!() @@ -49,3 +53,63 @@ impl Trial { } } } + +/// Push a scalar value to the working grapheme cluster, returning the previous cluster if it was finished. +fn push_to_working_cluster(working_grapheme_cluster: &mut String, scalar: char) -> Option { + working_grapheme_cluster.push(scalar); + + let mut clusters = working_grapheme_cluster.graphemes(true); + let first_cluster = clusters.next().unwrap(); + + if let Some(new_cluster) = clusters.next() { + let first_cluster = first_cluster.to_owned(); + let new_cluster = new_cluster.to_owned(); + + *working_grapheme_cluster = new_cluster; + + Some(first_cluster) + } else { + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn push_to_working_cluster_handles_latin() { + let mut working_grapheme_cluster = String::new(); + + assert_eq!( + push_to_working_cluster(&mut working_grapheme_cluster, 'a'), + None + ); + assert_eq!( + push_to_working_cluster(&mut working_grapheme_cluster, 'a'), + Some("a".to_owned()) + ); + + assert_eq!( + push_to_working_cluster(&mut working_grapheme_cluster, 'é'), + Some("a".to_owned()) + ); + assert_eq!( + push_to_working_cluster(&mut working_grapheme_cluster, 'a'), + Some("é".to_owned()) + ); + + assert_eq!( + push_to_working_cluster(&mut working_grapheme_cluster, 'a'), + Some("a".to_owned()) + ); + assert_eq!( + push_to_working_cluster(&mut working_grapheme_cluster, '\u{0302}'), // combining circumflex accent + None + ); + assert_eq!( + push_to_working_cluster(&mut working_grapheme_cluster, 'a'), + Some("a\u{0302}".to_owned()) + ); + } +}