use unicode_width::UnicodeWidthStr;
pub fn display_width(s: &str) -> usize {
UnicodeWidthStr::width(s)
}
pub fn truncate_to_width(s: &str, max_width: usize) -> String {
let width = display_width(s);
if width <= max_width {
return s.to_string();
}
if max_width == 0 {
return String::new();
}
if max_width == 1 {
return "…".to_string();
}
let target_width = max_width - 1;
let mut result = String::new();
let mut current_width = 0;
for c in s.chars() {
let char_width = unicode_width::UnicodeWidthChar::width(c).unwrap_or(0);
if current_width + char_width > target_width {
break;
}
result.push(c);
current_width += char_width;
}
result.push('…');
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_display_width_ascii() {
assert_eq!(display_width("hello"), 5);
assert_eq!(display_width(""), 0);
assert_eq!(display_width("a"), 1);
}
#[test]
fn test_display_width_unicode() {
assert_eq!(display_width("日本語"), 6);
assert_eq!(display_width("🚀"), 2);
}
#[test]
fn test_display_width_mixed() {
assert_eq!(display_width("hello世界"), 9); }
#[test]
fn test_truncate_to_width_no_truncation() {
assert_eq!(truncate_to_width("hello", 10), "hello");
assert_eq!(truncate_to_width("hello", 5), "hello");
}
#[test]
fn test_truncate_to_width_basic() {
assert_eq!(truncate_to_width("hello world", 8), "hello w…");
}
#[test]
fn test_truncate_to_width_edge_cases() {
assert_eq!(truncate_to_width("hello", 0), "");
assert_eq!(truncate_to_width("hello", 1), "…");
assert_eq!(truncate_to_width("hello", 2), "h…");
}
#[test]
fn test_truncate_to_width_unicode() {
let result = truncate_to_width("日本語", 4);
assert!(display_width(&result) <= 4);
}
}