use unicode_width::UnicodeWidthChar;
pub fn elide(s: &str, max: usize) -> String {
if max == 0 {
return String::new();
}
let total: usize = s.chars().filter_map(UnicodeWidthChar::width).sum();
if total <= max {
return s.to_owned();
}
let budget = max - 1;
let mut kept = String::new();
let mut width = 0;
for ch in s.chars() {
let w = ch.width().unwrap_or(0);
if width + w > budget {
break;
}
kept.push(ch);
width += w;
}
kept.push('…');
kept
}
#[cfg(test)]
mod tests {
use super::elide;
#[test]
fn an_ascii_string_under_budget_is_untouched() {
assert_eq!(elide("hello", 10), "hello");
}
#[test]
fn an_ascii_string_over_budget_is_cut_and_marked() {
assert_eq!(elide("hello world", 8), "hello w…");
}
#[test]
fn a_wide_glyph_string_is_cut_by_display_width_not_char_count() {
assert_eq!(elide("你好世界", 5), "你好…");
}
#[test]
fn a_wide_glyph_under_budget_is_untouched() {
assert_eq!(elide("你好", 4), "你好");
}
#[test]
fn zero_budget_elides_to_nothing() {
assert_eq!(elide("anything", 0), "");
}
}