gpui_markup/
lib.rs

1//! gpui-markup - A declarative markup DSL for building GPUI applications.
2//!
3//! This crate provides a JSX-like 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//!         </div>
11//!     </div>
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/// // Children use chained .child() calls
57/// ui! {
58///     <div>
59///         {"First"}
60///         {"Second"}
61///     </div>
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///     </div>
77/// }
78/// // -> div().children(items)
79///
80/// // Can be mixed with regular children
81/// ui! {
82///     <div>
83///         {"Header"}
84///         {..items}
85///         {"Footer"}
86///     </div>
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///     </div>
104/// }
105/// ```
106///
107/// ## Components
108///
109/// ```ignore
110/// ui! { <Header/> }                 // -> Header::new()
111/// ui! { <{NavItem::new(path)}/> }   // -> NavItem::new(path)
112/// ```
113///
114/// ## Expression Tags
115///
116/// ```ignore
117/// // Self-closing expression tag
118/// ui! { <{Container::new(title)}/> }
119///
120/// // Expression tag with attributes and children
121/// ui! {
122///     <{Container::new(title)} flex>
123///         {"Content"}
124///     </{}>
125/// }
126/// ```
127#[proc_macro]
128#[proc_macro_error]
129pub fn ui(input: TokenStream) -> TokenStream {
130    let markup = parse_macro_input!(input as Markup);
131    let output = quote! { #markup };
132    output.into()
133}