use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
pub fn ch_width(c: char) -> usize {
UnicodeWidthChar::width(c).unwrap_or(0)
}
pub fn str_width(s: &str) -> usize {
UnicodeWidthStr::width(s)
}
pub fn wrap_line(s: &str, width: usize) -> Vec<String> {
let width = width.max(1);
let mut lines = Vec::new();
for logical in s.split('\n') {
let mut cur = String::new();
let mut cur_len = 0usize;
for word in logical.split_inclusive(' ') {
let wlen = word.chars().count();
if cur_len + wlen > width && cur_len > 0 {
lines.push(std::mem::take(&mut cur));
cur_len = 0;
}
if wlen > width {
for ch in word.chars() {
if cur_len == width {
lines.push(std::mem::take(&mut cur));
cur_len = 0;
}
cur.push(ch);
cur_len += 1;
}
} else {
cur.push_str(word);
cur_len += wlen;
}
}
lines.push(cur);
}
lines
}
#[cfg(test)]
mod tests {
use super::{ch_width, str_width};
#[test]
fn a_cjk_string_measures_in_cells_not_chars_or_bytes() {
assert_eq!(str_width("日本"), 4);
assert_eq!("日本".chars().count(), 2, "the char count is NOT the width");
assert_eq!("日本".len(), 6, "and neither is the byte count");
assert_eq!(ch_width('日'), 2);
assert_eq!(ch_width('\u{0301}'), 0);
}
}