gpui_markup/
lib.rs

1//! gpui-markup - A declarative markup DSL for building GPUI applications.
2//!
3//! This crate provides a Rust-native syntax for building GPUI UIs:
4//!
5//! ```ignore
6//! ui! {
7//!     div @[flex, flex_col, w: px(200.0), bg: theme.secondary] {
8//!         div @[text_size: px(16.0)] {
9//!             "Hello World",
10//!         },
11//!     }
12//! }
13//! ```
14//!
15//! Which expands to:
16//!
17//! ```ignore
18//! div()
19//!     .flex()
20//!     .flex_col()
21//!     .w(px(200.0))
22//!     .bg(theme.secondary)
23//!     .child(
24//!         div()
25//!             .text_size(px(16.0))
26//!             .child("Hello World")
27//!     )
28//! ```
29
30mod ast;
31mod codegen;
32mod parser;
33
34use proc_macro::TokenStream;
35use proc_macro_error2::proc_macro_error;
36use quote::quote;
37use syn::parse_macro_input;
38
39use crate::ast::Markup;
40
41/// A declarative markup macro for building GPUI UIs.
42///
43/// # Syntax
44///
45/// ## Basic Elements
46///
47/// ```ignore
48/// ui! { div {} }                        // -> div()
49/// ui! { div @[flex] {} }                // -> div().flex()
50/// ui! { div @[w: px(200.0)] {} }        // -> div().w(px(200.0))
51/// ```
52///
53/// ## Children
54///
55/// ```ignore
56/// // Comma-separated children
57/// ui! {
58///     div {
59///         "First",
60///         "Second",
61///     }
62/// }
63/// // -> div().child("First").child("Second")
64/// ```
65///
66/// ## Spread Children
67///
68/// Use `..expr` to spread an iterable as children:
69///
70/// ```ignore
71/// let items: Vec<Div> = vec![div(), div()];
72///
73/// ui! {
74///     div {
75///         ..items,
76///     }
77/// }
78/// // -> div().children(items)
79///
80/// // Can be mixed with regular children
81/// ui! {
82///     div {
83///         "Header",
84///         ..items,
85///         "Footer",
86///     }
87/// }
88/// // -> div().child("Header").children(items).child("Footer")
89/// ```
90///
91/// ## Method Chains
92///
93/// Use `.method(args)` to insert method calls at any position.
94/// Supports method chains and generics:
95///
96/// ```ignore
97/// ui! {
98///     div {
99///         "static child",
100///         .when(condition, |d| d.child("dynamic")),
101///         .flex().gap_2(),
102///         .map::<Div, _>(|d| d),
103///     }
104/// }
105/// ```
106///
107/// ## Comments
108///
109/// Use standard Rust comments (`//` or `/* */`) inside `ui!`.
110///
111/// ## Expression Elements
112///
113/// Any expression can be used as an element (braces required at top level):
114///
115/// ```ignore
116/// ui! { Button::new("Click") {} }              // -> Button::new("Click")
117/// ui! { Button::new("Click") @[style: Primary] {} }
118///                                              // -> Button::new("Click").style(Primary)
119/// ui! {
120///     div().flex() @[flex_col] {
121///         "Content",
122///     }
123/// }
124/// // -> div().flex().flex_col().child("Content")
125///
126/// // Parentheses for complex expressions (braces optional)
127/// ui! { (a + b) }                              // -> a + b
128/// ```
129///
130/// **Why braces at top level?** The `ui!` macro builds a component tree.
131/// Braces declare "this is a UI element" - they mark it as a tree node,
132/// trigger implicit `::new()` for components, and provide a place for
133/// attributes and children.
134///
135/// ## Multi-value Attributes
136///
137/// Use tuples for attributes with multiple arguments:
138///
139/// ```ignore
140/// ui! { div @[when: (condition, |d| d.flex())] {} }
141/// // -> div().when(condition, |d| d.flex())
142/// ```
143#[proc_macro]
144#[proc_macro_error]
145pub fn ui(input: TokenStream) -> TokenStream {
146    let markup = parse_macro_input!(input as Markup);
147    let output = quote! { #markup };
148    output.into()
149}