src/content/docs/highlights/v0.28.md
https://github.com/ratatui/ratatui/releases/tag/v0.28.0
⚠️ See the breaking changes for this release.
Crossterm is updated to version
0.28.0, which is a
semver incompatible version with the previous version (0.27.0). Ratatui re-exports the version of
crossterm that it is compatible with under ratatui::crossterm, which can be used to avoid
incompatible versions in your dependency list.
See this issue for more information.
We have introduced a new variant to GraphType, named Bar, which is designed to draw a bar for
each point in the dataset:
let chart = Chart::new(vec![Dataset::default()
.data(&data)
.marker(symbols::Marker::Dot)
.graph_type(GraphType::Bar)]);
We added a new example which demonstrates how to use Ratatui with widgets that fetch data asynchronously.
The code is available here.
Previously, Axis::labels accepted a Vec<Span>. To make it more flexible, we have changed it to
accept a vector of any type that can be converted into a [Line] (e.g., &str, String, &Line,
Span, etc.). This means any code using conversion methods that infer the type will need to be
rewritten as follows.
- Axis::default().labels(vec!["a".into(), "b".into()])
+ Axis::default().labels(["a", "b"])
try_draw ✨We have added a new method to Terminal called try_draw, which functions similarly to
Terminal::draw but allows the render callback to be a function or closure that returns a Result
instead of nothing (()).
This makes it easier to handle fallible rendering methods using the ? operator:
terminal.try_draw(|frame| {
some_method_that_can_fail()?;
another_fallible_method()?;
Ok(())
})?;
The method returns Result::Ok with a CompletedFrame if successful, or Result::Err with the
std::io::Error that caused the failure.
terminal module private 🔒The terminal module is now private and can not be used directly. The types under this module are exported from the root of the crate.
- use ratatui::terminal::{CompletedFrame, Frame, Terminal, TerminalOptions, ViewPort};
+ use ratatui::{CompletedFrame, Frame, Terminal, TerminalOptions, ViewPort};
This simplifies the public API, making it more user-friendly for those unfamiliar with Rust's
re-exports and avoiding clashes with other modules named terminal in backend code.
get/set_cursor_position() 📍If you implement the Backend trait yourself, you need to update the implementation and add the
get/set_cursor_position methods, which indicates more clearly what about the cursor to set.
These new methods return/accept Into<Position> which can be either a Position or a (u16, u16)
tuple.
backend.set_cursor_position(Position { x: 0, y: 20 })?;
let position = backend.get_cursor_position()?;
terminal.set_cursor_position((0, 20))?;
let position = terminal.set_cursor_position()?;
You can remove the get/set_cursor methods from your implementation as they are deprecated and a
default implementation for them exists.
cell, cell_mut and index 🧩Buffer used to access elements with buf.get(x, y) or buf.get_mut(x, y). Now, we have added
support for index operators and introduced buf.cell() and buf.cell_mut() methods.
These new methods use Into<Position> for coordinates, making them easier to use and safer by
returning Option<&Cell> and Option<&mut Cell>, which helps avoid panics (yay).
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 10));
// Access cells
let cell = buf[(0, 0)];
let cell = buf[Position::new(0, 0)];
// Get symbol
let symbol = buf.cell((0, 0)).map(|cell| cell.symbol());
let symbol = buf.cell(Position::new(0, 0)).map(|cell| cell.symbol());
// Set symbol
buf[(0, 0)].set_symbol("🐀");
buf[Position::new(0, 0)].set_symbol("🐀");
buf.cell_mut((0, 0)).map(|cell| cell.set_symbol("🐀"));
buf.cell_mut(Position::new(0, 0)).map(|cell| cell.set_symbol("🐀"));
The existing get() and get_mut() methods are now marked as deprecated.
size() to area() 🔄It is just the more correct name. 🧀
Frame::size is now deprecated.
Add and AddAssign implementations ✏️You can now combine Line, Span, and Text types together while inferring their types!
let line = Span::raw("Red").red() + Span::raw("blue").blue();
let line = Line::raw("Red").red() + Span::raw("blue").blue();
let line = Line::raw("Red").red() + Line::raw("Blue").blue();
let text = Line::raw("Red").red() + Line::raw("Blue").blue();
let text = Text::raw("Red").red() + Line::raw("Blue").blue();
let mut line = Line::raw("Red").red();
line += Span::raw("Blue").blue();
let mut text = Text::raw("Red").red();
text += Line::raw("Blue").blue();
line.extend(vec![Span::raw("1"), Span::raw("2"), Span::raw("3")]);
The ToText trait no longer has a
lifetime parameter.
This change simplifies the trait and makes it easier to implement.
We have implemented new scroll_down_by(u16) and scroll_up_by(u16) methods for both ListState
and TableState, which allow you to scroll through the items by a specified number of positions.
let mut state = ListState::default();
state.select(Some(2));
state.scroll_down_by(4);
assert_eq!(state.selected, Some(6));
let mut state = TableState::default();
state.select(Some(3));
state.scroll_up_by(3);
assert_eq!(state.selected, Some(0));
You can now navigate in the Table widget by using the following methods!
let mut state = TableState::default();
state.select_first();
state.select_next();
state.select_previous();
state.select_last();
This is the equivalent API as in ListState.
We started using Bencher.dev to track benchmarks over time and easily catch any regressions.
You can view our benchmarks at https://bencher.dev/console/projects/ratatui.
For discussions about future improvements, check out the tracking issue.
We have started experimenting with
cargo-semver-checks in our CI to lint our API
for semver violations!
See the PR for related discussion.
Size from Backend::size instead of Rect
(#1254)Layout cache
(#1245)
Layout::init_cache no longer returns bool and takes a NonZeroUsize instead of usizeLines
(#1237)List &
Table(#1244 &
#1242)Size::ZERO and Position::ORIGIN constants to Layout
(#1253)Margin, Position, Rect and Size
(#1255)TestBackend (changes the serde representation)
(#1252)Chart
(#1282)Line
(#1247)"If you are what you eat, then I only want to eat the good stuff." – Remy