| Crates.io | rxtui-macros |
| lib.rs | rxtui-macros |
| version | 0.1.5 |
| created_at | 2025-08-22 07:42:08.765602+00 |
| updated_at | 2025-09-23 18:52:20.764965+00 |
| description | Procedural macros for the rxtui terminal UI framework |
| homepage | https://github.com/microsandbox/rxtui |
| repository | https://github.com/microsandbox/rxtui |
| max_upload_size | |
| id | 1806020 |
| size | 46,990 |
Procedural macros for the RxTUI terminal UI framework.
Note: This crate provides procedural macros for RxTUI. You should use the main
rxtuicrate directly, which re-exports these macros.
Add RxTUI to your project (not this crate directly):
[dependencies]
rxtui = "0.1"
#[derive(Component)]Automatically implements the Component trait for your struct:
use rxtui::prelude::*;
#[derive(Component)]
struct MyApp;
impl MyApp {
// Add #[update] and #[view] methods
}
#[update]Marks a method as the component's update handler. Automatically handles message downcasting and state management:
#[update]
fn update(&self, ctx: &Context, msg: MyMsg, mut state: MyState) -> Action {
match msg {
MyMsg::Increment => {
state.count += 1;
Action::update(state)
}
MyMsg::Exit => Action::exit()
}
}
The macro automatically:
#[update(msg = AppMessage, topics = ["dialog" => DialogMsg, "nav" => NavMsg])]
fn update(&self, ctx: &Context, messages: Messages, mut state: AppState) -> Action {
match messages {
Messages::AppMessage(msg) => {
// Handle app messages
Action::update(state)
}
Messages::DialogMsg(msg) => {
// Handle dialog messages from "dialog" topic
Action::update(state)
}
Messages::NavMsg(msg) => {
// Handle navigation messages from "nav" topic
Action::update(state)
}
}
}
The macro generates an enum Messages with variants for each message type.
#[update("navigation")]
fn handle_nav(&self, ctx: &Context, msg: NavMsg, state: State) -> Action {
// Handle navigation messages
}
#[update("user")]
fn handle_user(&self, ctx: &Context, msg: UserMsg, state: State) -> Action {
// Handle user messages
}
#[view]Marks a method as the component's view renderer:
#[view]
fn view(&self, ctx: &Context, state: MyState) -> Node {
node! {
div(bg: black, pad: 2) [
text(format!("Count: {}", state.count))
]
}
}
The macro automatically:
#[effect]Creates async background tasks (requires effects feature):
#[effect]
async fn tick(&self, ctx: &Context) {
loop {
tokio::time::sleep(Duration::from_secs(1)).await;
ctx.send("tick");
}
}
Effects run automatically when the component is mounted and are cancelled when unmounted.
use rxtui::prelude::*;
use std::time::Duration;
#[derive(Debug, Clone)]
enum CounterMsg {
Increment,
Decrement,
Reset,
Exit,
}
#[derive(Debug, Clone, Default)]
struct CounterState {
count: i32,
}
#[derive(Component)]
struct Counter;
impl Counter {
#[update]
fn update(&self, _ctx: &Context, msg: CounterMsg, mut state: CounterState) -> Action {
match msg {
CounterMsg::Increment => {
state.count += 1;
Action::update(state)
}
CounterMsg::Decrement => {
state.count -= 1;
Action::update(state)
}
CounterMsg::Reset => {
state.count = 0;
Action::update(state)
}
CounterMsg::Exit => Action::exit()
}
}
#[view]
fn view(&self, ctx: &Context, state: CounterState) -> Node {
node! {
div(
bg: black,
pad: 2,
@key(up): ctx.handler(CounterMsg::Increment),
@key(down): ctx.handler(CounterMsg::Decrement),
@key(r): ctx.handler(CounterMsg::Reset),
@key(esc): ctx.handler(CounterMsg::Exit)
) [
text(format!("Count: {}", state.count), color: white, bold),
text("↑/↓: change | r: reset | esc: exit", color: bright_black)
]
}
}
#[cfg(feature = "effects")]
#[effect]
async fn auto_increment(&self, ctx: &Context) {
loop {
tokio::time::sleep(Duration::from_secs(5)).await;
ctx.send(CounterMsg::Increment);
}
}
}
fn main() -> std::io::Result<()> {
App::new()?.run(Counter)
}
For complete documentation and more examples, see the main RxTUI documentation.
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.