textual_macros/lib.rs
1//! Proc macros for the textual TUI framework.
2//!
3//! Provides `#[derive(Reactive)]` for reactive field system.
4
5extern crate proc_macro;
6use proc_macro::TokenStream;
7
8mod reactive;
9
10/// Derive macro for the reactive field system.
11///
12/// Annotate struct fields with `#[reactive]`, `#[reactive(layout)]`,
13/// `#[reactive(watch)]`, or `#[var]` to generate getters, setters with
14/// change detection, and watcher dispatch.
15#[proc_macro_derive(Reactive, attributes(reactive, var, computed))]
16pub fn derive_reactive(input: TokenStream) -> TokenStream {
17 reactive::derive_reactive_impl(input.into()).into()
18}
19
20mod widget;
21
22/// Attribute macro that generates a full `impl Widget` (and `impl Renderable`)
23/// forwarding the structural / propagation method surface to a `base` field,
24/// so a compound widget can "inherit" from a container without hand-forwarding
25/// all ~63 delegated `Widget` methods.
26///
27/// This is the first-class replacement for the deprecated declarative
28/// `delegate_widget_to!` / `delegate_widget_method!` macros.
29///
30/// # Usage
31///
32/// ```ignore
33/// #[widget(base = VerticalGroup)]
34/// #[derive(Reactive)]
35/// struct StatCard {
36/// base: VerticalGroup,
37/// #[reactive] count: i32,
38/// }
39/// ```
40///
41/// # Options
42///
43/// - `base = <Type>` (required) — the container type being "inherited".
44/// - `field = <ident>` — delegate to a differently-named field (default `base`).
45/// - `style_type = "Name"` — emit a custom CSS type; otherwise the widget's own
46/// concrete type name is used (NOT the base's).
47/// - `reactive` — route `reactive_widget` to `Some(self)` (opt-in for
48/// `#[derive(Reactive)]` compound widgets).
49/// - `override(m1, m2, ..)` — do not forward these methods; call the user's
50/// inherent method of the same name/signature instead.
51#[proc_macro_attribute]
52pub fn widget(attr: TokenStream, item: TokenStream) -> TokenStream {
53 widget::widget_impl(attr.into(), item.into()).into()
54}
55
56mod on_handler;
57
58/// Attribute macro for typed message handler dispatch.
59///
60/// Apply to a method to generate a companion `__on_dispatch_<name>` dispatch
61/// method that pattern-matches the `Message` type and calls the handler with the
62/// typed payload and a `&mut WidgetCtx`.
63///
64/// # Usage
65///
66/// ```ignore
67/// #[on(ButtonPressed)]
68/// fn handle_button(&mut self, event: &ButtonPressed, ctx: &mut WidgetCtx) { ... }
69///
70/// #[on(ButtonPressed, selector = "#save")] // selector matching is deferred
71/// fn handle_save(&mut self, event: &ButtonPressed, ctx: &mut WidgetCtx) { ... }
72/// ```
73///
74/// # Wiring
75///
76/// The dispatcher is only *called* when you list the handler in the widget's
77/// delegation derive: `#[widget(base = .., on(handle_button, ..))]`. If the
78/// compiler warns that `__on_dispatch_<name>` is never used, you forgot to add
79/// `<name>` to `#[widget(on(..))]` (the dispatcher deliberately carries NO
80/// `#[allow(dead_code)]` so that omission is a compile-time warning).
81///
82/// # Semantics
83///
84/// `#[on]` does NOT auto-consume the message — like Python Textual, the message
85/// keeps bubbling to ancestors after your handler runs. Call `ctx.set_handled()`
86/// to stop propagation. Handlers see the message via routing's bubble phase, not
87/// via the base-forward.
88#[proc_macro_attribute]
89pub fn on(attr: TokenStream, item: TokenStream) -> TokenStream {
90 on_handler::on_handler_impl(attr.into(), item.into()).into()
91}