use ratatui::text::Line; use ratatui::text::Span; use unicode_width::UnicodeWidthChar; use unicode_width::UnicodeWidthStr; pub(crate) fn line_width(line: &Line<'_>) -> usize { line.iter() .map(|span| UnicodeWidthStr::width(span.content.as_ref())) .sum() } pub(crate) fn truncate_line_to_width(line: Line<'static>, max_width: usize) -> Line<'static> { if max_width == 0 { return Line::from(Vec::>::new()); } let Line { style, alignment, spans, } = line; let mut used = 0usize; let mut spans_out: Vec> = Vec::with_capacity(spans.len()); for span in spans { let span_width = UnicodeWidthStr::width(span.content.as_ref()); if span_width == 0 { spans_out.push(span); continue; } if used >= max_width { break; } if used + span_width <= max_width { used += span_width; spans_out.push(span); continue; } let style = span.style; let text = span.content.as_ref(); let mut end_idx = 0usize; for (idx, ch) in text.char_indices() { let ch_width = UnicodeWidthChar::width(ch).unwrap_or(0); if used + ch_width > max_width { break; } end_idx = idx + ch.len_utf8(); used += ch_width; } if end_idx > 0 { spans_out.push(Span::styled(text[..end_idx].to_string(), style)); } break; } Line { style, alignment, spans: spans_out, } } /// Truncate a styled line to `max_width` and append an ellipsis on overflow. /// /// Intended for short UI rows. This preserves a fast no-overflow path (width /// pre-scan + return original line unchanged) and uses `truncate_line_to_width` /// for the overflow case. /// Performance should be reevaluated if using this method in loops/over larger content in the future. pub(crate) fn truncate_line_with_ellipsis_if_overflow( line: Line<'static>, max_width: usize, ) -> Line<'static> { if max_width == 0 { return Line::from(Vec::>::new()); } if line_width(&line) <= max_width { return line; } let truncated = truncate_line_to_width(line, max_width.saturating_sub(1)); let Line { style, alignment, mut spans, } = truncated; let ellipsis_style = spans.last().map(|span| span.style).unwrap_or_default(); spans.push(Span::styled("…", ellipsis_style)); Line { style, alignment, spans, } }