fix: fix handling of multi-byte chars in bar chart (#1934)

The split_at method requires that the split point is at a valid utf8
character boundary.

Fixes: https://github.com/ratatui/ratatui/issues/1928
This commit is contained in:
Josh McKinney 2025-06-25 00:55:18 -07:00 committed by GitHub
parent ca2ad4a1f9
commit 21e3b598ce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 38 additions and 0 deletions

View File

@ -1441,4 +1441,35 @@ mod tests {
assert_eq!(updated_chart.data.len(), 2);
assert_eq!(updated_chart.data[1].bars, [Bar::with_label("Blue", 3)]);
}
/// Regression test for issue <https://github.com/ratatui/ratatui/issues/1928>
///
/// This test ensures that the `BarChart` doesn't panic when rendering text labels with
/// multi-byte characters in the bar labels.
#[test]
fn regression_1928() {
let text_value = "\u{202f}"; // Narrow No-Break Space
let bars = [
Bar::default().text_value(text_value).value(0),
Bar::default().text_value(text_value).value(1),
Bar::default().text_value(text_value).value(2),
Bar::default().text_value(text_value).value(3),
Bar::default().text_value(text_value).value(4),
];
let chart = BarChart::default()
.data(BarGroup::default().bars(&bars))
.bar_gap(0)
.direction(Direction::Horizontal);
let mut buffer = Buffer::empty(Rect::new(0, 0, 4, 5));
chart.render(buffer.area, &mut buffer);
#[rustfmt::skip]
let expected = Buffer::with_lines([
"\u{202f} ",
"\u{202f} ",
"\u{202f}",
"\u{202f}██ ",
"\u{202f}███",
]);
assert_eq!(buffer, expected);
}
}

View File

@ -216,6 +216,13 @@ impl<'a> Bar<'a> {
buf.set_stringn(area.x, area.y, text, bar_length, style);
// render the second part with the bar_style
if text.len() > bar_length {
// Find the last character boundary at or before bar_length
let bar_length = text
.char_indices()
.take_while(|(i, _)| *i < bar_length)
.last()
.map_or(0, |(i, c)| i + c.len_utf8());
let (first, second) = text.split_at(bar_length);
let style = bar_style.patch(self.style);