euv_macros/lib.rs
1//! euv_macros
2//!
3//! Procedural macros for the euv UI framework, including the `html!` macro
4//! for declarative UI syntax, the `class!` macro for CSS class definitions,
5//! the `vars!` macro for CSS custom properties, the `watch!` macro for
6//! reactive side effects, the `computed!` macro for reactive computed signals,
7//! and the `component` attribute macro.
8
9#[macro_use]
10extern crate syn;
11
12mod class;
13mod computed;
14mod html;
15mod ident;
16mod raw_html;
17mod var;
18mod watch;
19
20pub(crate) use {class::*, computed::*, html::*, ident::*, raw_html::*, var::*, watch::*};
21
22pub(crate) use proc_macro2::TokenTree;
23pub(crate) use std::fmt::{Debug, Formatter};
24
25use std::{
26 collections::{HashMap, hash_map::DefaultHasher},
27 env::{self, VarError},
28 ffi::OsStr,
29 fmt::{self, Write},
30 fs::{create_dir_all, metadata, read_dir, read_to_string, write},
31 hash::{Hash, Hasher},
32 io,
33 iter::Peekable,
34 mem::MaybeUninit,
35 path::PathBuf,
36 time::UNIX_EPOCH,
37};
38
39use {
40 lombok_macros::*,
41 proc_macro::TokenStream,
42 proc_macro2::Span,
43 quote::{ToTokens, quote, quote_spanned},
44 syn::{
45 Attribute, Block, Expr, Field, File, Generics, Ident, Item, LitStr, Path, Stmt, Token,
46 Type, Visibility, WhereClause, braced, parenthesized, parse,
47 parse::{Parse, ParseBuffer, ParseStream},
48 parse_file, parse2,
49 token::{Brace, Colon, Paren, Semi},
50 },
51};
52
53/// The `html!` macro for writing declarative UI in euv.
54///
55/// This macro accepts a syntax similar to Dioxus HTML:
56///
57#[proc_macro]
58pub fn html(input: TokenStream) -> TokenStream {
59 parse_html(input)
60}
61
62/// The `class!` macro for defining CSS classes with style properties.
63///
64/// Each class definition creates a `Css` function that can be used
65/// in `html!` via the `class:` attribute. Styles are automatically injected
66/// into the DOM on first use.
67///
68/// Parameterized classes keep the normal function-call syntax. Wrap a
69/// parameter reference in `{}` to make it part of the generated class name
70/// by value; parameters referenced without braces keep the default
71/// type-based class name.
72///
73#[proc_macro]
74pub fn class(input: TokenStream) -> TokenStream {
75 parse_class(input)
76}
77
78/// The `watch!` macro for creating reactive side effects.
79///
80/// Watches one or more signals and executes a closure whenever any of them changes.
81/// The closure is also executed once immediately with the current signal values
82/// during initialisation. This initial execution is wrapped in a suppressed-update
83/// scope so that any `.set()` calls inside the body do not trigger unnecessary
84/// DynamicNode re-renders.
85///
86/// The number of signal expressions must match the number of closure parameters.
87/// Each closure parameter receives the current value (via `.get()`) of the
88/// corresponding signal. Parameter types are optional and can be annotated
89/// after a colon.
90///
91#[proc_macro]
92pub fn watch(input: TokenStream) -> TokenStream {
93 parse_watch(input)
94}
95
96/// The `computed!` macro for creating reactive computed signals.
97///
98/// Watches one or more signals and derives a new signal whose value is
99/// automatically computed from the closure return value whenever any input
100/// signal changes. The closure must return a value of the specified return type.
101///
102/// The number of signal expressions must match the number of closure parameters.
103/// Each closure parameter receives the current value (via `.get()`) of the
104/// corresponding signal. Parameter types are optional and can be annotated
105/// after a colon. The return type must be specified after `->`.
106///
107/// The result signal is created via `use_signal` and updated via `set()`
108/// to mark its dependents dirty precisely. The initial value is computed immediately
109/// during first render.
110///
111#[proc_macro]
112pub fn computed(input: TokenStream) -> TokenStream {
113 parse_computed(input)
114}
115
116/// The `vars!` macro for defining CSS custom properties.
117///
118/// Each variable block creates a `Css` function that, when called,
119/// injects the CSS custom properties into the DOM. Variable names are
120/// automatically prefixed with `--`.
121///
122/// Variable names can be written as unquoted kebab-case identifiers
123/// (e.g., `bg-primary`) or as quoted string literals (e.g., `"bg-primary"`).
124///
125#[proc_macro]
126pub fn vars(input: TokenStream) -> TokenStream {
127 parse_vars(input)
128}
129
130/// The `var!` macro for referencing CSS custom properties defined via `vars!`.
131///
132/// The variable name can be written as an unquoted kebab-case identifier
133/// (e.g., `bg-primary`) or as a quoted string literal (e.g., `"bg-primary"`),
134/// and expands to the CSS string `"var(--bg-primary)"`.
135///
136#[proc_macro]
137pub fn var(input: TokenStream) -> TokenStream {
138 parse_var(input)
139}
140
141/// The `unsafe_no_inline!` macro — escape hatch for raw HTML.
142///
143/// Accepts a string literal and emits a `euv::vdom::RawHtml` value
144/// constructed via `RawHtml::new`. The `unsafe_no_` prefix is a
145/// deliberately loud warning that the string is NOT escaped; treat
146/// it like `Element.innerHTML` in JavaScript.
147///
148#[proc_macro]
149pub fn unsafe_no_inline(input: TokenStream) -> TokenStream {
150 parse_unsafe_no_inline(input)
151}
152
153/// The `component` attribute macro for marking component functions.
154///
155/// Only functions annotated with `#[component]` are treated as components
156/// in the `html!` macro. All other identifier tags are treated as native
157/// HTML elements (with `Tag::Element`).
158///
159/// The `html!` macro scans the project source to find `#[component]`-annotated
160/// functions at compile time, so this attribute must be present for the
161/// `html!` macro to generate a component function call.
162///
163/// # Arguments
164///
165/// - `TokenStream` - The attribute arguments (unused).
166/// - `TokenStream` - The item being annotated (passed through unchanged).
167///
168/// # Returns
169///
170/// - `TokenStream` - The original item unchanged.
171#[proc_macro_attribute]
172pub fn component(_attr: TokenStream, item: TokenStream) -> TokenStream {
173 item
174}