pub(super) fn flush_sentences(buffer: &mut String, segments: &mut Vec<String>) {
loop {
let boundary = buffer.char_indices().position(|(i, ch)| {
if matches!(ch, '。' | '!' | '?') {
true
} else if matches!(ch, '.' | '!' | '?') {
let after = i + ch.len_utf8();
after >= buffer.len() || buffer[after..].starts_with(|c: char| c.is_whitespace())
} else {
false
}
});
let Some(pos) = boundary else {
break;
};
let (byte_offset, punct_char) = buffer.char_indices().nth(pos).unwrap_or((0, '.'));
let split_at = byte_offset + punct_char.len_utf8();
let sentence = buffer[..split_at].trim().to_string();
if !sentence.is_empty() {
println!("{}", sentence);
segments.push(sentence);
}
let remainder = buffer[split_at..].trim_start().to_string();
let blank = " ".repeat(buffer.len());
eprint!("\r{}\r", blank);
*buffer = remainder;
if !buffer.is_empty() {
eprint!("\r{}", buffer);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_flush_sentences_single_sentence() {
let mut buf = "Hello world.".to_string();
let mut segs: Vec<String> = Vec::new();
flush_sentences(&mut buf, &mut segs);
assert_eq!(segs, vec!["Hello world."]);
assert_eq!(buf, "");
}
#[test]
fn test_flush_sentences_trailing_partial() {
let mut buf = "First sentence. And then".to_string();
let mut segs: Vec<String> = Vec::new();
flush_sentences(&mut buf, &mut segs);
assert_eq!(segs, vec!["First sentence."]);
assert_eq!(buf, "And then");
}
#[test]
fn test_flush_sentences_multiple() {
let mut buf = "One. Two! Three? Rest".to_string();
let mut segs: Vec<String> = Vec::new();
flush_sentences(&mut buf, &mut segs);
assert_eq!(segs, vec!["One.", "Two!", "Three?"]);
assert_eq!(buf, "Rest");
}
#[test]
fn test_flush_sentences_no_punctuation() {
let mut buf = "no punctuation here".to_string();
let mut segs: Vec<String> = Vec::new();
flush_sentences(&mut buf, &mut segs);
assert!(segs.is_empty());
assert_eq!(buf, "no punctuation here");
}
#[test]
fn test_flush_sentences_chinese_punctuation() {
let mut buf = "你好。世界".to_string();
let mut segs: Vec<String> = Vec::new();
flush_sentences(&mut buf, &mut segs);
assert_eq!(segs, vec!["你好。"]);
assert_eq!(buf, "世界");
}
#[test]
fn test_flush_sentences_period_at_end() {
let mut buf = "End of text.".to_string();
let mut segs: Vec<String> = Vec::new();
flush_sentences(&mut buf, &mut segs);
assert_eq!(segs, vec!["End of text."]);
assert_eq!(buf, "");
}
}