better error handling
This commit is contained in:
1 parent
29be00e9f5
commit
2183ecf3fb
7 files changed
+174
-89
No files matched your search
+88
-39
@@ -1,56 +1,105 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
dioxus::web::launch_with_props(with_hot_reload, app, |c| c);
|
dioxus::desktop::launch_with_props(with_hot_reload, app, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
let count = use_state(&cx, || 170);
|
let rsx_code = use_state(&cx, || {
|
||||||
let rsx_code = use_state(&cx, || None);
|
r##"div {
|
||||||
let re_render = cx.schedule_update();
|
|
||||||
|
|
||||||
cx.render(rsx! {
|
|
||||||
div {
|
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "500px",
|
height: "500px",
|
||||||
onclick: move |_| {
|
onclick: move |_| {
|
||||||
count.modify(|count| *count + 10);
|
count.modify(|count| *count + 10);
|
||||||
},
|
},
|
||||||
|
|
||||||
div {
|
p {
|
||||||
display: "flex",
|
"High-Five counter: {count}",
|
||||||
flex_direction: "row",
|
|
||||||
width: "100%",
|
|
||||||
height: "50%",
|
|
||||||
textarea {
|
|
||||||
width: "90%",
|
|
||||||
value: {
|
|
||||||
if rsx_code.get().is_none() {
|
|
||||||
let rsx_text_index: RsxTextIndex = cx.consume_context().unwrap();
|
|
||||||
let read = rsx_text_index.read();
|
|
||||||
rsx_code.set(Some(read.get(&__line_num).unwrap().clone()));
|
|
||||||
}
|
|
||||||
(*rsx_code.current()).clone().unwrap()
|
|
||||||
},
|
|
||||||
oninput: move |evt| {
|
|
||||||
rsx_code.set(Some(evt.value.clone()));
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
height: "100%",
|
|
||||||
width: "10%",
|
|
||||||
onclick: move |_|{
|
|
||||||
if let Some(code) = rsx_code.get(){
|
|
||||||
let rsx_text_index: RsxTextIndex = cx.consume_context().unwrap();
|
|
||||||
rsx_text_index.insert(__line_num.clone(), code.clone());
|
|
||||||
re_render();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"submit"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
width: "{count}px",
|
||||||
|
height: "10px",
|
||||||
|
background_color: "red",
|
||||||
|
}
|
||||||
|
|
||||||
|
Comp {
|
||||||
|
color: "#083289"
|
||||||
|
}
|
||||||
|
|
||||||
|
Comp {
|
||||||
|
color: "green"
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
(0..10).map(|i| {
|
||||||
|
cx.render(rsx!{p {"{i}"}})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}"##
|
||||||
|
.to_string()
|
||||||
|
});
|
||||||
|
let submitted_rsx_code = use_state(&cx, || None);
|
||||||
|
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
display: "flex",
|
||||||
|
flex_direction: "row",
|
||||||
|
width: "100%",
|
||||||
|
height: "50%",
|
||||||
|
Editable{
|
||||||
|
current_code: submitted_rsx_code.get().clone(),
|
||||||
|
},
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
width: "90%",
|
||||||
|
value:
|
||||||
|
rsx_code
|
||||||
|
,
|
||||||
|
oninput: move |evt| {
|
||||||
|
rsx_code.set(evt.value.clone());
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
height: "100%",
|
||||||
|
width: "10%",
|
||||||
|
onclick: move |_|{
|
||||||
|
submitted_rsx_code.set(Some(rsx_code.get().clone()));
|
||||||
|
},
|
||||||
|
"submit"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Props)]
|
||||||
|
struct EditableProps {
|
||||||
|
#[props(!optional)]
|
||||||
|
current_code: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Editable(cx: Scope<EditableProps>) -> Element {
|
||||||
|
let count = use_state(&cx, || 170);
|
||||||
|
if let Some(code) = cx.props.current_code.as_ref() {
|
||||||
|
let rsx_index: RsxTextIndex = cx.consume_context().unwrap();
|
||||||
|
rsx_index.insert(
|
||||||
|
CodeLocation {
|
||||||
|
file: r"examples\hot_reload.rs".to_string(),
|
||||||
|
line: 95,
|
||||||
|
column: 15,
|
||||||
|
},
|
||||||
|
code.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
width: "100%",
|
||||||
|
height: "500px",
|
||||||
|
onclick: move |_| {
|
||||||
|
count.modify(|count| *count + 10);
|
||||||
|
},
|
||||||
|
|
||||||
p {
|
p {
|
||||||
"High-Five counter: {count}",
|
"High-Five counter: {count}",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::{quote, ToTokens};
|
use quote::ToTokens;
|
||||||
use syn::parse_macro_input;
|
use syn::parse_macro_input;
|
||||||
|
|
||||||
mod inlineprops;
|
mod inlineprops;
|
||||||
@@ -189,7 +189,7 @@ pub fn rsx(s: TokenStream) -> TokenStream {
|
|||||||
use dioxus_rsx_interperter::captuered_context::CapturedContextBuilder;
|
use dioxus_rsx_interperter::captuered_context::CapturedContextBuilder;
|
||||||
|
|
||||||
let captured = CapturedContextBuilder::from_call_body(body);
|
let captured = CapturedContextBuilder::from_call_body(body);
|
||||||
quote! {
|
quote::quote! {
|
||||||
{
|
{
|
||||||
let __line_num = get_line_num();
|
let __line_num = get_line_num();
|
||||||
let __rsx_text_index: RsxTextIndex = cx.consume_context().unwrap();
|
let __rsx_text_index: RsxTextIndex = cx.consume_context().unwrap();
|
||||||
@@ -206,11 +206,14 @@ pub fn rsx(s: TokenStream) -> TokenStream {
|
|||||||
// clone prevents deadlock on nested rsx calls
|
// clone prevents deadlock on nested rsx calls
|
||||||
read.get(&__line_num).cloned()
|
read.get(&__line_num).cloned()
|
||||||
} {
|
} {
|
||||||
interpert_rsx(
|
match interpert_rsx(
|
||||||
__cx,
|
__cx,
|
||||||
&__text,
|
&__text,
|
||||||
#captured
|
#captured
|
||||||
)
|
){
|
||||||
|
Ok(vnode) => vnode,
|
||||||
|
Err(err) => __cx.text(format_args!("{:?}", err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
panic!("rsx: line number {:?} not found in rsx index", __line_num);
|
panic!("rsx: line number {:?} not found in rsx index", __line_num);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ edition = "2021"
|
|||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
syn = "1.0"
|
syn = { version = "1.0", features = ["extra-traits"] }
|
||||||
quote = "1.0"
|
quote = "1.0"
|
||||||
dioxus-rsx = { path = "../rsx", default-features = false }
|
dioxus-rsx = { path = "../rsx", default-features = false }
|
||||||
dioxus-ssr = { path = "../ssr" }
|
dioxus-ssr = { path = "../ssr" }
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
ParseError(syn::Error),
|
||||||
|
RecompileRequiredError(RecompileReason),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum RecompileReason {
|
||||||
|
CapturedVariable(String),
|
||||||
|
CapturedExpression(String),
|
||||||
|
CapturedComponent(String),
|
||||||
|
CapturedListener(String),
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ use syn::{parse2, parse_str, Expr};
|
|||||||
use crate::attributes::attrbute_to_static_str;
|
use crate::attributes::attrbute_to_static_str;
|
||||||
use crate::captuered_context::{CapturedContext, IfmtArgs};
|
use crate::captuered_context::{CapturedContext, IfmtArgs};
|
||||||
use crate::elements::element_to_static_str;
|
use crate::elements::element_to_static_str;
|
||||||
|
use crate::error::{Error, RecompileReason};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Segment {
|
enum Segment {
|
||||||
@@ -88,25 +89,25 @@ pub fn build<'a>(
|
|||||||
rsx: CallBody,
|
rsx: CallBody,
|
||||||
mut ctx: CapturedContext<'a>,
|
mut ctx: CapturedContext<'a>,
|
||||||
factory: &NodeFactory<'a>,
|
factory: &NodeFactory<'a>,
|
||||||
) -> VNode<'a> {
|
) -> Result<VNode<'a>, Error> {
|
||||||
let children_built = factory.bump().alloc(Vec::new());
|
let children_built = factory.bump().alloc(Vec::new());
|
||||||
for child in rsx.roots {
|
for child in rsx.roots {
|
||||||
children_built.push(build_node(child, &mut ctx, factory));
|
children_built.push(build_node(child, &mut ctx, factory)?);
|
||||||
}
|
}
|
||||||
factory.fragment_from_iter(children_built.iter())
|
Ok(factory.fragment_from_iter(children_built.iter()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_node<'a>(
|
fn build_node<'a>(
|
||||||
node: BodyNode,
|
node: BodyNode,
|
||||||
ctx: &mut CapturedContext<'a>,
|
ctx: &mut CapturedContext<'a>,
|
||||||
factory: &NodeFactory<'a>,
|
factory: &NodeFactory<'a>,
|
||||||
) -> Option<VNode<'a>> {
|
) -> Result<VNode<'a>, Error> {
|
||||||
let bump = factory.bump();
|
let bump = factory.bump();
|
||||||
match node {
|
match node {
|
||||||
BodyNode::Text(text) => {
|
BodyNode::Text(text) => {
|
||||||
let ifmt: InterperedIfmt = text.value().parse().unwrap();
|
let ifmt: InterperedIfmt = text.value().parse().unwrap();
|
||||||
let text = bump.alloc(ifmt.resolve(&ctx.captured));
|
let text = bump.alloc(ifmt.resolve(&ctx.captured));
|
||||||
Some(factory.text(format_args!("{}", text)))
|
Ok(factory.text(format_args!("{}", text)))
|
||||||
}
|
}
|
||||||
BodyNode::Element(el) => {
|
BodyNode::Element(el) => {
|
||||||
let attributes: &mut Vec<Attribute> = bump.alloc(Vec::new());
|
let attributes: &mut Vec<Attribute> = bump.alloc(Vec::new());
|
||||||
@@ -132,8 +133,6 @@ fn build_node<'a>(
|
|||||||
is_volatile: false,
|
is_volatile: false,
|
||||||
namespace,
|
namespace,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +164,11 @@ fn build_node<'a>(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("could not resolve expression {:?}", value);
|
return Err(Error::RecompileRequiredError(
|
||||||
|
RecompileReason::CapturedExpression(
|
||||||
|
value.into_token_stream().to_string(),
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@@ -174,7 +177,7 @@ fn build_node<'a>(
|
|||||||
let children = bump.alloc(Vec::new());
|
let children = bump.alloc(Vec::new());
|
||||||
for child in el.children {
|
for child in el.children {
|
||||||
let node = build_node(child, ctx, factory);
|
let node = build_node(child, ctx, factory);
|
||||||
if let Some(node) = node {
|
if let Ok(node) = node {
|
||||||
children.push(node);
|
children.push(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,20 +185,23 @@ fn build_node<'a>(
|
|||||||
for attr in el.attributes {
|
for attr in el.attributes {
|
||||||
match attr.attr {
|
match attr.attr {
|
||||||
ElementAttr::EventTokens { .. } => {
|
ElementAttr::EventTokens { .. } => {
|
||||||
let expr: Expr = parse2(attr.to_token_stream()).unwrap();
|
let expr: Expr =
|
||||||
if let Some(idx) = ctx
|
parse2(attr.to_token_stream()).map_err(|err| Error::ParseError(err))?;
|
||||||
.listeners
|
if let Some(idx) = ctx.listeners.iter().position(|(code, _)| {
|
||||||
.iter()
|
if let Ok(parsed) = parse_str::<Expr>(*code) {
|
||||||
.position(|(code, _)| parse_str::<Expr>(*code).unwrap() == expr)
|
parsed == expr
|
||||||
{
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}) {
|
||||||
let (_, listener) = ctx.listeners.remove(idx);
|
let (_, listener) = ctx.listeners.remove(idx);
|
||||||
listeners.push(listener)
|
listeners.push(listener)
|
||||||
} else {
|
} else {
|
||||||
panic!(
|
return Err(Error::RecompileRequiredError(
|
||||||
"could not resolve listener {:?} \n in: {:#?}",
|
RecompileReason::CapturedListener(
|
||||||
expr.to_token_stream().to_string(),
|
expr.to_token_stream().to_string(),
|
||||||
ctx.listeners.iter().map(|(s, _)| s).collect::<Vec<_>>()
|
),
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@@ -204,7 +210,7 @@ fn build_node<'a>(
|
|||||||
let tag = bump.alloc(el.name.to_string());
|
let tag = bump.alloc(el.name.to_string());
|
||||||
if let Some((tag, ns)) = element_to_static_str(tag) {
|
if let Some((tag, ns)) = element_to_static_str(tag) {
|
||||||
match el.key {
|
match el.key {
|
||||||
None => Some(factory.raw_element(
|
None => Ok(factory.raw_element(
|
||||||
tag,
|
tag,
|
||||||
ns,
|
ns,
|
||||||
listeners,
|
listeners,
|
||||||
@@ -216,7 +222,7 @@ fn build_node<'a>(
|
|||||||
let ifmt: InterperedIfmt = lit.value().parse().unwrap();
|
let ifmt: InterperedIfmt = lit.value().parse().unwrap();
|
||||||
let key = bump.alloc(ifmt.resolve(&ctx.captured));
|
let key = bump.alloc(ifmt.resolve(&ctx.captured));
|
||||||
|
|
||||||
Some(factory.raw_element(
|
Ok(factory.raw_element(
|
||||||
tag,
|
tag,
|
||||||
ns,
|
ns,
|
||||||
listeners,
|
listeners,
|
||||||
@@ -227,36 +233,44 @@ fn build_node<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
Err(Error::ParseError(syn::Error::new(
|
||||||
|
el.name.span(),
|
||||||
|
"unknown element",
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BodyNode::Component(comp) => {
|
BodyNode::Component(comp) => {
|
||||||
let expr: Expr = parse2(comp.to_token_stream()).unwrap();
|
let expr: Expr =
|
||||||
if let Some(idx) = ctx
|
parse2(comp.to_token_stream()).map_err(|err| Error::ParseError(err))?;
|
||||||
.components
|
if let Some(idx) = ctx.components.iter().position(|(code, _)| {
|
||||||
.iter()
|
if let Ok(parsed) = parse_str::<Expr>(*code) {
|
||||||
.position(|(code, _)| parse_str::<Expr>(*code).unwrap() == expr)
|
parsed == expr
|
||||||
{
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}) {
|
||||||
let (_, vnode) = ctx.components.remove(idx);
|
let (_, vnode) = ctx.components.remove(idx);
|
||||||
Some(vnode)
|
Ok(vnode)
|
||||||
} else {
|
} else {
|
||||||
panic!("could not resolve component {:?}", comp.name);
|
Err(Error::RecompileRequiredError(
|
||||||
|
RecompileReason::CapturedComponent(comp.name.to_token_stream().to_string()),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BodyNode::RawExpr(iterator) => {
|
BodyNode::RawExpr(iterator) => {
|
||||||
if let Some(idx) = ctx
|
if let Some(idx) = ctx.iterators.iter().position(|(code, _)| {
|
||||||
.iterators
|
if let Ok(parsed) = parse_str::<Expr>(*code) {
|
||||||
.iter()
|
parsed == iterator
|
||||||
.position(|(code, _)| parse_str::<Expr>(*code).unwrap() == iterator)
|
} else {
|
||||||
{
|
false
|
||||||
|
}
|
||||||
|
}) {
|
||||||
let (_, vnode) = ctx.iterators.remove(idx);
|
let (_, vnode) = ctx.iterators.remove(idx);
|
||||||
Some(vnode)
|
Ok(vnode)
|
||||||
} else {
|
} else {
|
||||||
panic!(
|
Err(Error::RecompileRequiredError(
|
||||||
"could not resolve iterator {} \n fron {:?}",
|
RecompileReason::CapturedExpression(iterator.to_token_stream().to_string()),
|
||||||
iterator.to_token_stream(),
|
))
|
||||||
ctx.iterators.iter().map(|(s, _)| s).collect::<Vec<_>>()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use dioxus_core::{Component, Element, LazyNodes, Scope, VNode};
|
use dioxus_core::{Component, Element, LazyNodes, Scope, VNode};
|
||||||
use dioxus_hooks::*;
|
use dioxus_hooks::*;
|
||||||
|
use error::Error;
|
||||||
use interperter::build;
|
use interperter::build;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::panic::Location;
|
use std::panic::Location;
|
||||||
@@ -10,6 +11,7 @@ use syn::parse_str;
|
|||||||
mod attributes;
|
mod attributes;
|
||||||
pub mod captuered_context;
|
pub mod captuered_context;
|
||||||
mod elements;
|
mod elements;
|
||||||
|
mod error;
|
||||||
mod interperter;
|
mod interperter;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
@@ -35,8 +37,12 @@ pub fn interpert_rsx<'a, 'b>(
|
|||||||
factory: dioxus_core::NodeFactory<'a>,
|
factory: dioxus_core::NodeFactory<'a>,
|
||||||
text: &str,
|
text: &str,
|
||||||
context: captuered_context::CapturedContext<'a>,
|
context: captuered_context::CapturedContext<'a>,
|
||||||
) -> VNode<'a> {
|
) -> Result<VNode<'a>, Error> {
|
||||||
build(parse_str(text).unwrap(), context, &factory)
|
build(
|
||||||
|
parse_str(text).map_err(|err| Error::ParseError(err))?,
|
||||||
|
context,
|
||||||
|
&factory,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
|||||||
+1
-1
@@ -62,6 +62,6 @@ pub mod prelude {
|
|||||||
#[cfg(feature = "hot_reload")]
|
#[cfg(feature = "hot_reload")]
|
||||||
pub use dioxus_rsx_interperter::{
|
pub use dioxus_rsx_interperter::{
|
||||||
captuered_context::{CapturedContext, IfmtArgs},
|
captuered_context::{CapturedContext, IfmtArgs},
|
||||||
get_line_num, interpert_rsx, with_hot_reload, RsxTextIndex,
|
get_line_num, interpert_rsx, with_hot_reload, CodeLocation, RsxTextIndex,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user