use unicode_width::UnicodeWidthChar;
const ZERO_WIDTH_SPACE: char = '\u{200b}';
pub fn vanishes(before: char, after: char) -> bool {
before == ZERO_WIDTH_SPACE
|| after == ZERO_WIDTH_SPACE
|| (is_east_asian_wide(before) && is_east_asian_wide(after))
}
fn is_east_asian_wide(ch: char) -> bool {
let halfwidth = matches!(ch, '\u{20a9}' | '\u{ff61}'..='\u{ff9f}' | '\u{ffe8}'..='\u{ffee}');
(halfwidth || ch.width() == Some(2)) && !is_hangul(ch)
}
fn is_hangul(ch: char) -> bool {
matches!(
ch,
'\u{1100}'..='\u{11ff}'
| '\u{302e}'..='\u{302f}'
| '\u{3130}'..='\u{318f}'
| '\u{3200}'..='\u{321e}'
| '\u{3260}'..='\u{327e}'
| '\u{a960}'..='\u{a97f}'
| '\u{ac00}'..='\u{d7ff}'
| '\u{ffa0}'..='\u{ffdc}'
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_break_between_cjk_glyphs_vanishes() {
for (before, after) in [
('の', 'リ'),
('語', '、'),
('。', '中'),
('ア', 'イ'),
('文', 'A'),
] {
assert!(vanishes(before, after), "{before:?} {after:?}");
}
}
#[test]
fn a_break_beside_latin_or_hangul_stays_a_space() {
for (before, after) in [
('の', 'a'),
('a', 'の'),
('a', 'b'),
('어', '문'),
('の', '한'),
('ᄀ', 'ア'),
('の', ' '),
('の', '“'),
] {
assert!(!vanishes(before, after), "{before:?} {after:?}");
}
}
#[test]
fn a_break_beside_a_zero_width_space_vanishes() {
assert!(vanishes('a', ZERO_WIDTH_SPACE));
assert!(vanishes(ZERO_WIDTH_SPACE, 'b'));
}
}