use super::{Overflow, Text};
use crate::utils::spans::spans_width;
pub(crate) use crate::utils::spans::split_spans_on_newlines;
pub fn measure_text_constrained(text: &Text, max_w: Option<u16>) -> (u16, u16) {
let wrap_width = if matches!(text.overflow, Overflow::Wrap | Overflow::Auto) {
max_w
} else {
None
};
let logical_lines = split_spans_on_newlines(&text.spans);
let mut max_line_w = 0usize;
let mut total_h = 0usize;
for logical_line in &logical_lines {
let logical_w = spans_width(logical_line);
max_line_w = max_line_w.max(logical_w);
match wrap_width {
Some(ww) if ww > 0 => {
let wrapped = crate::utils::text::wrap_spans_for_budgets(logical_line, ww, ww);
total_h += wrapped.len();
}
Some(_) => {
}
None => {
total_h += 1;
}
}
}
let width = max_w
.map(|w| max_line_w.min(w as usize))
.unwrap_or(max_line_w);
let h = total_h.max(1).min(u16::MAX as usize) as u16;
let w = width.min(u16::MAX as usize) as u16;
(w, h)
}
#[cfg(test)]
mod tests {
use crate::style::Span;
use crate::widgets::{Overflow, Text};
use super::measure_text_constrained;
#[test]
fn measures_newlines_across_span_boundaries() {
let text = Text::from_spans([Span::from("ab"), Span::from("\ncd")]);
assert_eq!(measure_text_constrained(&text, None), (2, 2));
}
#[test]
fn measurement_skips_control_characters() {
let text = Text::new("a\0\u{7}b");
assert_eq!(measure_text_constrained(&text, None), (2, 1));
}
#[test]
fn wraps_across_span_boundaries_without_flattening() {
let text =
Text::from_spans([Span::from("hello "), Span::from("world")]).overflow(Overflow::Wrap);
assert_eq!(measure_text_constrained(&text, Some(8)), (8, 2));
}
#[test]
fn wraps_at_slash_break_char() {
let text = Text::new("foo/bar/baz").overflow(Overflow::Wrap);
assert_eq!(measure_text_constrained(&text, Some(5)), (5, 3));
}
#[test]
fn wraps_at_dot_break_char() {
let text = Text::new("src.widgets.text").overflow(Overflow::Wrap);
assert_eq!(measure_text_constrained(&text, Some(6)), (6, 3));
}
#[test]
fn long_word_force_breaks() {
let text = Text::new("abcdefghij").overflow(Overflow::Wrap);
assert_eq!(measure_text_constrained(&text, Some(4)), (4, 3));
}
#[test]
fn wraps_wide_characters_correctly() {
let text = Text::new("你好世界").overflow(Overflow::Wrap);
assert_eq!(measure_text_constrained(&text, Some(5)), (5, 2));
assert_eq!(measure_text_constrained(&text, Some(3)), (3, 4));
}
}