fix(text): fix panic when rendering out of bounds (#997)

Previously it was possible to cause a panic when rendering to an area
outside of the buffer bounds. Instead this now correctly renders nothing
to the buffer.
This commit is contained in:
Josh McKinney
2024-03-24 22:06:31 -07:00
committed by GitHub
parent 8719608bda
commit 742a5ead06
3 changed files with 43 additions and 0 deletions

View File

@@ -587,6 +587,11 @@ mod tests {
use super::*;
#[fixture]
fn small_buf() -> Buffer {
Buffer::empty(Rect::new(0, 0, 10, 1))
}
#[test]
fn raw_str() {
let line = Line::raw("test content");
@@ -832,6 +837,7 @@ mod tests {
const GREEN: Style = Style::new().fg(Color::Green);
const ITALIC: Style = Style::new().add_modifier(Modifier::ITALIC);
#[fixture]
fn hello_world() -> Line<'static> {
Line::from(vec![
Span::styled("Hello ", BLUE),
@@ -851,6 +857,13 @@ mod tests {
assert_buffer_eq!(buf, expected);
}
#[rstest]
fn render_out_of_bounds(hello_world: Line<'static>, mut small_buf: Buffer) {
let out_of_bounds = Rect::new(20, 20, 10, 1);
hello_world.render(out_of_bounds, &mut small_buf);
assert_buffer_eq!(small_buf, Buffer::empty(small_buf.area));
}
#[test]
fn render_only_styles_line_area() {
let mut buf = Buffer::empty(Rect::new(0, 0, 20, 1));

View File

@@ -363,6 +363,7 @@ impl Widget for Span<'_> {
impl WidgetRef for Span<'_> {
fn render_ref(&self, area: Rect, buf: &mut Buffer) {
let area = area.intersection(buf.area);
let Rect {
x: mut current_x,
y,
@@ -402,8 +403,15 @@ impl std::fmt::Display for Span<'_> {
#[cfg(test)]
mod tests {
use rstest::fixture;
use super::*;
#[fixture]
fn small_buf() -> Buffer {
Buffer::empty(Rect::new(0, 0, 10, 1))
}
#[test]
fn default() {
let span = Span::default();
@@ -533,6 +541,8 @@ mod tests {
}
mod widget {
use rstest::rstest;
use super::*;
use crate::assert_buffer_eq;
@@ -550,6 +560,13 @@ mod tests {
assert_buffer_eq!(buf, expected);
}
#[rstest]
fn render_out_of_bounds(mut small_buf: Buffer) {
let out_of_bounds = Rect::new(20, 20, 10, 1);
Span::raw("Hello, World!").render(out_of_bounds, &mut small_buf);
assert_eq!(small_buf, Buffer::empty(small_buf.area));
}
/// When the content of the span is longer than the area passed to render, the content
/// should be truncated
#[test]

View File

@@ -559,6 +559,7 @@ impl Widget for Text<'_> {
impl WidgetRef for Text<'_> {
fn render_ref(&self, area: Rect, buf: &mut Buffer) {
let area = area.intersection(buf.area);
buf.set_style(area, self.style);
for (line, row) in self.iter().zip(area.rows()) {
let line_width = line.width() as u16;
@@ -601,6 +602,11 @@ mod tests {
use super::*;
#[fixture]
fn small_buf() -> Buffer {
Buffer::empty(Rect::new(0, 0, 10, 1))
}
#[test]
fn raw() {
let text = Text::raw("The first line\nThe second line");
@@ -865,6 +871,13 @@ mod tests {
assert_buffer_eq!(buf, expected_buf);
}
#[rstest]
fn render_out_of_bounds(mut small_buf: Buffer) {
let out_of_bounds_area = Rect::new(20, 20, 10, 1);
Text::from("Hello, world!").render(out_of_bounds_area, &mut small_buf);
assert_eq!(small_buf, Buffer::empty(small_buf.area));
}
#[test]
fn render_right_aligned() {
let text = Text::from("foo").alignment(Alignment::Right);