pub(crate) fn rendered_height(output: &str, width: usize) -> usize {
let mut lines: Vec<&str> = output.split('\n').collect();
lines.pop();
lines.iter().map(|line| rows_for(line, width)).sum()
}
pub(crate) fn rendered_rows(output: &str, width: usize) -> usize {
output.split('\n').map(|line| rows_for(line, width)).sum()
}
fn rows_for(line: &str, width: usize) -> usize {
let printed = console::measure_text_width(line);
if width == 0 || printed <= width {
1
} else {
printed.div_ceil(width)
}
}
#[cfg(test)]
mod tests {
use super::rendered_height;
#[test]
fn drops_the_trailing_reset_fragment() {
assert_eq!(rendered_height("title\noption\n\x1b[0m", 80), 2);
}
#[test]
fn counts_a_line_that_fits_as_one_row() {
assert_eq!(rendered_height("12345678\n\x1b[0m", 8), 1);
}
#[test]
fn counts_the_rows_an_over_wide_line_wraps_into() {
assert_eq!(rendered_height("123456789\n\x1b[0m", 8), 2);
assert_eq!(
rendered_height(&format!("{}\n\x1b[0m", "x".repeat(17)), 8),
3
);
}
#[test]
fn measures_printed_width_not_byte_length() {
let colored = format!("\x1b[38;5;252m{}\x1b[0m\n\x1b[0m", "x".repeat(8));
assert_eq!(rendered_height(&colored, 8), 1);
}
#[test]
fn treats_zero_width_as_one_row_per_line() {
assert_eq!(rendered_height("aaaa\nbbbb\n\x1b[0m", 0), 2);
}
#[test]
fn rendered_rows_counts_a_frame_the_cursor_sits_inside() {
use super::rendered_rows;
assert_eq!(rendered_height("/ Loading", 80), 0);
assert_eq!(rendered_rows("/ Loading", 80), 1);
assert_eq!(rendered_rows(&format!("/ {}", "x".repeat(100)), 80), 2);
}
}