#[inline]
pub fn display_width(s: &str) -> usize {
s.chars().map(char_display_width).sum()
}
pub fn char_display_width(c: char) -> usize {
use std::cmp::Ordering::*;
match c {
'\u{0000}' => 0, '\u{0001}'..='\u{001F}' | '\u{007F}' => 0,
'\u{0300}'..='\u{036F}'
| '\u{1AB0}'..='\u{1AFF}'
| '\u{1DC0}'..='\u{1DFF}'
| '\u{20D0}'..='\u{20FF}'
| '\u{FE20}'..='\u{FE2F}' => 0,
_ => match unicode_width_hint(c) {
Less => 1,
Equal | Greater => 2,
},
}
}
fn unicode_width_hint(c: char) -> std::cmp::Ordering {
match c as u32 {
0x1100..=0x115F
| 0x2329
| 0x232A
| 0x2E80..=0xA4CF
| 0xAC00..=0xD7A3
| 0xF900..=0xFAFF
| 0xFE10..=0xFE19
| 0xFE30..=0xFE6F
| 0xFF00..=0xFF60
| 0xFFE0..=0xFFE6
| 0x1F300..=0x1F64F
| 0x1F900..=0x1F9FF => std::cmp::Ordering::Greater,
_ => std::cmp::Ordering::Less,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_display_width() {
for (s, expected) in [
("hello", 5), ("你好", 4), ("á", 1), ] {
assert_eq!(display_width(s), expected);
}
}
}