use unicode_width::UnicodeWidthChar;
pub fn truncate_to_width(s: &str, max_width: usize) -> String {
if max_width == 0 {
return String::new();
}
let total_width: usize = s
.chars()
.map(|ch| UnicodeWidthChar::width(ch).unwrap_or(0))
.sum();
if total_width <= max_width {
return s.to_string();
}
let target = max_width.saturating_sub(1);
let mut width = 0usize;
let mut end = 0usize;
for (i, ch) in s.char_indices() {
let cw = UnicodeWidthChar::width(ch).unwrap_or(0);
if width + cw > target {
break;
}
width += cw;
end = i + ch.len_utf8();
}
format!("{}\u{2026}", &s[..end])
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_truncate_to_width() {
let text = "hello world";
assert_eq!(truncate_to_width(text, 100), "hello world");
assert_eq!(truncate_to_width(text, 5), "hell…");
assert_eq!(truncate_to_width(text, 0), "");
assert_eq!(truncate_to_width("hello", 5), "hello");
assert_eq!(truncate_to_width("abc", 3), "abc");
assert_eq!(truncate_to_width("ABCD", 4), "ABCD");
assert_eq!(truncate_to_width("ABCDEFGH", 5), "ABCD…");
}
}