RSX-based interface to reduce boilerplate code
d4h0 opened this issue · comments
Problem
Hi,
I'm wondering if it would be possible to add an RSX-based interface (i.e., an HTML-like macro) to reduce boilerplate code.
Solution
In case you are not aware of it, there is the rstml
crate which could do most of the heavy lifting (rstml
is a fork of syn-rsx
whose maintainer unfortunately passed away).
Alternatives
None, just continuing to write a lot of boilerplate code.
Additional context
Here is a list of the features that rstml
offers and how it would look like.
rstml
is used by leptos
so also should be good for ratatui
.
PS: Whoever came up with the name ratatui
is a genius..! :D
Edit:
Here is how RSX could improve the ergonomics of ratatui
(taken from my comment below):
Let's take the following example from the README:
use ratatui::{prelude::*, widgets::*};
fn ui(frame: &mut Frame) {
let main_layout = Layout::new(
Direction::Vertical,
[
Constraint::Length(1),
Constraint::Min(0),
Constraint::Length(1),
],
)
.split(frame.size());
frame.render_widget(
Block::new().borders(Borders::TOP).title("Title Bar"),
main_layout[0],
);
frame.render_widget(
Block::new().borders(Borders::TOP).title("Status Bar"),
main_layout[2],
);
let inner_layout = Layout::new(
Direction::Horizontal,
[Constraint::Percentage(50), Constraint::Percentage(50)],
)
.split(main_layout[1]);
frame.render_widget(
Block::bordered().title("Left"),
inner_layout[0],
);
frame.render_widget(
Block::bordered().title("Right"),
inner_layout[1],
);
}
With JSX it could look like this:
(Please note, that I haven't used ratatui
yet, so the following might not make complete sense. However, something similar to it seems possible)
use ratatui::{prelude::*, widgets::*};
fn ui(frame: &mut Frame) {
rsx! {
<VLayout split=frame.size()>
<Block title="Title Bar" border:top length=1><Block>
<HLayout min=0 split:available>
<Block title="Left" border></Block>
<Block title="Right" border></Block>
</HLayout>
<Block title="Status Bar" length=1><Block>
</VLayout>
}
}
And again with some comments:
use ratatui::{prelude::*, widgets::*};
fn ui(frame: &mut Frame) {
rsx! {
<VLayout split=frame.size()>
// Or `<VerticalLayout>` but I like short names like `<VLayout>` more
<Block title="Title Bar" border:top length=1>
// Note: `border:top` is a boolean property and a shorthand for
// `border:top=true`. The `:` is just for namespacing (so could
// also be `border_top`).
// Note: the `main_layout[0]` is here defined by the order of the RSX elements
<Block>
<HLayout min=0 split:available>
// Note: `split:available` is the replacement for `.split(main_layout[1])`.
// The meaning is "split the available space". Not sure if that makes sense.
// There most-likely also should be a `split=whatever` attribute, to specify
// custom values.
<Block title="Left" border></Block>
<Block title="Right" border></Block>
// Note: `border`, of course, also could be `bordered`. For consistency I'd
// prefer `border`, however.
</HLayout>
<Block title="Status Bar" length=1><Block>
</VLayout>
}
}
Much nicer, isn't it..?
To be honest, I'm not a big fan of macros and HTML-like syntax - however, I'm even less a fan of writing a lot of unnecessary boilerplate code.
I seriously think, adding RSX would take ratatui
to the next level.
I've been following tui.rs
/ratatui
already many years, but I have never used it - mostly because it seems incredibly unergonomic to use (compared to how ergonomic it could be). It just always seemed easier to build a simple web application (e.g., for personal tools), however, I really like the idea of TUI applications.
PS: Whoever came up with the name
ratatui
is a genius..! :D
That was @sayanarijit in #72.
I'm wondering if it would be possible to add an RSX-based interface (i.e., an HTML-like macro) to reduce boilerplate code.
There's a few things we've experimented with in https://github.com/ratatui-org/ratatui-macros (for line, span, text, as well as constraints / layout). I suspect we'll probably bring the line/span/text stuff into ratatui core at some point in the next few releases.
Do you have any ideas about what an RSX-based approach might look from a syntax perspective?
PS: Whoever came up with the name ratatui is a genius..! :D
That was @sayanarijit in #72.
Good job, @sayanarijit!
There's a few things we've experimented with in https://github.com/ratatui-org/ratatui-macros (for line, span, text, as well as constraints / layout).
Yes, I saw those already (which I should have mentioned), but unfortunately, I believe this isn't going far enough.
Do you have any ideas about what an RSX-based approach might look from a syntax perspective?
Sure.
Let's take the following example from the README:
use ratatui::{prelude::*, widgets::*};
fn ui(frame: &mut Frame) {
let main_layout = Layout::new(
Direction::Vertical,
[
Constraint::Length(1),
Constraint::Min(0),
Constraint::Length(1),
],
)
.split(frame.size());
frame.render_widget(
Block::new().borders(Borders::TOP).title("Title Bar"),
main_layout[0],
);
frame.render_widget(
Block::new().borders(Borders::TOP).title("Status Bar"),
main_layout[2],
);
let inner_layout = Layout::new(
Direction::Horizontal,
[Constraint::Percentage(50), Constraint::Percentage(50)],
)
.split(main_layout[1]);
frame.render_widget(
Block::bordered().title("Left"),
inner_layout[0],
);
frame.render_widget(
Block::bordered().title("Right"),
inner_layout[1],
);
}
With JSX it could look like this:
(Please note, that I haven't used ratatui
yet, so the following might not make complete sense. However, something similar to it seems possible)
use ratatui::{prelude::*, widgets::*};
fn ui(frame: &mut Frame) {
rsx! {
<VLayout split=frame.size()>
<Block title="Title Bar" border:top length=1><Block>
<HLayout min=0 split:available>
<Block title="Left" border></Block>
<Block title="Right" border></Block>
</HLayout>
<Block title="Status Bar" length=1><Block>
</VLayout>
}
}
And again with some comments:
use ratatui::{prelude::*, widgets::*};
fn ui(frame: &mut Frame) {
rsx! {
<VLayout split=frame.size()>
// Or `<VerticalLayout>` but I like short names like `<VLayout>` more
<Block title="Title Bar" border:top length=1>
// Note: `border:top` is a boolean property and a shorthand for
// `border:top=true`. The `:` is just for namespacing (so could
// also be `border_top`).
// Note: the `main_layout[0]` is here defined by the order of the RSX elements
<Block>
<HLayout min=0 split:available>
// Note: `split:available` is the replacement for `.split(main_layout[1])`.
// The meaning is "split the available space". Not sure if that makes sense.
// There most-likely also should be a `split=whatever` attribute, to specify
// custom values.
<Block title="Left" border></Block>
<Block title="Right" border></Block>
// Note: `border`, of course, also could be `bordered`. For consistency I'd
// prefer `border`, however.
</HLayout>
<Block title="Status Bar" length=1><Block>
</VLayout>
}
}
Much nicer, isn't it..?
To be honest, I'm not a big fan of macros and HTML-like syntax - however, I'm even less a fan of writing a lot of unnecessary boilerplate code.
I seriously think, adding RSX would take ratatui
to the next level.
I've been following tui.rs
/ratatui
already many years, but I have never used it - mostly because it seems incredibly unergonomic to use (compared to how ergonomic it could be). It just always seemed easier to build a simple web application (e.g., for personal tools), however, I really like the idea of TUI applications.
(Another issue is, that basic building blocks are missing or require importing third-party libraries, like for example input widgets. I might open another issue for this, at some point)
PS: I've added most of the above to my initial post.
I'd imagine this is probably possible to write outside of Ratatui core. There's nothing preventing you from adding something like this on top of the existing system afaik, maintenance burden is one thing that would steer me personally away from it in the short term (i.e. I'd imagine this would be a lot of code, which would be difficult to keep up to date with any changes to the core internals - doubling the work / tests / etc.)
I'd definitely encourage you to experiment with this - you may end up with something pretty neat for building TUIs.
Alright, that is too bad. Feel free to close this issue then. I'm not closing it myself in case you are interested in hearing further feedback from other people.
I'm going to convert this to a discussion rather than an issue. You might also consider posting it on the new (launched this week) Ratatui forum to see if anyone is interested in working on this.