From 05d24de73148e3ea82c7e7f1c8ee298617bb0d47 Mon Sep 17 00:00:00 2001 From: Andrew Schneider Date: Wed, 21 Jul 2021 10:30:20 -0700 Subject: [PATCH] Fix for table panic Initial fix for issue #470 --- CHANGELOG.md | 5 ++++ Cargo.toml | 2 +- src/buffer.rs | 4 ++- tests/widgets_table.rs | 63 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da5085cb..26900265 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## To be released +### Fixes + +* Some combinations of `Table` widths and `Rect` width would cause a panic due to accessing area +outside the buffer - (#470) + ## v0.15.0 - 2021-05-02 ### Features diff --git a/Cargo.toml b/Cargo.toml index 8eb85fa7..cd9c705e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tui" -version = "0.15.0" +version = "0.15.1" authors = ["Florian Dehau "] description = """ A library to build rich terminal user interfaces or dashboards diff --git a/src/buffer.rs b/src/buffer.rs index 14699d83..87eaae9b 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -353,8 +353,10 @@ impl Buffer { } pub fn set_style(&mut self, area: Rect, style: Style) { + // Ensure styling doesn't overflow buffer - https://github.com/fdehau/tui-rs/issues/470 + let right = min(area.right(), self.area.width); for y in area.top()..area.bottom() { - for x in area.left()..area.right() { + for x in area.left()..right { self.get_mut(x, y).set_style(style); } } diff --git a/tests/widgets_table.rs b/tests/widgets_table.rs index f71169c1..9a354fcc 100644 --- a/tests/widgets_table.rs +++ b/tests/widgets_table.rs @@ -715,3 +715,66 @@ fn widgets_table_should_render_even_if_empty() { terminal.backend().assert_buffer(&expected); } + +/// Testing fix for https://github.com/fdehau/tui-rs/issues/470 +#[test] +fn widgets_table_columns_dont_panic() { + let test_case = |state: &mut TableState, table: Table, width: u16| { + let backend = TestBackend::new(width, 8); + let mut terminal = Terminal::new(backend).unwrap(); + terminal + .draw(|f| { + let size = f.size(); + f.render_stateful_widget(table, size, state); + }) + .unwrap(); + }; + + // based on https://github.com/fdehau/tui-rs/issues/470#issuecomment-852562848 + let table1_width = 98; + let table1 = Table::new(vec![Row::new(vec!["r1", "r2", "r3", "r4"])]) + .header(Row::new(vec!["h1", "h2", "h3", "h4"])) + .block(Block::default().borders(Borders::ALL)) + .highlight_symbol(">> ") + .column_spacing(1) + .widths(&[ + Constraint::Percentage(15), + Constraint::Percentage(15), + Constraint::Percentage(25), + Constraint::Percentage(45), + ]); + + // based on https://github.com/fdehau/tui-rs/issues/470#issuecomment-831171722 + let table2_width = 189; + let table2 = Table::new(vec![Row::new(vec![ + "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + ])]) + .header(Row::new(vec![ + "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "h9", "h10", + ])) + .block(Block::default().borders(Borders::TOP)) + .highlight_style(Style::default().add_modifier(Modifier::REVERSED)) + .highlight_symbol("=>") + .widths(&[ + Constraint::Percentage(30), + Constraint::Percentage(10), + Constraint::Percentage(15), + Constraint::Percentage(10), + Constraint::Percentage(5), + Constraint::Percentage(5), + Constraint::Percentage(5), + Constraint::Percentage(5), + Constraint::Percentage(5), + Constraint::Percentage(10), + ]); + + let mut state = TableState::default(); + // no selection, no panic + test_case(&mut state, table1.clone(), table1_width); + test_case(&mut state, table2.clone(), table2_width); + + // select first, which would cause a panic before fix + state.select(Some(0)); + test_case(&mut state, table1.clone(), table1_width); + test_case(&mut state, table2.clone(), table2_width); +}