From abfac0d59b620cdf3af77c80aadb07266e0d651b Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 17 Jan 2022 16:37:44 -0500 Subject: [PATCH 1/8] wip: move macro lib out of proc macro crate --- Cargo.toml | 5 +- examples/rsx_autocomplete.rs | 27 ++++++ packages/core-macro/Cargo.toml | 1 + packages/core-macro/src/lib.rs | 7 +- packages/macro-inner/Cargo.toml | 13 +++ .../{core-macro => macro-inner}/src/htm.rs | 0 .../{core-macro => macro-inner}/src/ifmt.rs | 0 .../src/inlineprops.rs | 0 packages/macro-inner/src/lib.rs | 5 + .../src/props/mod.rs | 0 .../{core-macro => macro-inner}/src/router.rs | 0 .../src/rsx/component.rs | 8 +- .../src/rsx/element.rs | 93 ++++++++++++------- .../src/rsx/mod.rs | 4 +- .../src/rsx/node.rs | 0 .../src/rsxtemplate.rs | 0 16 files changed, 116 insertions(+), 47 deletions(-) create mode 100644 examples/rsx_autocomplete.rs create mode 100644 packages/macro-inner/Cargo.toml rename packages/{core-macro => macro-inner}/src/htm.rs (100%) rename packages/{core-macro => macro-inner}/src/ifmt.rs (100%) rename packages/{core-macro => macro-inner}/src/inlineprops.rs (100%) create mode 100644 packages/macro-inner/src/lib.rs rename packages/{core-macro => macro-inner}/src/props/mod.rs (100%) rename packages/{core-macro => macro-inner}/src/router.rs (100%) rename packages/{core-macro => macro-inner}/src/rsx/component.rs (98%) rename packages/{core-macro => macro-inner}/src/rsx/element.rs (80%) rename packages/{core-macro => macro-inner}/src/rsx/mod.rs (97%) rename packages/{core-macro => macro-inner}/src/rsx/node.rs (100%) rename packages/{core-macro => macro-inner}/src/rsxtemplate.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 884513a5b..98da05bcc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ keywords = ["dom", "ui", "gui", "react", "wasm"] dioxus-core = { path = "./packages/core", version = "^0.1.7" } dioxus-html = { path = "./packages/html", version = "^0.1.4", optional = true } dioxus-core-macro = { path = "./packages/core-macro", version = "^0.1.6", optional = true } +dioxus-macro-inner = { path = "./packages/macro-inner", optional = true } dioxus-hooks = { path = "./packages/hooks", version = "^0.1.6", optional = true } dioxus-web = { path = "./packages/web", version = "^0.0.4", optional = true } @@ -27,7 +28,7 @@ dioxus-mobile = { path = "./packages/mobile", version = "^0.0.3", optional = tru [features] default = ["macro", "hooks", "html"] -macro = ["dioxus-core-macro"] +macro = ["dioxus-core-macro", "dioxus-macro-inner"] hooks = ["dioxus-hooks"] html = ["dioxus-html"] ssr = ["dioxus-ssr"] @@ -35,6 +36,7 @@ web = ["dioxus-web"] desktop = ["dioxus-desktop"] router = ["dioxus-router"] + # "dioxus-router/web" # "dioxus-router/desktop" # desktop = ["dioxus-desktop", "dioxus-router/desktop"] @@ -46,6 +48,7 @@ router = ["dioxus-router"] members = [ "packages/core", "packages/core-macro", + "packages/macro-inner", "packages/html", "packages/hooks", "packages/web", diff --git a/examples/rsx_autocomplete.rs b/examples/rsx_autocomplete.rs new file mode 100644 index 000000000..99afe7521 --- /dev/null +++ b/examples/rsx_autocomplete.rs @@ -0,0 +1,27 @@ +//! This example shows that autocomplete works in RSX + +use dioxus::prelude::*; + +fn main() { + dioxus::desktop::launch(app); +} + +fn app(cx: Scope) -> Element { + cx.render(rsx! { + div { + onclick: move |_| { + } + // class: "asd", + // style { + // media: "Ad", + // } + // div { + + // } + // { + // let t = String::new(); + // t. + // } + } + }) +} diff --git a/packages/core-macro/Cargo.toml b/packages/core-macro/Cargo.toml index ee3dc2883..8f2b81cba 100644 --- a/packages/core-macro/Cargo.toml +++ b/packages/core-macro/Cargo.toml @@ -15,6 +15,7 @@ keywords = ["dom", "ui", "gui", "react", "wasm"] proc-macro = true [dependencies] +dioxus-macro-inner = { path = "../macro-inner" } once_cell = "1.8" proc-macro-error = "1.0.4" proc-macro2 = { version = "1.0.6" } diff --git a/packages/core-macro/src/lib.rs b/packages/core-macro/src/lib.rs index 4ad7543a2..3579039b5 100644 --- a/packages/core-macro/src/lib.rs +++ b/packages/core-macro/src/lib.rs @@ -1,13 +1,8 @@ +use dioxus_macro_inner::*; use proc_macro::TokenStream; use quote::ToTokens; use syn::parse_macro_input; -pub(crate) mod ifmt; -pub(crate) mod inlineprops; -pub(crate) mod props; -pub(crate) mod router; -pub(crate) mod rsx; - #[proc_macro] pub fn format_args_f(input: TokenStream) -> TokenStream { use ifmt::*; diff --git a/packages/macro-inner/Cargo.toml b/packages/macro-inner/Cargo.toml new file mode 100644 index 000000000..63fcbbd9b --- /dev/null +++ b/packages/macro-inner/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "dioxus-macro-inner" +version = "0.0.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +once_cell = "1.8" +proc-macro-error = "1.0.4" +proc-macro2 = { version = "1.0.6" } +quote = "1.0" +syn = { version = "1.0.11", features = ["full", "extra-traits"] } diff --git a/packages/core-macro/src/htm.rs b/packages/macro-inner/src/htm.rs similarity index 100% rename from packages/core-macro/src/htm.rs rename to packages/macro-inner/src/htm.rs diff --git a/packages/core-macro/src/ifmt.rs b/packages/macro-inner/src/ifmt.rs similarity index 100% rename from packages/core-macro/src/ifmt.rs rename to packages/macro-inner/src/ifmt.rs diff --git a/packages/core-macro/src/inlineprops.rs b/packages/macro-inner/src/inlineprops.rs similarity index 100% rename from packages/core-macro/src/inlineprops.rs rename to packages/macro-inner/src/inlineprops.rs diff --git a/packages/macro-inner/src/lib.rs b/packages/macro-inner/src/lib.rs new file mode 100644 index 000000000..69e4b743f --- /dev/null +++ b/packages/macro-inner/src/lib.rs @@ -0,0 +1,5 @@ +pub mod ifmt; +pub mod inlineprops; +pub mod props; +pub mod router; +pub mod rsx; diff --git a/packages/core-macro/src/props/mod.rs b/packages/macro-inner/src/props/mod.rs similarity index 100% rename from packages/core-macro/src/props/mod.rs rename to packages/macro-inner/src/props/mod.rs diff --git a/packages/core-macro/src/router.rs b/packages/macro-inner/src/router.rs similarity index 100% rename from packages/core-macro/src/router.rs rename to packages/macro-inner/src/router.rs diff --git a/packages/core-macro/src/rsx/component.rs b/packages/macro-inner/src/rsx/component.rs similarity index 98% rename from packages/core-macro/src/rsx/component.rs rename to packages/macro-inner/src/rsx/component.rs index 5257022a4..26305359d 100644 --- a/packages/core-macro/src/rsx/component.rs +++ b/packages/macro-inner/src/rsx/component.rs @@ -23,10 +23,10 @@ use syn::{ }; pub struct Component { - name: syn::Path, - body: Vec, - children: Vec, - manual_props: Option, + pub name: syn::Path, + pub body: Vec, + pub children: Vec, + pub manual_props: Option, } impl Parse for Component { diff --git a/packages/core-macro/src/rsx/element.rs b/packages/macro-inner/src/rsx/element.rs similarity index 80% rename from packages/core-macro/src/rsx/element.rs rename to packages/macro-inner/src/rsx/element.rs index ebc401b6e..c612e9f1b 100644 --- a/packages/core-macro/src/rsx/element.rs +++ b/packages/macro-inner/src/rsx/element.rs @@ -4,19 +4,18 @@ use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens, TokenStreamExt}; use syn::{ parse::{Parse, ParseBuffer, ParseStream}, - Expr, Ident, LitStr, Result, Token, + Expr, ExprClosure, Ident, LitStr, Result, Token, }; // ======================================= // Parse the VNode::Element type // ======================================= pub struct Element { - name: Ident, - key: Option, - attributes: Vec, - listeners: Vec, - children: Vec, - _is_static: bool, + pub name: Ident, + pub key: Option, + pub attributes: Vec, + pub children: Vec, + pub _is_static: bool, } impl Parse for Element { @@ -28,7 +27,6 @@ impl Parse for Element { syn::braced!(content in stream); let mut attributes: Vec = vec![]; - let mut listeners: Vec = vec![]; let mut children: Vec = vec![]; let mut key = None; let mut _el_ref = None; @@ -54,6 +52,7 @@ impl Parse for Element { }); } else { let value = content.parse::()?; + attributes.push(ElementAttrNamed { el_name: el_name.clone(), attr: ElementAttr::CustomAttrExpression { name, value }, @@ -82,13 +81,24 @@ impl Parse for Element { content.parse::()?; if name_str.starts_with("on") { - listeners.push(ElementAttrNamed { - el_name: el_name.clone(), - attr: ElementAttr::EventTokens { - name, - tokens: content.parse()?, - }, - }); + if content.fork().parse::().is_ok() { + // + attributes.push(ElementAttrNamed { + el_name: el_name.clone(), + attr: ElementAttr::EventClosure { + name, + closure: content.parse()?, + }, + }); + } else { + attributes.push(ElementAttrNamed { + el_name: el_name.clone(), + attr: ElementAttr::EventTokens { + name, + tokens: content.parse()?, + }, + }); + } } else { match name_str.as_str() { "key" => { @@ -182,7 +192,7 @@ impl Parse for Element { name: el_name, attributes, children, - listeners, + // listeners, _is_static: false, }) } @@ -193,14 +203,29 @@ impl ToTokens for Element { let name = &self.name; let children = &self.children; - let listeners = &self.listeners; - let attr = &self.attributes; + // let listeners = &self.listeners; let key = match &self.key { Some(ty) => quote! { Some(format_args_f!(#ty)) }, None => quote! { None }, }; + let listeners = self.attributes.iter().filter(|f| { + if let ElementAttr::EventTokens { .. } = f.attr { + true + } else { + false + } + }); + + let attr = self.attributes.iter().filter(|f| { + if let ElementAttr::EventTokens { .. } = f.attr { + false + } else { + true + } + }); + tokens.append_all(quote! { __cx.element( dioxus_elements::#name, @@ -213,29 +238,29 @@ impl ToTokens for Element { } } -enum ElementAttr { - // attribute: "valuee {}" +pub enum ElementAttr { + /// attribute: "valuee {}" AttrText { name: Ident, value: LitStr }, - // attribute: true, + /// attribute: true, AttrExpression { name: Ident, value: Expr }, - // "attribute": "value {}" + /// "attribute": "value {}" CustomAttrText { name: LitStr, value: LitStr }, - // "attribute": true, + /// "attribute": true, CustomAttrExpression { name: LitStr, value: Expr }, - // // onclick: move |_| {} - // EventClosure { name: Ident, closure: ExprClosure }, + /// onclick: move |_| {} + EventClosure { name: Ident, closure: ExprClosure }, - // onclick: {} + /// onclick: {} EventTokens { name: Ident, tokens: Expr }, } -struct ElementAttrNamed { - el_name: Ident, - attr: ElementAttr, +pub struct ElementAttrNamed { + pub el_name: Ident, + pub attr: ElementAttr, } impl ToTokens for ElementAttrNamed { @@ -263,11 +288,11 @@ impl ToTokens for ElementAttrNamed { __cx.attr( #name, format_args_f!(#value), None, false ) } } - // ElementAttr::EventClosure { name, closure } => { - // quote! { - // dioxus_elements::on::#name(__cx, #closure) - // } - // } + ElementAttr::EventClosure { name, closure } => { + quote! { + dioxus_elements::on::#name(__cx, #closure) + } + } ElementAttr::EventTokens { name, tokens } => { quote! { dioxus_elements::on::#name(__cx, #tokens) diff --git a/packages/core-macro/src/rsx/mod.rs b/packages/macro-inner/src/rsx/mod.rs similarity index 97% rename from packages/core-macro/src/rsx/mod.rs rename to packages/macro-inner/src/rsx/mod.rs index 5ff5d85f7..87b324dfc 100644 --- a/packages/core-macro/src/rsx/mod.rs +++ b/packages/macro-inner/src/rsx/mod.rs @@ -29,8 +29,8 @@ use syn::{ }; pub struct CallBody { - custom_context: Option, - roots: Vec, + pub custom_context: Option, + pub roots: Vec, } impl Parse for CallBody { diff --git a/packages/core-macro/src/rsx/node.rs b/packages/macro-inner/src/rsx/node.rs similarity index 100% rename from packages/core-macro/src/rsx/node.rs rename to packages/macro-inner/src/rsx/node.rs diff --git a/packages/core-macro/src/rsxtemplate.rs b/packages/macro-inner/src/rsxtemplate.rs similarity index 100% rename from packages/core-macro/src/rsxtemplate.rs rename to packages/macro-inner/src/rsxtemplate.rs From 174d2870625c8f052b041207c15c1062e8356c14 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 17 Jan 2022 23:02:36 -0500 Subject: [PATCH 2/8] wip: extract to rsx module --- Cargo.toml | 4 +- .../{macro-inner => core-macro}/src/ifmt.rs | 0 .../src/inlineprops.rs | 0 .../src/props/mod.rs | 0 packages/macro-inner/src/router.rs | 214 ------------------ packages/macro-inner/src/rsxtemplate.rs | 84 ------- packages/{macro-inner => rsx}/Cargo.toml | 2 +- packages/{macro-inner => rsx}/src/htm.rs | 0 packages/{macro-inner => rsx}/src/lib.rs | 1 - .../{macro-inner => rsx}/src/rsx/component.rs | 0 .../{macro-inner => rsx}/src/rsx/element.rs | 0 packages/{macro-inner => rsx}/src/rsx/mod.rs | 0 packages/{macro-inner => rsx}/src/rsx/node.rs | 0 13 files changed, 3 insertions(+), 302 deletions(-) rename packages/{macro-inner => core-macro}/src/ifmt.rs (100%) rename packages/{macro-inner => core-macro}/src/inlineprops.rs (100%) rename packages/{macro-inner => core-macro}/src/props/mod.rs (100%) delete mode 100644 packages/macro-inner/src/router.rs delete mode 100644 packages/macro-inner/src/rsxtemplate.rs rename packages/{macro-inner => rsx}/Cargo.toml (91%) rename packages/{macro-inner => rsx}/src/htm.rs (100%) rename packages/{macro-inner => rsx}/src/lib.rs (79%) rename packages/{macro-inner => rsx}/src/rsx/component.rs (100%) rename packages/{macro-inner => rsx}/src/rsx/element.rs (100%) rename packages/{macro-inner => rsx}/src/rsx/mod.rs (100%) rename packages/{macro-inner => rsx}/src/rsx/node.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 98da05bcc..c8075c545 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ keywords = ["dom", "ui", "gui", "react", "wasm"] dioxus-core = { path = "./packages/core", version = "^0.1.7" } dioxus-html = { path = "./packages/html", version = "^0.1.4", optional = true } dioxus-core-macro = { path = "./packages/core-macro", version = "^0.1.6", optional = true } -dioxus-macro-inner = { path = "./packages/macro-inner", optional = true } +dioxus-macro-inner = { path = "./packages/rsx", optional = true } dioxus-hooks = { path = "./packages/hooks", version = "^0.1.6", optional = true } dioxus-web = { path = "./packages/web", version = "^0.0.4", optional = true } @@ -48,7 +48,7 @@ router = ["dioxus-router"] members = [ "packages/core", "packages/core-macro", - "packages/macro-inner", + "packages/rsx", "packages/html", "packages/hooks", "packages/web", diff --git a/packages/macro-inner/src/ifmt.rs b/packages/core-macro/src/ifmt.rs similarity index 100% rename from packages/macro-inner/src/ifmt.rs rename to packages/core-macro/src/ifmt.rs diff --git a/packages/macro-inner/src/inlineprops.rs b/packages/core-macro/src/inlineprops.rs similarity index 100% rename from packages/macro-inner/src/inlineprops.rs rename to packages/core-macro/src/inlineprops.rs diff --git a/packages/macro-inner/src/props/mod.rs b/packages/core-macro/src/props/mod.rs similarity index 100% rename from packages/macro-inner/src/props/mod.rs rename to packages/core-macro/src/props/mod.rs diff --git a/packages/macro-inner/src/router.rs b/packages/macro-inner/src/router.rs deleted file mode 100644 index 3edad75e3..000000000 --- a/packages/macro-inner/src/router.rs +++ /dev/null @@ -1,214 +0,0 @@ -#![allow(dead_code)] - -use proc_macro2::TokenStream; -use quote::quote; -use syn::parse::{Parse, ParseStream}; -use syn::punctuated::Punctuated; -use syn::spanned::Spanned; -use syn::{Data, DeriveInput, Fields, Ident, LitStr, Variant}; - -const AT_ATTR_IDENT: &str = "at"; -const NOT_FOUND_ATTR_IDENT: &str = "not_found"; - -pub struct Routable { - ident: Ident, - ats: Vec, - variants: Punctuated, - not_found_route: Option, -} - -impl Parse for Routable { - fn parse(input: ParseStream) -> syn::Result { - let DeriveInput { ident, data, .. } = input.parse()?; - - let data = match data { - Data::Enum(data) => data, - Data::Struct(s) => { - return Err(syn::Error::new( - s.struct_token.span(), - "expected enum, found struct", - )) - } - Data::Union(u) => { - return Err(syn::Error::new( - u.union_token.span(), - "expected enum, found union", - )) - } - }; - - let (not_found_route, ats) = parse_variants_attributes(&data.variants)?; - - Ok(Self { - ident, - variants: data.variants, - ats, - not_found_route, - }) - } -} - -fn parse_variants_attributes( - variants: &Punctuated, -) -> syn::Result<(Option, Vec)> { - let mut not_founds = vec![]; - let mut ats: Vec = vec![]; - - let mut not_found_attrs = vec![]; - - for variant in variants.iter() { - if let Fields::Unnamed(ref field) = variant.fields { - return Err(syn::Error::new( - field.span(), - "only named fields are supported", - )); - } - - let attrs = &variant.attrs; - let at_attrs = attrs - .iter() - .filter(|attr| attr.path.is_ident(AT_ATTR_IDENT)) - .collect::>(); - - let attr = match at_attrs.len() { - 1 => *at_attrs.first().unwrap(), - 0 => { - return Err(syn::Error::new( - variant.span(), - format!( - "{} attribute must be present on every variant", - AT_ATTR_IDENT - ), - )) - } - _ => { - return Err(syn::Error::new_spanned( - quote! { #(#at_attrs)* }, - format!("only one {} attribute must be present", AT_ATTR_IDENT), - )) - } - }; - - let lit = attr.parse_args::()?; - ats.push(lit); - - for attr in attrs.iter() { - if attr.path.is_ident(NOT_FOUND_ATTR_IDENT) { - not_found_attrs.push(attr); - not_founds.push(variant.ident.clone()) - } - } - } - - if not_founds.len() > 1 { - return Err(syn::Error::new_spanned( - quote! { #(#not_found_attrs)* }, - format!("there can only be one {}", NOT_FOUND_ATTR_IDENT), - )); - } - - Ok((not_founds.into_iter().next(), ats)) -} - -impl Routable { - // fn build_from_path(&self) -> TokenStream { - // let from_path_matches = self.variants.iter().enumerate().map(|(i, variant)| { - // let ident = &variant.ident; - // let right = match &variant.fields { - // Fields::Unit => quote! { Self::#ident }, - // Fields::Named(field) => { - // let fields = field.named.iter().map(|it| { - // //named fields have idents - // it.ident.as_ref().unwrap() - // }); - // quote! { Self::#ident { #(#fields: params.get(stringify!(#fields))?.parse().ok()?,)* } } - // } - // Fields::Unnamed(_) => unreachable!(), // already checked - // }; - - // let left = self.ats.get(i).unwrap(); - // quote! { - // #left => ::std::option::Option::Some(#right) - // } - // }); - - // quote! { - // fn from_path(path: &str, params: &::std::collections::HashMap<&str, &str>) -> ::std::option::Option { - // match path { - // #(#from_path_matches),*, - // _ => ::std::option::Option::None, - // } - // } - // } - // } - - // fn build_to_path(&self) -> TokenStream { - // let to_path_matches = self.variants.iter().enumerate().map(|(i, variant)| { - // let ident = &variant.ident; - // let mut right = self.ats.get(i).unwrap().value(); - - // match &variant.fields { - // Fields::Unit => quote! { Self::#ident => ::std::string::ToString::to_string(#right) }, - // Fields::Named(field) => { - // let fields = field - // .named - // .iter() - // .map(|it| it.ident.as_ref().unwrap()) - // .collect::>(); - - // for field in fields.iter() { - // // :param -> {param} - // // so we can pass it to `format!("...", param)` - // right = right.replace(&format!(":{}", field), &format!("{{{}}}", field)) - // } - - // quote! { - // Self::#ident { #(#fields),* } => ::std::format!(#right, #(#fields = #fields),*) - // } - // } - // Fields::Unnamed(_) => unreachable!(), // already checked - // } - // }); - - // quote! { - // fn to_path(&self) -> ::std::string::String { - // match self { - // #(#to_path_matches),*, - // } - // } - // } - // } -} - -pub fn routable_derive_impl(input: Routable) -> TokenStream { - let Routable { - // ats, - // not_found_route, - // ident, - .. - } = &input; - - // let from_path = input.build_from_path(); - // let to_path = input.build_to_path(); - - quote! { - // #[automatically_derived] - // impl ::dioxus::router::Routable for #ident { - - // fn recognize(pathname: &str) -> ::std::option::Option { - // todo!() - // // ::std::thread_local! { - // // static ROUTER: ::dioxus::router::__macro::Router = ::dioxus::router::__macro::build_router::<#ident>(); - // // } - // // let route = ROUTER.with(|router| ::dioxus::router::__macro::recognize_with_router(router, pathname)); - // // { - // // let route = ::std::clone::Clone::clone(&route); - // // #cache_thread_local_ident.with(move |val| { - // // *val.borrow_mut() = route; - // // }); - // // } - // // route - // } - // } - } -} diff --git a/packages/macro-inner/src/rsxtemplate.rs b/packages/macro-inner/src/rsxtemplate.rs deleted file mode 100644 index 9222d7117..000000000 --- a/packages/macro-inner/src/rsxtemplate.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::{rsx::RsxBody, util::is_valid_svg_tag}; - -use { - proc_macro::TokenStream, - proc_macro2::{Span, TokenStream as TokenStream2}, - quote::{quote, ToTokens, TokenStreamExt}, - syn::{ - ext::IdentExt, - parse::{Parse, ParseStream}, - token, Error, Expr, ExprClosure, Ident, LitBool, LitStr, Path, Result, Token, - }, -}; - -// ============================================== -// Parse any stream coming from the html! macro -// ============================================== -pub struct RsxTemplate { - inner: RsxBody, -} - -impl Parse for RsxTemplate { - fn parse(s: ParseStream) -> Result { - if s.peek(LitStr) { - use std::str::FromStr; - - let lit = s.parse::()?; - let g = lit.span(); - let mut value = lit.value(); - if value.ends_with('\n') { - value.pop(); - if value.ends_with('\r') { - value.pop(); - } - } - let lit = LitStr::new(&value, lit.span()); - - // panic!("{:#?}", lit); - match lit.parse::() { - Ok(r) => Ok(Self { inner: r }), - Err(e) => Err(e), - } - } else { - panic!("Not a str lit") - } - // let t = s.parse::()?; - - // let new_stream = TokenStream::from(t.to_s) - - // let cx: Ident = s.parse()?; - // s.parse::()?; - // if elements are in an array, return a bumpalo::collections::Vec rather than a Node. - // let kind = if s.peek(token::Bracket) { - // let nodes_toks; - // syn::bracketed!(nodes_toks in s); - // let mut nodes: Vec> = vec![nodes_toks.parse()?]; - // while nodes_toks.peek(Token![,]) { - // nodes_toks.parse::()?; - // nodes.push(nodes_toks.parse()?); - // } - // NodeOrList::List(NodeList(nodes)) - // } else { - // NodeOrList::Node(s.parse()?) - // }; - // Ok(HtmlRender { kind }) - } -} - -impl ToTokens for RsxTemplate { - fn to_tokens(&self, out_tokens: &mut TokenStream2) { - self.inner.to_tokens(out_tokens); - // let new_toks = ToToksCtx::new(&self.kind).to_token_stream(); - - // // create a lazy tree that accepts a bump allocator - // let final_tokens = quote! { - // dioxus::prelude::LazyNodes::new(move |cx| { - // let bump = &cx.bump(); - - // #new_toks - // }) - // }; - - // final_tokens.to_tokens(out_tokens); - } -} diff --git a/packages/macro-inner/Cargo.toml b/packages/rsx/Cargo.toml similarity index 91% rename from packages/macro-inner/Cargo.toml rename to packages/rsx/Cargo.toml index 63fcbbd9b..4cad9064c 100644 --- a/packages/macro-inner/Cargo.toml +++ b/packages/rsx/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "dioxus-macro-inner" +name = "dioxus-rsx" version = "0.0.0" edition = "2018" diff --git a/packages/macro-inner/src/htm.rs b/packages/rsx/src/htm.rs similarity index 100% rename from packages/macro-inner/src/htm.rs rename to packages/rsx/src/htm.rs diff --git a/packages/macro-inner/src/lib.rs b/packages/rsx/src/lib.rs similarity index 79% rename from packages/macro-inner/src/lib.rs rename to packages/rsx/src/lib.rs index 69e4b743f..b9911dedc 100644 --- a/packages/macro-inner/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -1,5 +1,4 @@ pub mod ifmt; pub mod inlineprops; pub mod props; -pub mod router; pub mod rsx; diff --git a/packages/macro-inner/src/rsx/component.rs b/packages/rsx/src/rsx/component.rs similarity index 100% rename from packages/macro-inner/src/rsx/component.rs rename to packages/rsx/src/rsx/component.rs diff --git a/packages/macro-inner/src/rsx/element.rs b/packages/rsx/src/rsx/element.rs similarity index 100% rename from packages/macro-inner/src/rsx/element.rs rename to packages/rsx/src/rsx/element.rs diff --git a/packages/macro-inner/src/rsx/mod.rs b/packages/rsx/src/rsx/mod.rs similarity index 100% rename from packages/macro-inner/src/rsx/mod.rs rename to packages/rsx/src/rsx/mod.rs diff --git a/packages/macro-inner/src/rsx/node.rs b/packages/rsx/src/rsx/node.rs similarity index 100% rename from packages/macro-inner/src/rsx/node.rs rename to packages/rsx/src/rsx/node.rs From 3c54ce06f2c2359aadf6f1c4ad0a4eeca4bcb403 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Sun, 13 Feb 2022 12:43:15 -0500 Subject: [PATCH 3/8] fix: disable more --- .github/workflows/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3e1ec15c0..07ccd8069 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,6 +34,7 @@ jobs: command: check test: + if: github.event.pull_request.draft == false name: Test Suite runs-on: ubuntu-latest steps: @@ -55,6 +56,7 @@ jobs: args: tests fmt: + if: github.event.pull_request.draft == false name: Rustfmt runs-on: ubuntu-latest steps: @@ -72,6 +74,7 @@ jobs: args: --all -- --check clippy: + if: github.event.pull_request.draft == false name: Clippy runs-on: ubuntu-latest steps: @@ -91,6 +94,7 @@ jobs: args: -- -D warnings coverage: + if: github.event.pull_request.draft == false name: Coverage runs-on: ubuntu-latest container: From b93487282de4faaac3db5b830215c4b1dbdeb16f Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Fri, 18 Feb 2022 20:54:30 -0500 Subject: [PATCH 4/8] feat: move files around --- Cargo.toml | 4 +- examples/rsx_autocomplete.rs | 27 -- packages/core-macro/Cargo.toml | 2 +- packages/rsx/src/{rsx => }/component.rs | 0 packages/rsx/src/{rsx => }/element.rs | 0 packages/rsx/src/htm.rs | 443 ------------------------ packages/rsx/src/lib.rs | 101 +++++- packages/rsx/src/{rsx => }/node.rs | 0 packages/rsx/src/pretty.rs | 1 + packages/rsx/src/rsx/mod.rs | 95 ----- 10 files changed, 101 insertions(+), 572 deletions(-) delete mode 100644 examples/rsx_autocomplete.rs rename packages/rsx/src/{rsx => }/component.rs (100%) rename packages/rsx/src/{rsx => }/element.rs (100%) delete mode 100644 packages/rsx/src/htm.rs rename packages/rsx/src/{rsx => }/node.rs (100%) create mode 100644 packages/rsx/src/pretty.rs delete mode 100644 packages/rsx/src/rsx/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 871810a76..63f1c938c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ dioxus-core = { path = "./packages/core", version = "^0.1.9" } dioxus-html = { path = "./packages/html", version = "^0.1.6", optional = true } dioxus-core-macro = { path = "./packages/core-macro", version = "^0.1.7", optional = true } dioxus-hooks = { path = "./packages/hooks", version = "^0.1.7", optional = true } -dioxus-macro-inner = { path = "./packages/rsx", optional = true } +dioxus-rsx = { path = "./packages/rsx", optional = true } fermi = { path = "./packages/fermi", version = "^0.1.0", optional = true } dioxus-web = { path = "./packages/web", version = "^0.0.5", optional = true } @@ -30,7 +30,7 @@ dioxus-interpreter-js = { path = "./packages/interpreter", version = "^0.0.0", o [features] default = ["macro", "hooks", "html"] -macro = ["dioxus-core-macro", "dioxus-macro-inner"] +macro = ["dioxus-core-macro", "dioxus-rsx"] hooks = ["dioxus-hooks"] html = ["dioxus-html"] ssr = ["dioxus-ssr"] diff --git a/examples/rsx_autocomplete.rs b/examples/rsx_autocomplete.rs deleted file mode 100644 index 99afe7521..000000000 --- a/examples/rsx_autocomplete.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! This example shows that autocomplete works in RSX - -use dioxus::prelude::*; - -fn main() { - dioxus::desktop::launch(app); -} - -fn app(cx: Scope) -> Element { - cx.render(rsx! { - div { - onclick: move |_| { - } - // class: "asd", - // style { - // media: "Ad", - // } - // div { - - // } - // { - // let t = String::new(); - // t. - // } - } - }) -} diff --git a/packages/core-macro/Cargo.toml b/packages/core-macro/Cargo.toml index 94f8e6e87..ed5d34e53 100644 --- a/packages/core-macro/Cargo.toml +++ b/packages/core-macro/Cargo.toml @@ -15,7 +15,7 @@ keywords = ["dom", "ui", "gui", "react", "wasm"] proc-macro = true [dependencies] -dioxus-macro-inner = { path = "../macro-inner" } +dioxus-rsx = { path = "../rsx" } proc-macro-error = "1.0.4" proc-macro2 = { version = "1.0.6" } quote = "1.0" diff --git a/packages/rsx/src/rsx/component.rs b/packages/rsx/src/component.rs similarity index 100% rename from packages/rsx/src/rsx/component.rs rename to packages/rsx/src/component.rs diff --git a/packages/rsx/src/rsx/element.rs b/packages/rsx/src/element.rs similarity index 100% rename from packages/rsx/src/rsx/element.rs rename to packages/rsx/src/element.rs diff --git a/packages/rsx/src/htm.rs b/packages/rsx/src/htm.rs deleted file mode 100644 index ca53096f6..000000000 --- a/packages/rsx/src/htm.rs +++ /dev/null @@ -1,443 +0,0 @@ -//! -//! TODO: -//! - [ ] Support for VComponents -//! - [ ] Support for inline format in text -//! - [ ] Support for expressions in attribute positions -//! - [ ] Support for iterators -//! - [ ] support for inline html! -//! -//! -//! -//! -//! -//! -//! - -use { - proc_macro2::TokenStream as TokenStream2, - quote::{quote, ToTokens, TokenStreamExt}, - syn::{ - ext::IdentExt, - parse::{Parse, ParseStream}, - token, Error, Expr, ExprClosure, Ident, LitStr, Result, Token, - }, -}; - -// ============================================== -// Parse any stream coming from the html! macro -// ============================================== -pub struct HtmlRender { - kind: NodeOrList, -} - -impl Parse for HtmlRender { - fn parse(input: ParseStream) -> Result { - if input.peek(LitStr) { - return input.parse::()?.parse::(); - } - - // let __cx: Ident = s.parse()?; - // s.parse::()?; - // if elements are in an array, return a bumpalo::collections::Vec rather than a Node. - let kind = if input.peek(token::Bracket) { - let nodes_toks; - syn::bracketed!(nodes_toks in input); - let mut nodes: Vec> = vec![nodes_toks.parse()?]; - while nodes_toks.peek(Token![,]) { - nodes_toks.parse::()?; - nodes.push(nodes_toks.parse()?); - } - NodeOrList::List(NodeList(nodes)) - } else { - NodeOrList::Node(input.parse()?) - }; - Ok(HtmlRender { kind }) - } -} - -impl ToTokens for HtmlRender { - fn to_tokens(&self, out_tokens: &mut TokenStream2) { - let new_toks = ToToksCtx::new(&self.kind).to_token_stream(); - - // create a lazy tree that accepts a bump allocator - let final_tokens = quote! { - dioxus::prelude::LazyNodes::new(move |__cx| { - let bump = __cx.bump(); - - #new_toks - }) - }; - - final_tokens.to_tokens(out_tokens); - } -} - -/// ============================================= -/// Parse any child as a node or list of nodes -/// ============================================= -/// - [ ] Allow iterators -/// -/// -enum NodeOrList { - Node(Node), - List(NodeList), -} - -impl ToTokens for ToToksCtx<&NodeOrList> { - fn to_tokens(&self, tokens: &mut TokenStream2) { - match self.inner { - NodeOrList::Node(node) => self.recurse(node).to_tokens(tokens), - NodeOrList::List(list) => self.recurse(list).to_tokens(tokens), - } - } -} - -struct NodeList(Vec>); - -impl ToTokens for ToToksCtx<&NodeList> { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let nodes = self.inner.0.iter().map(|node| self.recurse(node)); - tokens.append_all(quote! { - dioxus::bumpalo::vec![in bump; - #(#nodes),* - ] - }); - } -} - -enum Node { - Element(Element), - Text(TextNode), -} - -impl ToTokens for ToToksCtx<&Node> { - fn to_tokens(&self, tokens: &mut TokenStream2) { - match &self.inner { - Node::Element(el) => self.recurse(el).to_tokens(tokens), - Node::Text(txt) => self.recurse(txt).to_tokens(tokens), - } - } -} - -impl Node { - fn _peek(s: ParseStream) -> bool { - (s.peek(Token![<]) && !s.peek2(Token![/])) || s.peek(token::Brace) || s.peek(LitStr) - } -} - -impl Parse for Node { - fn parse(s: ParseStream) -> Result { - Ok(if s.peek(Token![<]) { - Node::Element(s.parse()?) - } else { - Node::Text(s.parse()?) - }) - } -} - -/// ======================================= -/// Parse the VNode::Element type -/// ======================================= -/// - [ ] Allow VComponent -/// -/// -struct Element { - name: Ident, - attrs: Vec, - children: MaybeExpr>, -} - -impl ToTokens for ToToksCtx<&Element> { - fn to_tokens(&self, tokens: &mut TokenStream2) { - // let __cx = self.__cx; - let name = &self.inner.name; - // let name = &self.inner.name.to_string(); - tokens.append_all(quote! { - __cx.element(dioxus_elements::#name) - // dioxus::builder::ElementBuilder::new( #name) - }); - for attr in self.inner.attrs.iter() { - self.recurse(attr).to_tokens(tokens); - } - - // if is_valid_svg_tag(&name.to_string()) { - // tokens.append_all(quote! { - // .namespace(Some("http://www.w3.org/2000/svg")) - // }); - // } - - match &self.inner.children { - MaybeExpr::Expr(expr) => tokens.append_all(quote! { - .children(#expr) - }), - MaybeExpr::Literal(nodes) => { - let mut children = nodes.iter(); - if let Some(child) = children.next() { - let mut inner_toks = TokenStream2::new(); - self.recurse(child).to_tokens(&mut inner_toks); - for child in children { - quote!(,).to_tokens(&mut inner_toks); - self.recurse(child).to_tokens(&mut inner_toks); - } - tokens.append_all(quote! { - .children([#inner_toks]) - }); - } - } - } - tokens.append_all(quote! { - .finish() - }); - } -} - -impl Parse for Element { - fn parse(s: ParseStream) -> Result { - s.parse::()?; - let name = Ident::parse_any(s)?; - let mut attrs = vec![]; - let _children: Vec = vec![]; - - // keep looking for attributes - while !s.peek(Token![>]) { - // self-closing - if s.peek(Token![/]) { - s.parse::()?; - s.parse::]>()?; - return Ok(Self { - name, - attrs, - children: MaybeExpr::Literal(vec![]), - }); - } - attrs.push(s.parse()?); - } - s.parse::]>()?; - - // Contents of an element can either be a brace (in which case we just copy verbatim), or a - // sequence of nodes. - let children = if s.peek(token::Brace) { - // expr - let content; - syn::braced!(content in s); - MaybeExpr::Expr(content.parse()?) - } else { - // nodes - let mut children = vec![]; - while !(s.peek(Token![<]) && s.peek2(Token![/])) { - children.push(s.parse()?); - } - MaybeExpr::Literal(children) - }; - - // closing element - s.parse::()?; - s.parse::()?; - let close = Ident::parse_any(s)?; - if close != name { - return Err(Error::new_spanned( - close, - "closing element does not match opening", - )); - } - s.parse::]>()?; - - Ok(Self { - name, - attrs, - children, - }) - } -} - -/// ======================================= -/// Parse a VElement's Attributes -/// ======================================= -/// - [ ] Allow expressions as attribute -/// -/// -struct Attr { - name: Ident, - ty: AttrType, -} - -impl Parse for Attr { - fn parse(s: ParseStream) -> Result { - let mut name = Ident::parse_any(s)?; - let name_str = name.to_string(); - s.parse::()?; - - // Check if this is an event handler - // If so, parse into literal tokens - let ty = if name_str.starts_with("on") { - // remove the "on" bit - name = Ident::new(name_str.trim_start_matches("on"), name.span()); - let content; - syn::braced!(content in s); - // AttrType::Value(content.parse()?) - AttrType::Event(content.parse()?) - // AttrType::Event(content.parse()?) - } else { - let lit_str = if name_str == "style" && s.peek(token::Brace) { - // special-case to deal with literal styles. - let outer; - syn::braced!(outer in s); - // double brace for inline style. - // todo!("Style support not ready yet"); - - // if outer.peek(token::Brace) { - // let inner; - // syn::braced!(inner in outer); - // let styles: Styles = inner.parse()?; - // MaybeExpr::Literal(LitStr::new(&styles.to_string(), Span::call_site())) - // } else { - // just parse as an expression - MaybeExpr::Expr(outer.parse()?) - // } - } else { - s.parse()? - }; - AttrType::Value(lit_str) - }; - Ok(Attr { name, ty }) - } -} - -impl ToTokens for ToToksCtx<&Attr> { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let name = self.inner.name.to_string(); - let _attr_stream = TokenStream2::new(); - match &self.inner.ty { - AttrType::Value(value) => { - let value = self.recurse(value); - if name == "xmlns" { - tokens.append_all(quote! { - .namespace(Some(#value)) - }); - } else { - tokens.append_all(quote! { - .attr(#name, format_args_f!(#value)) - }); - } - } - AttrType::Event(event) => { - tokens.append_all(quote! { - .on(#name, #event) - }); - } - } - } -} - -enum AttrType { - Value(MaybeExpr), - Event(ExprClosure), - // todo Bool(MaybeExpr) -} - -/// ======================================= -/// Parse just plain text -/// ======================================= -/// - [ ] Perform formatting automatically -/// -/// -struct TextNode(MaybeExpr); - -impl Parse for TextNode { - fn parse(s: ParseStream) -> Result { - Ok(Self(s.parse()?)) - } -} - -impl ToTokens for ToToksCtx<&TextNode> { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let mut token_stream = TokenStream2::new(); - self.recurse(&self.inner.0).to_tokens(&mut token_stream); - tokens.append_all(quote! { - __cx.text(format_args_f!(#token_stream)) - }); - } -} - -#[allow(clippy::large_enum_variant)] -enum MaybeExpr { - Literal(T), - Expr(Expr), -} - -impl Parse for MaybeExpr { - fn parse(s: ParseStream) -> Result { - if s.peek(token::Brace) { - let content; - syn::braced!(content in s); - Ok(MaybeExpr::Expr(content.parse()?)) - } else { - Ok(MaybeExpr::Literal(s.parse()?)) - } - } -} - -impl<'a, T> ToTokens for ToToksCtx<&'a MaybeExpr> -where - T: 'a, - ToToksCtx<&'a T>: ToTokens, -{ - fn to_tokens(&self, tokens: &mut TokenStream2) { - match &self.inner { - MaybeExpr::Literal(v) => self.recurse(v).to_tokens(tokens), - MaybeExpr::Expr(expr) => expr.to_tokens(tokens), - } - } -} - -/// ToTokens context -struct ToToksCtx { - inner: T, -} - -impl<'a, T> ToToksCtx { - fn new(inner: T) -> Self { - ToToksCtx { inner } - } - - fn recurse(&self, inner: U) -> ToToksCtx { - ToToksCtx { inner } - } -} - -impl ToTokens for ToToksCtx<&LitStr> { - fn to_tokens(&self, tokens: &mut TokenStream2) { - self.inner.to_tokens(tokens) - } -} - -#[cfg(test)] -mod test { - fn parse(input: &str) -> super::Result { - syn::parse_str(input) - } - - #[test] - fn div() { - parse("bump,
").unwrap(); - } - - #[test] - fn nested() { - parse("bump,
\"text\"
").unwrap(); - } - - #[test] - fn complex() { - parse( - "bump, -
{contact_details}
- ", - ) - .unwrap(); - } -} diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index b9911dedc..e20d80dec 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -1,4 +1,97 @@ -pub mod ifmt; -pub mod inlineprops; -pub mod props; -pub mod rsx; +//! Parse the root tokens in the rsx!{} macro +//! ========================================= +//! +//! This parsing path emerges directly from the macro call, with `RsxRender` being the primary entrance into parsing. +//! This feature must support: +//! - [x] Optionally rendering if the `in XYZ` pattern is present +//! - [x] Fragments as top-level element (through ambiguous) +//! - [x] Components as top-level element (through ambiguous) +//! - [x] Tags as top-level elements (through ambiguous) +//! - [x] Good errors if parsing fails +//! +//! Any errors in using rsx! will likely occur when people start using it, so the first errors must be really helpful. + +mod component; +mod element; +mod node; + +pub mod pretty; + +// Re-export the namespaces into each other +pub use component::*; +pub use element::*; +pub use node::*; + +// imports +use proc_macro2::TokenStream as TokenStream2; +use quote::{quote, ToTokens, TokenStreamExt}; +use syn::{ + parse::{Parse, ParseStream}, + Ident, Result, Token, +}; + +pub struct CallBody { + pub custom_context: Option, + pub roots: Vec, +} + +impl Parse for CallBody { + fn parse(input: ParseStream) -> Result { + let custom_context = if input.peek(Ident) && input.peek2(Token![,]) { + let name = input.parse::()?; + input.parse::()?; + + Some(name) + } else { + None + }; + + let mut roots = Vec::new(); + + while !input.is_empty() { + let node = input.parse::()?; + + if input.peek(Token![,]) { + let _ = input.parse::(); + } + + roots.push(node); + } + + Ok(Self { + custom_context, + roots, + }) + } +} + +/// Serialize the same way, regardless of flavor +impl ToTokens for CallBody { + fn to_tokens(&self, out_tokens: &mut TokenStream2) { + let inner = if self.roots.len() == 1 { + let inner = &self.roots[0]; + quote! { #inner } + } else { + let childs = &self.roots; + quote! { __cx.fragment_root([ #(#childs),* ]) } + }; + + match &self.custom_context { + // The `in cx` pattern allows directly rendering + Some(ident) => out_tokens.append_all(quote! { + #ident.render(LazyNodes::new_some(move |__cx: NodeFactory| -> VNode { + use dioxus_elements::{GlobalAttributes, SvgAttributes}; + #inner + })) + }), + + // Otherwise we just build the LazyNode wrapper + None => out_tokens.append_all(quote! { + LazyNodes::new_some(move |__cx: NodeFactory| -> VNode { + use dioxus_elements::{GlobalAttributes, SvgAttributes}; + #inner + }) + }), + }; + } +} diff --git a/packages/rsx/src/rsx/node.rs b/packages/rsx/src/node.rs similarity index 100% rename from packages/rsx/src/rsx/node.rs rename to packages/rsx/src/node.rs diff --git a/packages/rsx/src/pretty.rs b/packages/rsx/src/pretty.rs new file mode 100644 index 000000000..26ad54006 --- /dev/null +++ b/packages/rsx/src/pretty.rs @@ -0,0 +1 @@ +//! pretty printer for rsx! diff --git a/packages/rsx/src/rsx/mod.rs b/packages/rsx/src/rsx/mod.rs deleted file mode 100644 index 87b324dfc..000000000 --- a/packages/rsx/src/rsx/mod.rs +++ /dev/null @@ -1,95 +0,0 @@ -//! Parse the root tokens in the rsx!{} macro -//! ========================================= -//! -//! This parsing path emerges directly from the macro call, with `RsxRender` being the primary entrance into parsing. -//! This feature must support: -//! - [x] Optionally rendering if the `in XYZ` pattern is present -//! - [x] Fragments as top-level element (through ambiguous) -//! - [x] Components as top-level element (through ambiguous) -//! - [x] Tags as top-level elements (through ambiguous) -//! - [x] Good errors if parsing fails -//! -//! Any errors in using rsx! will likely occur when people start using it, so the first errors must be really helpful. - -mod component; -mod element; -mod node; - -// Re-export the namespaces into each other -pub use component::*; -pub use element::*; -pub use node::*; - -// imports -use proc_macro2::TokenStream as TokenStream2; -use quote::{quote, ToTokens, TokenStreamExt}; -use syn::{ - parse::{Parse, ParseStream}, - Ident, Result, Token, -}; - -pub struct CallBody { - pub custom_context: Option, - pub roots: Vec, -} - -impl Parse for CallBody { - fn parse(input: ParseStream) -> Result { - let custom_context = if input.peek(Ident) && input.peek2(Token![,]) { - let name = input.parse::()?; - input.parse::()?; - - Some(name) - } else { - None - }; - - let mut roots = Vec::new(); - - while !input.is_empty() { - let node = input.parse::()?; - - if input.peek(Token![,]) { - let _ = input.parse::(); - } - - roots.push(node); - } - - Ok(Self { - custom_context, - roots, - }) - } -} - -/// Serialize the same way, regardless of flavor -impl ToTokens for CallBody { - fn to_tokens(&self, out_tokens: &mut TokenStream2) { - let inner = if self.roots.len() == 1 { - let inner = &self.roots[0]; - quote! { #inner } - } else { - let childs = &self.roots; - quote! { __cx.fragment_root([ #(#childs),* ]) } - }; - - match &self.custom_context { - // The `in cx` pattern allows directly rendering - Some(ident) => out_tokens.append_all(quote! { - #ident.render(LazyNodes::new_some(move |__cx: NodeFactory| -> VNode { - use dioxus_elements::{GlobalAttributes, SvgAttributes}; - #inner - })) - }), - - // Otherwise we just build the LazyNode wrapper - None => out_tokens.append_all(quote! { - LazyNodes::new_some(move |__cx: NodeFactory| -> VNode { - use dioxus_elements::{GlobalAttributes, SvgAttributes}; - #inner - }) - }), - }; - } -} From 185902f935b545b6af70fcff53f130031d98fa50 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Fri, 18 Feb 2022 23:14:17 -0500 Subject: [PATCH 5/8] fix: macro compiles --- packages/core-macro/src/lib.rs | 37 +++++----------------------------- 1 file changed, 5 insertions(+), 32 deletions(-) diff --git a/packages/core-macro/src/lib.rs b/packages/core-macro/src/lib.rs index b2e4ffbb1..96ea0ce87 100644 --- a/packages/core-macro/src/lib.rs +++ b/packages/core-macro/src/lib.rs @@ -1,8 +1,11 @@ -use dioxus_macro_inner::*; use proc_macro::TokenStream; use quote::ToTokens; use syn::parse_macro_input; +mod ifmt; +mod inlineprops; +mod props; + #[proc_macro] pub fn format_args_f(input: TokenStream) -> TokenStream { use ifmt::*; @@ -175,42 +178,12 @@ pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::Token #[proc_macro_error::proc_macro_error] #[proc_macro] pub fn rsx(s: TokenStream) -> TokenStream { - match syn::parse::(s) { + match syn::parse::(s) { Err(err) => err.to_compile_error().into(), Ok(stream) => stream.to_token_stream().into(), } } -/// Derive macro used to mark an enum as Routable. -/// -/// This macro can only be used on enums. Every varient of the macro needs to be marked -/// with the `at` attribute to specify the URL of the route. It generates an implementation of -/// `yew_router::Routable` trait and `const`s for the routes passed which are used with `Route` -/// component. -/// -/// # Example -/// -/// ``` -/// # use yew_router::Routable; -/// #[derive(Debug, Clone, Copy, PartialEq, Routable)] -/// enum Routes { -/// #[at("/")] -/// Home, -/// #[at("/secure")] -/// Secure, -/// #[at("/profile/{id}")] -/// Profile(u32), -/// #[at("/404")] -/// NotFound, -/// } -/// ``` -#[proc_macro_derive(Routable, attributes(at, not_found))] -pub fn routable_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - use router::{routable_derive_impl, Routable}; - let input = parse_macro_input!(input as Routable); - routable_derive_impl(input).into() -} - /// Derive props for a component within the component definition. /// /// This macro provides a simple transformation from `Scope<{}>` to `Scope

`, From 9438cc14bc8c2dd8781908a598684e723d45ec45 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Fri, 18 Feb 2022 23:17:33 -0500 Subject: [PATCH 6/8] fix: make listeners up to date --- packages/rsx/src/element.rs | 84 ++++++++++++++++++------------------- src/lib.rs | 2 +- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/packages/rsx/src/element.rs b/packages/rsx/src/element.rs index c612e9f1b..2c295d9a0 100644 --- a/packages/rsx/src/element.rs +++ b/packages/rsx/src/element.rs @@ -4,7 +4,7 @@ use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens, TokenStreamExt}; use syn::{ parse::{Parse, ParseBuffer, ParseStream}, - Expr, ExprClosure, Ident, LitStr, Result, Token, + Expr, Ident, LitStr, Result, Token, }; // ======================================= @@ -81,24 +81,31 @@ impl Parse for Element { content.parse::()?; if name_str.starts_with("on") { - if content.fork().parse::().is_ok() { - // - attributes.push(ElementAttrNamed { - el_name: el_name.clone(), - attr: ElementAttr::EventClosure { - name, - closure: content.parse()?, - }, - }); - } else { - attributes.push(ElementAttrNamed { - el_name: el_name.clone(), - attr: ElementAttr::EventTokens { - name, - tokens: content.parse()?, - }, - }); - } + attributes.push(ElementAttrNamed { + el_name: el_name.clone(), + attr: ElementAttr::EventTokens { + name, + tokens: content.parse()?, + }, + }); + // if content.fork().parse::().is_ok() { + // // + // attributes.push(ElementAttrNamed { + // el_name: el_name.clone(), + // attr: ElementAttr::EventClosure { + // name, + // closure: content.parse()?, + // }, + // }); + // } else { + // attributes.push(ElementAttrNamed { + // el_name: el_name.clone(), + // attr: ElementAttr::EventTokens { + // name, + // tokens: content.parse()?, + // }, + // }); + // } } else { match name_str.as_str() { "key" => { @@ -203,28 +210,20 @@ impl ToTokens for Element { let name = &self.name; let children = &self.children; - // let listeners = &self.listeners; - let key = match &self.key { Some(ty) => quote! { Some(format_args_f!(#ty)) }, None => quote! { None }, }; - let listeners = self.attributes.iter().filter(|f| { - if let ElementAttr::EventTokens { .. } = f.attr { - true - } else { - false - } - }); + let listeners = self + .attributes + .iter() + .filter(|f| matches!(f.attr, ElementAttr::EventTokens { .. })); - let attr = self.attributes.iter().filter(|f| { - if let ElementAttr::EventTokens { .. } = f.attr { - false - } else { - true - } - }); + let attr = self + .attributes + .iter() + .filter(|f| !matches!(f.attr, ElementAttr::EventTokens { .. })); tokens.append_all(quote! { __cx.element( @@ -251,9 +250,8 @@ pub enum ElementAttr { /// "attribute": true, CustomAttrExpression { name: LitStr, value: Expr }, - /// onclick: move |_| {} - EventClosure { name: Ident, closure: ExprClosure }, - + // /// onclick: move |_| {} + // EventClosure { name: Ident, closure: ExprClosure }, /// onclick: {} EventTokens { name: Ident, tokens: Expr }, } @@ -288,11 +286,11 @@ impl ToTokens for ElementAttrNamed { __cx.attr( #name, format_args_f!(#value), None, false ) } } - ElementAttr::EventClosure { name, closure } => { - quote! { - dioxus_elements::on::#name(__cx, #closure) - } - } + // ElementAttr::EventClosure { name, closure } => { + // quote! { + // dioxus_elements::on::#name(__cx, #closure) + // } + // } ElementAttr::EventTokens { name, tokens } => { quote! { dioxus_elements::on::#name(__cx, #tokens) diff --git a/src/lib.rs b/src/lib.rs index 2db210bee..488b1ee9b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -353,7 +353,7 @@ pub mod events { pub mod prelude { pub use dioxus_core::prelude::*; - pub use dioxus_core_macro::{format_args_f, inline_props, rsx, Props, Routable}; + pub use dioxus_core_macro::{format_args_f, inline_props, rsx, Props}; pub use dioxus_elements::{GlobalAttributes, SvgAttributes}; pub use dioxus_hooks::*; pub use dioxus_html as dioxus_elements; From 5d56326f74e07dbc70141100bb71826ed7033152 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Fri, 18 Feb 2022 23:18:52 -0500 Subject: [PATCH 7/8] feat: collapse rsx --- packages/rsx/src/element.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/packages/rsx/src/element.rs b/packages/rsx/src/element.rs index 2c295d9a0..fa8fc9f51 100644 --- a/packages/rsx/src/element.rs +++ b/packages/rsx/src/element.rs @@ -88,24 +88,6 @@ impl Parse for Element { tokens: content.parse()?, }, }); - // if content.fork().parse::().is_ok() { - // // - // attributes.push(ElementAttrNamed { - // el_name: el_name.clone(), - // attr: ElementAttr::EventClosure { - // name, - // closure: content.parse()?, - // }, - // }); - // } else { - // attributes.push(ElementAttrNamed { - // el_name: el_name.clone(), - // attr: ElementAttr::EventTokens { - // name, - // tokens: content.parse()?, - // }, - // }); - // } } else { match name_str.as_str() { "key" => { @@ -199,7 +181,6 @@ impl Parse for Element { name: el_name, attributes, children, - // listeners, _is_static: false, }) } From 237f036a801244f5ae3dc664e58f244c2cf1d561 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Fri, 18 Feb 2022 23:26:47 -0500 Subject: [PATCH 8/8] wip: add meta to rsx --- packages/rsx/src/node.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/rsx/src/node.rs b/packages/rsx/src/node.rs index d5d701767..eeee421b0 100644 --- a/packages/rsx/src/node.rs +++ b/packages/rsx/src/node.rs @@ -4,7 +4,7 @@ use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens, TokenStreamExt}; use syn::{ parse::{Parse, ParseStream}, - token, Expr, LitStr, Result, Token, + token, Attribute, Expr, LitStr, Result, Token, }; /* @@ -20,6 +20,7 @@ pub enum BodyNode { Component(Component), Text(LitStr), RawExpr(Expr), + Meta(Attribute), } impl Parse for BodyNode { @@ -79,6 +80,7 @@ impl ToTokens for BodyNode { BodyNode::RawExpr(exp) => tokens.append_all(quote! { __cx.fragment_from_iter(#exp) }), + BodyNode::Meta(_) => {} } } }