use crate::helpers::string_helper::is_chinese_or_japanese_character;
use crate::models::{FullSyllableInfo, LineInfo, SyllableInfo, SyllableItem};
pub fn merge(line: &mut LineInfo) {
let Some(syllables) = line.syllables_mut() else {
return;
};
if syllables.len() < 2 {
return;
}
let mut merged: Vec<SyllableItem> = Vec::with_capacity(syllables.len());
for current in syllables.drain(..) {
match merged.pop() {
Some(previous) if should_merge(&previous, ¤t) => {
merged.push(merge_items(previous, current));
}
Some(previous) => {
merged.push(previous);
merged.push(current);
}
None => merged.push(current),
}
}
*syllables = merged;
}
fn chars_of(item: &SyllableItem) -> impl DoubleEndedIterator<Item = char> + '_ {
item.parts().iter().flat_map(|part| part.text.chars())
}
fn should_merge(previous: &SyllableItem, current: &SyllableItem) -> bool {
let (Some(previous_last), Some(current_first)) =
(chars_of(previous).next_back(), chars_of(current).next())
else {
return false;
};
if previous_last.is_whitespace() || current_first.is_whitespace() {
return false;
}
if chars_of(previous).any(is_chinese_or_japanese_character)
|| chars_of(current).any(is_chinese_or_japanese_character)
{
return false;
}
chars_of(previous).any(char::is_alphanumeric) && chars_of(current).any(char::is_alphanumeric)
}
fn merge_items(previous: SyllableItem, current: SyllableItem) -> SyllableItem {
let current_items = into_parts(current);
match previous {
SyllableItem::Full(mut full_previous) => {
full_previous.extend_sub_items(current_items);
SyllableItem::Full(full_previous)
}
other => {
let mut items = into_parts(other);
items.extend(current_items);
SyllableItem::Full(FullSyllableInfo::new(items))
}
}
}
fn into_parts(item: SyllableItem) -> Vec<SyllableInfo> {
match item {
SyllableItem::Syllable(syllable) => vec![syllable],
SyllableItem::Full(full) => full.into_sub_items(),
}
}