Context
R3BL TUI library & suite of apps focused on developer productivity
We are working on building command line apps in Rust which have rich text user interfaces (TUI). We want to lean into the terminal as a place of productivity, and build all kinds of awesome apps for it.
-
🔮 Instead of just building one app, we are building a library to enable any kind of rich TUI development w/ a twist: taking concepts that work really well for the frontend mobile and web development world and re-imagining them for TUI & Rust.
- Taking things like React, JSX, CSS, and Redux, but making everything async (they can be run in parallel & concurrent via Tokio).
- Even the thread running the main event loop doesn't block since it is async.
- Using proc macros to create DSLs to implement CSS & JSX.
-
🌎 We are building apps to enhance developer productivity & workflows.
- The idea here is not to rebuild tmux in Rust (separate processes mux'd onto a single terminal window). Rather it is to build a set of integrated "apps" (or "tasks") that run in the same process that renders to one terminal window.
- Inside of this terminal window, we can implement things like "app" switching, routing, tiling layout, stacking layout, etc. so that we can manage a lot of TUI apps (which are tightly integrated) that are running in the same process, in the same window. So you can imagine that all these "app"s have shared application state (that is in a Redux store). Each "app" may also have its own Redux store.
- Here are some examples of the types of "app"s we want to build:
- multi user text editors w/ syntax highlighting
- integrations w/ github issues
- integrations w/ calendar, email, contacts APIs
r3bl_rs_utils_macro
This crate is related to the first thing that's described above. It provides lots of useful functionality to help you build TUI (text user interface) apps, along w/ general niceties & ergonomics that all Rustaceans 🦀 can enjoy 🎉:
Macros
Procedural
All the procedural macros are organized in 3 crates using an internal or core crate: the public crate, an internal or core crate, and the proc macro crate.
style! macro
Here's an example of the style!
macro:
style!
color_fg
and color_bg
can take any of the following:
- Color enum value.
- Rgb value.
- Variable holding either of the above.
Builder derive macro
This derive macro makes it easy to generate builders when annotating a struct
or enum
. It
generates It has full support for generics. It can be used like this.
let my_pt: = new
.set_x
.set_y
.build;
assert_eq!;
assert_eq!;
make_struct_safe_to_share_and_mutate!
This function like macro (with custom syntax) makes it easy to manage shareability and interior mutability of a struct. We call this pattern the "manager" of "things").
🪄 You can read all about it here.
- This struct gets wrapped in a
RwLock
for thread safety. - That is then wrapped inside an
Arc
so we can share it across threads. - Additionally it works w/ Tokio so that it is totally async. It also fully supports generics and
trait bounds w/ an optional
where
clause.
Here's a very simple usage:
make_struct_safe_to_share_and_mutate!
Here's an async example.
async
make_safe_async_fn_wrapper!
This function like macro (with custom syntax) makes it easy to share functions and lambdas that are async. They should be safe to share between threads and they should support either being invoked or spawned.
🪄 You can read all about how to write proc macros here.
- A struct is generated that wraps the given function or lambda in an
Arc<RwLock<>>
for thread safety and interior mutability. - A
get()
method is generated which makes it possible to share this struct across threads. - A
from()
method is generated which makes it easy to create this struct from a function or lambda. - A
spawn()
method is generated which makes it possible to spawn the enclosed function or lambda asynchronously using Tokio. - An
invoke()
method is generated which makes it possible to invoke the enclosed function or lambda synchronously.
Here's an example of how to use this macro.
use make_safe_async_fn_wrapper;
make_safe_async_fn_wrapper!
Here's another example.
use make_safe_async_fn_wrapper;
make_safe_async_fn_wrapper!
Other crates that depend on this
This crate is a dependency of r3bl_rs_utils
crate (the
"main" library).
Issues, comments, feedback, and PRs
Please report any issues to the issue tracker. And if you have any feature requests, feel free to add them there too 👍.