The context of the answer was:
On a sidenote, I wonder why it was never considered to use Frame instead of Buffer as argument to render().
Basically historical reasons
Ratatui didn’t pop into being as Ratatui, it was a fork of tui-rs which came before it. I only got involved in Ratatui after the fork happened so I don’t have much insight into why certain choices were made, and they likely made sense at the time. To understand them I’d recommend digging into the commit and PR history of the original repo.
Widgets would be implement multiple methods for layout, handling events, rendering,
Much of my thinking on this comes from Announcing Masonry 0.1, and my vision for Rust UI · PoignardAzur as well as pretty much everything in https://raphlinus.github.io/ and other related Xilem blogs (| Homepage for the Linebender organization). It would be difficult to summarize all that other than to say that using Widget
as a simple function that takes an area and a buffer and writes things is really anemic. It focuses heavily on just one portion of the output side of a UI, and ignores layout, interaction with events, and user interaction. Likely the missing pieces look like extra methods on traits to implement those parts. But there’s lots of prior art in this area. In particular a redesigned TUI should draw heavily from BubbleTea and Textualize, but bear in mind that Rust’s borrow checker plays a part in designing things and such a redesign should look to egui, imgui, dioxus, etc. for inspiration on various things too. There’d likely still be a Widget trait, and there’d be a much greater focus on the compositional ideas (containers, grids, flex layout etc)
Widget methods would have access to a context that helps them play nicely with each other
The context on this statement is that one of the things that is a problem for the current widget trait is that it’s difficult to improve and add cross cutting functionality to. This is due to the limited parameters - a buffer and an area. If instead of these parameters we had a WidgetContext
or RenderContext
struct, then we’d be able to add more fields as they become necessary. E.g. event related fields, layout related fields, application context. This would allow such ideas as performing a layout step for all widgets first, working out the area that the widget will be drawn into based on all the other various parts of state, and then in another method doing the actual drawing based on the previous calculations.
Buffer would be a trait, to make it possible to give portions of a frame to write to instead of the entire frame
One of the things this opens up is that buffers can now be implemented in a way where the backing store of the buffer is not just a contiguous vector. Maybe we want that to be an ndarray for some performance reason. Maybe we want that to be implemented in a way where writes are a passthrough for some areas and noop for others. E.g., tui-scrollview currently has to allocate a full sized buffer and then copy the region that is displayed. Instead it might be nice to just ignore anything not currently being displayed and write directly to the actual buffer. Ndarray types allow mutable views onto regions of a larger array, which if we reimplemented buffer on top of that could make it impossible for widgets to draw outside of their specific allocated space (right now they don’t have to respect the area parameter at all).
A bunch of other things.
I don’t have a good list of what these other things are. But they’re mainly around making Ratatui a more full app development framework rather than a library. The answer to this basically comes down to looking at other TUI frameworks and seeing what parts are easy that are difficult in Ratatui, and then working backwards from that to work out what we’d need to make a Rust TUI as easy to do the same things. Do this enough times and you’ll build up a good list of redesignable parts in Ratatui.
I hope this helps understand that post a bit better.
Something that I find also helps in thinking about these things is to sit down with ChatGPT (or your LLM of choice) and LLMsplain up a design of a TUI framework from first principles. LLMs are good at telling you obvious things in simple ways, which makes them sometimes good for validating what is the right way that something should work. I’ve often seen them hallucinate a method or struct name that looks right and would be a better name / design / approach than the actual design. Do this enough times and you’ll get a simple and obvious framework that works closer to how people might expect it to than you might imagine upfront.