1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
use crate::node::NodeTree;
use crate::prelude::*;
mod node;
mod prelude;
struct BodyCall(Vec<NodeTree>);
impl Parse for BodyCall {
fn parse(input: ParseStream) -> Result<Self> {
let mut nodes = Vec::new();
while !input.is_empty() {
nodes.push(input.parse()?);
}
Ok(Self(nodes))
}
}
impl ToTokens for BodyCall {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let nodes = self.0.as_slice();
quote!({
use ::cercis::html::*;
VBody::new()#(.child(#nodes))*
})
.to_tokens(tokens)
}
}
/// Macro ```rsx!``` write HTML templates in Rust code like jsx
///
/// > Return VBody struct that can render to string by ```.render()``` method
///
/// # Examples
///
/// ## Formatting
///
/// ```
/// use cercis::prelude::*;
///
/// let text = "Hello World!";
/// rsx!(h1 { "{text}" });
/// ```
///
/// ## Nested
///
/// ```
/// use cercis::prelude::*;
///
/// let text = "Hello World!";
/// rsx!(div {
/// p { "{text}" }
/// span { "Lorem ipsum" }
/// });
/// ```
///
/// ## Attributes
///
/// ```
/// use cercis::prelude::*;
///
/// let container_name = "main";
/// rsx!(div {
/// class: "container-{container_name}",
///
/// p { "Lorem ipsum" }
/// });
/// ```
#[proc_macro]
pub fn rsx(input: TokenStream) -> TokenStream {
match syn::parse::<BodyCall>(input) {
Ok(body) => body.into_token_stream().into(),
Err(err) => err.to_compile_error().into(),
}
}