Skip to main content

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