rxtui-macros

Crates.iorxtui-macros
lib.rsrxtui-macros
version0.1.5
created_at2025-08-22 07:42:08.765602+00
updated_at2025-09-23 18:52:20.764965+00
descriptionProcedural macros for the rxtui terminal UI framework
homepagehttps://github.com/microsandbox/rxtui
repositoryhttps://github.com/microsandbox/rxtui
max_upload_size
id1806020
size46,990
Stephen Akinyemi (appcypher)

documentation

https://docs.rs/rxtui-macros

README

rxtui-macros

Crates.io docs.rs License

Procedural macros for the RxTUI terminal UI framework.

Note: This crate provides procedural macros for RxTUI. You should use the main rxtui crate directly, which re-exports these macros.

Usage

Add RxTUI to your project (not this crate directly):

[dependencies]
rxtui = "0.1"

Provided Macros

#[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:

  • Downcasts incoming messages to your message type
  • Retrieves and updates component state
  • Handles multiple message types if needed

Advanced: Multiple Message Types

#[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.

Topic-Based Updates

#[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:

  • Retrieves the current component state
  • Passes it to your view function
  • Returns the rendered node tree

#[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.

Complete Example

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)
}

Documentation

For complete documentation and more examples, see the main RxTUI documentation.

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

Commit count: 32

cargo fmt