#![cfg_attr(
not(target_os = "macos"),
allow(dead_code, reason = "only the macOS view records it, for now")
)]
use std::ops::Range;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub(crate) struct MarkedReplacement {
range: Option<Range<usize>>,
}
impl MarkedReplacement {
pub(crate) fn record(&mut self, range: Option<Range<usize>>) {
self.range = range;
}
pub(crate) fn take(&mut self) -> Option<Range<usize>> {
self.range.take()
}
pub(crate) fn clear(&mut self) {
self.range = None;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_recorded_range_is_taken_once() {
let mut slot = MarkedReplacement::default();
slot.record(Some(7727..7728));
assert_eq!(slot.take(), Some(7727..7728));
assert_eq!(slot.take(), None, "the same preedit, or a later one");
}
#[test]
fn marked_text_without_a_range_clears_one_left_untaken() {
let mut slot = MarkedReplacement::default();
slot.record(Some(10..14));
slot.record(None);
assert_eq!(slot.take(), None);
}
#[test]
fn the_latest_range_wins() {
let mut slot = MarkedReplacement::default();
slot.record(Some(1..2));
slot.record(Some(3..5));
assert_eq!(slot.take(), Some(3..5));
}
#[test]
fn a_key_press_or_the_end_of_the_composition_clears_it() {
let mut slot = MarkedReplacement::default();
slot.record(Some(0..1));
slot.clear();
assert_eq!(slot.take(), None);
}
#[test]
fn an_empty_range_is_kept_as_an_insertion_point() {
let mut slot = MarkedReplacement::default();
slot.record(Some(4..4));
assert_eq!(slot.take(), Some(4..4));
}
}