fix(list): saturating_sub to fix highlight_symbol overflow (#949)

An overflow (pedantically an underflow) can occur if the
highlight_symbol is a multi-byte char, and area is reduced to a size
less than that char length.
This commit is contained in:
Jack Wills 2024-03-16 22:58:39 +00:00 committed by GitHub
parent 078e97e4ff
commit c56f49b9fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -973,7 +973,7 @@ impl StatefulWidgetRef for List<'_> {
let highlight_symbol_width = self.highlight_symbol.unwrap_or("").width() as u16;
Rect {
x: row_area.x + highlight_symbol_width,
width: row_area.width - highlight_symbol_width,
width: row_area.width.saturating_sub(highlight_symbol_width),
..row_area
}
} else {
@ -1046,7 +1046,7 @@ mod tests {
use std::borrow::Cow;
use pretty_assertions::assert_eq;
use rstest::rstest;
use rstest::{fixture, rstest};
use super::*;
use crate::{assert_buffer_eq, widgets::Borders};
@ -2234,4 +2234,30 @@ mod tests {
" ",
]));
}
#[fixture]
fn single_line_buf() -> Buffer {
Buffer::empty(Rect::new(0, 0, 10, 1))
}
/// Regression test for a bug where highlight symbol being greater than width caused a panic due
/// to subtraction with underflow.
///
/// See [#949](https://github.com/ratatui-org/ratatui/pull/949) for details
#[rstest]
#[case::under(">>>>", "Item1", ">>>>Item1 ")] // enough space to render the highlight symbol
#[case::exact(">>>>>", "Item1", ">>>>>Item1")] // exact space to render the highlight symbol
#[case::overflow(">>>>>>", "Item1", ">>>>>>Item")] // not enough space
fn highlight_symbol_overflow(
#[case] highlight_symbol: &str,
#[case] item: &str,
#[case] expected: &str,
mut single_line_buf: Buffer,
) {
let list = List::new(vec![item]).highlight_symbol(highlight_symbol);
let mut state = ListState::default();
state.select(Some(0));
StatefulWidget::render(list, single_line_buf.area, &mut single_line_buf, &mut state);
assert_buffer_eq!(single_line_buf, Buffer::with_lines(vec![expected]));
}
}