From e4d60c8dfcf7c1633d9868dd91a65afcdf48dfb7 Mon Sep 17 00:00:00 2001 From: Pascal Date: Wed, 6 Dec 2023 21:39:31 +0100 Subject: [PATCH 01/28] add default menu bar in dioxus-desktop to resolve #1691 fixup naming and expose disable_default_menu_bar with builder function --- packages/desktop/src/cfg.rs | 8 +++++ packages/desktop/src/webview.rs | 64 +++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/packages/desktop/src/cfg.rs b/packages/desktop/src/cfg.rs index 07281e364..ba42ffa01 100644 --- a/packages/desktop/src/cfg.rs +++ b/packages/desktop/src/cfg.rs @@ -36,6 +36,7 @@ pub struct Config { pub(crate) root_name: String, pub(crate) background_color: Option<(u8, u8, u8, u8)>, pub(crate) last_window_close_behaviour: WindowCloseBehaviour, + pub(crate) disable_default_menu_bar: bool, } type DropHandler = Box bool>; @@ -65,9 +66,16 @@ impl Config { root_name: "main".to_string(), background_color: None, last_window_close_behaviour: WindowCloseBehaviour::LastWindowExitsApp, + disable_default_menu_bar: false, } } + /// Set whether the default menu bar should be disabled. + pub fn with_disable_default_menu_bar(mut self, disable: bool) -> Self { + self.disable_default_menu_bar = disable; + self + } + /// set the directory from which assets will be searched in release mode pub fn with_resource_directory(mut self, path: impl Into) -> Self { self.resource_dir = Some(path.into()); diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index 6e6d26b17..9beae702a 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -4,6 +4,7 @@ use crate::{desktop_context::UserWindowEvent, Config}; use tao::event_loop::{EventLoopProxy, EventLoopWindowTarget}; pub use wry; pub use wry::application as tao; +use wry::application::menu::{MenuBar, MenuItem}; use wry::application::window::Window; use wry::webview::{WebContext, WebView, WebViewBuilder}; @@ -12,13 +13,18 @@ pub fn build( event_loop: &EventLoopWindowTarget, proxy: EventLoopProxy, ) -> (WebView, WebContext) { - let builder = cfg.window.clone(); - let window = builder.with_visible(false).build(event_loop).unwrap(); + let mut builder = cfg.window.clone(); let file_handler = cfg.file_drop_handler.take(); let custom_head = cfg.custom_head.clone(); let index_file = cfg.custom_index.clone(); let root_name = cfg.root_name.clone(); + if !cfg.disable_default_menu_bar { + builder = builder.with_menu(create_default_menu_bar()); + } + + let window = builder.with_visible(false).build(event_loop).unwrap(); + // We assume that if the icon is None in cfg, then the user just didnt set it if cfg.window.window.window_icon.is_none() { window.set_window_icon(Some( @@ -96,3 +102,57 @@ pub fn build( (webview.build().unwrap(), web_context) } + +/// Creates a standard menu bar depending on the platform +fn create_default_menu_bar() -> MenuBar { + let mut menu_bar = MenuBar::new(); + + // since it is uncommon on windows to have an "application menu" + // we add a "window" menu to be more consistent across platforms with the standard menu + let mut window_menu = MenuBar::new(); + #[cfg(target_os = "macos")] + { + window_menu.add_native_item(MenuItem::EnterFullScreen); + window_menu.add_native_item(MenuItem::Zoom); + window_menu.add_native_item(MenuItem::Separator); + } + + window_menu.add_native_item(MenuItem::Hide); + + #[cfg(target_os = "macos")] + { + window_menu.add_native_item(MenuItem::HideOthers); + window_menu.add_native_item(MenuItem::ShowAll); + } + + window_menu.add_native_item(MenuItem::Minimize); + window_menu.add_native_item(MenuItem::CloseWindow); + window_menu.add_native_item(MenuItem::Separator); + window_menu.add_native_item(MenuItem::Quit); + menu_bar.add_submenu("Window", true, window_menu); + + // since tao supports none of the below items on linux we should only add them on macos/windows + #[cfg(not(target_os = "linux"))] + { + let mut edit_menu = MenuBar::new(); + #[cfg(target_os = "macos")] + { + edit_menu.add_native_item(MenuItem::Undo); + edit_menu.add_native_item(MenuItem::Redo); + edit_menu.add_native_item(MenuItem::Separator); + } + + edit_menu.add_native_item(MenuItem::Cut); + edit_menu.add_native_item(MenuItem::Copy); + edit_menu.add_native_item(MenuItem::Paste); + + #[cfg(target_os = "macos")] + { + edit_menu.add_native_item(MenuItem::Separator); + edit_menu.add_native_item(MenuItem::SelectAll); + } + menu_bar.add_submenu("Edit", true, edit_menu); + } + + menu_bar +} From adfbb6c380ba2079ed7159e9cf84175e301476c7 Mon Sep 17 00:00:00 2001 From: Pascal Date: Thu, 7 Dec 2023 16:36:20 +0100 Subject: [PATCH 02/28] improved documentation and refactored naming to be more self-explanatory --- examples/all_events.rs | 15 +- examples/callback.rs | 19 +- examples/compose.rs | 15 +- examples/error_handle.rs | 9 +- examples/eval.rs | 27 +- examples/file_explorer.rs | 11 +- examples/framework_benchmark.rs | 55 +- examples/login_form.rs | 42 +- examples/openid_connect_demo/src/oidc.rs | 11 +- .../openid_connect_demo/src/views/header.rs | 42 +- examples/rsx_compile_fail.rs | 26 +- examples/svg.rs | 30 +- examples/todomvc.rs | 15 +- packages/autofmt/src/expr.rs | 15 +- packages/cli/src/builder.rs | 109 ++-- packages/cli/src/cargo.rs | 6 +- packages/cli/src/cli/autoformat.rs | 73 +-- packages/cli/src/cli/create.rs | 15 +- packages/cli/src/plugin/interface/fs.rs | 11 +- packages/cli/src/plugin/mod.rs | 11 +- packages/cli/src/server/output.rs | 36 +- packages/cli/src/server/web/mod.rs | 13 +- packages/cli/src/tools.rs | 50 +- .../inline_props.rs | 31 +- packages/core-macro/src/props/mod.rs | 217 ++++--- packages/core-macro/src/utils.rs | 11 +- packages/core/src/create.rs | 15 +- packages/core/src/nodes.rs | 6 +- packages/core/src/virtual_dom.rs | 9 +- packages/core/tests/attr_cleanup.rs | 29 +- packages/core/tests/bubble_error.rs | 11 +- packages/core/tests/create_dom.rs | 47 +- packages/core/tests/create_fragments.rs | 13 +- packages/core/tests/diff_unkeyed_list.rs | 63 +- packages/core/tests/fuzzing.rs | 113 ++-- packages/desktop/headless_tests/rendering.rs | 11 +- packages/desktop/src/cfg.rs | 12 +- packages/desktop/src/lib.rs | 20 +- packages/desktop/src/webview.rs | 12 +- .../examples/all_terminal_events.rs | 7 +- packages/dioxus/benches/jsframework.rs | 55 +- packages/dioxus/examples/stress.rs | 55 +- .../fullstack/examples/axum-auth/src/main.rs | 13 +- .../examples/static-hydrated/src/main.rs | 6 +- .../fullstack/src/adapters/axum_adapter.rs | 19 +- .../fullstack/src/adapters/salvo_adapter.rs | 19 +- .../fullstack/src/html_storage/deserialize.rs | 15 +- packages/fullstack/src/layer.rs | 8 +- packages/fullstack/src/render.rs | 9 +- packages/fullstack/src/serve_config.rs | 16 +- packages/fullstack/src/server_context.rs | 18 +- packages/hooks/src/use_coroutine.rs | 11 +- packages/hooks/src/use_shared_state.rs | 43 +- packages/hooks/src/use_state.rs | 49 +- packages/liveview/examples/axum.rs | 6 +- packages/liveview/src/pool.rs | 15 +- packages/native-core-macro/src/lib.rs | 93 +-- packages/native-core/examples/custom_attr.rs | 13 +- packages/native-core/examples/simple.rs | 13 +- .../native-core/examples/simple_dioxus.rs | 13 +- packages/native-core/src/layout_attributes.rs | 51 +- .../src/utils/persistant_iterator.rs | 5 +- packages/native-core/tests/fuzzing.rs | 62 +- packages/rink/src/focus.rs | 51 +- packages/rink/src/hooks.rs | 90 +-- packages/rink/src/layout.rs | 11 +- packages/rink/src/prevent_default.rs | 43 +- packages/rink/src/style.rs | 34 +- packages/rink/src/widgets/button.rs | 11 +- packages/rink/src/widgets/slider.rs | 29 +- packages/router-macro/src/route.rs | 24 +- packages/router-macro/src/segment.rs | 37 +- packages/router/src/history/liveview.rs | 23 +- packages/router/src/history/web.rs | 34 +- packages/router/src/navigation.rs | 8 +- packages/router/src/routable.rs | 11 +- .../router/src/utils/use_router_internal.rs | 13 +- packages/rsx-rosetta/tests/simple.rs | 5 +- packages/rsx/src/component.rs | 18 +- packages/rsx/src/element.rs | 97 +-- .../src/hot_reload/hot_reloading_file_map.rs | 11 +- packages/rsx/src/ifmt.rs | 35 +- packages/rsx/src/lib.rs | 22 +- packages/server-macro/src/lib.rs | 9 +- packages/signals/src/effect.rs | 11 +- packages/signals/src/selector.rs | 7 +- packages/signals/tests/create.rs | 43 +- packages/signals/tests/selector.rs | 17 +- packages/web/src/cache.rs | 601 +++++++++--------- packages/web/src/dom.rs | 13 +- packages/web/src/eval.rs | 18 +- 91 files changed, 1663 insertions(+), 1553 deletions(-) diff --git a/examples/all_events.rs b/examples/all_events.rs index 594a736d5..5f3b257bb 100644 --- a/examples/all_events.rs +++ b/examples/all_events.rs @@ -43,14 +43,15 @@ const RECT_STYLE: &str = r#" fn app(cx: Scope) -> Element { let events = use_ref(cx, std::collections::VecDeque::new); - let log_event = move |event: Event| { - let mut events = events.write(); + let log_event = + move |event: Event| { + let mut events = events.write(); - if events.len() >= MAX_EVENTS { - events.pop_front(); - } - events.push_back(event); - }; + if events.len() >= MAX_EVENTS { + events.pop_front(); + } + events.push_back(event); + }; cx.render(rsx! ( div { diff --git a/examples/callback.rs b/examples/callback.rs index cb300b701..ff07607b7 100644 --- a/examples/callback.rs +++ b/examples/callback.rs @@ -5,16 +5,17 @@ fn main() { } fn app(cx: Scope) -> Element { - let login = use_callback!(cx, move |_| async move { - let res = reqwest::get("https://dog.ceo/api/breeds/list/all") - .await - .unwrap() - .text() - .await - .unwrap(); + let login = + use_callback!(cx, move |_| async move { + let res = reqwest::get("https://dog.ceo/api/breeds/list/all") + .await + .unwrap() + .text() + .await + .unwrap(); - println!("{res:#?}, "); - }); + println!("{res:#?}, "); + }); cx.render(rsx! { button { onclick: login, "Click me!" } diff --git a/examples/compose.rs b/examples/compose.rs index 3ee6d36ae..d5a5d5c90 100644 --- a/examples/compose.rs +++ b/examples/compose.rs @@ -12,14 +12,15 @@ fn app(cx: Scope) -> Element { let window = use_window(cx); let emails_sent = use_ref(cx, Vec::new); - let tx = use_coroutine(cx, |mut rx: UnboundedReceiver| { - to_owned![emails_sent]; - async move { - while let Some(message) = rx.next().await { - emails_sent.write().push(message); + let tx = + use_coroutine(cx, |mut rx: UnboundedReceiver| { + to_owned![emails_sent]; + async move { + while let Some(message) = rx.next().await { + emails_sent.write().push(message); + } } - } - }); + }); cx.render(rsx! { div { diff --git a/examples/error_handle.rs b/examples/error_handle.rs index d1fb57933..c0524f741 100644 --- a/examples/error_handle.rs +++ b/examples/error_handle.rs @@ -8,10 +8,11 @@ fn main() { fn App(cx: Scope) -> Element { let val = use_state(cx, || "0.0001"); - let num = match val.parse::() { - Err(_) => return cx.render(rsx!("Parsing failed")), - Ok(num) => num, - }; + let num = + match val.parse::() { + Err(_) => return cx.render(rsx!("Parsing failed")), + Ok(num) => num, + }; cx.render(rsx! { h1 { "The parsed value is {num}" } diff --git a/examples/eval.rs b/examples/eval.rs index 54959df69..f6a61ae15 100644 --- a/examples/eval.rs +++ b/examples/eval.rs @@ -7,25 +7,26 @@ fn main() { fn app(cx: Scope) -> Element { let eval_provider = use_eval(cx); - let future = use_future(cx, (), |_| { - to_owned![eval_provider]; - async move { - let eval = eval_provider( - r#" + let future = + use_future(cx, (), |_| { + to_owned![eval_provider]; + async move { + let eval = eval_provider( + r#" dioxus.send("Hi from JS!"); let msg = await dioxus.recv(); console.log(msg); return "hello world"; "#, - ) - .unwrap(); + ) + .unwrap(); - eval.send("Hi from Rust!".into()).unwrap(); - let res = eval.recv().await.unwrap(); - println!("{:?}", eval.await); - res - } - }); + eval.send("Hi from Rust!".into()).unwrap(); + let res = eval.recv().await.unwrap(); + println!("{:?}", eval.await); + res + } + }); match future.value() { Some(v) => cx.render(rsx!( diff --git a/examples/file_explorer.rs b/examples/file_explorer.rs index 88b37789d..cea860643 100644 --- a/examples/file_explorer.rs +++ b/examples/file_explorer.rs @@ -73,11 +73,12 @@ struct Files { impl Files { fn new() -> Self { - let mut files = Self { - path_stack: vec!["./".to_string()], - path_names: vec![], - err: None, - }; + let mut files = + Self { + path_stack: vec!["./".to_string()], + path_names: vec![], + err: None, + }; files.reload_path_list(); diff --git a/examples/framework_benchmark.rs b/examples/framework_benchmark.rs index 7e7a320a9..f1d75d8e9 100644 --- a/examples/framework_benchmark.rs +++ b/examples/framework_benchmark.rs @@ -112,33 +112,34 @@ fn ActionButton<'a>(cx: Scope<'a, ActionButtonProps<'a>>) -> Element { }) } -static ADJECTIVES: &[&str] = &[ - "pretty", - "large", - "big", - "small", - "tall", - "short", - "long", - "handsome", - "plain", - "quaint", - "clean", - "elegant", - "easy", - "angry", - "crazy", - "helpful", - "mushy", - "odd", - "unsightly", - "adorable", - "important", - "inexpensive", - "cheap", - "expensive", - "fancy", -]; +static ADJECTIVES: &[&str] = + &[ + "pretty", + "large", + "big", + "small", + "tall", + "short", + "long", + "handsome", + "plain", + "quaint", + "clean", + "elegant", + "easy", + "angry", + "crazy", + "helpful", + "mushy", + "odd", + "unsightly", + "adorable", + "important", + "inexpensive", + "cheap", + "expensive", + "fancy", + ]; static COLOURS: &[&str] = &[ "red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", diff --git a/examples/login_form.rs b/examples/login_form.rs index 5ee47e4b5..585fe15f6 100644 --- a/examples/login_form.rs +++ b/examples/login_form.rs @@ -8,28 +8,32 @@ fn main() { } fn app(cx: Scope) -> Element { - let onsubmit = move |evt: FormEvent| { - cx.spawn(async move { - let resp = reqwest::Client::new() - .post("http://localhost:8080/login") - .form(&[ - ("username", &evt.values["username"]), - ("password", &evt.values["password"]), - ]) - .send() - .await; + let onsubmit = + move |evt: FormEvent| { + cx.spawn(async move { + let resp = + reqwest::Client::new() + .post("http://localhost:8080/login") + .form(&[ + ("username", &evt.values["username"]), + ("password", &evt.values["password"]), + ]) + .send() + .await; - match resp { - // Parse data from here, such as storing a response token - Ok(_data) => println!("Login successful!"), + match resp { + // Parse data from here, such as storing a response token + Ok(_data) => println!("Login successful!"), - //Handle any errors from the fetch here - Err(_err) => { - println!("Login failed - you need a login server running on localhost:8080.") + //Handle any errors from the fetch here + Err(_err) => { + println!( + "Login failed - you need a login server running on localhost:8080." + ) + } } - } - }); - }; + }); + }; cx.render(rsx! { h1 { "Login" } diff --git a/examples/openid_connect_demo/src/oidc.rs b/examples/openid_connect_demo/src/oidc.rs index 7fa96c14b..07c9b2314 100644 --- a/examples/openid_connect_demo/src/oidc.rs +++ b/examples/openid_connect_demo/src/oidc.rs @@ -112,11 +112,12 @@ pub async fn exchange_refresh_token( pub async fn log_out_url(id_token_hint: CoreIdToken) -> Result { let provider_metadata = init_provider_metadata().await?; - let end_session_url = provider_metadata - .additional_metadata() - .clone() - .end_session_endpoint - .unwrap(); + let end_session_url = + provider_metadata + .additional_metadata() + .clone() + .end_session_endpoint + .unwrap(); let logout_request: LogoutRequest = LogoutRequest::from(end_session_url); Ok(logout_request .set_client_id(ClientId::new(DIOXUS_FRONT_CLIENT_ID.to_string())) diff --git a/examples/openid_connect_demo/src/views/header.rs b/examples/openid_connect_demo/src/views/header.rs index 1f2c6e057..4a0ccea0d 100644 --- a/examples/openid_connect_demo/src/views/header.rs +++ b/examples/openid_connect_demo/src/views/header.rs @@ -22,29 +22,31 @@ pub fn LogOut(cx: Scope) -> Element { Some(fermi_auth_token_read) => match fermi_auth_token_read.id_token.clone() { Some(id_token) => match log_out_url_state.get() { Some(log_out_url_result) => match log_out_url_result { - Some(uri) => match uri { - Ok(uri) => { - rsx! { - Link { - onclick: move |_| { - { - AuthTokenState::persistent_set( - fermi_auth_token, - Some(AuthTokenState::default()), - ); - } - }, - to: uri.to_string(), - "Log out" + Some(uri) => { + match uri { + Ok(uri) => { + rsx! { + Link { + onclick: move |_| { + { + AuthTokenState::persistent_set( + fermi_auth_token, + Some(AuthTokenState::default()), + ); + } + }, + to: uri.to_string(), + "Log out" + } + } + } + Err(error) => { + rsx! { + div { format!{"Failed to load disconnection url: {:?}", error} } } } } - Err(error) => { - rsx! { - div { format!{"Failed to load disconnection url: {:?}", error} } - } - } - }, + } None => { rsx! { div { "Loading... Please wait" } } } diff --git a/examples/rsx_compile_fail.rs b/examples/rsx_compile_fail.rs index 40bad709b..f6df332ff 100644 --- a/examples/rsx_compile_fail.rs +++ b/examples/rsx_compile_fail.rs @@ -13,19 +13,21 @@ fn main() { } fn example(cx: Scope) -> Element { - let items = use_state(cx, || { - vec![Thing { - a: "asd".to_string(), - b: 10, - }] - }); + let items = + use_state(cx, || { + vec![Thing { + a: "asd".to_string(), + b: 10, + }] + }); - let things = use_ref(cx, || { - vec![Thing { - a: "asd".to_string(), - b: 10, - }] - }); + let things = + use_ref(cx, || { + vec![Thing { + a: "asd".to_string(), + b: 10, + }] + }); let things_list = things.read(); let mything = use_ref(cx, || Some(String::from("asd"))); diff --git a/examples/svg.rs b/examples/svg.rs index 329cbe6ae..e947c575a 100644 --- a/examples/svg.rs +++ b/examples/svg.rs @@ -63,23 +63,23 @@ pub fn Die<'a>(cx: Scope<'a, DieProps<'a>>) -> Element { let active_dots = &DOTS_FOR_VALUE[(value - 1) as usize]; let fill = if keep { HELD_COLOR } else { UNHELD_COLOR }; - let dots = DOTS - .iter() - .zip(active_dots.iter()) - .filter(|(_, &active)| active) - .map(|((x, y), _)| { - let dcx = x * OFFSET; - let dcy = y * OFFSET; + let dots = + DOTS.iter() + .zip(active_dots.iter()) + .filter(|(_, &active)| active) + .map(|((x, y), _)| { + let dcx = x * OFFSET; + let dcy = y * OFFSET; - rsx! { - circle { - cx: "{dcx}", - cy: "{dcy}", - r: "{DOT_RADIUS}", - fill: "#333" + rsx! { + circle { + cx: "{dcx}", + cy: "{dcy}", + r: "{DOT_RADIUS}", + fill: "#333" + } } - } - }); + }); cx.render(rsx! { svg { diff --git a/examples/todomvc.rs b/examples/todomvc.rs index 9ec2dc228..a5a687374 100644 --- a/examples/todomvc.rs +++ b/examples/todomvc.rs @@ -202,13 +202,14 @@ pub fn ListFooter<'a>(cx: Scope<'a, ListFooterProps<'a>>) -> Element { let active_todo_count = cx.props.active_todo_count; let active_todo_text = cx.props.active_todo_text; - let selected = |state| { - if *cx.props.filter == state { - "selected" - } else { - "false" - } - }; + let selected = + |state| { + if *cx.props.filter == state { + "selected" + } else { + "false" + } + }; cx.render(rsx! { footer { class: "footer", diff --git a/packages/autofmt/src/expr.rs b/packages/autofmt/src/expr.rs index b0257f8c3..dc8417c35 100644 --- a/packages/autofmt/src/expr.rs +++ b/packages/autofmt/src/expr.rs @@ -34,13 +34,14 @@ impl Writer<'_> { for (id, line) in self.src[start.line..end.line].iter().enumerate() { writeln!(self.out)?; // check if this is the last line - let line = { - if id == (end.line - start.line) - 1 { - &line[..end.column] - } else { - line - } - }; + let line = + { + if id == (end.line - start.line) - 1 { + &line[..end.column] + } else { + line + } + }; // trim the leading whitespace let previous_indent = crate::leading_whitespaces(line) / 4; diff --git a/packages/cli/src/builder.rs b/packages/cli/src/builder.rs index 08e636237..2352ed262 100644 --- a/packages/cli/src/builder.rs +++ b/packages/cli/src/builder.rs @@ -67,19 +67,21 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result { cmd.arg("--quiet") }; - let cmd = if config.custom_profile.is_some() { - let custom_profile = config.custom_profile.as_ref().unwrap(); - cmd.arg("--profile").arg(custom_profile) - } else { - cmd - }; + let cmd = + if config.custom_profile.is_some() { + let custom_profile = config.custom_profile.as_ref().unwrap(); + cmd.arg("--profile").arg(custom_profile) + } else { + cmd + }; - let cmd = if config.features.is_some() { - let features_str = config.features.as_ref().unwrap().join(" "); - cmd.arg("--features").arg(features_str) - } else { - cmd - }; + let cmd = + if config.features.is_some() { + let features_str = config.features.as_ref().unwrap().join(" "); + cmd.arg("--features").arg(features_str) + } else { + cmd + }; let cmd = match executable { ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), @@ -92,13 +94,14 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result { // [2] Establish the output directory structure let bindgen_outdir = out_dir.join("assets").join("dioxus"); - let build_profile = if config.custom_profile.is_some() { - config.custom_profile.as_ref().unwrap() - } else if config.release { - "release" - } else { - "debug" - }; + let build_profile = + if config.custom_profile.is_some() { + config.custom_profile.as_ref().unwrap() + } else if config.release { + "release" + } else { + "debug" + }; let input_path = match executable { ExecutableType::Binary(name) | ExecutableType::Lib(name) => target_dir @@ -207,14 +210,15 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result { } // this code will copy all public file to the output dir - let copy_options = fs_extra::dir::CopyOptions { - overwrite: true, - skip_exist: false, - buffer_size: 64000, - copy_inside: false, - content_only: false, - depth: 0, - }; + let copy_options = + fs_extra::dir::CopyOptions { + overwrite: true, + skip_exist: false, + buffer_size: 64000, + copy_inside: false, + content_only: false, + depth: 0, + }; if asset_dir.is_dir() { for entry in std::fs::read_dir(asset_dir)? { let path = entry?.path(); @@ -287,20 +291,21 @@ pub fn build_desktop(config: &CrateConfig, _is_serve: bool) -> Result { - file_name = name.clone(); - config.target_dir.join(release_type).join(name) - } - crate::ExecutableType::Example(name) => { - file_name = name.clone(); - config - .target_dir - .join(release_type) - .join("examples") - .join(name) - } - }; + let mut res_path = + match &config.executable { + crate::ExecutableType::Binary(name) | crate::ExecutableType::Lib(name) => { + file_name = name.clone(); + config.target_dir.join(release_type).join(name) + } + crate::ExecutableType::Example(name) => { + file_name = name.clone(); + config + .target_dir + .join(release_type) + .join("examples") + .join(name) + } + }; let target_file = if cfg!(windows) { res_path.set_extension("exe"); @@ -396,9 +401,7 @@ fn prettier_build(cmd: subprocess::Exec) -> anyhow::Result> { match message.level { cargo_metadata::diagnostic::DiagnosticLevel::Error => { return { - Err(anyhow::anyhow!(message - .rendered - .unwrap_or("Unknown".into()))) + Err(anyhow::anyhow!(message.rendered.unwrap_or("Unknown".into()))) }; } cargo_metadata::diagnostic::DiagnosticLevel::Warning => { @@ -475,10 +478,7 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { let mut script_str = String::new(); for script in script_list { - script_str.push_str(&format!( - "\n", - &script.to_str().unwrap(), - )) + script_str.push_str(&format!("\n", &script.to_str().unwrap(),)) } replace_or_insert_before("{script_include}", &script_str, " String { html = html.replace("{base_path}", base_path); } else { // If not, insert the script - html = html.replace( - " + html = + html.replace( + " import init from "/{base_path}/assets/dioxus/{app_name}.js"; init("/{base_path}/assets/dioxus/{app_name}_bg.wasm").then(wasm => {{ if (wasm.__wbindgen_start == undefined) {{ @@ -514,8 +515,8 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { }}); Result { } None }) - .ok_or_else(|| { - Error::CargoError("Failed to find directory containing Cargo.toml".to_string()) - }) + .ok_or_else( + || Error::CargoError("Failed to find directory containing Cargo.toml".to_string()) + ) } /// Checks if the directory contains `Cargo.toml` diff --git a/packages/cli/src/cli/autoformat.rs b/packages/cli/src/cli/autoformat.rs index 1d1cbcd24..4f6c42751 100644 --- a/packages/cli/src/cli/autoformat.rs +++ b/packages/cli/src/cli/autoformat.rs @@ -93,47 +93,48 @@ async fn autoformat_project(check: bool) -> Result<()> { let mut files_to_format = vec![]; collect_rs_files(&crate_config.crate_dir, &mut files_to_format); - let counts = files_to_format - .into_iter() - .filter(|file| { - if file.components().any(|f| f.as_os_str() == "target") { - return false; - } - - true - }) - .map(|path| async { - let _path = path.clone(); - let res = tokio::spawn(async move { - let contents = tokio::fs::read_to_string(&path).await?; - - let edits = dioxus_autofmt::fmt_file(&contents); - let len = edits.len(); - - if !edits.is_empty() { - let out = dioxus_autofmt::apply_formats(&contents, edits); - tokio::fs::write(&path, out).await?; + let counts = + files_to_format + .into_iter() + .filter(|file| { + if file.components().any(|f| f.as_os_str() == "target") { + return false; } - Ok(len) as Result + true }) - .await; + .map(|path| async { + let _path = path.clone(); + let res = tokio::spawn(async move { + let contents = tokio::fs::read_to_string(&path).await?; - match res { - Err(err) => { - eprintln!("error formatting file: {}\n{err}", _path.display()); - None + let edits = dioxus_autofmt::fmt_file(&contents); + let len = edits.len(); + + if !edits.is_empty() { + let out = dioxus_autofmt::apply_formats(&contents, edits); + tokio::fs::write(&path, out).await?; + } + + Ok(len) as Result + }) + .await; + + match res { + Err(err) => { + eprintln!("error formatting file: {}\n{err}", _path.display()); + None + } + Ok(Err(err)) => { + eprintln!("error formatting file: {}\n{err}", _path.display()); + None + } + Ok(Ok(res)) => Some(res), } - Ok(Err(err)) => { - eprintln!("error formatting file: {}\n{err}", _path.display()); - None - } - Ok(Ok(res)) => Some(res), - } - }) - .collect::>() - .collect::>() - .await; + }) + .collect::>() + .collect::>() + .await; let files_formatted: usize = counts .into_iter() diff --git a/packages/cli/src/cli/create.rs b/packages/cli/src/cli/create.rs index 92b0334f5..4893dab80 100644 --- a/packages/cli/src/cli/create.rs +++ b/packages/cli/src/cli/create.rs @@ -35,13 +35,14 @@ impl Create { let toml_paths = [path.join("Cargo.toml"), path.join("Dioxus.toml")]; for toml_path in &toml_paths { let toml = std::fs::read_to_string(toml_path)?; - let mut toml = toml.parse::().map_err(|e| { - anyhow::anyhow!( - "failed to parse toml at {}: {}", - toml_path.display(), - e.to_string() - ) - })?; + let mut toml = + toml.parse::().map_err(|e| { + anyhow::anyhow!( + "failed to parse toml at {}: {}", + toml_path.display(), + e.to_string() + ) + })?; toml.as_table_mut().fmt(); diff --git a/packages/cli/src/plugin/interface/fs.rs b/packages/cli/src/plugin/interface/fs.rs index 5668dbe33..18918a592 100644 --- a/packages/cli/src/plugin/interface/fs.rs +++ b/packages/cli/src/plugin/interface/fs.rs @@ -67,11 +67,12 @@ impl UserData for PluginFileSystem { let file = PathBuf::from(args.0); let target = PathBuf::from(args.1); - let tar_gz = if let Ok(v) = File::open(file) { - v - } else { - return Ok(false); - }; + let tar_gz = + if let Ok(v) = File::open(file) { + v + } else { + return Ok(false); + }; let tar = GzDecoder::new(tar_gz); let mut archive = Archive::new(tar); diff --git a/packages/cli/src/plugin/mod.rs b/packages/cli/src/plugin/mod.rs index 481dd0984..97adaf08f 100644 --- a/packages/cli/src/plugin/mod.rs +++ b/packages/cli/src/plugin/mod.rs @@ -317,11 +317,12 @@ impl PluginManager { let name = i.get::<_, String>("name").unwrap(); let loader = i.get::<_, bool>("loader").unwrap(); - let text = if loader { - format!("{name} [:loader]") - } else { - name - }; + let text = + if loader { + format!("{name} [:loader]") + } else { + name + }; res.push(text); } } diff --git a/packages/cli/src/server/output.rs b/packages/cli/src/server/output.rs index 71323dd29..92a286c9a 100644 --- a/packages/cli/src/server/output.rs +++ b/packages/cli/src/server/output.rs @@ -22,12 +22,13 @@ pub fn print_console_info( options: PrettierOptions, web_info: Option, ) { - if let Ok(native_clearseq) = Command::new(if cfg!(target_os = "windows") { - "cls" - } else { - "clear" - }) - .output() + if let Ok(native_clearseq) = + Command::new(if cfg!(target_os = "windows") { + "cls" + } else { + "clear" + }) + .output() { print!("{}", String::from_utf8_lossy(&native_clearseq.stdout)); } else { @@ -46,17 +47,18 @@ pub fn print_console_info( } else { "Default" }; - let url_rewrite = if config - .dioxus_config - .web - .watcher - .index_on_404 - .unwrap_or(false) - { - "True" - } else { - "False" - }; + let url_rewrite = + if config + .dioxus_config + .web + .watcher + .index_on_404 + .unwrap_or(false) + { + "True" + } else { + "False" + }; let proxies = config.dioxus_config.web.proxy.as_ref(); diff --git a/packages/cli/src/server/web/mod.rs b/packages/cli/src/server/web/mod.rs index 0e1413597..f507f78e6 100644 --- a/packages/cli/src/server/web/mod.rs +++ b/packages/cli/src/server/web/mod.rs @@ -165,9 +165,7 @@ async fn get_rustls(config: &CrateConfig) -> Result> { get_rustls_without_mkcert(web_config)? }; - Ok(Some( - RustlsConfig::from_pem_file(cert_path, key_path).await?, - )) + Ok(Some(RustlsConfig::from_pem_file(cert_path, key_path).await?)) } fn get_rustls_with_mkcert(web_config: &WebHttpsConfig) -> Result<(String, String)> { @@ -314,10 +312,11 @@ async fn setup_router( )); // Setup routes - router = router - .route("/_dioxus/hot_reload", get(hot_reload_handler)) - .layer(cors) - .layer(Extension(ws_reload)); + router = + router + .route("/_dioxus/hot_reload", get(hot_reload_handler)) + .layer(cors) + .layer(Extension(ws_reload)); if let Some(hot_reload) = hot_reload { router = router.layer(Extension(hot_reload)) diff --git a/packages/cli/src/tools.rs b/packages/cli/src/tools.rs index 4045b236e..9b8801e0a 100644 --- a/packages/cli/src/tools.rs +++ b/packages/cli/src/tools.rs @@ -162,10 +162,11 @@ impl Tool { ) } Self::Tailwind => { - let windows_extension = match self.target_platform() { - "windows" => ".exe", - _ => "", - }; + let windows_extension = + match self.target_platform() { + "windows" => ".exe", + _ => "", + }; format!( "https://github.com/tailwindlabs/tailwindcss/releases/download/{version}/tailwindcss-{target}-x64{optional_ext}", version = self.tool_version(), @@ -280,29 +281,30 @@ impl Tool { pub fn call(&self, command: &str, args: Vec<&str>) -> anyhow::Result> { let bin_path = tools_path().join(self.name()).join(self.bin_path()); - let command_file = match self { - Tool::Binaryen => { - if cfg!(target_os = "windows") { - format!("{}.exe", command) - } else { - command.to_string() + let command_file = + match self { + Tool::Binaryen => { + if cfg!(target_os = "windows") { + format!("{}.exe", command) + } else { + command.to_string() + } } - } - Tool::Sass => { - if cfg!(target_os = "windows") { - format!("{}.bat", command) - } else { - command.to_string() + Tool::Sass => { + if cfg!(target_os = "windows") { + format!("{}.bat", command) + } else { + command.to_string() + } } - } - Tool::Tailwind => { - if cfg!(target_os = "windows") { - format!("{}.exe", command) - } else { - command.to_string() + Tool::Tailwind => { + if cfg!(target_os = "windows") { + format!("{}.exe", command) + } else { + command.to_string() + } } - } - }; + }; if !bin_path.join(&command_file).is_file() { return Err(anyhow::anyhow!("Command file not found.")); diff --git a/packages/core-macro/src/component_body_deserializers/inline_props.rs b/packages/core-macro/src/component_body_deserializers/inline_props.rs index d51132623..e56ba32b2 100644 --- a/packages/core-macro/src/component_body_deserializers/inline_props.rs +++ b/packages/core-macro/src/component_body_deserializers/inline_props.rs @@ -67,11 +67,12 @@ fn get_props_struct(component_body: &ComponentBody) -> ItemStruct { let struct_ident = Ident::new(&format!("{fn_ident}Props"), fn_ident.span()); - let first_lifetime = if let Some(GenericParam::Lifetime(lt)) = generics.params.first() { - Some(lt) - } else { - None - }; + let first_lifetime = + if let Some(GenericParam::Lifetime(lt)) = generics.params.first() { + Some(lt) + } else { + None + }; let struct_attrs = if first_lifetime.is_some() { quote! { #[derive(Props)] } @@ -250,16 +251,18 @@ fn get_function(component_body: &ComponentBody) -> ItemFn { let struct_ident = Ident::new(&format!("{fn_ident}Props"), fn_ident.span()); // Skip first arg since that's the context - let struct_field_names = inputs.iter().skip(1).filter_map(|f| match f { - FnArg::Receiver(_) => unreachable!(), // ComponentBody prohibits receiver parameters. - FnArg::Typed(pt) => Some(&pt.pat), - }); + let struct_field_names = + inputs.iter().skip(1).filter_map(|f| match f { + FnArg::Receiver(_) => unreachable!(), // ComponentBody prohibits receiver parameters. + FnArg::Typed(pt) => Some(&pt.pat), + }); - let first_lifetime = if let Some(GenericParam::Lifetime(lt)) = generics.params.first() { - Some(lt) - } else { - None - }; + let first_lifetime = + if let Some(GenericParam::Lifetime(lt)) = generics.params.first() { + Some(lt) + } else { + None + }; let (scope_lifetime, fn_generics) = if let Some(lt) = first_lifetime { (quote! { #lt, }, generics.clone()) diff --git a/packages/core-macro/src/props/mod.rs b/packages/core-macro/src/props/mod.rs index 6e6c43d66..6a87fb7ad 100644 --- a/packages/core-macro/src/props/mod.rs +++ b/packages/core-macro/src/props/mod.rs @@ -41,16 +41,10 @@ pub fn impl_my_derive(ast: &syn::DeriveInput) -> Result { } } syn::Fields::Unnamed(_) => { - return Err(Error::new( - ast.span(), - "Props is not supported for tuple structs", - )) + return Err(Error::new(ast.span(), "Props is not supported for tuple structs")) } syn::Fields::Unit => { - return Err(Error::new( - ast.span(), - "Props is not supported for unit structs", - )) + return Err(Error::new(ast.span(), "Props is not supported for unit structs")) } }, syn::Data::Enum(_) => { @@ -334,10 +328,9 @@ mod field_info { } Ok(()) } - _ => Err(Error::new_spanned( - &assign, - format!("Unknown parameter {name:?}"), - )), + _ => { + Err(Error::new_spanned(&assign, format!("Unknown parameter {name:?}"))) + } } } @@ -452,12 +445,13 @@ fn type_from_inside_option(ty: &syn::Type, check_option_name: bool) -> Option<&s if check_option_name && segment.ident != "Option" { return None; } - let generic_params = - if let syn::PathArguments::AngleBracketed(generic_params) = &segment.arguments { - generic_params - } else { - return None; - }; + let generic_params = if let syn::PathArguments::AngleBracketed(generic_params) = + &segment.arguments + { + generic_params + } else { + return None; + }; if let syn::GenericArgument::Type(ty) = generic_params.args.first()? { Some(ty) } else { @@ -562,37 +556,38 @@ mod struct_info { } syn::GenericParam::Const(_cnst) => None, }); - let builder_method_doc = match self.builder_attr.builder_method_doc { - Some(ref doc) => quote!(#doc), - None => { - let doc = format!( - " + let builder_method_doc = + match self.builder_attr.builder_method_doc { + Some(ref doc) => quote!(#doc), + None => { + let doc = format!( + " Create a builder for building `{name}`. On the builder, call {setters} to set the values of the fields. Finally, call `.build()` to create the instance of `{name}`. ", - name = self.name, - setters = { - let mut result = String::new(); - let mut is_first = true; - for field in self.included_fields() { - use std::fmt::Write; - if is_first { - is_first = false; - } else { - write!(&mut result, ", ").unwrap(); - } - write!(&mut result, "`.{}(...)`", field.name).unwrap(); - if field.builder_attr.default.is_some() { - write!(&mut result, "(optional)").unwrap(); + name = self.name, + setters = { + let mut result = String::new(); + let mut is_first = true; + for field in self.included_fields() { + use std::fmt::Write; + if is_first { + is_first = false; + } else { + write!(&mut result, ", ").unwrap(); + } + write!(&mut result, "`.{}(...)`", field.name).unwrap(); + if field.builder_attr.default.is_some() { + write!(&mut result, "(optional)").unwrap(); + } } + result } - result - } - ); - quote!(#doc) - } - }; + ); + quote!(#doc) + } + }; let builder_type_doc = if self.builder_attr.doc { match self.builder_attr.builder_type_doc { Some(ref doc) => quote!(#[doc = #doc]), @@ -623,10 +618,11 @@ Finally, call `.build()` to create the instance of `{name}`. false => quote! { self == other }, }; - let is_static = match are_there_generics { - true => quote! { false }, - false => quote! { true }, - }; + let is_static = + match are_there_generics { + true => quote! { false }, + false => quote! { true }, + }; Ok(quote! { impl #impl_generics #name #ty_generics #where_clause { @@ -711,14 +707,15 @@ Finally, call `.build()` to create the instance of `{name}`. ref builder_name, .. } = *self; - let descructuring = self.included_fields().map(|f| { - if f.ordinal == field.ordinal { - quote!(_) - } else { - let name = f.name; - quote!(#name) - } - }); + let descructuring = + self.included_fields().map(|f| { + if f.ordinal == field.ordinal { + quote!(_) + } else { + let name = f.name; + quote!(#name) + } + }); let reconstructing = self.included_fields().map(|f| f.name); let mut ty_generics: Vec = self @@ -785,16 +782,17 @@ Finally, call `.build()` to create the instance of `{name}`. // NOTE: both auto_into and strip_option affect `arg_type` and `arg_expr`, but the order of // nesting is different so we have to do this little dance. - let arg_type = if field.builder_attr.strip_option { - field.type_from_inside_option(false).ok_or_else(|| { - Error::new_spanned( - field_type, - "can't `strip_option` - field is not `Option<...>`", - ) - })? - } else { - field_type - }; + let arg_type = + if field.builder_attr.strip_option { + field.type_from_inside_option(false).ok_or_else(|| { + Error::new_spanned( + field_type, + "can't `strip_option` - field is not `Option<...>`", + ) + })? + } else { + field_type + }; let (arg_type, arg_expr) = if field.builder_attr.auto_into { ( quote!(impl ::core::convert::Into<#arg_type>), @@ -880,44 +878,45 @@ Finally, call `.build()` to create the instance of `{name}`. }) .collect(); let mut builder_generics_tuple = empty_type_tuple(); - let generics = self.modify_generics(|g| { - let index_after_lifetime_in_generics = g - .params - .iter() - .filter(|arg| matches!(arg, syn::GenericParam::Lifetime(_))) - .count(); - for f in self.included_fields() { - if f.builder_attr.default.is_some() { - // `f` is not mandatory - it does not have it's own fake `build` method, so `field` will need - // to warn about missing `field` whether or not `f` is set. - assert!( - f.ordinal != field.ordinal, - "`required_field_impl` called for optional field {}", - field.name - ); - g.params - .insert(index_after_lifetime_in_generics, f.generic_ty_param()); - builder_generics_tuple.elems.push_value(f.type_ident()); - } else if f.ordinal < field.ordinal { - // Only add a `build` method that warns about missing `field` if `f` is set. If `f` is not set, - // `f`'s `build` method will warn, since it appears earlier in the argument list. - builder_generics_tuple - .elems - .push_value(f.tuplized_type_ty_param()); - } else if f.ordinal == field.ordinal { - builder_generics_tuple.elems.push_value(empty_type()); - } else { - // `f` appears later in the argument list after `field`, so if they are both missing we will - // show a warning for `field` and not for `f` - which means this warning should appear whether - // or not `f` is set. - g.params - .insert(index_after_lifetime_in_generics, f.generic_ty_param()); - builder_generics_tuple.elems.push_value(f.type_ident()); - } + let generics = + self.modify_generics(|g| { + let index_after_lifetime_in_generics = g + .params + .iter() + .filter(|arg| matches!(arg, syn::GenericParam::Lifetime(_))) + .count(); + for f in self.included_fields() { + if f.builder_attr.default.is_some() { + // `f` is not mandatory - it does not have it's own fake `build` method, so `field` will need + // to warn about missing `field` whether or not `f` is set. + assert!( + f.ordinal != field.ordinal, + "`required_field_impl` called for optional field {}", + field.name + ); + g.params + .insert(index_after_lifetime_in_generics, f.generic_ty_param()); + builder_generics_tuple.elems.push_value(f.type_ident()); + } else if f.ordinal < field.ordinal { + // Only add a `build` method that warns about missing `field` if `f` is set. If `f` is not set, + // `f`'s `build` method will warn, since it appears earlier in the argument list. + builder_generics_tuple + .elems + .push_value(f.tuplized_type_ty_param()); + } else if f.ordinal == field.ordinal { + builder_generics_tuple.elems.push_value(empty_type()); + } else { + // `f` appears later in the argument list after `field`, so if they are both missing we will + // show a warning for `field` and not for `f` - which means this warning should appear whether + // or not `f` is set. + g.params + .insert(index_after_lifetime_in_generics, f.generic_ty_param()); + builder_generics_tuple.elems.push_value(f.type_ident()); + } - builder_generics_tuple.elems.push_punct(Default::default()); - } - }); + builder_generics_tuple.elems.push_punct(Default::default()); + } + }); let index_after_lifetime_in_generics = builder_generics .iter() @@ -1139,10 +1138,9 @@ Finally, call `.build()` to create the instance of `{name}`. self.doc = true; Ok(()) } - _ => Err(Error::new_spanned( - &assign, - format!("Unknown parameter {name:?}"), - )), + _ => { + Err(Error::new_spanned(&assign, format!("Unknown parameter {name:?}"))) + } } } syn::Expr::Path(path) => { @@ -1153,10 +1151,9 @@ Finally, call `.build()` to create the instance of `{name}`. self.doc = true; Ok(()) } - _ => Err(Error::new_spanned( - &path, - format!("Unknown parameter {name:?}"), - )), + _ => { + Err(Error::new_spanned(&path, format!("Unknown parameter {name:?}"))) + } } } syn::Expr::Call(call) => { diff --git a/packages/core-macro/src/utils.rs b/packages/core-macro/src/utils.rs index 7e066f773..114a07e73 100644 --- a/packages/core-macro/src/utils.rs +++ b/packages/core-macro/src/utils.rs @@ -31,9 +31,9 @@ pub fn format_type_string(ty: &Type) -> String { // This should always be valid syntax. // Not Rust code, but syntax, which is the only thing that `syn` cares about. - let Ok(file_unformatted) = syn::parse_file(&format!( - "{FORMATTED_TYPE_START}{ty_unformatted}{FORMATTED_TYPE_END}" - )) else { + let Ok(file_unformatted) = + syn::parse_file(&format!("{FORMATTED_TYPE_START}{ty_unformatted}{FORMATTED_TYPE_END}")) + else { return ty_unformatted.to_string(); }; @@ -60,10 +60,7 @@ impl DeprecatedAttribute { /// Returns `None` if the given attribute was not a valid form of the `#[deprecated]` attribute. pub fn from_meta(meta: &Meta) -> syn::Result { if meta.path() != &parse_quote!(deprecated) { - return Err(syn::Error::new( - meta.span(), - "attribute path is not `deprecated`", - )); + return Err(syn::Error::new(meta.span(), "attribute path is not `deprecated`")); } match &meta { diff --git a/packages/core/src/create.rs b/packages/core/src/create.rs index a61a8cace..b68cd6086 100644 --- a/packages/core/src/create.rs +++ b/packages/core/src/create.rs @@ -36,13 +36,14 @@ fn sort_bfs(paths: &[&'static [u8]]) -> Vec<(usize, &'static [u8])> { #[test] #[cfg(debug_assertions)] fn sorting() { - let r: [(usize, &[u8]); 5] = [ - (0, &[0, 1]), - (1, &[0, 2]), - (2, &[1, 0]), - (3, &[1, 0, 1]), - (4, &[1, 2]), - ]; + let r: [(usize, &[u8]); 5] = + [ + (0, &[0, 1]), + (1, &[0, 2]), + (2, &[1, 0]), + (3, &[1, 0, 1]), + (4, &[1, 2]), + ]; assert_eq!( sort_bfs(&[&[0, 1,], &[0, 2,], &[1, 0,], &[1, 0, 1,], &[1, 2,],]), r diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index c83b1059a..a1c6e7be9 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -531,9 +531,9 @@ impl<'a> From<&'a AttributeValue<'a>> for BorrowedAttributeValue<'a> { } AttributeValue::Any(value) => { let value = value.borrow(); - BorrowedAttributeValue::Any(std::cell::Ref::map(value, |value| { - &**value.as_ref().unwrap() - })) + BorrowedAttributeValue::Any( + std::cell::Ref::map(value, |value| &**value.as_ref().unwrap()) + ) } AttributeValue::None => BorrowedAttributeValue::None, } diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 2d83ba63a..4c8adfdb6 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -267,10 +267,11 @@ impl VirtualDom { suspended_scopes: Default::default(), }; - let root = dom.new_scope( - Box::new(VProps::new(root, |_, _| unreachable!(), root_props)), - "app", - ); + let root = + dom.new_scope( + Box::new(VProps::new(root, |_, _| unreachable!(), root_props)), + "app", + ); // Unlike react, we provide a default error boundary that just renders the error as a string root.provide_context(Rc::new(ErrorBoundary::new(ScopeId::ROOT))); diff --git a/packages/core/tests/attr_cleanup.rs b/packages/core/tests/attr_cleanup.rs index 539a0b399..ea8135dd6 100644 --- a/packages/core/tests/attr_cleanup.rs +++ b/packages/core/tests/attr_cleanup.rs @@ -9,20 +9,23 @@ use dioxus_core::BorrowedAttributeValue; #[test] fn attrs_cycle() { - let mut dom = VirtualDom::new(|cx| { - let id = cx.generation(); - match cx.generation() % 2 { - 0 => cx.render(rsx! { - div {} - }), - 1 => cx.render(rsx! { - div { - h1 { class: "{id}", id: "{id}" } + let mut dom = + VirtualDom::new(|cx| { + let id = cx.generation(); + match cx.generation() % 2 { + 0 => { + cx.render(rsx! { + div {} + }) } - }), - _ => unreachable!(), - } - }); + 1 => cx.render(rsx! { + div { + h1 { class: "{id}", id: "{id}" } + } + }), + _ => unreachable!(), + } + }); let bump = Bump::new(); diff --git a/packages/core/tests/bubble_error.rs b/packages/core/tests/bubble_error.rs index af2a34219..901f93f46 100644 --- a/packages/core/tests/bubble_error.rs +++ b/packages/core/tests/bubble_error.rs @@ -3,11 +3,12 @@ use dioxus::prelude::*; fn app(cx: Scope) -> Element { - let raw = match cx.generation() % 2 { - 0 => "123.123", - 1 => "123.123.123", - _ => unreachable!(), - }; + let raw = + match cx.generation() % 2 { + 0 => "123.123", + 1 => "123.123.123", + _ => unreachable!(), + }; let value = raw.parse::().unwrap_or(123.123); diff --git a/packages/core/tests/create_dom.rs b/packages/core/tests/create_dom.rs index 5e5005d3f..b923a9eec 100644 --- a/packages/core/tests/create_dom.rs +++ b/packages/core/tests/create_dom.rs @@ -11,15 +11,16 @@ use dioxus_core::ElementId; #[test] fn test_original_diff() { - let mut dom = VirtualDom::new(|cx| { - cx.render(rsx! { - div { + let mut dom = + VirtualDom::new(|cx| { + cx.render(rsx! { div { - "Hello, world!" + div { + "Hello, world!" + } } - } - }) - }); + }) + }); let edits = dom.rebuild().santize(); @@ -82,11 +83,12 @@ fn create() { #[test] fn create_list() { - let mut dom = VirtualDom::new(|cx| { - cx.render(rsx! { - (0..3).map(|f| rsx!( div { "hello" } )) - }) - }); + let mut dom = + VirtualDom::new(|cx| { + cx.render(rsx! { + (0..3).map(|f| rsx!( div { "hello" } )) + }) + }); let _edits = dom.rebuild().santize(); @@ -160,16 +162,17 @@ fn create_components() { #[test] fn anchors() { - let mut dom = VirtualDom::new(|cx| { - cx.render(rsx! { - if true { - rsx!( div { "hello" } ) - } - if false { - rsx!( div { "goodbye" } ) - } - }) - }); + let mut dom = + VirtualDom::new(|cx| { + cx.render(rsx! { + if true { + rsx!( div { "hello" } ) + } + if false { + rsx!( div { "goodbye" } ) + } + }) + }); // note that the template under "false" doesn't show up since it's not loaded let edits = dom.rebuild().santize(); diff --git a/packages/core/tests/create_fragments.rs b/packages/core/tests/create_fragments.rs index ee312f34b..4e94fddbe 100644 --- a/packages/core/tests/create_fragments.rs +++ b/packages/core/tests/create_fragments.rs @@ -24,12 +24,13 @@ fn empty_fragment_creates_nothing() { #[test] fn root_fragments_work() { - let mut vdom = VirtualDom::new(|cx| { - cx.render(rsx!( - div { "hello" } - div { "goodbye" } - )) - }); + let mut vdom = + VirtualDom::new(|cx| { + cx.render(rsx!( + div { "hello" } + div { "goodbye" } + )) + }); assert_eq!( vdom.rebuild().edits.last().unwrap(), diff --git a/packages/core/tests/diff_unkeyed_list.rs b/packages/core/tests/diff_unkeyed_list.rs index b5be161ef..d51ecf452 100644 --- a/packages/core/tests/diff_unkeyed_list.rs +++ b/packages/core/tests/diff_unkeyed_list.rs @@ -4,17 +4,18 @@ use pretty_assertions::assert_eq; #[test] fn list_creates_one_by_one() { - let mut dom = VirtualDom::new(|cx| { - let gen = cx.generation(); + let mut dom = + VirtualDom::new(|cx| { + let gen = cx.generation(); - cx.render(rsx! { - div { - (0..gen).map(|i| rsx! { - div { "{i}" } - }) - } - }) - }); + cx.render(rsx! { + div { + (0..gen).map(|i| rsx! { + div { "{i}" } + }) + } + }) + }); // load the div and then assign the empty fragment as a placeholder assert_eq!( @@ -73,17 +74,18 @@ fn list_creates_one_by_one() { #[test] fn removes_one_by_one() { - let mut dom = VirtualDom::new(|cx| { - let gen = 3 - cx.generation() % 4; + let mut dom = + VirtualDom::new(|cx| { + let gen = 3 - cx.generation() % 4; - cx.render(rsx! { - div { - (0..gen).map(|i| rsx! { - div { "{i}" } - }) - } - }) - }); + cx.render(rsx! { + div { + (0..gen).map(|i| rsx! { + div { "{i}" } + }) + } + }) + }); // load the div and then assign the empty fragment as a placeholder assert_eq!( @@ -150,16 +152,17 @@ fn removes_one_by_one() { #[test] fn list_shrink_multiroot() { - let mut dom = VirtualDom::new(|cx| { - cx.render(rsx! { - div { - (0..cx.generation()).map(|i| rsx! { - div { "{i}" } - div { "{i}" } - }) - } - }) - }); + let mut dom = + VirtualDom::new(|cx| { + cx.render(rsx! { + div { + (0..cx.generation()).map(|i| rsx! { + div { "{i}" } + div { "{i}" } + }) + } + }) + }); assert_eq!( dom.rebuild().santize().edits, diff --git a/packages/core/tests/fuzzing.rs b/packages/core/tests/fuzzing.rs index 1523c4e22..4338a49c1 100644 --- a/packages/core/tests/fuzzing.rs +++ b/packages/core/tests/fuzzing.rs @@ -8,9 +8,7 @@ fn random_ns() -> Option<&'static str> { let namespace = rand::random::() % 2; match namespace { 0 => None, - 1 => Some(Box::leak( - format!("ns{}", rand::random::()).into_boxed_str(), - )), + 1 => Some(Box::leak(format!("ns{}", rand::random::()).into_boxed_str())), _ => unreachable!(), } } @@ -22,13 +20,15 @@ fn create_random_attribute(attr_idx: &mut usize) -> TemplateAttribute<'static> { value: Box::leak(format!("value{}", rand::random::()).into_boxed_str()), namespace: random_ns(), }, - 1 => TemplateAttribute::Dynamic { - id: { - let old_idx = *attr_idx; - *attr_idx += 1; - old_idx - }, - }, + 1 => { + TemplateAttribute::Dynamic { + id: { + let old_idx = *attr_idx; + *attr_idx += 1; + old_idx + }, + } + } _ => unreachable!(), } } @@ -73,22 +73,26 @@ fn create_random_template_node( 1 => TemplateNode::Text { text: Box::leak(format!("{}", rand::random::()).into_boxed_str()), }, - 2 => TemplateNode::DynamicText { - id: { - let old_idx = *template_idx; - *template_idx += 1; - dynamic_node_types.push(DynamicNodeType::Text); - old_idx - }, - }, - 3 => TemplateNode::Dynamic { - id: { - let old_idx = *template_idx; - *template_idx += 1; - dynamic_node_types.push(DynamicNodeType::Other); - old_idx - }, - }, + 2 => { + TemplateNode::DynamicText { + id: { + let old_idx = *template_idx; + *template_idx += 1; + dynamic_node_types.push(DynamicNodeType::Text); + old_idx + }, + } + } + 3 => { + TemplateNode::Dynamic { + id: { + let old_idx = *template_idx; + *template_idx += 1; + dynamic_node_types.push(DynamicNodeType::Other); + old_idx + }, + } + } _ => unreachable!(), } } @@ -207,9 +211,9 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode { fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute { let value = match rand::random::() % 7 { - 0 => AttributeValue::Text(Box::leak( - format!("{}", rand::random::()).into_boxed_str(), - )), + 0 => { + AttributeValue::Text(Box::leak(format!("{}", rand::random::()).into_boxed_str())) + } 1 => AttributeValue::Float(rand::random()), 2 => AttributeValue::Int(rand::random()), 3 => AttributeValue::Bool(rand::random()), @@ -272,31 +276,32 @@ fn create_random_element(cx: Scope) -> Element { .into_boxed_str(), )); // println!("{template:#?}"); - let node = VNode { - key: None, - parent: None, - template: Cell::new(template), - root_ids: bumpalo::collections::Vec::new_in(cx.bump()).into(), - dynamic_nodes: { - let dynamic_nodes: Vec<_> = dynamic_node_types - .iter() - .map(|ty| match ty { - DynamicNodeType::Text => DynamicNode::Text(VText::new(Box::leak( - format!("{}", rand::random::()).into_boxed_str(), - ))), - DynamicNodeType::Other => { - create_random_dynamic_node(cx, cx.props.depth + 1) - } - }) - .collect(); - cx.bump().alloc(dynamic_nodes) - }, - dynamic_attrs: cx.bump().alloc( - (0..template.attr_paths.len()) - .map(|_| create_random_dynamic_attr(cx)) - .collect::>(), - ), - }; + let node = + VNode { + key: None, + parent: None, + template: Cell::new(template), + root_ids: bumpalo::collections::Vec::new_in(cx.bump()).into(), + dynamic_nodes: { + let dynamic_nodes: Vec<_> = dynamic_node_types + .iter() + .map(|ty| match ty { + DynamicNodeType::Text => DynamicNode::Text(VText::new(Box::leak( + format!("{}", rand::random::()).into_boxed_str(), + ))), + DynamicNodeType::Other => { + create_random_dynamic_node(cx, cx.props.depth + 1) + } + }) + .collect(); + cx.bump().alloc(dynamic_nodes) + }, + dynamic_attrs: cx.bump().alloc( + (0..template.attr_paths.len()) + .map(|_| create_random_dynamic_attr(cx)) + .collect::>(), + ), + }; Some(node) } _ => None, diff --git a/packages/desktop/headless_tests/rendering.rs b/packages/desktop/headless_tests/rendering.rs index 0907121d4..31dc28256 100644 --- a/packages/desktop/headless_tests/rendering.rs +++ b/packages/desktop/headless_tests/rendering.rs @@ -34,12 +34,13 @@ fn use_inner_html(cx: &ScopeState, id: &'static str) -> Option { to_owned![value, eval_provider]; async move { tokio::time::sleep(std::time::Duration::from_millis(100)).await; - let html = eval_provider(&format!( - r#"let element = document.getElementById('{}'); + let html = + eval_provider(&format!( + r#"let element = document.getElementById('{}'); return element.innerHTML"#, - id - )) - .unwrap(); + id + )) + .unwrap(); if let Ok(serde_json::Value::String(html)) = html.await { println!("html: {}", html); value.set(Some(html)); diff --git a/packages/desktop/src/cfg.rs b/packages/desktop/src/cfg.rs index ba42ffa01..3b0409ae8 100644 --- a/packages/desktop/src/cfg.rs +++ b/packages/desktop/src/cfg.rs @@ -36,7 +36,7 @@ pub struct Config { pub(crate) root_name: String, pub(crate) background_color: Option<(u8, u8, u8, u8)>, pub(crate) last_window_close_behaviour: WindowCloseBehaviour, - pub(crate) disable_default_menu_bar: bool, + pub(crate) enable_default_menu_bar: bool, } type DropHandler = Box bool>; @@ -66,13 +66,15 @@ impl Config { root_name: "main".to_string(), background_color: None, last_window_close_behaviour: WindowCloseBehaviour::LastWindowExitsApp, - disable_default_menu_bar: false, + enable_default_menu_bar: true, } } - /// Set whether the default menu bar should be disabled. - pub fn with_disable_default_menu_bar(mut self, disable: bool) -> Self { - self.disable_default_menu_bar = disable; + /// Set whether the default menu bar should be enabled. + /// + /// > Note: `enable` is `true` by default. To disable the default menu bar pass `false`. + pub fn with_default_menu_bar(mut self, enable: bool) -> Self { + self.enable_default_menu_bar = enable; self } diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 63a8914f3..7b8f024be 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -240,18 +240,20 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) Event::UserEvent(event) => match event.0 { #[cfg(all(feature = "hot-reload", debug_assertions))] - EventData::HotReloadEvent(msg) => match msg { - dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => { - for webview in webviews.values_mut() { - webview.dom.replace_template(template); + EventData::HotReloadEvent(msg) => { + match msg { + dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => { + for webview in webviews.values_mut() { + webview.dom.replace_template(template); - poll_vdom(webview); + poll_vdom(webview); + } + } + dioxus_hot_reload::HotReloadMsg::Shutdown => { + *control_flow = ControlFlow::Exit; } } - dioxus_hot_reload::HotReloadMsg::Shutdown => { - *control_flow = ControlFlow::Exit; - } - }, + } EventData::CloseWindow => { webviews.remove(&event.1); diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index 9beae702a..f03878242 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -19,8 +19,8 @@ pub fn build( let index_file = cfg.custom_index.clone(); let root_name = cfg.root_name.clone(); - if !cfg.disable_default_menu_bar { - builder = builder.with_menu(create_default_menu_bar()); + if cfg.enable_default_menu_bar { + builder = builder.with_menu(build_default_menu_bar()); } let window = builder.with_visible(false).build(event_loop).unwrap(); @@ -103,8 +103,12 @@ pub fn build( (webview.build().unwrap(), web_context) } -/// Creates a standard menu bar depending on the platform -fn create_default_menu_bar() -> MenuBar { +/// Builds a standard menu bar depending on the users platform. It may be used as a starting point +/// to further customize the menu bar and pass it to a [`WindowBuilder`](tao::window::WindowBuilder). +/// > Note: The default menu bar enables macOS shortcuts like cut/copy/paste. +/// > The menu bar differs per platform because of constraints introduced +/// > by [`MenuItem`](tao::menu::MenuItem). +pub fn build_default_menu_bar() -> MenuBar { let mut menu_bar = MenuBar::new(); // since it is uncommon on windows to have an "application menu" diff --git a/packages/dioxus-tui/examples/all_terminal_events.rs b/packages/dioxus-tui/examples/all_terminal_events.rs index 483e9afdf..dd160c9b7 100644 --- a/packages/dioxus-tui/examples/all_terminal_events.rs +++ b/packages/dioxus-tui/examples/all_terminal_events.rs @@ -40,9 +40,10 @@ fn app(cx: Scope) -> Element { rsx!(p { "{trimmed}" }) }); - let log_event = move |event: Event| { - events.write().push(event); - }; + let log_event = + move |event: Event| { + events.write().push(event); + }; cx.render(rsx! { div { diff --git a/packages/dioxus/benches/jsframework.rs b/packages/dioxus/benches/jsframework.rs index b3405b2bd..e313cdee6 100644 --- a/packages/dioxus/benches/jsframework.rs +++ b/packages/dioxus/benches/jsframework.rs @@ -87,33 +87,34 @@ impl Label { } } -static ADJECTIVES: &[&str] = &[ - "pretty", - "large", - "big", - "small", - "tall", - "short", - "long", - "handsome", - "plain", - "quaint", - "clean", - "elegant", - "easy", - "angry", - "crazy", - "helpful", - "mushy", - "odd", - "unsightly", - "adorable", - "important", - "inexpensive", - "cheap", - "expensive", - "fancy", -]; +static ADJECTIVES: &[&str] = + &[ + "pretty", + "large", + "big", + "small", + "tall", + "short", + "long", + "handsome", + "plain", + "quaint", + "clean", + "elegant", + "easy", + "angry", + "crazy", + "helpful", + "mushy", + "odd", + "unsightly", + "adorable", + "important", + "inexpensive", + "cheap", + "expensive", + "fancy", + ]; static COLOURS: &[&str] = &[ "red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", diff --git a/packages/dioxus/examples/stress.rs b/packages/dioxus/examples/stress.rs index 248d851d2..ef0bbbf6c 100644 --- a/packages/dioxus/examples/stress.rs +++ b/packages/dioxus/examples/stress.rs @@ -62,33 +62,34 @@ impl Label { } } -static ADJECTIVES: &[&str] = &[ - "pretty", - "large", - "big", - "small", - "tall", - "short", - "long", - "handsome", - "plain", - "quaint", - "clean", - "elegant", - "easy", - "angry", - "crazy", - "helpful", - "mushy", - "odd", - "unsightly", - "adorable", - "important", - "inexpensive", - "cheap", - "expensive", - "fancy", -]; +static ADJECTIVES: &[&str] = + &[ + "pretty", + "large", + "big", + "small", + "tall", + "short", + "long", + "handsome", + "plain", + "quaint", + "clean", + "elegant", + "easy", + "angry", + "crazy", + "helpful", + "mushy", + "odd", + "unsightly", + "adorable", + "important", + "inexpensive", + "cheap", + "expensive", + "fancy", + ]; static COLOURS: &[&str] = &[ "red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", diff --git a/packages/fullstack/examples/axum-auth/src/main.rs b/packages/fullstack/examples/axum-auth/src/main.rs index 6643f718b..ea7a0efe0 100644 --- a/packages/fullstack/examples/axum-auth/src/main.rs +++ b/packages/fullstack/examples/axum-auth/src/main.rs @@ -37,12 +37,13 @@ fn main() { //To enable Private cookies for integrity, and authenticity please check the next Example. let session_config = SessionConfig::default().with_table_name("test_table"); let auth_config = AuthConfig::::default().with_anonymous_user_id(Some(1)); - let session_store = SessionStore::::new( - Some(pool.clone().into()), - session_config, - ) - .await - .unwrap(); + let session_store = + SessionStore::::new( + Some(pool.clone().into()), + session_config, + ) + .await + .unwrap(); //Create the Database table for storing our Session Data. session_store.initiate().await.unwrap(); diff --git a/packages/fullstack/examples/static-hydrated/src/main.rs b/packages/fullstack/examples/static-hydrated/src/main.rs index 2539d0deb..536971524 100644 --- a/packages/fullstack/examples/static-hydrated/src/main.rs +++ b/packages/fullstack/examples/static-hydrated/src/main.rs @@ -16,9 +16,9 @@ use serde::{Deserialize, Serialize}; #[tokio::main] async fn main() { pre_cache_static_routes_with_props( - &ServeConfigBuilder::new_with_router(dioxus_fullstack::router::FullstackRouterConfig::< - Route, - >::default()) + &ServeConfigBuilder::new_with_router( + dioxus_fullstack::router::FullstackRouterConfig::::default() + ) .assets_path("docs") .incremental(IncrementalRendererConfig::default().static_dir("docs")) .build(), diff --git a/packages/fullstack/src/adapters/axum_adapter.rs b/packages/fullstack/src/adapters/axum_adapter.rs index 41a7c92be..089784c94 100644 --- a/packages/fullstack/src/adapters/axum_adapter.rs +++ b/packages/fullstack/src/adapters/axum_adapter.rs @@ -280,12 +280,13 @@ where let assets_path = assets_path.into(); // Serve all files in dist folder except index.html - let dir = std::fs::read_dir(&assets_path).unwrap_or_else(|e| { - panic!( - "Couldn't read assets directory at {:?}: {}", - &assets_path, e - ) - }); + let dir = + std::fs::read_dir(&assets_path).unwrap_or_else(|e| { + panic!( + "Couldn't read assets directory at {:?}: {}", + &assets_path, e + ) + }); for entry in dir.flatten() { let path = entry.path(); @@ -297,9 +298,9 @@ where .unwrap() .iter() .map(|segment| { - segment.to_str().unwrap_or_else(|| { - panic!("Failed to convert path segment {:?} to string", segment) - }) + segment.to_str().unwrap_or_else( + || panic!("Failed to convert path segment {:?} to string", segment) + ) }) .collect::>() .join("/"); diff --git a/packages/fullstack/src/adapters/salvo_adapter.rs b/packages/fullstack/src/adapters/salvo_adapter.rs index 674722665..9953a1192 100644 --- a/packages/fullstack/src/adapters/salvo_adapter.rs +++ b/packages/fullstack/src/adapters/salvo_adapter.rs @@ -244,12 +244,13 @@ impl DioxusRouterExt for Router { let assets_path = assets_path.into(); // Serve all files in dist folder except index.html - let dir = std::fs::read_dir(&assets_path).unwrap_or_else(|e| { - panic!( - "Couldn't read assets directory at {:?}: {}", - &assets_path, e - ) - }); + let dir = + std::fs::read_dir(&assets_path).unwrap_or_else(|e| { + panic!( + "Couldn't read assets directory at {:?}: {}", + &assets_path, e + ) + }); for entry in dir.flatten() { let path = entry.path(); @@ -261,9 +262,9 @@ impl DioxusRouterExt for Router { .unwrap() .iter() .map(|segment| { - segment.to_str().unwrap_or_else(|| { - panic!("Failed to convert path segment {:?} to string", segment) - }) + segment.to_str().unwrap_or_else( + || panic!("Failed to convert path segment {:?} to string", segment) + ) }) .collect::>() .join("/"); diff --git a/packages/fullstack/src/html_storage/deserialize.rs b/packages/fullstack/src/html_storage/deserialize.rs index 7fc70ba6c..1c860a7a2 100644 --- a/packages/fullstack/src/html_storage/deserialize.rs +++ b/packages/fullstack/src/html_storage/deserialize.rs @@ -7,13 +7,14 @@ use super::HTMLDataCursor; #[allow(unused)] pub(crate) fn serde_from_bytes(string: &[u8]) -> Option { - let decompressed = match STANDARD.decode(string) { - Ok(bytes) => bytes, - Err(err) => { - tracing::error!("Failed to decode base64: {}", err); - return None; - } - }; + let decompressed = + match STANDARD.decode(string) { + Ok(bytes) => bytes, + Err(err) => { + tracing::error!("Failed to decode base64: {}", err); + return None; + } + }; match postcard::from_bytes(&decompressed) { Ok(data) => Some(data), diff --git a/packages/fullstack/src/layer.rs b/packages/fullstack/src/layer.rs index 10e67b3f5..3b68fa2d6 100644 --- a/packages/fullstack/src/layer.rs +++ b/packages/fullstack/src/layer.rs @@ -46,11 +46,9 @@ where > + Send, >, > { - let fut = self.call(req).instrument(tracing::trace_span!( - "service", - "{}", - std::any::type_name::() - )); + let fut = self.call(req).instrument( + tracing::trace_span!("service", "{}", std::any::type_name::()) + ); Box::pin(async move { fut.await.map_err(|err| err.into()) }) } } diff --git a/packages/fullstack/src/render.rs b/packages/fullstack/src/render.rs index cda41f82c..f14b97acc 100644 --- a/packages/fullstack/src/render.rs +++ b/packages/fullstack/src/render.rs @@ -91,10 +91,11 @@ impl SsrRendererPool { Ok((freshness, html)) } Self::Incremental(pool) => { - let mut renderer = - pool.write().unwrap().pop().unwrap_or_else(|| { - incremental_pre_renderer(cfg.incremental.as_ref().unwrap()) - }); + let mut renderer = pool + .write() + .unwrap() + .pop() + .unwrap_or_else(|| incremental_pre_renderer(cfg.incremental.as_ref().unwrap())); let (tx, rx) = tokio::sync::oneshot::channel(); diff --git a/packages/fullstack/src/serve_config.rs b/packages/fullstack/src/serve_config.rs index 75a473c89..4d1a3c007 100644 --- a/packages/fullstack/src/serve_config.rs +++ b/packages/fullstack/src/serve_config.rs @@ -122,14 +122,16 @@ fn load_index_html(path: PathBuf, root_id: &'static str) -> IndexHtml { let (pre_main, post_main) = contents.split_once(&format!("id=\"{root_id}\"")).unwrap_or_else(|| panic!("Failed to find id=\"{root_id}\" in index.html. The id is used to inject the application into the page.")); - let post_main = post_main.split_once('>').unwrap_or_else(|| { - panic!("Failed to find closing > after id=\"{root_id}\" in index.html.") - }); + let post_main = + post_main.split_once('>').unwrap_or_else( + || panic!("Failed to find closing > after id=\"{root_id}\" in index.html.") + ); - let (pre_main, post_main) = ( - pre_main.to_string() + &format!("id=\"{root_id}\"") + post_main.0 + ">", - post_main.1.to_string(), - ); + let (pre_main, post_main) = + ( + pre_main.to_string() + &format!("id=\"{root_id}\"") + post_main.0 + ">", + post_main.1.to_string(), + ); IndexHtml { pre_main, diff --git a/packages/fullstack/src/server_context.rs b/packages/fullstack/src/server_context.rs index 6f3b4b6c9..7d1bc63fe 100644 --- a/packages/fullstack/src/server_context.rs +++ b/packages/fullstack/src/server_context.rs @@ -22,9 +22,9 @@ impl Default for DioxusServerContext { fn default() -> Self { Self { shared_context: std::sync::Arc::new(std::sync::RwLock::new(anymap::Map::new())), - response_parts: std::sync::Arc::new(RwLock::new( - http::response::Response::new(()).into_parts().0, - )), + response_parts: std::sync::Arc::new( + RwLock::new(http::response::Response::new(()).into_parts().0) + ), parts: std::sync::Arc::new(RwLock::new(http::request::Request::new(()).into_parts().0)), html_data: Arc::new(RwLock::new(HTMLData::default())), } @@ -45,9 +45,9 @@ mod server_fn_impl { Self { parts: parts.into(), shared_context: Arc::new(RwLock::new(SendSyncAnyMap::new())), - response_parts: std::sync::Arc::new(RwLock::new( - http::response::Response::new(()).into_parts().0, - )), + response_parts: std::sync::Arc::new( + RwLock::new(http::response::Response::new(()).into_parts().0) + ), html_data: Arc::new(RwLock::new(HTMLData::default())), } } @@ -221,9 +221,9 @@ impl FromServerContext for FromContext { type Rejection = NotFoundInServerContext; async fn from_request(req: &DioxusServerContext) -> Result { - Ok(Self(req.clone().get::().ok_or_else(|| { - NotFoundInServerContext::(std::marker::PhantomData::) - })?)) + Ok(Self(req.clone().get::().ok_or_else( + || NotFoundInServerContext::(std::marker::PhantomData::) + )?)) } } diff --git a/packages/hooks/src/use_coroutine.rs b/packages/hooks/src/use_coroutine.rs index f2577b90c..c7990d0d1 100644 --- a/packages/hooks/src/use_coroutine.rs +++ b/packages/hooks/src/use_coroutine.rs @@ -129,11 +129,12 @@ mod tests { use futures_util::StreamExt; fn app(cx: Scope, name: String) -> Element { - let task = use_coroutine(cx, |mut rx: UnboundedReceiver| async move { - while let Some(msg) = rx.next().await { - println!("got message: {msg}"); - } - }); + let task = + use_coroutine(cx, |mut rx: UnboundedReceiver| async move { + while let Some(msg) = rx.next().await { + println!("got message: {msg}"); + } + }); let task2 = use_coroutine(cx, view_task); diff --git a/packages/hooks/src/use_shared_state.rs b/packages/hooks/src/use_shared_state.rs index 37226c759..54b7f720f 100644 --- a/packages/hooks/src/use_shared_state.rs +++ b/packages/hooks/src/use_shared_state.rs @@ -226,10 +226,12 @@ impl UseSharedState { pub fn read(&self) -> Ref<'_, T> { match self.try_read() { Ok(value) => value, - Err(message) => panic!( - "Reading the shared state failed: {}\n({:?})", - message, message - ), + Err(message) => { + panic!( + "Reading the shared state failed: {}\n({:?})", + message, message + ) + } } } @@ -258,10 +260,12 @@ impl UseSharedState { pub fn write(&self) -> RefMut<'_, T> { match self.try_write() { Ok(value) => value, - Err(message) => panic!( - "Writing to shared state failed: {}\n({:?})", - message, message - ), + Err(message) => { + panic!( + "Writing to shared state failed: {}\n({:?})", + message, message + ) + } } } @@ -284,10 +288,12 @@ impl UseSharedState { pub fn write_silent(&self) -> RefMut<'_, T> { match self.try_write_silent() { Ok(value) => value, - Err(message) => panic!( - "Writing to shared state silently failed: {}\n({:?})", - message, message - ), + Err(message) => { + panic!( + "Writing to shared state silently failed: {}\n({:?})", + message, message + ) + } } } @@ -363,12 +369,13 @@ impl PartialEq for UseSharedState { /// ``` pub fn use_shared_state_provider(cx: &ScopeState, f: impl FnOnce() -> T) { cx.use_hook(|| { - let state: ProvidedState = Rc::new(RefCell::new(ProvidedStateInner { - value: f(), - notify_any: cx.schedule_update_any(), - consumers: HashSet::new(), - gen: 0, - })); + let state: ProvidedState = + Rc::new(RefCell::new(ProvidedStateInner { + value: f(), + notify_any: cx.schedule_update_any(), + consumers: HashSet::new(), + gen: 0, + })); cx.provide_context(state); }); diff --git a/packages/hooks/src/use_state.rs b/packages/hooks/src/use_state.rs index 254493510..21120abf0 100644 --- a/packages/hooks/src/use_state.rs +++ b/packages/hooks/src/use_state.rs @@ -35,36 +35,37 @@ pub fn use_state( cx: &ScopeState, initial_state_fn: impl FnOnce() -> T, ) -> &UseState { - let hook = cx.use_hook(move || { - let current_val = Rc::new(initial_state_fn()); - let update_callback = cx.schedule_update(); - let slot = Rc::new(RefCell::new(current_val.clone())); - let setter = Rc::new({ - to_owned![update_callback, slot]; - move |new| { - { - let mut slot = slot.borrow_mut(); + let hook = + cx.use_hook(move || { + let current_val = Rc::new(initial_state_fn()); + let update_callback = cx.schedule_update(); + let slot = Rc::new(RefCell::new(current_val.clone())); + let setter = Rc::new({ + to_owned![update_callback, slot]; + move |new| { + { + let mut slot = slot.borrow_mut(); - // if there's only one reference (weak or otherwise), we can just swap the values - // Typically happens when the state is set multiple times - we don't want to create a new Rc for each new value - if let Some(val) = Rc::get_mut(&mut slot) { - *val = new; - } else { - *slot = Rc::new(new); + // if there's only one reference (weak or otherwise), we can just swap the values + // Typically happens when the state is set multiple times - we don't want to create a new Rc for each new value + if let Some(val) = Rc::get_mut(&mut slot) { + *val = new; + } else { + *slot = Rc::new(new); + } } + update_callback(); } - update_callback(); + }); + + UseState { + current_val, + update_callback, + setter, + slot, } }); - UseState { - current_val, - update_callback, - setter, - slot, - } - }); - hook.current_val = hook.slot.borrow().clone(); hook diff --git a/packages/liveview/examples/axum.rs b/packages/liveview/examples/axum.rs index 6584d5e9b..b188e8270 100644 --- a/packages/liveview/examples/axum.rs +++ b/packages/liveview/examples/axum.rs @@ -37,9 +37,9 @@ async fn main() { .route( "/", get(move || async move { - index_page_with_glue(&dioxus_liveview::interpreter_glue(&format!( - "ws://{addr}/ws" - ))) + index_page_with_glue( + &dioxus_liveview::interpreter_glue(&format!("ws://{addr}/ws")) + ) }), ) .route( diff --git a/packages/liveview/src/pool.rs b/packages/liveview/src/pool.rs index 2fd06cec6..05e892f47 100644 --- a/packages/liveview/src/pool.rs +++ b/packages/liveview/src/pool.rs @@ -112,13 +112,14 @@ impl LiveViewSocket for S where /// You might need to transform the error types of the web backend into the LiveView error type. pub async fn run(mut vdom: VirtualDom, ws: impl LiveViewSocket) -> Result<(), LiveViewError> { #[cfg(all(feature = "hot-reload", debug_assertions))] - let mut hot_reload_rx = { - let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); - dioxus_hot_reload::connect(move |template| { - let _ = tx.send(template); - }); - rx - }; + let mut hot_reload_rx = + { + let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); + dioxus_hot_reload::connect(move |template| { + let _ = tx.send(template); + }); + rx + }; // Create the a proxy for query engine let (query_tx, mut query_rx) = tokio::sync::mpsc::unbounded_channel(); diff --git a/packages/native-core-macro/src/lib.rs b/packages/native-core-macro/src/lib.rs index fdaa12cf5..3d5ba4464 100644 --- a/packages/native-core-macro/src/lib.rs +++ b/packages/native-core-macro/src/lib.rs @@ -66,12 +66,13 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream { Some(tuple) => { let mut parent_dependencies = Vec::new(); for type_ in &tuple.elems { - let mut type_ = extract_type_path(type_).unwrap_or_else(|| { - panic!( - "ParentDependencies must be a tuple of type paths, found {}", - quote!(#type_) - ) - }); + let mut type_ = + extract_type_path(type_).unwrap_or_else(|| { + panic!( + "ParentDependencies must be a tuple of type paths, found {}", + quote!(#type_) + ) + }); if type_ == self_path { type_ = this_type.clone(); } @@ -80,21 +81,24 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream { } parent_dependencies } - _ => panic!( - "ParentDependencies must be a tuple, found {}", - quote!(#parent_dependencies) - ), + _ => { + panic!( + "ParentDependencies must be a tuple, found {}", + quote!(#parent_dependencies) + ) + } }; let child_dependencies = match extract_tuple(child_dependencies) { Some(tuple) => { let mut child_dependencies = Vec::new(); for type_ in &tuple.elems { - let mut type_ = extract_type_path(type_).unwrap_or_else(|| { - panic!( - "ChildDependencies must be a tuple of type paths, found {}", - quote!(#type_) - ) - }); + let mut type_ = + extract_type_path(type_).unwrap_or_else(|| { + panic!( + "ChildDependencies must be a tuple of type paths, found {}", + quote!(#type_) + ) + }); if type_ == self_path { type_ = this_type.clone(); } @@ -103,34 +107,39 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream { } child_dependencies } - _ => panic!( - "ChildDependencies must be a tuple, found {}", - quote!(#child_dependencies) - ), - }; - let node_dependencies = match extract_tuple(node_dependencies) { - Some(tuple) => { - let mut node_dependencies = Vec::new(); - for type_ in &tuple.elems { - let mut type_ = extract_type_path(type_).unwrap_or_else(|| { - panic!( - "NodeDependencies must be a tuple of type paths, found {}", - quote!(#type_) - ) - }); - if type_ == self_path { - type_ = this_type.clone(); - } - combined_dependencies.insert(type_.clone()); - node_dependencies.push(type_); - } - node_dependencies + _ => { + panic!( + "ChildDependencies must be a tuple, found {}", + quote!(#child_dependencies) + ) } - _ => panic!( - "NodeDependencies must be a tuple, found {}", - quote!(#node_dependencies) - ), }; + let node_dependencies = + match extract_tuple(node_dependencies) { + Some(tuple) => { + let mut node_dependencies = Vec::new(); + for type_ in &tuple.elems { + let mut type_ = extract_type_path(type_).unwrap_or_else(|| { + panic!( + "NodeDependencies must be a tuple of type paths, found {}", + quote!(#type_) + ) + }); + if type_ == self_path { + type_ = this_type.clone(); + } + combined_dependencies.insert(type_.clone()); + node_dependencies.push(type_); + } + node_dependencies + } + _ => { + panic!( + "NodeDependencies must be a tuple, found {}", + quote!(#node_dependencies) + ) + } + }; combined_dependencies.insert(this_type.clone()); let combined_dependencies: Vec<_> = combined_dependencies.into_iter().collect(); diff --git a/packages/native-core/examples/custom_attr.rs b/packages/native-core/examples/custom_attr.rs index e7bbb36ea..1089766ed 100644 --- a/packages/native-core/examples/custom_attr.rs +++ b/packages/native-core/examples/custom_attr.rs @@ -160,12 +160,13 @@ impl State for Border { _context: &SendAnyMap, ) -> bool { // check if the node contians a border attribute - let new = Self( - node_view - .attributes() - .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) - .is_some(), - ); + let new = + Self( + node_view + .attributes() + .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) + .is_some(), + ); // check if the member has changed let changed = new != *self; *self = new; diff --git a/packages/native-core/examples/simple.rs b/packages/native-core/examples/simple.rs index 276d06d08..02ce83886 100644 --- a/packages/native-core/examples/simple.rs +++ b/packages/native-core/examples/simple.rs @@ -151,12 +151,13 @@ impl State for Border { _context: &SendAnyMap, ) -> bool { // check if the node contians a border attribute - let new = Self( - node_view - .attributes() - .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) - .is_some(), - ); + let new = + Self( + node_view + .attributes() + .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) + .is_some(), + ); // check if the member has changed let changed = new != *self; *self = new; diff --git a/packages/native-core/examples/simple_dioxus.rs b/packages/native-core/examples/simple_dioxus.rs index af0e4ca00..d3f1cdfcb 100644 --- a/packages/native-core/examples/simple_dioxus.rs +++ b/packages/native-core/examples/simple_dioxus.rs @@ -152,12 +152,13 @@ impl State for Border { _context: &SendAnyMap, ) -> bool { // check if the node contians a border attribute - let new = Self( - node_view - .attributes() - .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) - .is_some(), - ); + let new = + Self( + node_view + .attributes() + .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) + .is_some(), + ); // check if the member has changed let changed = new != *self; *self = new; diff --git a/packages/native-core/src/layout_attributes.rs b/packages/native-core/src/layout_attributes.rs index 4eb39292b..c5c2c2aa4 100644 --- a/packages/native-core/src/layout_attributes.rs +++ b/packages/native-core/src/layout_attributes.rs @@ -340,26 +340,27 @@ pub fn apply_layout_attributes_cfg( } Property::JustifyContent(justify, _) => { use AlignContent::*; - style.justify_content = match justify { - align::JustifyContent::ContentDistribution(distribution) => { - match distribution { - align::ContentDistribution::SpaceBetween => Some(SpaceBetween), - align::ContentDistribution::SpaceAround => Some(SpaceAround), - align::ContentDistribution::SpaceEvenly => Some(SpaceEvenly), - _ => return, + style.justify_content = + match justify { + align::JustifyContent::ContentDistribution(distribution) => { + match distribution { + align::ContentDistribution::SpaceBetween => Some(SpaceBetween), + align::ContentDistribution::SpaceAround => Some(SpaceAround), + align::ContentDistribution::SpaceEvenly => Some(SpaceEvenly), + _ => return, + } } - } - align::JustifyContent::ContentPosition { - value: position, .. - } => match position { - align::ContentPosition::Center => Some(Center), - align::ContentPosition::Start => Some(Start), - align::ContentPosition::FlexStart => Some(FlexStart), - align::ContentPosition::End => Some(End), - align::ContentPosition::FlexEnd => Some(FlexEnd), - }, - _ => return, - }; + align::JustifyContent::ContentPosition { + value: position, .. + } => match position { + align::ContentPosition::Center => Some(Center), + align::ContentPosition::Start => Some(Start), + align::ContentPosition::FlexStart => Some(FlexStart), + align::ContentPosition::End => Some(End), + align::ContentPosition::FlexEnd => Some(FlexEnd), + }, + _ => return, + }; } Property::AlignSelf(align, _) => { use AlignItems::*; @@ -585,11 +586,13 @@ fn convert_grid_track_size(input: grid::TrackSize) -> NonRepeatedTrackSizingFunc convert_track_breadth_min(&min), convert_track_breadth_max(&max), ), - grid::TrackSize::FitContent(limit) => match limit { - DimensionPercentage::Dimension(LengthValue::Px(len)) => minmax(auto(), points(len)), - DimensionPercentage::Percentage(Percentage(pct)) => minmax(auto(), percent(pct)), - _ => unimplemented!(), - }, + grid::TrackSize::FitContent(limit) => { + match limit { + DimensionPercentage::Dimension(LengthValue::Px(len)) => minmax(auto(), points(len)), + DimensionPercentage::Percentage(Percentage(pct)) => minmax(auto(), percent(pct)), + _ => unimplemented!(), + } + } } } diff --git a/packages/native-core/src/utils/persistant_iterator.rs b/packages/native-core/src/utils/persistant_iterator.rs index 2442af29f..fbaab5bed 100644 --- a/packages/native-core/src/utils/persistant_iterator.rs +++ b/packages/native-core/src/utils/persistant_iterator.rs @@ -488,8 +488,5 @@ fn persist_instertions_after() { )); let text = "hello world".to_string(); let idx = iter.next(&rdom).id(); - assert!(matches!( - &*rdom.get(idx).unwrap().node_type(), - NodeType::Text(text) - )); + assert!(matches!(&*rdom.get(idx).unwrap().node_type(), NodeType::Text(text))); } diff --git a/packages/native-core/tests/fuzzing.rs b/packages/native-core/tests/fuzzing.rs index 4f0a34b70..6c56178f8 100644 --- a/packages/native-core/tests/fuzzing.rs +++ b/packages/native-core/tests/fuzzing.rs @@ -9,9 +9,7 @@ fn random_ns() -> Option<&'static str> { let namespace = rand::random::() % 2; match namespace { 0 => None, - 1 => Some(Box::leak( - format!("ns{}", rand::random::()).into_boxed_str(), - )), + 1 => Some(Box::leak(format!("ns{}", rand::random::()).into_boxed_str())), _ => unreachable!(), } } @@ -23,13 +21,15 @@ fn create_random_attribute(attr_idx: &mut usize) -> TemplateAttribute<'static> { value: Box::leak(format!("value{}", rand::random::()).into_boxed_str()), namespace: random_ns(), }, - 1 => TemplateAttribute::Dynamic { - id: { - let old_idx = *attr_idx; - *attr_idx += 1; - old_idx - }, - }, + 1 => { + TemplateAttribute::Dynamic { + id: { + let old_idx = *attr_idx; + *attr_idx += 1; + old_idx + }, + } + } _ => unreachable!(), } } @@ -74,22 +74,26 @@ fn create_random_template_node( 1 => TemplateNode::Text { text: Box::leak(format!("{}", rand::random::()).into_boxed_str()), }, - 2 => TemplateNode::DynamicText { - id: { - let old_idx = *template_idx; - *template_idx += 1; - dynamic_node_types.push(DynamicNodeType::Text); - old_idx - }, - }, - 3 => TemplateNode::Dynamic { - id: { - let old_idx = *template_idx; - *template_idx += 1; - dynamic_node_types.push(DynamicNodeType::Other); - old_idx - }, - }, + 2 => { + TemplateNode::DynamicText { + id: { + let old_idx = *template_idx; + *template_idx += 1; + dynamic_node_types.push(DynamicNodeType::Text); + old_idx + }, + } + } + 3 => { + TemplateNode::Dynamic { + id: { + let old_idx = *template_idx; + *template_idx += 1; + dynamic_node_types.push(DynamicNodeType::Other); + old_idx + }, + } + } _ => unreachable!(), } } @@ -206,9 +210,9 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode { fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute { let value = match rand::random::() % 6 { - 0 => AttributeValue::Text(Box::leak( - format!("{}", rand::random::()).into_boxed_str(), - )), + 0 => { + AttributeValue::Text(Box::leak(format!("{}", rand::random::()).into_boxed_str())) + } 1 => AttributeValue::Float(rand::random()), 2 => AttributeValue::Int(rand::random()), 3 => AttributeValue::Bool(rand::random()), diff --git a/packages/rink/src/focus.rs b/packages/rink/src/focus.rs index 704d13b46..3f1ebb2d8 100644 --- a/packages/rink/src/focus.rs +++ b/packages/rink/src/focus.rs @@ -83,36 +83,37 @@ impl State for Focus { _: &SendAnyMap, ) -> bool { let new = Focus { - level: if let Some(a) = node_view - .attributes() - .and_then(|mut a| a.find(|a| a.attribute.name == "tabindex")) - { - if let Some(index) = a - .value - .as_int() - .or_else(|| a.value.as_text().and_then(|v| v.parse::().ok())) + level: + if let Some(a) = node_view + .attributes() + .and_then(|mut a| a.find(|a| a.attribute.name == "tabindex")) { - match index.cmp(&0) { - Ordering::Less => FocusLevel::Unfocusable, - Ordering::Equal => FocusLevel::Focusable, - Ordering::Greater => { - FocusLevel::Ordered(NonZeroU16::new(index as u16).unwrap()) + if let Some(index) = a + .value + .as_int() + .or_else(|| a.value.as_text().and_then(|v| v.parse::().ok())) + { + match index.cmp(&0) { + Ordering::Less => FocusLevel::Unfocusable, + Ordering::Equal => FocusLevel::Focusable, + Ordering::Greater => { + FocusLevel::Ordered(NonZeroU16::new(index as u16).unwrap()) + } } + } else { + FocusLevel::Unfocusable } + } else if node_view + .listeners() + .and_then( + |mut listeners| listeners.any(|l| FOCUS_EVENTS.contains(&l)).then_some(()) + ) + .is_some() + { + FocusLevel::Focusable } else { FocusLevel::Unfocusable - } - } else if node_view - .listeners() - .and_then(|mut listeners| { - listeners.any(|l| FOCUS_EVENTS.contains(&l)).then_some(()) - }) - .is_some() - { - FocusLevel::Focusable - } else { - FocusLevel::Unfocusable - }, + }, }; if *self != new { *self = new; diff --git a/packages/rink/src/hooks.rs b/packages/rink/src/hooks.rs index f8c4500d2..7afed77e4 100644 --- a/packages/rink/src/hooks.rs +++ b/packages/rink/src/hooks.rs @@ -585,13 +585,14 @@ impl RinkInputHandler { let queued_events = Rc::new(RefCell::new(Vec::new())); let queued_events2 = Rc::downgrade(&queued_events); - let regester_event = move |evt: crossterm::event::Event| { - if let Some(evt) = get_event(evt) { - if let Some(v) = queued_events2.upgrade() { - (*v).borrow_mut().push(evt); + let regester_event = + move |evt: crossterm::event::Event| { + if let Some(evt) = get_event(evt) { + if let Some(v) = queued_events2.upgrade() { + (*v).borrow_mut().push(evt); + } } - } - }; + }; let state = Rc::new(RefCell::new(InnerInputState::create(rdom))); @@ -680,48 +681,49 @@ fn get_event(evt: TermEvent) -> Option<(&'static str, EventData)> { let ctrl = m.modifiers.contains(KeyModifiers::CONTROL); let meta = false; - let get_mouse_data = |crossterm_button: Option| { - let button = crossterm_button.map(|b| match b { - MouseButton::Left => DioxusMouseButton::Primary, - MouseButton::Right => DioxusMouseButton::Secondary, - MouseButton::Middle => DioxusMouseButton::Auxiliary, - }); + let get_mouse_data = + |crossterm_button: Option| { + let button = crossterm_button.map(|b| match b { + MouseButton::Left => DioxusMouseButton::Primary, + MouseButton::Right => DioxusMouseButton::Secondary, + MouseButton::Middle => DioxusMouseButton::Auxiliary, + }); - // from https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent + // from https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent - // The `page` and `screen` coordinates are inconsistent with the MDN definition, as they are relative to the viewport (client), not the target element/page/screen, respectively. - // todo? - // But then, MDN defines them in terms of pixels, yet crossterm provides only row/column, and it might not be possible to get pixels. So we can't get 100% consistency anyway. - let coordinates = Coordinates::new( - ScreenPoint::new(x, y), - ClientPoint::new(x, y), - // offset x/y are set when the origin of the event is assigned to an element - ElementPoint::new(0., 0.), - PagePoint::new(x, y), - ); + // The `page` and `screen` coordinates are inconsistent with the MDN definition, as they are relative to the viewport (client), not the target element/page/screen, respectively. + // todo? + // But then, MDN defines them in terms of pixels, yet crossterm provides only row/column, and it might not be possible to get pixels. So we can't get 100% consistency anyway. + let coordinates = Coordinates::new( + ScreenPoint::new(x, y), + ClientPoint::new(x, y), + // offset x/y are set when the origin of the event is assigned to an element + ElementPoint::new(0., 0.), + PagePoint::new(x, y), + ); - let mut modifiers = Modifiers::empty(); - if shift { - modifiers.insert(Modifiers::SHIFT); - } - if ctrl { - modifiers.insert(Modifiers::CONTROL); - } - if meta { - modifiers.insert(Modifiers::META); - } - if alt { - modifiers.insert(Modifiers::ALT); - } + let mut modifiers = Modifiers::empty(); + if shift { + modifiers.insert(Modifiers::SHIFT); + } + if ctrl { + modifiers.insert(Modifiers::CONTROL); + } + if meta { + modifiers.insert(Modifiers::META); + } + if alt { + modifiers.insert(Modifiers::ALT); + } - // held mouse buttons get set later by maintaining state, as crossterm does not provide them - EventData::Mouse(MouseData::new( - coordinates, - button, - DioxusMouseButtons::empty(), - modifiers, - )) - }; + // held mouse buttons get set later by maintaining state, as crossterm does not provide them + EventData::Mouse(MouseData::new( + coordinates, + button, + DioxusMouseButtons::empty(), + modifiers, + )) + }; let get_wheel_data = |up| { let y = if up { -1.0 } else { 1.0 }; diff --git a/packages/rink/src/layout.rs b/packages/rink/src/layout.rs index dbdadac3f..f9a29408e 100644 --- a/packages/rink/src/layout.rs +++ b/packages/rink/src/layout.rs @@ -195,11 +195,12 @@ impl State for TaffyLayout { taffy.set_children(n, &child_layout).unwrap(); } } else { - self.node = PossiblyUninitalized::Initialized( - taffy - .new_with_children(scaled_style, &child_layout) - .unwrap(), - ); + self.node = + PossiblyUninitalized::Initialized( + taffy + .new_with_children(scaled_style, &child_layout) + .unwrap(), + ); changed = true; } } diff --git a/packages/rink/src/prevent_default.rs b/packages/rink/src/prevent_default.rs index 4ad5ad87f..d42516d9f 100644 --- a/packages/rink/src/prevent_default.rs +++ b/packages/rink/src/prevent_default.rs @@ -43,27 +43,28 @@ impl State for PreventDefault { _: Vec<::ElementBorrowed<'a>>, _: &SendAnyMap, ) -> bool { - let new = match node_view.attributes().and_then(|mut attrs| { - attrs - .find(|a| a.attribute.name == "dioxus-prevent-default") - .and_then(|a| a.value.as_text()) - }) { - Some("onfocus") => PreventDefault::Focus, - Some("onkeypress") => PreventDefault::KeyPress, - Some("onkeyrelease") => PreventDefault::KeyRelease, - Some("onkeydown") => PreventDefault::KeyDown, - Some("onkeyup") => PreventDefault::KeyUp, - Some("onclick") => PreventDefault::Click, - Some("onmousedown") => PreventDefault::MouseDown, - Some("onmouseup") => PreventDefault::MouseUp, - Some("onmouseenter") => PreventDefault::MouseEnter, - Some("onmouseover") => PreventDefault::MouseOver, - Some("onmouseleave") => PreventDefault::MouseLeave, - Some("onmouseout") => PreventDefault::MouseOut, - Some("onwheel") => PreventDefault::Wheel, - Some("oncontextmenu") => PreventDefault::ContextMenu, - _ => return false, - }; + let new = + match node_view.attributes().and_then(|mut attrs| { + attrs + .find(|a| a.attribute.name == "dioxus-prevent-default") + .and_then(|a| a.value.as_text()) + }) { + Some("onfocus") => PreventDefault::Focus, + Some("onkeypress") => PreventDefault::KeyPress, + Some("onkeyrelease") => PreventDefault::KeyRelease, + Some("onkeydown") => PreventDefault::KeyDown, + Some("onkeyup") => PreventDefault::KeyUp, + Some("onclick") => PreventDefault::Click, + Some("onmousedown") => PreventDefault::MouseDown, + Some("onmouseup") => PreventDefault::MouseUp, + Some("onmouseenter") => PreventDefault::MouseEnter, + Some("onmouseover") => PreventDefault::MouseOver, + Some("onmouseleave") => PreventDefault::MouseLeave, + Some("onmouseout") => PreventDefault::MouseOut, + Some("onwheel") => PreventDefault::Wheel, + Some("oncontextmenu") => PreventDefault::ContextMenu, + _ => return false, + }; if new == *self { false } else { diff --git a/packages/rink/src/style.rs b/packages/rink/src/style.rs index 905cc4b34..efd300774 100644 --- a/packages/rink/src/style.rs +++ b/packages/rink/src/style.rs @@ -350,24 +350,26 @@ pub fn convert(mode: RenderingMode, c: Color) -> Color { let rgb = to_rgb(c); Color::Rgb(rgb[0], rgb[1], rgb[2]) } - crate::RenderingMode::Ansi => match c { - Color::Indexed(_) => c, - _ => { - let rgb = to_rgb(c); - // 16-231: 6 Ă— 6 Ă— 6 color cube - // 232-255: 23 step grayscale - if rgb[0] == rgb[1] && rgb[1] == rgb[2] { - let idx = 232 + (rgb[0] as u16 * 23 / 255) as u8; - Color::Indexed(idx) - } else { - let r = (rgb[0] as u16 * 5) / 255; - let g = (rgb[1] as u16 * 5) / 255; - let b = (rgb[2] as u16 * 5) / 255; - let idx = 16 + r * 36 + g * 6 + b; - Color::Indexed(idx as u8) + crate::RenderingMode::Ansi => { + match c { + Color::Indexed(_) => c, + _ => { + let rgb = to_rgb(c); + // 16-231: 6 Ă— 6 Ă— 6 color cube + // 232-255: 23 step grayscale + if rgb[0] == rgb[1] && rgb[1] == rgb[2] { + let idx = 232 + (rgb[0] as u16 * 23 / 255) as u8; + Color::Indexed(idx) + } else { + let r = (rgb[0] as u16 * 5) / 255; + let g = (rgb[1] as u16 * 5) / 255; + let b = (rgb[2] as u16 * 5) / 255; + let idx = 16 + r * 36 + g * 6 + b; + Color::Indexed(idx as u8) + } } } - }, + } } } } diff --git a/packages/rink/src/widgets/button.rs b/packages/rink/src/widgets/button.rs index 523b2392a..bc1b16c9f 100644 --- a/packages/rink/src/widgets/button.rs +++ b/packages/rink/src/widgets/button.rs @@ -90,11 +90,12 @@ impl Button { } fn switch(&mut self, ctx: &WidgetContext, node: NodeMut) { - let data = FormData { - value: self.value.to_string(), - values: HashMap::new(), - files: None, - }; + let data = + FormData { + value: self.value.to_string(), + values: HashMap::new(), + files: None, + }; ctx.send(crate::Event { id: node.id(), name: "input", diff --git a/packages/rink/src/widgets/slider.rs b/packages/rink/src/widgets/slider.rs index 7080b6c12..1ed4f903e 100644 --- a/packages/rink/src/widgets/slider.rs +++ b/packages/rink/src/widgets/slider.rs @@ -236,10 +236,11 @@ impl Slider { let id = root.id(); let rdom = root.real_dom_mut(); let world = rdom.raw_world_mut(); - let taffy = { - let query: UniqueView = world.borrow().unwrap(); - query.stretch.clone() - }; + let taffy = + { + let query: UniqueView = world.borrow().unwrap(); + query.stretch.clone() + }; let taffy = taffy.lock().unwrap(); @@ -267,10 +268,11 @@ impl CustomElement for Slider { panic!("input must be an element") }; - let value = el.attributes.get(&OwnedAttributeDiscription { - name: "value".to_string(), - namespace: None, - }); + let value = + el.attributes.get(&OwnedAttributeDiscription { + name: "value".to_string(), + namespace: None, + }); let value = value .and_then(|value| match value { OwnedAttributeValue::Text(text) => text.as_str().parse().ok(), @@ -301,11 +303,12 @@ impl CustomElement for Slider { let cursor_text = rdom.create_node("|".to_string()); let cursor_text_id = cursor_text.id(); - let mut cursor_span = rdom.create_node(NodeType::Element(ElementNode { - tag: "div".to_string(), - attributes: [].into_iter().collect(), - ..Default::default() - })); + let mut cursor_span = + rdom.create_node(NodeType::Element(ElementNode { + tag: "div".to_string(), + attributes: [].into_iter().collect(), + ..Default::default() + })); cursor_span.add_child(cursor_text_id); let cursor_span_id = cursor_span.id(); diff --git a/packages/router-macro/src/route.rs b/packages/router-macro/src/route.rs index 26665e575..dd2689698 100644 --- a/packages/router-macro/src/route.rs +++ b/packages/router-macro/src/route.rs @@ -144,13 +144,14 @@ impl Route { _ => Vec::new(), }; - let (route_segments, query) = { - parse_route_segments( - variant.ident.span(), - fields.iter().map(|f| (&f.0, &f.1)), - &route, - )? - }; + let (route_segments, query) = + { + parse_route_segments( + variant.ident.span(), + fields.iter().map(|f| (&f.0, &f.1)), + &route, + )? + }; Ok(Self { ty, @@ -323,10 +324,11 @@ impl Route { pub fn error_type(&self) -> TokenStream2 { let error_name = self.error_ident(); - let child_type = match &self.ty { - RouteType::Child(field) => Some(&field.ty), - RouteType::Leaf { .. } => None, - }; + let child_type = + match &self.ty { + RouteType::Child(field) => Some(&field.ty), + RouteType::Leaf { .. } => None, + }; create_error_type(error_name, &self.segments, child_type) } diff --git a/packages/router-macro/src/segment.rs b/packages/router-macro/src/segment.rs index 7e4e40662..510bc13a2 100644 --- a/packages/router-macro/src/segment.rs +++ b/packages/router-macro/src/segment.rs @@ -135,10 +135,11 @@ pub fn parse_route_segments<'a>( ) -> syn::Result<(Vec, Option)> { let mut route_segments = Vec::new(); - let (route_string, query) = match route.rsplit_once('?') { - Some((route, query)) => (route, Some(query)), - None => (route, None), - }; + let (route_string, query) = + match route.rsplit_once('?') { + Some((route, query)) => (route, Some(query)), + None => (route, None), + }; let mut iterator = route_string.split('/'); // skip the first empty segment @@ -157,11 +158,12 @@ pub fn parse_route_segments<'a>( if let Some(segment) = segment.strip_prefix(':') { let spread = segment.starts_with(".."); - let ident = if spread { - segment[2..].to_string() - } else { - segment.to_string() - }; + let ident = + if spread { + segment[2..].to_string() + } else { + segment.to_string() + }; let field = fields.find(|(name, _)| **name == ident); @@ -205,14 +207,15 @@ pub fn parse_route_segments<'a>( let query_ident = Ident::new(query, Span::call_site()); let field = fields.find(|(name, _)| *name == &query_ident); - let ty = if let Some((_, ty)) = field { - ty.clone() - } else { - return Err(syn::Error::new( - route_span, - format!("Could not find a field with the name '{}'", query_ident), - )); - }; + let ty = + if let Some((_, ty)) = field { + ty.clone() + } else { + return Err(syn::Error::new( + route_span, + format!("Could not find a field with the name '{}'", query_ident), + )); + }; Some(QuerySegment { ident: query_ident, diff --git a/packages/router/src/history/liveview.rs b/packages/router/src/history/liveview.rs index 9ffb09c34..a7ecc89f6 100644 --- a/packages/router/src/history/liveview.rs +++ b/packages/router/src/history/liveview.rs @@ -77,17 +77,18 @@ where self.routes.retain(|&lhs, _| lhs <= last_visited); } }; - let state = match state { - Some(state) => { - self.current_index = state.index; - state - } - None => { - let index = depth - 1; - self.current_index = index; - State { index } - } - }; + let state = + match state { + Some(state) => { + self.current_index = state.index; + state + } + None => { + let index = depth - 1; + self.current_index = index; + State { index } + } + }; self.routes.insert(state.index, route); state } diff --git a/packages/router/src/history/web.rs b/packages/router/src/history/web.rs index 789eed76e..80cde3173 100644 --- a/packages/router/src/history/web.rs +++ b/packages/router/src/history/web.rs @@ -302,15 +302,16 @@ where let s = self.listener_animation_frame.clone(); let d = self.do_scroll_restoration; - self.listener_navigation = Some(EventListener::new(&self.window, "popstate", move |_| { - (*callback)(); - if d { - let mut s = s.lock().expect("unpoisoned scroll mutex"); - if let Some(current_state) = get_current::>(&h) { - *s = Some(current_state.scroll.scroll_to(w.clone())); + self.listener_navigation = + Some(EventListener::new(&self.window, "popstate", move |_| { + (*callback)(); + if d { + let mut s = s.lock().expect("unpoisoned scroll mutex"); + if let Some(current_state) = get_current::>(&h) { + *s = Some(current_state.scroll.scroll_to(w.clone())); + } } - } - })); + })); } } @@ -377,14 +378,15 @@ where let s = self.listener_animation_frame.clone(); let d = self.do_scroll_restoration; - self.listener_navigation = Some(EventListener::new(&self.window, "popstate", move |_| { - (*callback)(); - if d { - let mut s = s.lock().expect("unpoisoned scroll mutex"); - if let Some([x, y]) = get_current(&h) { - *s = Some(ScrollPosition { x, y }.scroll_to(w.clone())); + self.listener_navigation = + Some(EventListener::new(&self.window, "popstate", move |_| { + (*callback)(); + if d { + let mut s = s.lock().expect("unpoisoned scroll mutex"); + if let Some([x, y]) = get_current(&h) { + *s = Some(ScrollPosition { x, y }.scroll_to(w.clone())); + } } - } - })); + })); } } diff --git a/packages/router/src/navigation.rs b/packages/router/src/navigation.rs index 2d7a3f90f..e84a8b381 100644 --- a/packages/router/src/navigation.rs +++ b/packages/router/src/navigation.rs @@ -114,11 +114,9 @@ impl FromStr for NavigationTarget { fn from_str(s: &str) -> Result { match Url::parse(s) { Ok(_) => Ok(Self::External(s.to_string())), - Err(ParseError::RelativeUrlWithoutBase) => { - Ok(Self::Internal(R::from_str(s).map_err(|e| { - NavigationTargetParseError::InvalidInternalURL(e) - })?)) - } + Err(ParseError::RelativeUrlWithoutBase) => Ok(Self::Internal( + R::from_str(s).map_err(|e| NavigationTargetParseError::InvalidInternalURL(e))?, + )), Err(e) => Err(NavigationTargetParseError::InvalidUrl(e)), } } diff --git a/packages/router/src/routable.rs b/packages/router/src/routable.rs index b1bb6d915..094dcafe1 100644 --- a/packages/router/src/routable.rs +++ b/packages/router/src/routable.rs @@ -134,11 +134,12 @@ impl> FromRouteSegments for I { /// A flattened version of [`Routable::SITE_MAP`]. /// This essentially represents a `Vec>`, which you can collect it into. -type SiteMapFlattened<'a> = FlatMap< - Iter<'a, SiteMapSegment>, - Vec>, - fn(&SiteMapSegment) -> Vec>, ->; +type SiteMapFlattened<'a> = + FlatMap< + Iter<'a, SiteMapSegment>, + Vec>, + fn(&SiteMapSegment) -> Vec>, + >; fn seg_strs_to_route(segs_maybe: &Option>) -> Option where diff --git a/packages/router/src/utils/use_router_internal.rs b/packages/router/src/utils/use_router_internal.rs index 9ac33f5fb..32a71d13c 100644 --- a/packages/router/src/utils/use_router_internal.rs +++ b/packages/router/src/utils/use_router_internal.rs @@ -11,14 +11,15 @@ use crate::prelude::*; /// - [`None`], when the current component isn't a descendant of a [`Link`] component. /// - Otherwise [`Some`]. pub(crate) fn use_router_internal(cx: &ScopeState) -> &Option { - let inner = cx.use_hook(|| { - let router = cx.consume_context::()?; + let inner = + cx.use_hook(|| { + let router = cx.consume_context::()?; - let id = cx.scope_id(); - router.subscribe(id); + let id = cx.scope_id(); + router.subscribe(id); - Some(Subscription { router, id }) - }); + Some(Subscription { router, id }) + }); cx.use_hook(|| inner.as_ref().map(|s| s.router.clone())) } diff --git a/packages/rsx-rosetta/tests/simple.rs b/packages/rsx-rosetta/tests/simple.rs index b8fd095e1..de5e1c6a9 100644 --- a/packages/rsx-rosetta/tests/simple.rs +++ b/packages/rsx-rosetta/tests/simple.rs @@ -36,7 +36,8 @@ fn simple_elements() { #[test] fn deeply_nested() { - let html = r#" + let html = + r#"

@@ -48,7 +49,7 @@ fn deeply_nested() {
"# - .trim(); + .trim(); let dom = Dom::parse(html).unwrap(); diff --git a/packages/rsx/src/component.rs b/packages/rsx/src/component.rs index 6487e5ab7..f28859352 100644 --- a/packages/rsx/src/component.rs +++ b/packages/rsx/src/component.rs @@ -162,10 +162,11 @@ impl ToTokens for Component { } if !self.children.is_empty() { - let renderer: TemplateRenderer = TemplateRenderer { - roots: &self.children, - location: None, - }; + let renderer: TemplateRenderer = + TemplateRenderer { + roots: &self.children, + location: None, + }; toks.append_all(quote! { .children( @@ -183,10 +184,11 @@ impl ToTokens for Component { let fn_name = self.name.segments.last().unwrap().ident.to_string(); - let gen_name = match &self.prop_gen_args { - Some(gen) => quote! { #name #gen }, - None => quote! { #name }, - }; + let gen_name = + match &self.prop_gen_args { + Some(gen) => quote! { #name #gen }, + None => quote! { #name }, + }; tokens.append_all(quote! { __cx.component( diff --git a/packages/rsx/src/element.rs b/packages/rsx/src/element.rs index 8f45d91ff..136eeaea2 100644 --- a/packages/rsx/src/element.rs +++ b/packages/rsx/src/element.rs @@ -332,59 +332,60 @@ impl ToTokens for ElementAttrNamed { } }; - let attribute = match attr { - ElementAttr::AttrText { name, value } => { - let ns = ns(name); - let volitile = volitile(name); - let attribute = attribute(name); - quote! { - __cx.attr( - #attribute, - #value, - #ns, - #volitile - ) + let attribute = + match attr { + ElementAttr::AttrText { name, value } => { + let ns = ns(name); + let volitile = volitile(name); + let attribute = attribute(name); + quote! { + __cx.attr( + #attribute, + #value, + #ns, + #volitile + ) + } } - } - ElementAttr::AttrExpression { name, value } => { - let ns = ns(name); - let volitile = volitile(name); - let attribute = attribute(name); - quote! { - __cx.attr( - #attribute, - #value, - #ns, - #volitile - ) + ElementAttr::AttrExpression { name, value } => { + let ns = ns(name); + let volitile = volitile(name); + let attribute = attribute(name); + quote! { + __cx.attr( + #attribute, + #value, + #ns, + #volitile + ) + } } - } - ElementAttr::CustomAttrText { name, value } => { - quote! { - __cx.attr( - #name, - #value, - None, - false - ) + ElementAttr::CustomAttrText { name, value } => { + quote! { + __cx.attr( + #name, + #value, + None, + false + ) + } } - } - ElementAttr::CustomAttrExpression { name, value } => { - quote! { - __cx.attr( - #name, - #value, - None, - false - ) + ElementAttr::CustomAttrExpression { name, value } => { + quote! { + __cx.attr( + #name, + #value, + None, + false + ) + } } - } - ElementAttr::EventTokens { name, tokens } => { - quote! { - dioxus_elements::events::#name(__cx, #tokens) + ElementAttr::EventTokens { name, tokens } => { + quote! { + dioxus_elements::events::#name(__cx, #tokens) + } } - } - }; + }; tokens.append_all(attribute); } diff --git a/packages/rsx/src/hot_reload/hot_reloading_file_map.rs b/packages/rsx/src/hot_reload/hot_reloading_file_map.rs index 0393142b4..875323405 100644 --- a/packages/rsx/src/hot_reload/hot_reloading_file_map.rs +++ b/packages/rsx/src/hot_reload/hot_reloading_file_map.rs @@ -77,11 +77,12 @@ impl FileMap { } let FileMapSearchResult { map, errors } = find_rs_files(path, &mut filter)?; - let result = Self { - map, - in_workspace: HashMap::new(), - phantom: std::marker::PhantomData, - }; + let result = + Self { + map, + in_workspace: HashMap::new(), + phantom: std::marker::PhantomData, + }; Ok(FileMapBuildResult { map: result, errors, diff --git a/packages/rsx/src/ifmt.rs b/packages/rsx/src/ifmt.rs index 6c72f5025..31d7c6a78 100644 --- a/packages/rsx/src/ifmt.rs +++ b/packages/rsx/src/ifmt.rs @@ -99,10 +99,9 @@ impl FromStr for IfmtInput { current_literal.push(c); continue; } else { - return Err(Error::new( - Span::call_site(), - "unmatched closing '}' in format string", - )); + return Err( + Error::new(Span::call_site(), "unmatched closing '}' in format string") + ); } } current_literal.push(c); @@ -147,17 +146,18 @@ impl ToTokens for IfmtInput { } } - let positional_args = self.segments.iter().filter_map(|seg| { - if let Segment::Formatted(FormattedSegment { - segment: FormattedSegmentType::Expr(expr), - .. - }) = seg - { - Some(expr) - } else { - None - } - }); + let positional_args = + self.segments.iter().filter_map(|seg| { + if let Segment::Formatted(FormattedSegment { + segment: FormattedSegmentType::Expr(expr), + .. + }) = seg + { + Some(expr) + } else { + None + } + }); // remove duplicate idents let named_args_idents: HashSet<_> = self @@ -228,10 +228,7 @@ impl FormattedSegmentType { if let Ok(expr) = parse_str(input) { Ok(Self::Expr(Box::new(expr))) } else { - Err(Error::new( - Span::call_site(), - "Expected Ident or Expression", - )) + Err(Error::new(Span::call_site(), "Expected Ident or Expression")) } } } diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index bdf32b272..6657ac722 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -199,10 +199,11 @@ impl<'a> ToTokens for TemplateRenderer<'a> { _ => None, }; - let key_tokens = match key { - Some(tok) => quote! { Some( __cx.raw_text(#tok) ) }, - None => quote! { None }, - }; + let key_tokens = + match key { + Some(tok) => quote! { Some( __cx.raw_text(#tok) ) }, + None => quote! { None }, + }; let spndbg = format!("{:?}", self.roots[0].span()); let root_col = spndbg @@ -518,12 +519,13 @@ impl<'a> DynamicContext<'a> { let attrs = quote! { #(#static_attrs),*}; - let children = el.children.iter().enumerate().map(|(idx, root)| { - self.current_path.push(idx as u8); - let out = self.render_static_node(root); - self.current_path.pop(); - out - }); + let children = + el.children.iter().enumerate().map(|(idx, root)| { + self.current_path.push(idx as u8); + let out = self.render_static_node(root); + self.current_path.pop(); + out + }); let _opt = el.children.len() == 1; let children = quote! { #(#children),* }; diff --git a/packages/server-macro/src/lib.rs b/packages/server-macro/src/lib.rs index 5ad9a682b..75cf7790c 100644 --- a/packages/server-macro/src/lib.rs +++ b/packages/server-macro/src/lib.rs @@ -65,10 +65,11 @@ use syn::{ #[proc_macro_attribute] pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream { // before we pass this off to the server function macro, we apply extractors and middleware - let mut function: syn::ItemFn = match syn::parse(s).map_err(|e| e.to_compile_error()) { - Ok(f) => f, - Err(e) => return e.into(), - }; + let mut function: syn::ItemFn = + match syn::parse(s).map_err(|e| e.to_compile_error()) { + Ok(f) => f, + Err(e) => return e.into(), + }; // extract all #[middleware] attributes let mut middlewares: Vec = vec![]; diff --git a/packages/signals/src/effect.rs b/packages/signals/src/effect.rs index 307ee98ab..87755180b 100644 --- a/packages/signals/src/effect.rs +++ b/packages/signals/src/effect.rs @@ -87,11 +87,12 @@ impl Effect { /// /// The signal will be owned by the current component and will be dropped when the component is dropped. pub fn new(callback: impl FnMut() + 'static) -> Self { - let myself = Self { - source: current_scope_id().expect("in a virtual dom"), - callback: CopyValue::new(Box::new(callback)), - effect_stack: get_effect_stack(), - }; + let myself = + Self { + source: current_scope_id().expect("in a virtual dom"), + callback: CopyValue::new(Box::new(callback)), + effect_stack: get_effect_stack(), + }; myself.try_run(); diff --git a/packages/signals/src/selector.rs b/packages/signals/src/selector.rs index 556c8437c..3dd1c2291 100644 --- a/packages/signals/src/selector.rs +++ b/packages/signals/src/selector.rs @@ -72,9 +72,10 @@ where /// /// Selectors can be used to efficiently compute derived data from signals. pub fn selector(mut f: impl FnMut() -> R + 'static) -> ReadOnlySignal { - let state = Signal:: { - inner: CopyValue::invalid(), - }; + let state = + Signal:: { + inner: CopyValue::invalid(), + }; let effect = Effect { source: current_scope_id().expect("in a virtual dom"), callback: CopyValue::invalid(), diff --git a/packages/signals/tests/create.rs b/packages/signals/tests/create.rs index ecda2f376..0a172617e 100644 --- a/packages/signals/tests/create.rs +++ b/packages/signals/tests/create.rs @@ -6,13 +6,14 @@ use dioxus_signals::*; #[test] fn create_signals_global() { - let mut dom = VirtualDom::new(|cx| { - render! { - for _ in 0..10 { - Child {} + let mut dom = + VirtualDom::new(|cx| { + render! { + for _ in 0..10 { + Child {} + } } - } - }); + }); fn Child(cx: Scope) -> Element { let signal = create_without_cx(); @@ -31,13 +32,14 @@ fn create_signals_global() { #[test] fn deref_signal() { - let mut dom = VirtualDom::new(|cx| { - render! { - for _ in 0..10 { - Child {} + let mut dom = + VirtualDom::new(|cx| { + render! { + for _ in 0..10 { + Child {} + } } - } - }); + }); fn Child(cx: Scope) -> Element { let signal = Signal::new("hello world".to_string()); @@ -55,16 +57,17 @@ fn deref_signal() { #[test] fn drop_signals() { - let mut dom = VirtualDom::new(|cx| { - let generation = cx.generation(); + let mut dom = + VirtualDom::new(|cx| { + let generation = cx.generation(); - let count = if generation % 2 == 0 { 10 } else { 0 }; - render! { - for _ in 0..count { - Child {} + let count = if generation % 2 == 0 { 10 } else { 0 }; + render! { + for _ in 0..count { + Child {} + } } - } - }); + }); fn Child(cx: Scope) -> Element { let signal = create_without_cx(); diff --git a/packages/signals/tests/selector.rs b/packages/signals/tests/selector.rs index 811871e88..b31e32a89 100644 --- a/packages/signals/tests/selector.rs +++ b/packages/signals/tests/selector.rs @@ -100,14 +100,15 @@ fn memos_prevents_component_rerun() { let signal = cx.props.signal; counter.borrow_mut().component += 1; - let memo = cx.use_hook(move || { - to_owned![counter]; - selector(move || { - counter.borrow_mut().effect += 1; - println!("Signal: {:?}", signal); - signal.value() - }) - }); + let memo = + cx.use_hook(move || { + to_owned![counter]; + selector(move || { + counter.borrow_mut().effect += 1; + println!("Signal: {:?}", signal); + signal.value() + }) + }); match cx.generation() { 0 => { assert_eq!(memo.value(), 0); diff --git a/packages/web/src/cache.rs b/packages/web/src/cache.rs index e17203a65..7648b1c47 100644 --- a/packages/web/src/cache.rs +++ b/packages/web/src/cache.rs @@ -1,300 +1,301 @@ -pub static BUILTIN_INTERNED_STRINGS: &[&str] = &[ - // Important tags to dioxus - "dioxus-id", - "dioxus", - "dioxus-event-click", // todo: more events - "click", - // All the HTML Tags - "a", - "abbr", - "address", - "area", - "article", - "aside", - "audio", - "b", - "base", - "bdi", - "bdo", - "big", - "blockquote", - "body", - "br", - "button", - "canvas", - "caption", - "cite", - "code", - "col", - "colgroup", - "command", - "data", - "datalist", - "dd", - "del", - "details", - "dfn", - "dialog", - "div", - "dl", - "dt", - "em", - "embed", - "fieldset", - "figcaption", - "figure", - "footer", - "form", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "head", - "header", - "hr", - "html", - "i", - "iframe", - "img", - "input", - "ins", - "kbd", - "keygen", - "label", - "legend", - "li", - "link", - "main", - "map", - "mark", - "menu", - "menuitem", - "meta", - "meter", - "nav", - "noscript", - "object", - "ol", - "optgroup", - "option", - "output", - "p", - "param", - "picture", - "pre", - "progress", - "q", - "rp", - "rt", - "ruby", - "s", - "samp", - "script", - "section", - "select", - "small", - "source", - "span", - "strong", - "style", - "sub", - "summary", - "sup", - "table", - "tbody", - "td", - "textarea", - "tfoot", - "th", - "thead", - "time", - "title", - "tr", - "track", - "u", - "ul", - "var", - "video", - "wbr", - // All the event handlers - "Attribute", - "accept", - "accept-charset", - "accesskey", - "action", - "alt", - "async", - "autocomplete", - "autofocus", - "autoplay", - "charset", - "checked", - "cite", - "class", - "cols", - "colspan", - "content", - "contenteditable", - "controls", - "coords", - "data", - "data-*", - "datetime", - "default", - "defer", - "dir", - "dirname", - "disabled", - "download", - "draggable", - "enctype", - "for", - "form", - "formaction", - "headers", - "height", - "hidden", - "high", - "href", - "hreflang", - "http-equiv", - "id", - "ismap", - "kind", - "label", - "lang", - "list", - "loop", - "low", - "max", - "maxlength", - "media", - "method", - "min", - "multiple", - "muted", - "name", - "novalidate", - "onabort", - "onafterprint", - "onbeforeprint", - "onbeforeunload", - "onblur", - "oncanplay", - "oncanplaythrough", - "onchange", - "onclick", - "oncontextmenu", - "oncopy", - "oncuechange", - "oncut", - "ondblclick", - "ondrag", - "ondragend", - "ondragenter", - "ondragleave", - "ondragover", - "ondragstart", - "ondrop", - "ondurationchange", - "onemptied", - "onended", - "onerror", - "onfocus", - "onfocusout", - "onfocusin", - "onhashchange", - "oninput", - "oninvalid", - "onkeydown", - "onkeypress", - "onkeyup", - "onload", - "onloadeddata", - "onloadedmetadata", - "onloadstart", - "onmousedown", - "onmousemove", - "onmouseout", - "onmouseover", - "onmouseup", - "onmousewheel", - "onoffline", - "ononline", - "onpageshow", - "onpaste", - "onpause", - "onplay", - "onplaying", - "onprogress", - "onratechange", - "onreset", - "onresize", - "onscroll", - "onsearch", - "onseeked", - "onseeking", - "onselect", - "onstalled", - "onsubmit", - "onsuspend", - "ontimeupdate", - "ontoggle", - "onunload", - "onvolumechange", - "onwaiting", - "onwheel", - "open", - "optimum", - "pattern", - "placeholder", - "poster", - "preload", - "readonly", - "rel", - "required", - "reversed", - "rows", - "rowspan", - "sandbox", - "scope", - "selected", - "shape", - "size", - "sizes", - "span", - "spellcheck", - "src", - "srcdoc", - "srclang", - "srcset", - "start", - "step", - "style", - "tabindex", - "target", - "title", - "translate", - "type", - "usemap", - "value", - "width", - "wrap", - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", -]; +pub static BUILTIN_INTERNED_STRINGS: &[&str] = + &[ + // Important tags to dioxus + "dioxus-id", + "dioxus", + "dioxus-event-click", // todo: more events + "click", + // All the HTML Tags + "a", + "abbr", + "address", + "area", + "article", + "aside", + "audio", + "b", + "base", + "bdi", + "bdo", + "big", + "blockquote", + "body", + "br", + "button", + "canvas", + "caption", + "cite", + "code", + "col", + "colgroup", + "command", + "data", + "datalist", + "dd", + "del", + "details", + "dfn", + "dialog", + "div", + "dl", + "dt", + "em", + "embed", + "fieldset", + "figcaption", + "figure", + "footer", + "form", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "head", + "header", + "hr", + "html", + "i", + "iframe", + "img", + "input", + "ins", + "kbd", + "keygen", + "label", + "legend", + "li", + "link", + "main", + "map", + "mark", + "menu", + "menuitem", + "meta", + "meter", + "nav", + "noscript", + "object", + "ol", + "optgroup", + "option", + "output", + "p", + "param", + "picture", + "pre", + "progress", + "q", + "rp", + "rt", + "ruby", + "s", + "samp", + "script", + "section", + "select", + "small", + "source", + "span", + "strong", + "style", + "sub", + "summary", + "sup", + "table", + "tbody", + "td", + "textarea", + "tfoot", + "th", + "thead", + "time", + "title", + "tr", + "track", + "u", + "ul", + "var", + "video", + "wbr", + // All the event handlers + "Attribute", + "accept", + "accept-charset", + "accesskey", + "action", + "alt", + "async", + "autocomplete", + "autofocus", + "autoplay", + "charset", + "checked", + "cite", + "class", + "cols", + "colspan", + "content", + "contenteditable", + "controls", + "coords", + "data", + "data-*", + "datetime", + "default", + "defer", + "dir", + "dirname", + "disabled", + "download", + "draggable", + "enctype", + "for", + "form", + "formaction", + "headers", + "height", + "hidden", + "high", + "href", + "hreflang", + "http-equiv", + "id", + "ismap", + "kind", + "label", + "lang", + "list", + "loop", + "low", + "max", + "maxlength", + "media", + "method", + "min", + "multiple", + "muted", + "name", + "novalidate", + "onabort", + "onafterprint", + "onbeforeprint", + "onbeforeunload", + "onblur", + "oncanplay", + "oncanplaythrough", + "onchange", + "onclick", + "oncontextmenu", + "oncopy", + "oncuechange", + "oncut", + "ondblclick", + "ondrag", + "ondragend", + "ondragenter", + "ondragleave", + "ondragover", + "ondragstart", + "ondrop", + "ondurationchange", + "onemptied", + "onended", + "onerror", + "onfocus", + "onfocusout", + "onfocusin", + "onhashchange", + "oninput", + "oninvalid", + "onkeydown", + "onkeypress", + "onkeyup", + "onload", + "onloadeddata", + "onloadedmetadata", + "onloadstart", + "onmousedown", + "onmousemove", + "onmouseout", + "onmouseover", + "onmouseup", + "onmousewheel", + "onoffline", + "ononline", + "onpageshow", + "onpaste", + "onpause", + "onplay", + "onplaying", + "onprogress", + "onratechange", + "onreset", + "onresize", + "onscroll", + "onsearch", + "onseeked", + "onseeking", + "onselect", + "onstalled", + "onsubmit", + "onsuspend", + "ontimeupdate", + "ontoggle", + "onunload", + "onvolumechange", + "onwaiting", + "onwheel", + "open", + "optimum", + "pattern", + "placeholder", + "poster", + "preload", + "readonly", + "rel", + "required", + "reversed", + "rows", + "rowspan", + "sandbox", + "scope", + "selected", + "shape", + "size", + "sizes", + "span", + "spellcheck", + "src", + "srcdoc", + "srclang", + "srcset", + "start", + "step", + "style", + "tabindex", + "target", + "title", + "translate", + "type", + "usemap", + "value", + "width", + "wrap", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + ]; diff --git a/packages/web/src/dom.rs b/packages/web/src/dom.rs index f45d6558a..135ad8ede 100644 --- a/packages/web/src/dom.rs +++ b/packages/web/src/dom.rs @@ -80,12 +80,13 @@ impl WebsysDom { } let data = virtual_event_from_websys_event(event.clone(), target); - let _ = event_channel.unbounded_send(UiEvent { - name, - bubbles, - element, - data, - }); + let _ = + event_channel.unbounded_send(UiEvent { + name, + bubbles, + element, + data, + }); } } })); diff --git a/packages/web/src/eval.rs b/packages/web/src/eval.rs index eefece50e..f4da3e69b 100644 --- a/packages/web/src/eval.rs +++ b/packages/web/src/eval.rs @@ -62,24 +62,18 @@ impl WebEvaluator { if let Ok(stringified) = js_sys::JSON::stringify(&result) { if !stringified.is_undefined() && stringified.is_valid_utf16() { let string: String = stringified.into(); - Value::from_str(&string).map_err(|e| { - EvalError::Communication(format!("Failed to parse result - {}", e)) - })? + Value::from_str(&string).map_err( + |e| EvalError::Communication(format!("Failed to parse result - {}", e)) + )? } else { - return Err(EvalError::Communication( - "Failed to stringify result".into(), - )); + return Err(EvalError::Communication("Failed to stringify result".into())); } } else { - return Err(EvalError::Communication( - "Failed to stringify result".into(), - )); + return Err(EvalError::Communication("Failed to stringify result".into())); } } Err(err) => { - return Err(EvalError::InvalidJs( - err.as_string().unwrap_or("unknown".to_string()), - )); + return Err(EvalError::InvalidJs(err.as_string().unwrap_or("unknown".to_string()))); } }; From 906c466e780d56e9c48d9e78dd6a7d0b71fd31fc Mon Sep 17 00:00:00 2001 From: Pascal Date: Thu, 7 Dec 2023 17:11:56 +0100 Subject: [PATCH 03/28] Revert "improved documentation and refactored naming to be more self-explanatory" This reverts commit adfbb6c380ba2079ed7159e9cf84175e301476c7. --- examples/all_events.rs | 15 +- examples/callback.rs | 19 +- examples/compose.rs | 15 +- examples/error_handle.rs | 9 +- examples/eval.rs | 27 +- examples/file_explorer.rs | 11 +- examples/framework_benchmark.rs | 55 +- examples/login_form.rs | 42 +- examples/openid_connect_demo/src/oidc.rs | 11 +- .../openid_connect_demo/src/views/header.rs | 42 +- examples/rsx_compile_fail.rs | 26 +- examples/svg.rs | 30 +- examples/todomvc.rs | 15 +- packages/autofmt/src/expr.rs | 15 +- packages/cli/src/builder.rs | 109 ++-- packages/cli/src/cargo.rs | 6 +- packages/cli/src/cli/autoformat.rs | 75 ++- packages/cli/src/cli/create.rs | 15 +- packages/cli/src/plugin/interface/fs.rs | 11 +- packages/cli/src/plugin/mod.rs | 11 +- packages/cli/src/server/output.rs | 36 +- packages/cli/src/server/web/mod.rs | 13 +- packages/cli/src/tools.rs | 50 +- .../inline_props.rs | 31 +- packages/core-macro/src/props/mod.rs | 217 +++---- packages/core-macro/src/utils.rs | 11 +- packages/core/src/create.rs | 15 +- packages/core/src/nodes.rs | 6 +- packages/core/src/virtual_dom.rs | 9 +- packages/core/tests/attr_cleanup.rs | 29 +- packages/core/tests/bubble_error.rs | 11 +- packages/core/tests/create_dom.rs | 47 +- packages/core/tests/create_fragments.rs | 13 +- packages/core/tests/diff_unkeyed_list.rs | 63 +- packages/core/tests/fuzzing.rs | 113 ++-- packages/desktop/headless_tests/rendering.rs | 11 +- packages/desktop/src/cfg.rs | 12 +- packages/desktop/src/lib.rs | 20 +- packages/desktop/src/webview.rs | 12 +- .../examples/all_terminal_events.rs | 7 +- packages/dioxus/benches/jsframework.rs | 55 +- packages/dioxus/examples/stress.rs | 55 +- .../fullstack/examples/axum-auth/src/main.rs | 13 +- .../examples/static-hydrated/src/main.rs | 6 +- .../fullstack/src/adapters/axum_adapter.rs | 19 +- .../fullstack/src/adapters/salvo_adapter.rs | 19 +- .../fullstack/src/html_storage/deserialize.rs | 15 +- packages/fullstack/src/layer.rs | 8 +- packages/fullstack/src/render.rs | 9 +- packages/fullstack/src/serve_config.rs | 16 +- packages/fullstack/src/server_context.rs | 18 +- packages/hooks/src/use_coroutine.rs | 11 +- packages/hooks/src/use_shared_state.rs | 43 +- packages/hooks/src/use_state.rs | 49 +- packages/liveview/examples/axum.rs | 6 +- packages/liveview/src/pool.rs | 15 +- packages/native-core-macro/src/lib.rs | 91 ++- packages/native-core/examples/custom_attr.rs | 13 +- packages/native-core/examples/simple.rs | 13 +- .../native-core/examples/simple_dioxus.rs | 13 +- packages/native-core/src/layout_attributes.rs | 51 +- .../src/utils/persistant_iterator.rs | 5 +- packages/native-core/tests/fuzzing.rs | 62 +- packages/rink/src/focus.rs | 51 +- packages/rink/src/hooks.rs | 90 ++- packages/rink/src/layout.rs | 11 +- packages/rink/src/prevent_default.rs | 43 +- packages/rink/src/style.rs | 34 +- packages/rink/src/widgets/button.rs | 11 +- packages/rink/src/widgets/slider.rs | 29 +- packages/router-macro/src/route.rs | 24 +- packages/router-macro/src/segment.rs | 37 +- packages/router/src/history/liveview.rs | 23 +- packages/router/src/history/web.rs | 34 +- packages/router/src/navigation.rs | 8 +- packages/router/src/routable.rs | 11 +- .../router/src/utils/use_router_internal.rs | 13 +- packages/rsx-rosetta/tests/simple.rs | 5 +- packages/rsx/src/component.rs | 18 +- packages/rsx/src/element.rs | 97 ++- .../src/hot_reload/hot_reloading_file_map.rs | 11 +- packages/rsx/src/ifmt.rs | 35 +- packages/rsx/src/lib.rs | 22 +- packages/server-macro/src/lib.rs | 9 +- packages/signals/src/effect.rs | 11 +- packages/signals/src/selector.rs | 7 +- packages/signals/tests/create.rs | 43 +- packages/signals/tests/selector.rs | 17 +- packages/web/src/cache.rs | 601 +++++++++--------- packages/web/src/dom.rs | 13 +- packages/web/src/eval.rs | 18 +- 91 files changed, 1553 insertions(+), 1663 deletions(-) diff --git a/examples/all_events.rs b/examples/all_events.rs index 5f3b257bb..594a736d5 100644 --- a/examples/all_events.rs +++ b/examples/all_events.rs @@ -43,15 +43,14 @@ const RECT_STYLE: &str = r#" fn app(cx: Scope) -> Element { let events = use_ref(cx, std::collections::VecDeque::new); - let log_event = - move |event: Event| { - let mut events = events.write(); + let log_event = move |event: Event| { + let mut events = events.write(); - if events.len() >= MAX_EVENTS { - events.pop_front(); - } - events.push_back(event); - }; + if events.len() >= MAX_EVENTS { + events.pop_front(); + } + events.push_back(event); + }; cx.render(rsx! ( div { diff --git a/examples/callback.rs b/examples/callback.rs index ff07607b7..cb300b701 100644 --- a/examples/callback.rs +++ b/examples/callback.rs @@ -5,17 +5,16 @@ fn main() { } fn app(cx: Scope) -> Element { - let login = - use_callback!(cx, move |_| async move { - let res = reqwest::get("https://dog.ceo/api/breeds/list/all") - .await - .unwrap() - .text() - .await - .unwrap(); + let login = use_callback!(cx, move |_| async move { + let res = reqwest::get("https://dog.ceo/api/breeds/list/all") + .await + .unwrap() + .text() + .await + .unwrap(); - println!("{res:#?}, "); - }); + println!("{res:#?}, "); + }); cx.render(rsx! { button { onclick: login, "Click me!" } diff --git a/examples/compose.rs b/examples/compose.rs index d5a5d5c90..3ee6d36ae 100644 --- a/examples/compose.rs +++ b/examples/compose.rs @@ -12,15 +12,14 @@ fn app(cx: Scope) -> Element { let window = use_window(cx); let emails_sent = use_ref(cx, Vec::new); - let tx = - use_coroutine(cx, |mut rx: UnboundedReceiver| { - to_owned![emails_sent]; - async move { - while let Some(message) = rx.next().await { - emails_sent.write().push(message); - } + let tx = use_coroutine(cx, |mut rx: UnboundedReceiver| { + to_owned![emails_sent]; + async move { + while let Some(message) = rx.next().await { + emails_sent.write().push(message); } - }); + } + }); cx.render(rsx! { div { diff --git a/examples/error_handle.rs b/examples/error_handle.rs index c0524f741..d1fb57933 100644 --- a/examples/error_handle.rs +++ b/examples/error_handle.rs @@ -8,11 +8,10 @@ fn main() { fn App(cx: Scope) -> Element { let val = use_state(cx, || "0.0001"); - let num = - match val.parse::() { - Err(_) => return cx.render(rsx!("Parsing failed")), - Ok(num) => num, - }; + let num = match val.parse::() { + Err(_) => return cx.render(rsx!("Parsing failed")), + Ok(num) => num, + }; cx.render(rsx! { h1 { "The parsed value is {num}" } diff --git a/examples/eval.rs b/examples/eval.rs index f6a61ae15..54959df69 100644 --- a/examples/eval.rs +++ b/examples/eval.rs @@ -7,26 +7,25 @@ fn main() { fn app(cx: Scope) -> Element { let eval_provider = use_eval(cx); - let future = - use_future(cx, (), |_| { - to_owned![eval_provider]; - async move { - let eval = eval_provider( - r#" + let future = use_future(cx, (), |_| { + to_owned![eval_provider]; + async move { + let eval = eval_provider( + r#" dioxus.send("Hi from JS!"); let msg = await dioxus.recv(); console.log(msg); return "hello world"; "#, - ) - .unwrap(); + ) + .unwrap(); - eval.send("Hi from Rust!".into()).unwrap(); - let res = eval.recv().await.unwrap(); - println!("{:?}", eval.await); - res - } - }); + eval.send("Hi from Rust!".into()).unwrap(); + let res = eval.recv().await.unwrap(); + println!("{:?}", eval.await); + res + } + }); match future.value() { Some(v) => cx.render(rsx!( diff --git a/examples/file_explorer.rs b/examples/file_explorer.rs index cea860643..88b37789d 100644 --- a/examples/file_explorer.rs +++ b/examples/file_explorer.rs @@ -73,12 +73,11 @@ struct Files { impl Files { fn new() -> Self { - let mut files = - Self { - path_stack: vec!["./".to_string()], - path_names: vec![], - err: None, - }; + let mut files = Self { + path_stack: vec!["./".to_string()], + path_names: vec![], + err: None, + }; files.reload_path_list(); diff --git a/examples/framework_benchmark.rs b/examples/framework_benchmark.rs index f1d75d8e9..7e7a320a9 100644 --- a/examples/framework_benchmark.rs +++ b/examples/framework_benchmark.rs @@ -112,34 +112,33 @@ fn ActionButton<'a>(cx: Scope<'a, ActionButtonProps<'a>>) -> Element { }) } -static ADJECTIVES: &[&str] = - &[ - "pretty", - "large", - "big", - "small", - "tall", - "short", - "long", - "handsome", - "plain", - "quaint", - "clean", - "elegant", - "easy", - "angry", - "crazy", - "helpful", - "mushy", - "odd", - "unsightly", - "adorable", - "important", - "inexpensive", - "cheap", - "expensive", - "fancy", - ]; +static ADJECTIVES: &[&str] = &[ + "pretty", + "large", + "big", + "small", + "tall", + "short", + "long", + "handsome", + "plain", + "quaint", + "clean", + "elegant", + "easy", + "angry", + "crazy", + "helpful", + "mushy", + "odd", + "unsightly", + "adorable", + "important", + "inexpensive", + "cheap", + "expensive", + "fancy", +]; static COLOURS: &[&str] = &[ "red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", diff --git a/examples/login_form.rs b/examples/login_form.rs index 585fe15f6..5ee47e4b5 100644 --- a/examples/login_form.rs +++ b/examples/login_form.rs @@ -8,32 +8,28 @@ fn main() { } fn app(cx: Scope) -> Element { - let onsubmit = - move |evt: FormEvent| { - cx.spawn(async move { - let resp = - reqwest::Client::new() - .post("http://localhost:8080/login") - .form(&[ - ("username", &evt.values["username"]), - ("password", &evt.values["password"]), - ]) - .send() - .await; + let onsubmit = move |evt: FormEvent| { + cx.spawn(async move { + let resp = reqwest::Client::new() + .post("http://localhost:8080/login") + .form(&[ + ("username", &evt.values["username"]), + ("password", &evt.values["password"]), + ]) + .send() + .await; - match resp { - // Parse data from here, such as storing a response token - Ok(_data) => println!("Login successful!"), + match resp { + // Parse data from here, such as storing a response token + Ok(_data) => println!("Login successful!"), - //Handle any errors from the fetch here - Err(_err) => { - println!( - "Login failed - you need a login server running on localhost:8080." - ) - } + //Handle any errors from the fetch here + Err(_err) => { + println!("Login failed - you need a login server running on localhost:8080.") } - }); - }; + } + }); + }; cx.render(rsx! { h1 { "Login" } diff --git a/examples/openid_connect_demo/src/oidc.rs b/examples/openid_connect_demo/src/oidc.rs index 07c9b2314..7fa96c14b 100644 --- a/examples/openid_connect_demo/src/oidc.rs +++ b/examples/openid_connect_demo/src/oidc.rs @@ -112,12 +112,11 @@ pub async fn exchange_refresh_token( pub async fn log_out_url(id_token_hint: CoreIdToken) -> Result { let provider_metadata = init_provider_metadata().await?; - let end_session_url = - provider_metadata - .additional_metadata() - .clone() - .end_session_endpoint - .unwrap(); + let end_session_url = provider_metadata + .additional_metadata() + .clone() + .end_session_endpoint + .unwrap(); let logout_request: LogoutRequest = LogoutRequest::from(end_session_url); Ok(logout_request .set_client_id(ClientId::new(DIOXUS_FRONT_CLIENT_ID.to_string())) diff --git a/examples/openid_connect_demo/src/views/header.rs b/examples/openid_connect_demo/src/views/header.rs index 4a0ccea0d..1f2c6e057 100644 --- a/examples/openid_connect_demo/src/views/header.rs +++ b/examples/openid_connect_demo/src/views/header.rs @@ -22,31 +22,29 @@ pub fn LogOut(cx: Scope) -> Element { Some(fermi_auth_token_read) => match fermi_auth_token_read.id_token.clone() { Some(id_token) => match log_out_url_state.get() { Some(log_out_url_result) => match log_out_url_result { - Some(uri) => { - match uri { - Ok(uri) => { - rsx! { - Link { - onclick: move |_| { - { - AuthTokenState::persistent_set( - fermi_auth_token, - Some(AuthTokenState::default()), - ); - } - }, - to: uri.to_string(), - "Log out" - } - } - } - Err(error) => { - rsx! { - div { format!{"Failed to load disconnection url: {:?}", error} } + Some(uri) => match uri { + Ok(uri) => { + rsx! { + Link { + onclick: move |_| { + { + AuthTokenState::persistent_set( + fermi_auth_token, + Some(AuthTokenState::default()), + ); + } + }, + to: uri.to_string(), + "Log out" } } } - } + Err(error) => { + rsx! { + div { format!{"Failed to load disconnection url: {:?}", error} } + } + } + }, None => { rsx! { div { "Loading... Please wait" } } } diff --git a/examples/rsx_compile_fail.rs b/examples/rsx_compile_fail.rs index f6df332ff..40bad709b 100644 --- a/examples/rsx_compile_fail.rs +++ b/examples/rsx_compile_fail.rs @@ -13,21 +13,19 @@ fn main() { } fn example(cx: Scope) -> Element { - let items = - use_state(cx, || { - vec![Thing { - a: "asd".to_string(), - b: 10, - }] - }); + let items = use_state(cx, || { + vec![Thing { + a: "asd".to_string(), + b: 10, + }] + }); - let things = - use_ref(cx, || { - vec![Thing { - a: "asd".to_string(), - b: 10, - }] - }); + let things = use_ref(cx, || { + vec![Thing { + a: "asd".to_string(), + b: 10, + }] + }); let things_list = things.read(); let mything = use_ref(cx, || Some(String::from("asd"))); diff --git a/examples/svg.rs b/examples/svg.rs index e947c575a..329cbe6ae 100644 --- a/examples/svg.rs +++ b/examples/svg.rs @@ -63,23 +63,23 @@ pub fn Die<'a>(cx: Scope<'a, DieProps<'a>>) -> Element { let active_dots = &DOTS_FOR_VALUE[(value - 1) as usize]; let fill = if keep { HELD_COLOR } else { UNHELD_COLOR }; - let dots = - DOTS.iter() - .zip(active_dots.iter()) - .filter(|(_, &active)| active) - .map(|((x, y), _)| { - let dcx = x * OFFSET; - let dcy = y * OFFSET; + let dots = DOTS + .iter() + .zip(active_dots.iter()) + .filter(|(_, &active)| active) + .map(|((x, y), _)| { + let dcx = x * OFFSET; + let dcy = y * OFFSET; - rsx! { - circle { - cx: "{dcx}", - cy: "{dcy}", - r: "{DOT_RADIUS}", - fill: "#333" - } + rsx! { + circle { + cx: "{dcx}", + cy: "{dcy}", + r: "{DOT_RADIUS}", + fill: "#333" } - }); + } + }); cx.render(rsx! { svg { diff --git a/examples/todomvc.rs b/examples/todomvc.rs index a5a687374..9ec2dc228 100644 --- a/examples/todomvc.rs +++ b/examples/todomvc.rs @@ -202,14 +202,13 @@ pub fn ListFooter<'a>(cx: Scope<'a, ListFooterProps<'a>>) -> Element { let active_todo_count = cx.props.active_todo_count; let active_todo_text = cx.props.active_todo_text; - let selected = - |state| { - if *cx.props.filter == state { - "selected" - } else { - "false" - } - }; + let selected = |state| { + if *cx.props.filter == state { + "selected" + } else { + "false" + } + }; cx.render(rsx! { footer { class: "footer", diff --git a/packages/autofmt/src/expr.rs b/packages/autofmt/src/expr.rs index dc8417c35..b0257f8c3 100644 --- a/packages/autofmt/src/expr.rs +++ b/packages/autofmt/src/expr.rs @@ -34,14 +34,13 @@ impl Writer<'_> { for (id, line) in self.src[start.line..end.line].iter().enumerate() { writeln!(self.out)?; // check if this is the last line - let line = - { - if id == (end.line - start.line) - 1 { - &line[..end.column] - } else { - line - } - }; + let line = { + if id == (end.line - start.line) - 1 { + &line[..end.column] + } else { + line + } + }; // trim the leading whitespace let previous_indent = crate::leading_whitespaces(line) / 4; diff --git a/packages/cli/src/builder.rs b/packages/cli/src/builder.rs index 2352ed262..08e636237 100644 --- a/packages/cli/src/builder.rs +++ b/packages/cli/src/builder.rs @@ -67,21 +67,19 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result { cmd.arg("--quiet") }; - let cmd = - if config.custom_profile.is_some() { - let custom_profile = config.custom_profile.as_ref().unwrap(); - cmd.arg("--profile").arg(custom_profile) - } else { - cmd - }; + let cmd = if config.custom_profile.is_some() { + let custom_profile = config.custom_profile.as_ref().unwrap(); + cmd.arg("--profile").arg(custom_profile) + } else { + cmd + }; - let cmd = - if config.features.is_some() { - let features_str = config.features.as_ref().unwrap().join(" "); - cmd.arg("--features").arg(features_str) - } else { - cmd - }; + let cmd = if config.features.is_some() { + let features_str = config.features.as_ref().unwrap().join(" "); + cmd.arg("--features").arg(features_str) + } else { + cmd + }; let cmd = match executable { ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), @@ -94,14 +92,13 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result { // [2] Establish the output directory structure let bindgen_outdir = out_dir.join("assets").join("dioxus"); - let build_profile = - if config.custom_profile.is_some() { - config.custom_profile.as_ref().unwrap() - } else if config.release { - "release" - } else { - "debug" - }; + let build_profile = if config.custom_profile.is_some() { + config.custom_profile.as_ref().unwrap() + } else if config.release { + "release" + } else { + "debug" + }; let input_path = match executable { ExecutableType::Binary(name) | ExecutableType::Lib(name) => target_dir @@ -210,15 +207,14 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result { } // this code will copy all public file to the output dir - let copy_options = - fs_extra::dir::CopyOptions { - overwrite: true, - skip_exist: false, - buffer_size: 64000, - copy_inside: false, - content_only: false, - depth: 0, - }; + let copy_options = fs_extra::dir::CopyOptions { + overwrite: true, + skip_exist: false, + buffer_size: 64000, + copy_inside: false, + content_only: false, + depth: 0, + }; if asset_dir.is_dir() { for entry in std::fs::read_dir(asset_dir)? { let path = entry?.path(); @@ -291,21 +287,20 @@ pub fn build_desktop(config: &CrateConfig, _is_serve: bool) -> Result { - file_name = name.clone(); - config.target_dir.join(release_type).join(name) - } - crate::ExecutableType::Example(name) => { - file_name = name.clone(); - config - .target_dir - .join(release_type) - .join("examples") - .join(name) - } - }; + let mut res_path = match &config.executable { + crate::ExecutableType::Binary(name) | crate::ExecutableType::Lib(name) => { + file_name = name.clone(); + config.target_dir.join(release_type).join(name) + } + crate::ExecutableType::Example(name) => { + file_name = name.clone(); + config + .target_dir + .join(release_type) + .join("examples") + .join(name) + } + }; let target_file = if cfg!(windows) { res_path.set_extension("exe"); @@ -401,7 +396,9 @@ fn prettier_build(cmd: subprocess::Exec) -> anyhow::Result> { match message.level { cargo_metadata::diagnostic::DiagnosticLevel::Error => { return { - Err(anyhow::anyhow!(message.rendered.unwrap_or("Unknown".into()))) + Err(anyhow::anyhow!(message + .rendered + .unwrap_or("Unknown".into()))) }; } cargo_metadata::diagnostic::DiagnosticLevel::Warning => { @@ -478,7 +475,10 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { let mut script_str = String::new(); for script in script_list { - script_str.push_str(&format!("\n", &script.to_str().unwrap(),)) + script_str.push_str(&format!( + "\n", + &script.to_str().unwrap(), + )) } replace_or_insert_before("{script_include}", &script_str, " String { html = html.replace("{base_path}", base_path); } else { // If not, insert the script - html = - html.replace( - " + html = html.replace( + " import init from "/{base_path}/assets/dioxus/{app_name}.js"; init("/{base_path}/assets/dioxus/{app_name}_bg.wasm").then(wasm => {{ if (wasm.__wbindgen_start == undefined) {{ @@ -515,8 +514,8 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { }}); Result { } None }) - .ok_or_else( - || Error::CargoError("Failed to find directory containing Cargo.toml".to_string()) - ) + .ok_or_else(|| { + Error::CargoError("Failed to find directory containing Cargo.toml".to_string()) + }) } /// Checks if the directory contains `Cargo.toml` diff --git a/packages/cli/src/cli/autoformat.rs b/packages/cli/src/cli/autoformat.rs index 4f6c42751..1d1cbcd24 100644 --- a/packages/cli/src/cli/autoformat.rs +++ b/packages/cli/src/cli/autoformat.rs @@ -93,49 +93,48 @@ async fn autoformat_project(check: bool) -> Result<()> { let mut files_to_format = vec![]; collect_rs_files(&crate_config.crate_dir, &mut files_to_format); - let counts = - files_to_format - .into_iter() - .filter(|file| { - if file.components().any(|f| f.as_os_str() == "target") { - return false; + let counts = files_to_format + .into_iter() + .filter(|file| { + if file.components().any(|f| f.as_os_str() == "target") { + return false; + } + + true + }) + .map(|path| async { + let _path = path.clone(); + let res = tokio::spawn(async move { + let contents = tokio::fs::read_to_string(&path).await?; + + let edits = dioxus_autofmt::fmt_file(&contents); + let len = edits.len(); + + if !edits.is_empty() { + let out = dioxus_autofmt::apply_formats(&contents, edits); + tokio::fs::write(&path, out).await?; } - true + Ok(len) as Result }) - .map(|path| async { - let _path = path.clone(); - let res = tokio::spawn(async move { - let contents = tokio::fs::read_to_string(&path).await?; - - let edits = dioxus_autofmt::fmt_file(&contents); - let len = edits.len(); - - if !edits.is_empty() { - let out = dioxus_autofmt::apply_formats(&contents, edits); - tokio::fs::write(&path, out).await?; - } - - Ok(len) as Result - }) - .await; - - match res { - Err(err) => { - eprintln!("error formatting file: {}\n{err}", _path.display()); - None - } - Ok(Err(err)) => { - eprintln!("error formatting file: {}\n{err}", _path.display()); - None - } - Ok(Ok(res)) => Some(res), - } - }) - .collect::>() - .collect::>() .await; + match res { + Err(err) => { + eprintln!("error formatting file: {}\n{err}", _path.display()); + None + } + Ok(Err(err)) => { + eprintln!("error formatting file: {}\n{err}", _path.display()); + None + } + Ok(Ok(res)) => Some(res), + } + }) + .collect::>() + .collect::>() + .await; + let files_formatted: usize = counts .into_iter() .map(|f| match f { diff --git a/packages/cli/src/cli/create.rs b/packages/cli/src/cli/create.rs index 4893dab80..92b0334f5 100644 --- a/packages/cli/src/cli/create.rs +++ b/packages/cli/src/cli/create.rs @@ -35,14 +35,13 @@ impl Create { let toml_paths = [path.join("Cargo.toml"), path.join("Dioxus.toml")]; for toml_path in &toml_paths { let toml = std::fs::read_to_string(toml_path)?; - let mut toml = - toml.parse::().map_err(|e| { - anyhow::anyhow!( - "failed to parse toml at {}: {}", - toml_path.display(), - e.to_string() - ) - })?; + let mut toml = toml.parse::().map_err(|e| { + anyhow::anyhow!( + "failed to parse toml at {}: {}", + toml_path.display(), + e.to_string() + ) + })?; toml.as_table_mut().fmt(); diff --git a/packages/cli/src/plugin/interface/fs.rs b/packages/cli/src/plugin/interface/fs.rs index 18918a592..5668dbe33 100644 --- a/packages/cli/src/plugin/interface/fs.rs +++ b/packages/cli/src/plugin/interface/fs.rs @@ -67,12 +67,11 @@ impl UserData for PluginFileSystem { let file = PathBuf::from(args.0); let target = PathBuf::from(args.1); - let tar_gz = - if let Ok(v) = File::open(file) { - v - } else { - return Ok(false); - }; + let tar_gz = if let Ok(v) = File::open(file) { + v + } else { + return Ok(false); + }; let tar = GzDecoder::new(tar_gz); let mut archive = Archive::new(tar); diff --git a/packages/cli/src/plugin/mod.rs b/packages/cli/src/plugin/mod.rs index 97adaf08f..481dd0984 100644 --- a/packages/cli/src/plugin/mod.rs +++ b/packages/cli/src/plugin/mod.rs @@ -317,12 +317,11 @@ impl PluginManager { let name = i.get::<_, String>("name").unwrap(); let loader = i.get::<_, bool>("loader").unwrap(); - let text = - if loader { - format!("{name} [:loader]") - } else { - name - }; + let text = if loader { + format!("{name} [:loader]") + } else { + name + }; res.push(text); } } diff --git a/packages/cli/src/server/output.rs b/packages/cli/src/server/output.rs index 92a286c9a..71323dd29 100644 --- a/packages/cli/src/server/output.rs +++ b/packages/cli/src/server/output.rs @@ -22,13 +22,12 @@ pub fn print_console_info( options: PrettierOptions, web_info: Option, ) { - if let Ok(native_clearseq) = - Command::new(if cfg!(target_os = "windows") { - "cls" - } else { - "clear" - }) - .output() + if let Ok(native_clearseq) = Command::new(if cfg!(target_os = "windows") { + "cls" + } else { + "clear" + }) + .output() { print!("{}", String::from_utf8_lossy(&native_clearseq.stdout)); } else { @@ -47,18 +46,17 @@ pub fn print_console_info( } else { "Default" }; - let url_rewrite = - if config - .dioxus_config - .web - .watcher - .index_on_404 - .unwrap_or(false) - { - "True" - } else { - "False" - }; + let url_rewrite = if config + .dioxus_config + .web + .watcher + .index_on_404 + .unwrap_or(false) + { + "True" + } else { + "False" + }; let proxies = config.dioxus_config.web.proxy.as_ref(); diff --git a/packages/cli/src/server/web/mod.rs b/packages/cli/src/server/web/mod.rs index f507f78e6..0e1413597 100644 --- a/packages/cli/src/server/web/mod.rs +++ b/packages/cli/src/server/web/mod.rs @@ -165,7 +165,9 @@ async fn get_rustls(config: &CrateConfig) -> Result> { get_rustls_without_mkcert(web_config)? }; - Ok(Some(RustlsConfig::from_pem_file(cert_path, key_path).await?)) + Ok(Some( + RustlsConfig::from_pem_file(cert_path, key_path).await?, + )) } fn get_rustls_with_mkcert(web_config: &WebHttpsConfig) -> Result<(String, String)> { @@ -312,11 +314,10 @@ async fn setup_router( )); // Setup routes - router = - router - .route("/_dioxus/hot_reload", get(hot_reload_handler)) - .layer(cors) - .layer(Extension(ws_reload)); + router = router + .route("/_dioxus/hot_reload", get(hot_reload_handler)) + .layer(cors) + .layer(Extension(ws_reload)); if let Some(hot_reload) = hot_reload { router = router.layer(Extension(hot_reload)) diff --git a/packages/cli/src/tools.rs b/packages/cli/src/tools.rs index 9b8801e0a..4045b236e 100644 --- a/packages/cli/src/tools.rs +++ b/packages/cli/src/tools.rs @@ -162,11 +162,10 @@ impl Tool { ) } Self::Tailwind => { - let windows_extension = - match self.target_platform() { - "windows" => ".exe", - _ => "", - }; + let windows_extension = match self.target_platform() { + "windows" => ".exe", + _ => "", + }; format!( "https://github.com/tailwindlabs/tailwindcss/releases/download/{version}/tailwindcss-{target}-x64{optional_ext}", version = self.tool_version(), @@ -281,30 +280,29 @@ impl Tool { pub fn call(&self, command: &str, args: Vec<&str>) -> anyhow::Result> { let bin_path = tools_path().join(self.name()).join(self.bin_path()); - let command_file = - match self { - Tool::Binaryen => { - if cfg!(target_os = "windows") { - format!("{}.exe", command) - } else { - command.to_string() - } + let command_file = match self { + Tool::Binaryen => { + if cfg!(target_os = "windows") { + format!("{}.exe", command) + } else { + command.to_string() } - Tool::Sass => { - if cfg!(target_os = "windows") { - format!("{}.bat", command) - } else { - command.to_string() - } + } + Tool::Sass => { + if cfg!(target_os = "windows") { + format!("{}.bat", command) + } else { + command.to_string() } - Tool::Tailwind => { - if cfg!(target_os = "windows") { - format!("{}.exe", command) - } else { - command.to_string() - } + } + Tool::Tailwind => { + if cfg!(target_os = "windows") { + format!("{}.exe", command) + } else { + command.to_string() } - }; + } + }; if !bin_path.join(&command_file).is_file() { return Err(anyhow::anyhow!("Command file not found.")); diff --git a/packages/core-macro/src/component_body_deserializers/inline_props.rs b/packages/core-macro/src/component_body_deserializers/inline_props.rs index e56ba32b2..d51132623 100644 --- a/packages/core-macro/src/component_body_deserializers/inline_props.rs +++ b/packages/core-macro/src/component_body_deserializers/inline_props.rs @@ -67,12 +67,11 @@ fn get_props_struct(component_body: &ComponentBody) -> ItemStruct { let struct_ident = Ident::new(&format!("{fn_ident}Props"), fn_ident.span()); - let first_lifetime = - if let Some(GenericParam::Lifetime(lt)) = generics.params.first() { - Some(lt) - } else { - None - }; + let first_lifetime = if let Some(GenericParam::Lifetime(lt)) = generics.params.first() { + Some(lt) + } else { + None + }; let struct_attrs = if first_lifetime.is_some() { quote! { #[derive(Props)] } @@ -251,18 +250,16 @@ fn get_function(component_body: &ComponentBody) -> ItemFn { let struct_ident = Ident::new(&format!("{fn_ident}Props"), fn_ident.span()); // Skip first arg since that's the context - let struct_field_names = - inputs.iter().skip(1).filter_map(|f| match f { - FnArg::Receiver(_) => unreachable!(), // ComponentBody prohibits receiver parameters. - FnArg::Typed(pt) => Some(&pt.pat), - }); + let struct_field_names = inputs.iter().skip(1).filter_map(|f| match f { + FnArg::Receiver(_) => unreachable!(), // ComponentBody prohibits receiver parameters. + FnArg::Typed(pt) => Some(&pt.pat), + }); - let first_lifetime = - if let Some(GenericParam::Lifetime(lt)) = generics.params.first() { - Some(lt) - } else { - None - }; + let first_lifetime = if let Some(GenericParam::Lifetime(lt)) = generics.params.first() { + Some(lt) + } else { + None + }; let (scope_lifetime, fn_generics) = if let Some(lt) = first_lifetime { (quote! { #lt, }, generics.clone()) diff --git a/packages/core-macro/src/props/mod.rs b/packages/core-macro/src/props/mod.rs index 6a87fb7ad..6e6c43d66 100644 --- a/packages/core-macro/src/props/mod.rs +++ b/packages/core-macro/src/props/mod.rs @@ -41,10 +41,16 @@ pub fn impl_my_derive(ast: &syn::DeriveInput) -> Result { } } syn::Fields::Unnamed(_) => { - return Err(Error::new(ast.span(), "Props is not supported for tuple structs")) + return Err(Error::new( + ast.span(), + "Props is not supported for tuple structs", + )) } syn::Fields::Unit => { - return Err(Error::new(ast.span(), "Props is not supported for unit structs")) + return Err(Error::new( + ast.span(), + "Props is not supported for unit structs", + )) } }, syn::Data::Enum(_) => { @@ -328,9 +334,10 @@ mod field_info { } Ok(()) } - _ => { - Err(Error::new_spanned(&assign, format!("Unknown parameter {name:?}"))) - } + _ => Err(Error::new_spanned( + &assign, + format!("Unknown parameter {name:?}"), + )), } } @@ -445,13 +452,12 @@ fn type_from_inside_option(ty: &syn::Type, check_option_name: bool) -> Option<&s if check_option_name && segment.ident != "Option" { return None; } - let generic_params = if let syn::PathArguments::AngleBracketed(generic_params) = - &segment.arguments - { - generic_params - } else { - return None; - }; + let generic_params = + if let syn::PathArguments::AngleBracketed(generic_params) = &segment.arguments { + generic_params + } else { + return None; + }; if let syn::GenericArgument::Type(ty) = generic_params.args.first()? { Some(ty) } else { @@ -556,38 +562,37 @@ mod struct_info { } syn::GenericParam::Const(_cnst) => None, }); - let builder_method_doc = - match self.builder_attr.builder_method_doc { - Some(ref doc) => quote!(#doc), - None => { - let doc = format!( - " + let builder_method_doc = match self.builder_attr.builder_method_doc { + Some(ref doc) => quote!(#doc), + None => { + let doc = format!( + " Create a builder for building `{name}`. On the builder, call {setters} to set the values of the fields. Finally, call `.build()` to create the instance of `{name}`. ", - name = self.name, - setters = { - let mut result = String::new(); - let mut is_first = true; - for field in self.included_fields() { - use std::fmt::Write; - if is_first { - is_first = false; - } else { - write!(&mut result, ", ").unwrap(); - } - write!(&mut result, "`.{}(...)`", field.name).unwrap(); - if field.builder_attr.default.is_some() { - write!(&mut result, "(optional)").unwrap(); - } + name = self.name, + setters = { + let mut result = String::new(); + let mut is_first = true; + for field in self.included_fields() { + use std::fmt::Write; + if is_first { + is_first = false; + } else { + write!(&mut result, ", ").unwrap(); + } + write!(&mut result, "`.{}(...)`", field.name).unwrap(); + if field.builder_attr.default.is_some() { + write!(&mut result, "(optional)").unwrap(); } - result } - ); - quote!(#doc) - } - }; + result + } + ); + quote!(#doc) + } + }; let builder_type_doc = if self.builder_attr.doc { match self.builder_attr.builder_type_doc { Some(ref doc) => quote!(#[doc = #doc]), @@ -618,11 +623,10 @@ Finally, call `.build()` to create the instance of `{name}`. false => quote! { self == other }, }; - let is_static = - match are_there_generics { - true => quote! { false }, - false => quote! { true }, - }; + let is_static = match are_there_generics { + true => quote! { false }, + false => quote! { true }, + }; Ok(quote! { impl #impl_generics #name #ty_generics #where_clause { @@ -707,15 +711,14 @@ Finally, call `.build()` to create the instance of `{name}`. ref builder_name, .. } = *self; - let descructuring = - self.included_fields().map(|f| { - if f.ordinal == field.ordinal { - quote!(_) - } else { - let name = f.name; - quote!(#name) - } - }); + let descructuring = self.included_fields().map(|f| { + if f.ordinal == field.ordinal { + quote!(_) + } else { + let name = f.name; + quote!(#name) + } + }); let reconstructing = self.included_fields().map(|f| f.name); let mut ty_generics: Vec = self @@ -782,17 +785,16 @@ Finally, call `.build()` to create the instance of `{name}`. // NOTE: both auto_into and strip_option affect `arg_type` and `arg_expr`, but the order of // nesting is different so we have to do this little dance. - let arg_type = - if field.builder_attr.strip_option { - field.type_from_inside_option(false).ok_or_else(|| { - Error::new_spanned( - field_type, - "can't `strip_option` - field is not `Option<...>`", - ) - })? - } else { - field_type - }; + let arg_type = if field.builder_attr.strip_option { + field.type_from_inside_option(false).ok_or_else(|| { + Error::new_spanned( + field_type, + "can't `strip_option` - field is not `Option<...>`", + ) + })? + } else { + field_type + }; let (arg_type, arg_expr) = if field.builder_attr.auto_into { ( quote!(impl ::core::convert::Into<#arg_type>), @@ -878,45 +880,44 @@ Finally, call `.build()` to create the instance of `{name}`. }) .collect(); let mut builder_generics_tuple = empty_type_tuple(); - let generics = - self.modify_generics(|g| { - let index_after_lifetime_in_generics = g - .params - .iter() - .filter(|arg| matches!(arg, syn::GenericParam::Lifetime(_))) - .count(); - for f in self.included_fields() { - if f.builder_attr.default.is_some() { - // `f` is not mandatory - it does not have it's own fake `build` method, so `field` will need - // to warn about missing `field` whether or not `f` is set. - assert!( - f.ordinal != field.ordinal, - "`required_field_impl` called for optional field {}", - field.name - ); - g.params - .insert(index_after_lifetime_in_generics, f.generic_ty_param()); - builder_generics_tuple.elems.push_value(f.type_ident()); - } else if f.ordinal < field.ordinal { - // Only add a `build` method that warns about missing `field` if `f` is set. If `f` is not set, - // `f`'s `build` method will warn, since it appears earlier in the argument list. - builder_generics_tuple - .elems - .push_value(f.tuplized_type_ty_param()); - } else if f.ordinal == field.ordinal { - builder_generics_tuple.elems.push_value(empty_type()); - } else { - // `f` appears later in the argument list after `field`, so if they are both missing we will - // show a warning for `field` and not for `f` - which means this warning should appear whether - // or not `f` is set. - g.params - .insert(index_after_lifetime_in_generics, f.generic_ty_param()); - builder_generics_tuple.elems.push_value(f.type_ident()); - } - - builder_generics_tuple.elems.push_punct(Default::default()); + let generics = self.modify_generics(|g| { + let index_after_lifetime_in_generics = g + .params + .iter() + .filter(|arg| matches!(arg, syn::GenericParam::Lifetime(_))) + .count(); + for f in self.included_fields() { + if f.builder_attr.default.is_some() { + // `f` is not mandatory - it does not have it's own fake `build` method, so `field` will need + // to warn about missing `field` whether or not `f` is set. + assert!( + f.ordinal != field.ordinal, + "`required_field_impl` called for optional field {}", + field.name + ); + g.params + .insert(index_after_lifetime_in_generics, f.generic_ty_param()); + builder_generics_tuple.elems.push_value(f.type_ident()); + } else if f.ordinal < field.ordinal { + // Only add a `build` method that warns about missing `field` if `f` is set. If `f` is not set, + // `f`'s `build` method will warn, since it appears earlier in the argument list. + builder_generics_tuple + .elems + .push_value(f.tuplized_type_ty_param()); + } else if f.ordinal == field.ordinal { + builder_generics_tuple.elems.push_value(empty_type()); + } else { + // `f` appears later in the argument list after `field`, so if they are both missing we will + // show a warning for `field` and not for `f` - which means this warning should appear whether + // or not `f` is set. + g.params + .insert(index_after_lifetime_in_generics, f.generic_ty_param()); + builder_generics_tuple.elems.push_value(f.type_ident()); } - }); + + builder_generics_tuple.elems.push_punct(Default::default()); + } + }); let index_after_lifetime_in_generics = builder_generics .iter() @@ -1138,9 +1139,10 @@ Finally, call `.build()` to create the instance of `{name}`. self.doc = true; Ok(()) } - _ => { - Err(Error::new_spanned(&assign, format!("Unknown parameter {name:?}"))) - } + _ => Err(Error::new_spanned( + &assign, + format!("Unknown parameter {name:?}"), + )), } } syn::Expr::Path(path) => { @@ -1151,9 +1153,10 @@ Finally, call `.build()` to create the instance of `{name}`. self.doc = true; Ok(()) } - _ => { - Err(Error::new_spanned(&path, format!("Unknown parameter {name:?}"))) - } + _ => Err(Error::new_spanned( + &path, + format!("Unknown parameter {name:?}"), + )), } } syn::Expr::Call(call) => { diff --git a/packages/core-macro/src/utils.rs b/packages/core-macro/src/utils.rs index 114a07e73..7e066f773 100644 --- a/packages/core-macro/src/utils.rs +++ b/packages/core-macro/src/utils.rs @@ -31,9 +31,9 @@ pub fn format_type_string(ty: &Type) -> String { // This should always be valid syntax. // Not Rust code, but syntax, which is the only thing that `syn` cares about. - let Ok(file_unformatted) = - syn::parse_file(&format!("{FORMATTED_TYPE_START}{ty_unformatted}{FORMATTED_TYPE_END}")) - else { + let Ok(file_unformatted) = syn::parse_file(&format!( + "{FORMATTED_TYPE_START}{ty_unformatted}{FORMATTED_TYPE_END}" + )) else { return ty_unformatted.to_string(); }; @@ -60,7 +60,10 @@ impl DeprecatedAttribute { /// Returns `None` if the given attribute was not a valid form of the `#[deprecated]` attribute. pub fn from_meta(meta: &Meta) -> syn::Result { if meta.path() != &parse_quote!(deprecated) { - return Err(syn::Error::new(meta.span(), "attribute path is not `deprecated`")); + return Err(syn::Error::new( + meta.span(), + "attribute path is not `deprecated`", + )); } match &meta { diff --git a/packages/core/src/create.rs b/packages/core/src/create.rs index b68cd6086..a61a8cace 100644 --- a/packages/core/src/create.rs +++ b/packages/core/src/create.rs @@ -36,14 +36,13 @@ fn sort_bfs(paths: &[&'static [u8]]) -> Vec<(usize, &'static [u8])> { #[test] #[cfg(debug_assertions)] fn sorting() { - let r: [(usize, &[u8]); 5] = - [ - (0, &[0, 1]), - (1, &[0, 2]), - (2, &[1, 0]), - (3, &[1, 0, 1]), - (4, &[1, 2]), - ]; + let r: [(usize, &[u8]); 5] = [ + (0, &[0, 1]), + (1, &[0, 2]), + (2, &[1, 0]), + (3, &[1, 0, 1]), + (4, &[1, 2]), + ]; assert_eq!( sort_bfs(&[&[0, 1,], &[0, 2,], &[1, 0,], &[1, 0, 1,], &[1, 2,],]), r diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index a1c6e7be9..c83b1059a 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -531,9 +531,9 @@ impl<'a> From<&'a AttributeValue<'a>> for BorrowedAttributeValue<'a> { } AttributeValue::Any(value) => { let value = value.borrow(); - BorrowedAttributeValue::Any( - std::cell::Ref::map(value, |value| &**value.as_ref().unwrap()) - ) + BorrowedAttributeValue::Any(std::cell::Ref::map(value, |value| { + &**value.as_ref().unwrap() + })) } AttributeValue::None => BorrowedAttributeValue::None, } diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 4c8adfdb6..2d83ba63a 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -267,11 +267,10 @@ impl VirtualDom { suspended_scopes: Default::default(), }; - let root = - dom.new_scope( - Box::new(VProps::new(root, |_, _| unreachable!(), root_props)), - "app", - ); + let root = dom.new_scope( + Box::new(VProps::new(root, |_, _| unreachable!(), root_props)), + "app", + ); // Unlike react, we provide a default error boundary that just renders the error as a string root.provide_context(Rc::new(ErrorBoundary::new(ScopeId::ROOT))); diff --git a/packages/core/tests/attr_cleanup.rs b/packages/core/tests/attr_cleanup.rs index ea8135dd6..539a0b399 100644 --- a/packages/core/tests/attr_cleanup.rs +++ b/packages/core/tests/attr_cleanup.rs @@ -9,23 +9,20 @@ use dioxus_core::BorrowedAttributeValue; #[test] fn attrs_cycle() { - let mut dom = - VirtualDom::new(|cx| { - let id = cx.generation(); - match cx.generation() % 2 { - 0 => { - cx.render(rsx! { - div {} - }) + let mut dom = VirtualDom::new(|cx| { + let id = cx.generation(); + match cx.generation() % 2 { + 0 => cx.render(rsx! { + div {} + }), + 1 => cx.render(rsx! { + div { + h1 { class: "{id}", id: "{id}" } } - 1 => cx.render(rsx! { - div { - h1 { class: "{id}", id: "{id}" } - } - }), - _ => unreachable!(), - } - }); + }), + _ => unreachable!(), + } + }); let bump = Bump::new(); diff --git a/packages/core/tests/bubble_error.rs b/packages/core/tests/bubble_error.rs index 901f93f46..af2a34219 100644 --- a/packages/core/tests/bubble_error.rs +++ b/packages/core/tests/bubble_error.rs @@ -3,12 +3,11 @@ use dioxus::prelude::*; fn app(cx: Scope) -> Element { - let raw = - match cx.generation() % 2 { - 0 => "123.123", - 1 => "123.123.123", - _ => unreachable!(), - }; + let raw = match cx.generation() % 2 { + 0 => "123.123", + 1 => "123.123.123", + _ => unreachable!(), + }; let value = raw.parse::().unwrap_or(123.123); diff --git a/packages/core/tests/create_dom.rs b/packages/core/tests/create_dom.rs index b923a9eec..5e5005d3f 100644 --- a/packages/core/tests/create_dom.rs +++ b/packages/core/tests/create_dom.rs @@ -11,16 +11,15 @@ use dioxus_core::ElementId; #[test] fn test_original_diff() { - let mut dom = - VirtualDom::new(|cx| { - cx.render(rsx! { + let mut dom = VirtualDom::new(|cx| { + cx.render(rsx! { + div { div { - div { - "Hello, world!" - } + "Hello, world!" } - }) - }); + } + }) + }); let edits = dom.rebuild().santize(); @@ -83,12 +82,11 @@ fn create() { #[test] fn create_list() { - let mut dom = - VirtualDom::new(|cx| { - cx.render(rsx! { - (0..3).map(|f| rsx!( div { "hello" } )) - }) - }); + let mut dom = VirtualDom::new(|cx| { + cx.render(rsx! { + (0..3).map(|f| rsx!( div { "hello" } )) + }) + }); let _edits = dom.rebuild().santize(); @@ -162,17 +160,16 @@ fn create_components() { #[test] fn anchors() { - let mut dom = - VirtualDom::new(|cx| { - cx.render(rsx! { - if true { - rsx!( div { "hello" } ) - } - if false { - rsx!( div { "goodbye" } ) - } - }) - }); + let mut dom = VirtualDom::new(|cx| { + cx.render(rsx! { + if true { + rsx!( div { "hello" } ) + } + if false { + rsx!( div { "goodbye" } ) + } + }) + }); // note that the template under "false" doesn't show up since it's not loaded let edits = dom.rebuild().santize(); diff --git a/packages/core/tests/create_fragments.rs b/packages/core/tests/create_fragments.rs index 4e94fddbe..ee312f34b 100644 --- a/packages/core/tests/create_fragments.rs +++ b/packages/core/tests/create_fragments.rs @@ -24,13 +24,12 @@ fn empty_fragment_creates_nothing() { #[test] fn root_fragments_work() { - let mut vdom = - VirtualDom::new(|cx| { - cx.render(rsx!( - div { "hello" } - div { "goodbye" } - )) - }); + let mut vdom = VirtualDom::new(|cx| { + cx.render(rsx!( + div { "hello" } + div { "goodbye" } + )) + }); assert_eq!( vdom.rebuild().edits.last().unwrap(), diff --git a/packages/core/tests/diff_unkeyed_list.rs b/packages/core/tests/diff_unkeyed_list.rs index d51ecf452..b5be161ef 100644 --- a/packages/core/tests/diff_unkeyed_list.rs +++ b/packages/core/tests/diff_unkeyed_list.rs @@ -4,18 +4,17 @@ use pretty_assertions::assert_eq; #[test] fn list_creates_one_by_one() { - let mut dom = - VirtualDom::new(|cx| { - let gen = cx.generation(); + let mut dom = VirtualDom::new(|cx| { + let gen = cx.generation(); - cx.render(rsx! { - div { - (0..gen).map(|i| rsx! { - div { "{i}" } - }) - } - }) - }); + cx.render(rsx! { + div { + (0..gen).map(|i| rsx! { + div { "{i}" } + }) + } + }) + }); // load the div and then assign the empty fragment as a placeholder assert_eq!( @@ -74,18 +73,17 @@ fn list_creates_one_by_one() { #[test] fn removes_one_by_one() { - let mut dom = - VirtualDom::new(|cx| { - let gen = 3 - cx.generation() % 4; + let mut dom = VirtualDom::new(|cx| { + let gen = 3 - cx.generation() % 4; - cx.render(rsx! { - div { - (0..gen).map(|i| rsx! { - div { "{i}" } - }) - } - }) - }); + cx.render(rsx! { + div { + (0..gen).map(|i| rsx! { + div { "{i}" } + }) + } + }) + }); // load the div and then assign the empty fragment as a placeholder assert_eq!( @@ -152,17 +150,16 @@ fn removes_one_by_one() { #[test] fn list_shrink_multiroot() { - let mut dom = - VirtualDom::new(|cx| { - cx.render(rsx! { - div { - (0..cx.generation()).map(|i| rsx! { - div { "{i}" } - div { "{i}" } - }) - } - }) - }); + let mut dom = VirtualDom::new(|cx| { + cx.render(rsx! { + div { + (0..cx.generation()).map(|i| rsx! { + div { "{i}" } + div { "{i}" } + }) + } + }) + }); assert_eq!( dom.rebuild().santize().edits, diff --git a/packages/core/tests/fuzzing.rs b/packages/core/tests/fuzzing.rs index 4338a49c1..1523c4e22 100644 --- a/packages/core/tests/fuzzing.rs +++ b/packages/core/tests/fuzzing.rs @@ -8,7 +8,9 @@ fn random_ns() -> Option<&'static str> { let namespace = rand::random::() % 2; match namespace { 0 => None, - 1 => Some(Box::leak(format!("ns{}", rand::random::()).into_boxed_str())), + 1 => Some(Box::leak( + format!("ns{}", rand::random::()).into_boxed_str(), + )), _ => unreachable!(), } } @@ -20,15 +22,13 @@ fn create_random_attribute(attr_idx: &mut usize) -> TemplateAttribute<'static> { value: Box::leak(format!("value{}", rand::random::()).into_boxed_str()), namespace: random_ns(), }, - 1 => { - TemplateAttribute::Dynamic { - id: { - let old_idx = *attr_idx; - *attr_idx += 1; - old_idx - }, - } - } + 1 => TemplateAttribute::Dynamic { + id: { + let old_idx = *attr_idx; + *attr_idx += 1; + old_idx + }, + }, _ => unreachable!(), } } @@ -73,26 +73,22 @@ fn create_random_template_node( 1 => TemplateNode::Text { text: Box::leak(format!("{}", rand::random::()).into_boxed_str()), }, - 2 => { - TemplateNode::DynamicText { - id: { - let old_idx = *template_idx; - *template_idx += 1; - dynamic_node_types.push(DynamicNodeType::Text); - old_idx - }, - } - } - 3 => { - TemplateNode::Dynamic { - id: { - let old_idx = *template_idx; - *template_idx += 1; - dynamic_node_types.push(DynamicNodeType::Other); - old_idx - }, - } - } + 2 => TemplateNode::DynamicText { + id: { + let old_idx = *template_idx; + *template_idx += 1; + dynamic_node_types.push(DynamicNodeType::Text); + old_idx + }, + }, + 3 => TemplateNode::Dynamic { + id: { + let old_idx = *template_idx; + *template_idx += 1; + dynamic_node_types.push(DynamicNodeType::Other); + old_idx + }, + }, _ => unreachable!(), } } @@ -211,9 +207,9 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode { fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute { let value = match rand::random::() % 7 { - 0 => { - AttributeValue::Text(Box::leak(format!("{}", rand::random::()).into_boxed_str())) - } + 0 => AttributeValue::Text(Box::leak( + format!("{}", rand::random::()).into_boxed_str(), + )), 1 => AttributeValue::Float(rand::random()), 2 => AttributeValue::Int(rand::random()), 3 => AttributeValue::Bool(rand::random()), @@ -276,32 +272,31 @@ fn create_random_element(cx: Scope) -> Element { .into_boxed_str(), )); // println!("{template:#?}"); - let node = - VNode { - key: None, - parent: None, - template: Cell::new(template), - root_ids: bumpalo::collections::Vec::new_in(cx.bump()).into(), - dynamic_nodes: { - let dynamic_nodes: Vec<_> = dynamic_node_types - .iter() - .map(|ty| match ty { - DynamicNodeType::Text => DynamicNode::Text(VText::new(Box::leak( - format!("{}", rand::random::()).into_boxed_str(), - ))), - DynamicNodeType::Other => { - create_random_dynamic_node(cx, cx.props.depth + 1) - } - }) - .collect(); - cx.bump().alloc(dynamic_nodes) - }, - dynamic_attrs: cx.bump().alloc( - (0..template.attr_paths.len()) - .map(|_| create_random_dynamic_attr(cx)) - .collect::>(), - ), - }; + let node = VNode { + key: None, + parent: None, + template: Cell::new(template), + root_ids: bumpalo::collections::Vec::new_in(cx.bump()).into(), + dynamic_nodes: { + let dynamic_nodes: Vec<_> = dynamic_node_types + .iter() + .map(|ty| match ty { + DynamicNodeType::Text => DynamicNode::Text(VText::new(Box::leak( + format!("{}", rand::random::()).into_boxed_str(), + ))), + DynamicNodeType::Other => { + create_random_dynamic_node(cx, cx.props.depth + 1) + } + }) + .collect(); + cx.bump().alloc(dynamic_nodes) + }, + dynamic_attrs: cx.bump().alloc( + (0..template.attr_paths.len()) + .map(|_| create_random_dynamic_attr(cx)) + .collect::>(), + ), + }; Some(node) } _ => None, diff --git a/packages/desktop/headless_tests/rendering.rs b/packages/desktop/headless_tests/rendering.rs index 31dc28256..0907121d4 100644 --- a/packages/desktop/headless_tests/rendering.rs +++ b/packages/desktop/headless_tests/rendering.rs @@ -34,13 +34,12 @@ fn use_inner_html(cx: &ScopeState, id: &'static str) -> Option { to_owned![value, eval_provider]; async move { tokio::time::sleep(std::time::Duration::from_millis(100)).await; - let html = - eval_provider(&format!( - r#"let element = document.getElementById('{}'); + let html = eval_provider(&format!( + r#"let element = document.getElementById('{}'); return element.innerHTML"#, - id - )) - .unwrap(); + id + )) + .unwrap(); if let Ok(serde_json::Value::String(html)) = html.await { println!("html: {}", html); value.set(Some(html)); diff --git a/packages/desktop/src/cfg.rs b/packages/desktop/src/cfg.rs index 3b0409ae8..ba42ffa01 100644 --- a/packages/desktop/src/cfg.rs +++ b/packages/desktop/src/cfg.rs @@ -36,7 +36,7 @@ pub struct Config { pub(crate) root_name: String, pub(crate) background_color: Option<(u8, u8, u8, u8)>, pub(crate) last_window_close_behaviour: WindowCloseBehaviour, - pub(crate) enable_default_menu_bar: bool, + pub(crate) disable_default_menu_bar: bool, } type DropHandler = Box bool>; @@ -66,15 +66,13 @@ impl Config { root_name: "main".to_string(), background_color: None, last_window_close_behaviour: WindowCloseBehaviour::LastWindowExitsApp, - enable_default_menu_bar: true, + disable_default_menu_bar: false, } } - /// Set whether the default menu bar should be enabled. - /// - /// > Note: `enable` is `true` by default. To disable the default menu bar pass `false`. - pub fn with_default_menu_bar(mut self, enable: bool) -> Self { - self.enable_default_menu_bar = enable; + /// Set whether the default menu bar should be disabled. + pub fn with_disable_default_menu_bar(mut self, disable: bool) -> Self { + self.disable_default_menu_bar = disable; self } diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 7b8f024be..63a8914f3 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -240,20 +240,18 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) Event::UserEvent(event) => match event.0 { #[cfg(all(feature = "hot-reload", debug_assertions))] - EventData::HotReloadEvent(msg) => { - match msg { - dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => { - for webview in webviews.values_mut() { - webview.dom.replace_template(template); + EventData::HotReloadEvent(msg) => match msg { + dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => { + for webview in webviews.values_mut() { + webview.dom.replace_template(template); - poll_vdom(webview); - } - } - dioxus_hot_reload::HotReloadMsg::Shutdown => { - *control_flow = ControlFlow::Exit; + poll_vdom(webview); } } - } + dioxus_hot_reload::HotReloadMsg::Shutdown => { + *control_flow = ControlFlow::Exit; + } + }, EventData::CloseWindow => { webviews.remove(&event.1); diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index f03878242..9beae702a 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -19,8 +19,8 @@ pub fn build( let index_file = cfg.custom_index.clone(); let root_name = cfg.root_name.clone(); - if cfg.enable_default_menu_bar { - builder = builder.with_menu(build_default_menu_bar()); + if !cfg.disable_default_menu_bar { + builder = builder.with_menu(create_default_menu_bar()); } let window = builder.with_visible(false).build(event_loop).unwrap(); @@ -103,12 +103,8 @@ pub fn build( (webview.build().unwrap(), web_context) } -/// Builds a standard menu bar depending on the users platform. It may be used as a starting point -/// to further customize the menu bar and pass it to a [`WindowBuilder`](tao::window::WindowBuilder). -/// > Note: The default menu bar enables macOS shortcuts like cut/copy/paste. -/// > The menu bar differs per platform because of constraints introduced -/// > by [`MenuItem`](tao::menu::MenuItem). -pub fn build_default_menu_bar() -> MenuBar { +/// Creates a standard menu bar depending on the platform +fn create_default_menu_bar() -> MenuBar { let mut menu_bar = MenuBar::new(); // since it is uncommon on windows to have an "application menu" diff --git a/packages/dioxus-tui/examples/all_terminal_events.rs b/packages/dioxus-tui/examples/all_terminal_events.rs index dd160c9b7..483e9afdf 100644 --- a/packages/dioxus-tui/examples/all_terminal_events.rs +++ b/packages/dioxus-tui/examples/all_terminal_events.rs @@ -40,10 +40,9 @@ fn app(cx: Scope) -> Element { rsx!(p { "{trimmed}" }) }); - let log_event = - move |event: Event| { - events.write().push(event); - }; + let log_event = move |event: Event| { + events.write().push(event); + }; cx.render(rsx! { div { diff --git a/packages/dioxus/benches/jsframework.rs b/packages/dioxus/benches/jsframework.rs index e313cdee6..b3405b2bd 100644 --- a/packages/dioxus/benches/jsframework.rs +++ b/packages/dioxus/benches/jsframework.rs @@ -87,34 +87,33 @@ impl Label { } } -static ADJECTIVES: &[&str] = - &[ - "pretty", - "large", - "big", - "small", - "tall", - "short", - "long", - "handsome", - "plain", - "quaint", - "clean", - "elegant", - "easy", - "angry", - "crazy", - "helpful", - "mushy", - "odd", - "unsightly", - "adorable", - "important", - "inexpensive", - "cheap", - "expensive", - "fancy", - ]; +static ADJECTIVES: &[&str] = &[ + "pretty", + "large", + "big", + "small", + "tall", + "short", + "long", + "handsome", + "plain", + "quaint", + "clean", + "elegant", + "easy", + "angry", + "crazy", + "helpful", + "mushy", + "odd", + "unsightly", + "adorable", + "important", + "inexpensive", + "cheap", + "expensive", + "fancy", +]; static COLOURS: &[&str] = &[ "red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", diff --git a/packages/dioxus/examples/stress.rs b/packages/dioxus/examples/stress.rs index ef0bbbf6c..248d851d2 100644 --- a/packages/dioxus/examples/stress.rs +++ b/packages/dioxus/examples/stress.rs @@ -62,34 +62,33 @@ impl Label { } } -static ADJECTIVES: &[&str] = - &[ - "pretty", - "large", - "big", - "small", - "tall", - "short", - "long", - "handsome", - "plain", - "quaint", - "clean", - "elegant", - "easy", - "angry", - "crazy", - "helpful", - "mushy", - "odd", - "unsightly", - "adorable", - "important", - "inexpensive", - "cheap", - "expensive", - "fancy", - ]; +static ADJECTIVES: &[&str] = &[ + "pretty", + "large", + "big", + "small", + "tall", + "short", + "long", + "handsome", + "plain", + "quaint", + "clean", + "elegant", + "easy", + "angry", + "crazy", + "helpful", + "mushy", + "odd", + "unsightly", + "adorable", + "important", + "inexpensive", + "cheap", + "expensive", + "fancy", +]; static COLOURS: &[&str] = &[ "red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", diff --git a/packages/fullstack/examples/axum-auth/src/main.rs b/packages/fullstack/examples/axum-auth/src/main.rs index ea7a0efe0..6643f718b 100644 --- a/packages/fullstack/examples/axum-auth/src/main.rs +++ b/packages/fullstack/examples/axum-auth/src/main.rs @@ -37,13 +37,12 @@ fn main() { //To enable Private cookies for integrity, and authenticity please check the next Example. let session_config = SessionConfig::default().with_table_name("test_table"); let auth_config = AuthConfig::::default().with_anonymous_user_id(Some(1)); - let session_store = - SessionStore::::new( - Some(pool.clone().into()), - session_config, - ) - .await - .unwrap(); + let session_store = SessionStore::::new( + Some(pool.clone().into()), + session_config, + ) + .await + .unwrap(); //Create the Database table for storing our Session Data. session_store.initiate().await.unwrap(); diff --git a/packages/fullstack/examples/static-hydrated/src/main.rs b/packages/fullstack/examples/static-hydrated/src/main.rs index 536971524..2539d0deb 100644 --- a/packages/fullstack/examples/static-hydrated/src/main.rs +++ b/packages/fullstack/examples/static-hydrated/src/main.rs @@ -16,9 +16,9 @@ use serde::{Deserialize, Serialize}; #[tokio::main] async fn main() { pre_cache_static_routes_with_props( - &ServeConfigBuilder::new_with_router( - dioxus_fullstack::router::FullstackRouterConfig::::default() - ) + &ServeConfigBuilder::new_with_router(dioxus_fullstack::router::FullstackRouterConfig::< + Route, + >::default()) .assets_path("docs") .incremental(IncrementalRendererConfig::default().static_dir("docs")) .build(), diff --git a/packages/fullstack/src/adapters/axum_adapter.rs b/packages/fullstack/src/adapters/axum_adapter.rs index 089784c94..41a7c92be 100644 --- a/packages/fullstack/src/adapters/axum_adapter.rs +++ b/packages/fullstack/src/adapters/axum_adapter.rs @@ -280,13 +280,12 @@ where let assets_path = assets_path.into(); // Serve all files in dist folder except index.html - let dir = - std::fs::read_dir(&assets_path).unwrap_or_else(|e| { - panic!( - "Couldn't read assets directory at {:?}: {}", - &assets_path, e - ) - }); + let dir = std::fs::read_dir(&assets_path).unwrap_or_else(|e| { + panic!( + "Couldn't read assets directory at {:?}: {}", + &assets_path, e + ) + }); for entry in dir.flatten() { let path = entry.path(); @@ -298,9 +297,9 @@ where .unwrap() .iter() .map(|segment| { - segment.to_str().unwrap_or_else( - || panic!("Failed to convert path segment {:?} to string", segment) - ) + segment.to_str().unwrap_or_else(|| { + panic!("Failed to convert path segment {:?} to string", segment) + }) }) .collect::>() .join("/"); diff --git a/packages/fullstack/src/adapters/salvo_adapter.rs b/packages/fullstack/src/adapters/salvo_adapter.rs index 9953a1192..674722665 100644 --- a/packages/fullstack/src/adapters/salvo_adapter.rs +++ b/packages/fullstack/src/adapters/salvo_adapter.rs @@ -244,13 +244,12 @@ impl DioxusRouterExt for Router { let assets_path = assets_path.into(); // Serve all files in dist folder except index.html - let dir = - std::fs::read_dir(&assets_path).unwrap_or_else(|e| { - panic!( - "Couldn't read assets directory at {:?}: {}", - &assets_path, e - ) - }); + let dir = std::fs::read_dir(&assets_path).unwrap_or_else(|e| { + panic!( + "Couldn't read assets directory at {:?}: {}", + &assets_path, e + ) + }); for entry in dir.flatten() { let path = entry.path(); @@ -262,9 +261,9 @@ impl DioxusRouterExt for Router { .unwrap() .iter() .map(|segment| { - segment.to_str().unwrap_or_else( - || panic!("Failed to convert path segment {:?} to string", segment) - ) + segment.to_str().unwrap_or_else(|| { + panic!("Failed to convert path segment {:?} to string", segment) + }) }) .collect::>() .join("/"); diff --git a/packages/fullstack/src/html_storage/deserialize.rs b/packages/fullstack/src/html_storage/deserialize.rs index 1c860a7a2..7fc70ba6c 100644 --- a/packages/fullstack/src/html_storage/deserialize.rs +++ b/packages/fullstack/src/html_storage/deserialize.rs @@ -7,14 +7,13 @@ use super::HTMLDataCursor; #[allow(unused)] pub(crate) fn serde_from_bytes(string: &[u8]) -> Option { - let decompressed = - match STANDARD.decode(string) { - Ok(bytes) => bytes, - Err(err) => { - tracing::error!("Failed to decode base64: {}", err); - return None; - } - }; + let decompressed = match STANDARD.decode(string) { + Ok(bytes) => bytes, + Err(err) => { + tracing::error!("Failed to decode base64: {}", err); + return None; + } + }; match postcard::from_bytes(&decompressed) { Ok(data) => Some(data), diff --git a/packages/fullstack/src/layer.rs b/packages/fullstack/src/layer.rs index 3b68fa2d6..10e67b3f5 100644 --- a/packages/fullstack/src/layer.rs +++ b/packages/fullstack/src/layer.rs @@ -46,9 +46,11 @@ where > + Send, >, > { - let fut = self.call(req).instrument( - tracing::trace_span!("service", "{}", std::any::type_name::()) - ); + let fut = self.call(req).instrument(tracing::trace_span!( + "service", + "{}", + std::any::type_name::() + )); Box::pin(async move { fut.await.map_err(|err| err.into()) }) } } diff --git a/packages/fullstack/src/render.rs b/packages/fullstack/src/render.rs index f14b97acc..cda41f82c 100644 --- a/packages/fullstack/src/render.rs +++ b/packages/fullstack/src/render.rs @@ -91,11 +91,10 @@ impl SsrRendererPool { Ok((freshness, html)) } Self::Incremental(pool) => { - let mut renderer = pool - .write() - .unwrap() - .pop() - .unwrap_or_else(|| incremental_pre_renderer(cfg.incremental.as_ref().unwrap())); + let mut renderer = + pool.write().unwrap().pop().unwrap_or_else(|| { + incremental_pre_renderer(cfg.incremental.as_ref().unwrap()) + }); let (tx, rx) = tokio::sync::oneshot::channel(); diff --git a/packages/fullstack/src/serve_config.rs b/packages/fullstack/src/serve_config.rs index 4d1a3c007..75a473c89 100644 --- a/packages/fullstack/src/serve_config.rs +++ b/packages/fullstack/src/serve_config.rs @@ -122,16 +122,14 @@ fn load_index_html(path: PathBuf, root_id: &'static str) -> IndexHtml { let (pre_main, post_main) = contents.split_once(&format!("id=\"{root_id}\"")).unwrap_or_else(|| panic!("Failed to find id=\"{root_id}\" in index.html. The id is used to inject the application into the page.")); - let post_main = - post_main.split_once('>').unwrap_or_else( - || panic!("Failed to find closing > after id=\"{root_id}\" in index.html.") - ); + let post_main = post_main.split_once('>').unwrap_or_else(|| { + panic!("Failed to find closing > after id=\"{root_id}\" in index.html.") + }); - let (pre_main, post_main) = - ( - pre_main.to_string() + &format!("id=\"{root_id}\"") + post_main.0 + ">", - post_main.1.to_string(), - ); + let (pre_main, post_main) = ( + pre_main.to_string() + &format!("id=\"{root_id}\"") + post_main.0 + ">", + post_main.1.to_string(), + ); IndexHtml { pre_main, diff --git a/packages/fullstack/src/server_context.rs b/packages/fullstack/src/server_context.rs index 7d1bc63fe..6f3b4b6c9 100644 --- a/packages/fullstack/src/server_context.rs +++ b/packages/fullstack/src/server_context.rs @@ -22,9 +22,9 @@ impl Default for DioxusServerContext { fn default() -> Self { Self { shared_context: std::sync::Arc::new(std::sync::RwLock::new(anymap::Map::new())), - response_parts: std::sync::Arc::new( - RwLock::new(http::response::Response::new(()).into_parts().0) - ), + response_parts: std::sync::Arc::new(RwLock::new( + http::response::Response::new(()).into_parts().0, + )), parts: std::sync::Arc::new(RwLock::new(http::request::Request::new(()).into_parts().0)), html_data: Arc::new(RwLock::new(HTMLData::default())), } @@ -45,9 +45,9 @@ mod server_fn_impl { Self { parts: parts.into(), shared_context: Arc::new(RwLock::new(SendSyncAnyMap::new())), - response_parts: std::sync::Arc::new( - RwLock::new(http::response::Response::new(()).into_parts().0) - ), + response_parts: std::sync::Arc::new(RwLock::new( + http::response::Response::new(()).into_parts().0, + )), html_data: Arc::new(RwLock::new(HTMLData::default())), } } @@ -221,9 +221,9 @@ impl FromServerContext for FromContext { type Rejection = NotFoundInServerContext; async fn from_request(req: &DioxusServerContext) -> Result { - Ok(Self(req.clone().get::().ok_or_else( - || NotFoundInServerContext::(std::marker::PhantomData::) - )?)) + Ok(Self(req.clone().get::().ok_or_else(|| { + NotFoundInServerContext::(std::marker::PhantomData::) + })?)) } } diff --git a/packages/hooks/src/use_coroutine.rs b/packages/hooks/src/use_coroutine.rs index c7990d0d1..f2577b90c 100644 --- a/packages/hooks/src/use_coroutine.rs +++ b/packages/hooks/src/use_coroutine.rs @@ -129,12 +129,11 @@ mod tests { use futures_util::StreamExt; fn app(cx: Scope, name: String) -> Element { - let task = - use_coroutine(cx, |mut rx: UnboundedReceiver| async move { - while let Some(msg) = rx.next().await { - println!("got message: {msg}"); - } - }); + let task = use_coroutine(cx, |mut rx: UnboundedReceiver| async move { + while let Some(msg) = rx.next().await { + println!("got message: {msg}"); + } + }); let task2 = use_coroutine(cx, view_task); diff --git a/packages/hooks/src/use_shared_state.rs b/packages/hooks/src/use_shared_state.rs index 54b7f720f..37226c759 100644 --- a/packages/hooks/src/use_shared_state.rs +++ b/packages/hooks/src/use_shared_state.rs @@ -226,12 +226,10 @@ impl UseSharedState { pub fn read(&self) -> Ref<'_, T> { match self.try_read() { Ok(value) => value, - Err(message) => { - panic!( - "Reading the shared state failed: {}\n({:?})", - message, message - ) - } + Err(message) => panic!( + "Reading the shared state failed: {}\n({:?})", + message, message + ), } } @@ -260,12 +258,10 @@ impl UseSharedState { pub fn write(&self) -> RefMut<'_, T> { match self.try_write() { Ok(value) => value, - Err(message) => { - panic!( - "Writing to shared state failed: {}\n({:?})", - message, message - ) - } + Err(message) => panic!( + "Writing to shared state failed: {}\n({:?})", + message, message + ), } } @@ -288,12 +284,10 @@ impl UseSharedState { pub fn write_silent(&self) -> RefMut<'_, T> { match self.try_write_silent() { Ok(value) => value, - Err(message) => { - panic!( - "Writing to shared state silently failed: {}\n({:?})", - message, message - ) - } + Err(message) => panic!( + "Writing to shared state silently failed: {}\n({:?})", + message, message + ), } } @@ -369,13 +363,12 @@ impl PartialEq for UseSharedState { /// ``` pub fn use_shared_state_provider(cx: &ScopeState, f: impl FnOnce() -> T) { cx.use_hook(|| { - let state: ProvidedState = - Rc::new(RefCell::new(ProvidedStateInner { - value: f(), - notify_any: cx.schedule_update_any(), - consumers: HashSet::new(), - gen: 0, - })); + let state: ProvidedState = Rc::new(RefCell::new(ProvidedStateInner { + value: f(), + notify_any: cx.schedule_update_any(), + consumers: HashSet::new(), + gen: 0, + })); cx.provide_context(state); }); diff --git a/packages/hooks/src/use_state.rs b/packages/hooks/src/use_state.rs index 21120abf0..254493510 100644 --- a/packages/hooks/src/use_state.rs +++ b/packages/hooks/src/use_state.rs @@ -35,37 +35,36 @@ pub fn use_state( cx: &ScopeState, initial_state_fn: impl FnOnce() -> T, ) -> &UseState { - let hook = - cx.use_hook(move || { - let current_val = Rc::new(initial_state_fn()); - let update_callback = cx.schedule_update(); - let slot = Rc::new(RefCell::new(current_val.clone())); - let setter = Rc::new({ - to_owned![update_callback, slot]; - move |new| { - { - let mut slot = slot.borrow_mut(); + let hook = cx.use_hook(move || { + let current_val = Rc::new(initial_state_fn()); + let update_callback = cx.schedule_update(); + let slot = Rc::new(RefCell::new(current_val.clone())); + let setter = Rc::new({ + to_owned![update_callback, slot]; + move |new| { + { + let mut slot = slot.borrow_mut(); - // if there's only one reference (weak or otherwise), we can just swap the values - // Typically happens when the state is set multiple times - we don't want to create a new Rc for each new value - if let Some(val) = Rc::get_mut(&mut slot) { - *val = new; - } else { - *slot = Rc::new(new); - } + // if there's only one reference (weak or otherwise), we can just swap the values + // Typically happens when the state is set multiple times - we don't want to create a new Rc for each new value + if let Some(val) = Rc::get_mut(&mut slot) { + *val = new; + } else { + *slot = Rc::new(new); } - update_callback(); } - }); - - UseState { - current_val, - update_callback, - setter, - slot, + update_callback(); } }); + UseState { + current_val, + update_callback, + setter, + slot, + } + }); + hook.current_val = hook.slot.borrow().clone(); hook diff --git a/packages/liveview/examples/axum.rs b/packages/liveview/examples/axum.rs index b188e8270..6584d5e9b 100644 --- a/packages/liveview/examples/axum.rs +++ b/packages/liveview/examples/axum.rs @@ -37,9 +37,9 @@ async fn main() { .route( "/", get(move || async move { - index_page_with_glue( - &dioxus_liveview::interpreter_glue(&format!("ws://{addr}/ws")) - ) + index_page_with_glue(&dioxus_liveview::interpreter_glue(&format!( + "ws://{addr}/ws" + ))) }), ) .route( diff --git a/packages/liveview/src/pool.rs b/packages/liveview/src/pool.rs index 05e892f47..2fd06cec6 100644 --- a/packages/liveview/src/pool.rs +++ b/packages/liveview/src/pool.rs @@ -112,14 +112,13 @@ impl LiveViewSocket for S where /// You might need to transform the error types of the web backend into the LiveView error type. pub async fn run(mut vdom: VirtualDom, ws: impl LiveViewSocket) -> Result<(), LiveViewError> { #[cfg(all(feature = "hot-reload", debug_assertions))] - let mut hot_reload_rx = - { - let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); - dioxus_hot_reload::connect(move |template| { - let _ = tx.send(template); - }); - rx - }; + let mut hot_reload_rx = { + let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); + dioxus_hot_reload::connect(move |template| { + let _ = tx.send(template); + }); + rx + }; // Create the a proxy for query engine let (query_tx, mut query_rx) = tokio::sync::mpsc::unbounded_channel(); diff --git a/packages/native-core-macro/src/lib.rs b/packages/native-core-macro/src/lib.rs index 3d5ba4464..fdaa12cf5 100644 --- a/packages/native-core-macro/src/lib.rs +++ b/packages/native-core-macro/src/lib.rs @@ -66,13 +66,12 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream { Some(tuple) => { let mut parent_dependencies = Vec::new(); for type_ in &tuple.elems { - let mut type_ = - extract_type_path(type_).unwrap_or_else(|| { - panic!( - "ParentDependencies must be a tuple of type paths, found {}", - quote!(#type_) - ) - }); + let mut type_ = extract_type_path(type_).unwrap_or_else(|| { + panic!( + "ParentDependencies must be a tuple of type paths, found {}", + quote!(#type_) + ) + }); if type_ == self_path { type_ = this_type.clone(); } @@ -81,24 +80,21 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream { } parent_dependencies } - _ => { - panic!( - "ParentDependencies must be a tuple, found {}", - quote!(#parent_dependencies) - ) - } + _ => panic!( + "ParentDependencies must be a tuple, found {}", + quote!(#parent_dependencies) + ), }; let child_dependencies = match extract_tuple(child_dependencies) { Some(tuple) => { let mut child_dependencies = Vec::new(); for type_ in &tuple.elems { - let mut type_ = - extract_type_path(type_).unwrap_or_else(|| { - panic!( - "ChildDependencies must be a tuple of type paths, found {}", - quote!(#type_) - ) - }); + let mut type_ = extract_type_path(type_).unwrap_or_else(|| { + panic!( + "ChildDependencies must be a tuple of type paths, found {}", + quote!(#type_) + ) + }); if type_ == self_path { type_ = this_type.clone(); } @@ -107,39 +103,34 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream { } child_dependencies } - _ => { - panic!( - "ChildDependencies must be a tuple, found {}", - quote!(#child_dependencies) - ) - } + _ => panic!( + "ChildDependencies must be a tuple, found {}", + quote!(#child_dependencies) + ), }; - let node_dependencies = - match extract_tuple(node_dependencies) { - Some(tuple) => { - let mut node_dependencies = Vec::new(); - for type_ in &tuple.elems { - let mut type_ = extract_type_path(type_).unwrap_or_else(|| { - panic!( - "NodeDependencies must be a tuple of type paths, found {}", - quote!(#type_) - ) - }); - if type_ == self_path { - type_ = this_type.clone(); - } - combined_dependencies.insert(type_.clone()); - node_dependencies.push(type_); + let node_dependencies = match extract_tuple(node_dependencies) { + Some(tuple) => { + let mut node_dependencies = Vec::new(); + for type_ in &tuple.elems { + let mut type_ = extract_type_path(type_).unwrap_or_else(|| { + panic!( + "NodeDependencies must be a tuple of type paths, found {}", + quote!(#type_) + ) + }); + if type_ == self_path { + type_ = this_type.clone(); } - node_dependencies + combined_dependencies.insert(type_.clone()); + node_dependencies.push(type_); } - _ => { - panic!( - "NodeDependencies must be a tuple, found {}", - quote!(#node_dependencies) - ) - } - }; + node_dependencies + } + _ => panic!( + "NodeDependencies must be a tuple, found {}", + quote!(#node_dependencies) + ), + }; combined_dependencies.insert(this_type.clone()); let combined_dependencies: Vec<_> = combined_dependencies.into_iter().collect(); diff --git a/packages/native-core/examples/custom_attr.rs b/packages/native-core/examples/custom_attr.rs index 1089766ed..e7bbb36ea 100644 --- a/packages/native-core/examples/custom_attr.rs +++ b/packages/native-core/examples/custom_attr.rs @@ -160,13 +160,12 @@ impl State for Border { _context: &SendAnyMap, ) -> bool { // check if the node contians a border attribute - let new = - Self( - node_view - .attributes() - .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) - .is_some(), - ); + let new = Self( + node_view + .attributes() + .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) + .is_some(), + ); // check if the member has changed let changed = new != *self; *self = new; diff --git a/packages/native-core/examples/simple.rs b/packages/native-core/examples/simple.rs index 02ce83886..276d06d08 100644 --- a/packages/native-core/examples/simple.rs +++ b/packages/native-core/examples/simple.rs @@ -151,13 +151,12 @@ impl State for Border { _context: &SendAnyMap, ) -> bool { // check if the node contians a border attribute - let new = - Self( - node_view - .attributes() - .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) - .is_some(), - ); + let new = Self( + node_view + .attributes() + .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) + .is_some(), + ); // check if the member has changed let changed = new != *self; *self = new; diff --git a/packages/native-core/examples/simple_dioxus.rs b/packages/native-core/examples/simple_dioxus.rs index d3f1cdfcb..af0e4ca00 100644 --- a/packages/native-core/examples/simple_dioxus.rs +++ b/packages/native-core/examples/simple_dioxus.rs @@ -152,13 +152,12 @@ impl State for Border { _context: &SendAnyMap, ) -> bool { // check if the node contians a border attribute - let new = - Self( - node_view - .attributes() - .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) - .is_some(), - ); + let new = Self( + node_view + .attributes() + .and_then(|mut attrs| attrs.next().map(|a| a.attribute.name == "border")) + .is_some(), + ); // check if the member has changed let changed = new != *self; *self = new; diff --git a/packages/native-core/src/layout_attributes.rs b/packages/native-core/src/layout_attributes.rs index c5c2c2aa4..4eb39292b 100644 --- a/packages/native-core/src/layout_attributes.rs +++ b/packages/native-core/src/layout_attributes.rs @@ -340,27 +340,26 @@ pub fn apply_layout_attributes_cfg( } Property::JustifyContent(justify, _) => { use AlignContent::*; - style.justify_content = - match justify { - align::JustifyContent::ContentDistribution(distribution) => { - match distribution { - align::ContentDistribution::SpaceBetween => Some(SpaceBetween), - align::ContentDistribution::SpaceAround => Some(SpaceAround), - align::ContentDistribution::SpaceEvenly => Some(SpaceEvenly), - _ => return, - } + style.justify_content = match justify { + align::JustifyContent::ContentDistribution(distribution) => { + match distribution { + align::ContentDistribution::SpaceBetween => Some(SpaceBetween), + align::ContentDistribution::SpaceAround => Some(SpaceAround), + align::ContentDistribution::SpaceEvenly => Some(SpaceEvenly), + _ => return, } - align::JustifyContent::ContentPosition { - value: position, .. - } => match position { - align::ContentPosition::Center => Some(Center), - align::ContentPosition::Start => Some(Start), - align::ContentPosition::FlexStart => Some(FlexStart), - align::ContentPosition::End => Some(End), - align::ContentPosition::FlexEnd => Some(FlexEnd), - }, - _ => return, - }; + } + align::JustifyContent::ContentPosition { + value: position, .. + } => match position { + align::ContentPosition::Center => Some(Center), + align::ContentPosition::Start => Some(Start), + align::ContentPosition::FlexStart => Some(FlexStart), + align::ContentPosition::End => Some(End), + align::ContentPosition::FlexEnd => Some(FlexEnd), + }, + _ => return, + }; } Property::AlignSelf(align, _) => { use AlignItems::*; @@ -586,13 +585,11 @@ fn convert_grid_track_size(input: grid::TrackSize) -> NonRepeatedTrackSizingFunc convert_track_breadth_min(&min), convert_track_breadth_max(&max), ), - grid::TrackSize::FitContent(limit) => { - match limit { - DimensionPercentage::Dimension(LengthValue::Px(len)) => minmax(auto(), points(len)), - DimensionPercentage::Percentage(Percentage(pct)) => minmax(auto(), percent(pct)), - _ => unimplemented!(), - } - } + grid::TrackSize::FitContent(limit) => match limit { + DimensionPercentage::Dimension(LengthValue::Px(len)) => minmax(auto(), points(len)), + DimensionPercentage::Percentage(Percentage(pct)) => minmax(auto(), percent(pct)), + _ => unimplemented!(), + }, } } diff --git a/packages/native-core/src/utils/persistant_iterator.rs b/packages/native-core/src/utils/persistant_iterator.rs index fbaab5bed..2442af29f 100644 --- a/packages/native-core/src/utils/persistant_iterator.rs +++ b/packages/native-core/src/utils/persistant_iterator.rs @@ -488,5 +488,8 @@ fn persist_instertions_after() { )); let text = "hello world".to_string(); let idx = iter.next(&rdom).id(); - assert!(matches!(&*rdom.get(idx).unwrap().node_type(), NodeType::Text(text))); + assert!(matches!( + &*rdom.get(idx).unwrap().node_type(), + NodeType::Text(text) + )); } diff --git a/packages/native-core/tests/fuzzing.rs b/packages/native-core/tests/fuzzing.rs index 6c56178f8..4f0a34b70 100644 --- a/packages/native-core/tests/fuzzing.rs +++ b/packages/native-core/tests/fuzzing.rs @@ -9,7 +9,9 @@ fn random_ns() -> Option<&'static str> { let namespace = rand::random::() % 2; match namespace { 0 => None, - 1 => Some(Box::leak(format!("ns{}", rand::random::()).into_boxed_str())), + 1 => Some(Box::leak( + format!("ns{}", rand::random::()).into_boxed_str(), + )), _ => unreachable!(), } } @@ -21,15 +23,13 @@ fn create_random_attribute(attr_idx: &mut usize) -> TemplateAttribute<'static> { value: Box::leak(format!("value{}", rand::random::()).into_boxed_str()), namespace: random_ns(), }, - 1 => { - TemplateAttribute::Dynamic { - id: { - let old_idx = *attr_idx; - *attr_idx += 1; - old_idx - }, - } - } + 1 => TemplateAttribute::Dynamic { + id: { + let old_idx = *attr_idx; + *attr_idx += 1; + old_idx + }, + }, _ => unreachable!(), } } @@ -74,26 +74,22 @@ fn create_random_template_node( 1 => TemplateNode::Text { text: Box::leak(format!("{}", rand::random::()).into_boxed_str()), }, - 2 => { - TemplateNode::DynamicText { - id: { - let old_idx = *template_idx; - *template_idx += 1; - dynamic_node_types.push(DynamicNodeType::Text); - old_idx - }, - } - } - 3 => { - TemplateNode::Dynamic { - id: { - let old_idx = *template_idx; - *template_idx += 1; - dynamic_node_types.push(DynamicNodeType::Other); - old_idx - }, - } - } + 2 => TemplateNode::DynamicText { + id: { + let old_idx = *template_idx; + *template_idx += 1; + dynamic_node_types.push(DynamicNodeType::Text); + old_idx + }, + }, + 3 => TemplateNode::Dynamic { + id: { + let old_idx = *template_idx; + *template_idx += 1; + dynamic_node_types.push(DynamicNodeType::Other); + old_idx + }, + }, _ => unreachable!(), } } @@ -210,9 +206,9 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode { fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute { let value = match rand::random::() % 6 { - 0 => { - AttributeValue::Text(Box::leak(format!("{}", rand::random::()).into_boxed_str())) - } + 0 => AttributeValue::Text(Box::leak( + format!("{}", rand::random::()).into_boxed_str(), + )), 1 => AttributeValue::Float(rand::random()), 2 => AttributeValue::Int(rand::random()), 3 => AttributeValue::Bool(rand::random()), diff --git a/packages/rink/src/focus.rs b/packages/rink/src/focus.rs index 3f1ebb2d8..704d13b46 100644 --- a/packages/rink/src/focus.rs +++ b/packages/rink/src/focus.rs @@ -83,37 +83,36 @@ impl State for Focus { _: &SendAnyMap, ) -> bool { let new = Focus { - level: - if let Some(a) = node_view - .attributes() - .and_then(|mut a| a.find(|a| a.attribute.name == "tabindex")) + level: if let Some(a) = node_view + .attributes() + .and_then(|mut a| a.find(|a| a.attribute.name == "tabindex")) + { + if let Some(index) = a + .value + .as_int() + .or_else(|| a.value.as_text().and_then(|v| v.parse::().ok())) { - if let Some(index) = a - .value - .as_int() - .or_else(|| a.value.as_text().and_then(|v| v.parse::().ok())) - { - match index.cmp(&0) { - Ordering::Less => FocusLevel::Unfocusable, - Ordering::Equal => FocusLevel::Focusable, - Ordering::Greater => { - FocusLevel::Ordered(NonZeroU16::new(index as u16).unwrap()) - } + match index.cmp(&0) { + Ordering::Less => FocusLevel::Unfocusable, + Ordering::Equal => FocusLevel::Focusable, + Ordering::Greater => { + FocusLevel::Ordered(NonZeroU16::new(index as u16).unwrap()) } - } else { - FocusLevel::Unfocusable } - } else if node_view - .listeners() - .and_then( - |mut listeners| listeners.any(|l| FOCUS_EVENTS.contains(&l)).then_some(()) - ) - .is_some() - { - FocusLevel::Focusable } else { FocusLevel::Unfocusable - }, + } + } else if node_view + .listeners() + .and_then(|mut listeners| { + listeners.any(|l| FOCUS_EVENTS.contains(&l)).then_some(()) + }) + .is_some() + { + FocusLevel::Focusable + } else { + FocusLevel::Unfocusable + }, }; if *self != new { *self = new; diff --git a/packages/rink/src/hooks.rs b/packages/rink/src/hooks.rs index 7afed77e4..f8c4500d2 100644 --- a/packages/rink/src/hooks.rs +++ b/packages/rink/src/hooks.rs @@ -585,14 +585,13 @@ impl RinkInputHandler { let queued_events = Rc::new(RefCell::new(Vec::new())); let queued_events2 = Rc::downgrade(&queued_events); - let regester_event = - move |evt: crossterm::event::Event| { - if let Some(evt) = get_event(evt) { - if let Some(v) = queued_events2.upgrade() { - (*v).borrow_mut().push(evt); - } + let regester_event = move |evt: crossterm::event::Event| { + if let Some(evt) = get_event(evt) { + if let Some(v) = queued_events2.upgrade() { + (*v).borrow_mut().push(evt); } - }; + } + }; let state = Rc::new(RefCell::new(InnerInputState::create(rdom))); @@ -681,49 +680,48 @@ fn get_event(evt: TermEvent) -> Option<(&'static str, EventData)> { let ctrl = m.modifiers.contains(KeyModifiers::CONTROL); let meta = false; - let get_mouse_data = - |crossterm_button: Option| { - let button = crossterm_button.map(|b| match b { - MouseButton::Left => DioxusMouseButton::Primary, - MouseButton::Right => DioxusMouseButton::Secondary, - MouseButton::Middle => DioxusMouseButton::Auxiliary, - }); + let get_mouse_data = |crossterm_button: Option| { + let button = crossterm_button.map(|b| match b { + MouseButton::Left => DioxusMouseButton::Primary, + MouseButton::Right => DioxusMouseButton::Secondary, + MouseButton::Middle => DioxusMouseButton::Auxiliary, + }); - // from https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent + // from https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent - // The `page` and `screen` coordinates are inconsistent with the MDN definition, as they are relative to the viewport (client), not the target element/page/screen, respectively. - // todo? - // But then, MDN defines them in terms of pixels, yet crossterm provides only row/column, and it might not be possible to get pixels. So we can't get 100% consistency anyway. - let coordinates = Coordinates::new( - ScreenPoint::new(x, y), - ClientPoint::new(x, y), - // offset x/y are set when the origin of the event is assigned to an element - ElementPoint::new(0., 0.), - PagePoint::new(x, y), - ); + // The `page` and `screen` coordinates are inconsistent with the MDN definition, as they are relative to the viewport (client), not the target element/page/screen, respectively. + // todo? + // But then, MDN defines them in terms of pixels, yet crossterm provides only row/column, and it might not be possible to get pixels. So we can't get 100% consistency anyway. + let coordinates = Coordinates::new( + ScreenPoint::new(x, y), + ClientPoint::new(x, y), + // offset x/y are set when the origin of the event is assigned to an element + ElementPoint::new(0., 0.), + PagePoint::new(x, y), + ); - let mut modifiers = Modifiers::empty(); - if shift { - modifiers.insert(Modifiers::SHIFT); - } - if ctrl { - modifiers.insert(Modifiers::CONTROL); - } - if meta { - modifiers.insert(Modifiers::META); - } - if alt { - modifiers.insert(Modifiers::ALT); - } + let mut modifiers = Modifiers::empty(); + if shift { + modifiers.insert(Modifiers::SHIFT); + } + if ctrl { + modifiers.insert(Modifiers::CONTROL); + } + if meta { + modifiers.insert(Modifiers::META); + } + if alt { + modifiers.insert(Modifiers::ALT); + } - // held mouse buttons get set later by maintaining state, as crossterm does not provide them - EventData::Mouse(MouseData::new( - coordinates, - button, - DioxusMouseButtons::empty(), - modifiers, - )) - }; + // held mouse buttons get set later by maintaining state, as crossterm does not provide them + EventData::Mouse(MouseData::new( + coordinates, + button, + DioxusMouseButtons::empty(), + modifiers, + )) + }; let get_wheel_data = |up| { let y = if up { -1.0 } else { 1.0 }; diff --git a/packages/rink/src/layout.rs b/packages/rink/src/layout.rs index f9a29408e..dbdadac3f 100644 --- a/packages/rink/src/layout.rs +++ b/packages/rink/src/layout.rs @@ -195,12 +195,11 @@ impl State for TaffyLayout { taffy.set_children(n, &child_layout).unwrap(); } } else { - self.node = - PossiblyUninitalized::Initialized( - taffy - .new_with_children(scaled_style, &child_layout) - .unwrap(), - ); + self.node = PossiblyUninitalized::Initialized( + taffy + .new_with_children(scaled_style, &child_layout) + .unwrap(), + ); changed = true; } } diff --git a/packages/rink/src/prevent_default.rs b/packages/rink/src/prevent_default.rs index d42516d9f..4ad5ad87f 100644 --- a/packages/rink/src/prevent_default.rs +++ b/packages/rink/src/prevent_default.rs @@ -43,28 +43,27 @@ impl State for PreventDefault { _: Vec<::ElementBorrowed<'a>>, _: &SendAnyMap, ) -> bool { - let new = - match node_view.attributes().and_then(|mut attrs| { - attrs - .find(|a| a.attribute.name == "dioxus-prevent-default") - .and_then(|a| a.value.as_text()) - }) { - Some("onfocus") => PreventDefault::Focus, - Some("onkeypress") => PreventDefault::KeyPress, - Some("onkeyrelease") => PreventDefault::KeyRelease, - Some("onkeydown") => PreventDefault::KeyDown, - Some("onkeyup") => PreventDefault::KeyUp, - Some("onclick") => PreventDefault::Click, - Some("onmousedown") => PreventDefault::MouseDown, - Some("onmouseup") => PreventDefault::MouseUp, - Some("onmouseenter") => PreventDefault::MouseEnter, - Some("onmouseover") => PreventDefault::MouseOver, - Some("onmouseleave") => PreventDefault::MouseLeave, - Some("onmouseout") => PreventDefault::MouseOut, - Some("onwheel") => PreventDefault::Wheel, - Some("oncontextmenu") => PreventDefault::ContextMenu, - _ => return false, - }; + let new = match node_view.attributes().and_then(|mut attrs| { + attrs + .find(|a| a.attribute.name == "dioxus-prevent-default") + .and_then(|a| a.value.as_text()) + }) { + Some("onfocus") => PreventDefault::Focus, + Some("onkeypress") => PreventDefault::KeyPress, + Some("onkeyrelease") => PreventDefault::KeyRelease, + Some("onkeydown") => PreventDefault::KeyDown, + Some("onkeyup") => PreventDefault::KeyUp, + Some("onclick") => PreventDefault::Click, + Some("onmousedown") => PreventDefault::MouseDown, + Some("onmouseup") => PreventDefault::MouseUp, + Some("onmouseenter") => PreventDefault::MouseEnter, + Some("onmouseover") => PreventDefault::MouseOver, + Some("onmouseleave") => PreventDefault::MouseLeave, + Some("onmouseout") => PreventDefault::MouseOut, + Some("onwheel") => PreventDefault::Wheel, + Some("oncontextmenu") => PreventDefault::ContextMenu, + _ => return false, + }; if new == *self { false } else { diff --git a/packages/rink/src/style.rs b/packages/rink/src/style.rs index efd300774..905cc4b34 100644 --- a/packages/rink/src/style.rs +++ b/packages/rink/src/style.rs @@ -350,26 +350,24 @@ pub fn convert(mode: RenderingMode, c: Color) -> Color { let rgb = to_rgb(c); Color::Rgb(rgb[0], rgb[1], rgb[2]) } - crate::RenderingMode::Ansi => { - match c { - Color::Indexed(_) => c, - _ => { - let rgb = to_rgb(c); - // 16-231: 6 Ă— 6 Ă— 6 color cube - // 232-255: 23 step grayscale - if rgb[0] == rgb[1] && rgb[1] == rgb[2] { - let idx = 232 + (rgb[0] as u16 * 23 / 255) as u8; - Color::Indexed(idx) - } else { - let r = (rgb[0] as u16 * 5) / 255; - let g = (rgb[1] as u16 * 5) / 255; - let b = (rgb[2] as u16 * 5) / 255; - let idx = 16 + r * 36 + g * 6 + b; - Color::Indexed(idx as u8) - } + crate::RenderingMode::Ansi => match c { + Color::Indexed(_) => c, + _ => { + let rgb = to_rgb(c); + // 16-231: 6 Ă— 6 Ă— 6 color cube + // 232-255: 23 step grayscale + if rgb[0] == rgb[1] && rgb[1] == rgb[2] { + let idx = 232 + (rgb[0] as u16 * 23 / 255) as u8; + Color::Indexed(idx) + } else { + let r = (rgb[0] as u16 * 5) / 255; + let g = (rgb[1] as u16 * 5) / 255; + let b = (rgb[2] as u16 * 5) / 255; + let idx = 16 + r * 36 + g * 6 + b; + Color::Indexed(idx as u8) } } - } + }, } } } diff --git a/packages/rink/src/widgets/button.rs b/packages/rink/src/widgets/button.rs index bc1b16c9f..523b2392a 100644 --- a/packages/rink/src/widgets/button.rs +++ b/packages/rink/src/widgets/button.rs @@ -90,12 +90,11 @@ impl Button { } fn switch(&mut self, ctx: &WidgetContext, node: NodeMut) { - let data = - FormData { - value: self.value.to_string(), - values: HashMap::new(), - files: None, - }; + let data = FormData { + value: self.value.to_string(), + values: HashMap::new(), + files: None, + }; ctx.send(crate::Event { id: node.id(), name: "input", diff --git a/packages/rink/src/widgets/slider.rs b/packages/rink/src/widgets/slider.rs index 1ed4f903e..7080b6c12 100644 --- a/packages/rink/src/widgets/slider.rs +++ b/packages/rink/src/widgets/slider.rs @@ -236,11 +236,10 @@ impl Slider { let id = root.id(); let rdom = root.real_dom_mut(); let world = rdom.raw_world_mut(); - let taffy = - { - let query: UniqueView = world.borrow().unwrap(); - query.stretch.clone() - }; + let taffy = { + let query: UniqueView = world.borrow().unwrap(); + query.stretch.clone() + }; let taffy = taffy.lock().unwrap(); @@ -268,11 +267,10 @@ impl CustomElement for Slider { panic!("input must be an element") }; - let value = - el.attributes.get(&OwnedAttributeDiscription { - name: "value".to_string(), - namespace: None, - }); + let value = el.attributes.get(&OwnedAttributeDiscription { + name: "value".to_string(), + namespace: None, + }); let value = value .and_then(|value| match value { OwnedAttributeValue::Text(text) => text.as_str().parse().ok(), @@ -303,12 +301,11 @@ impl CustomElement for Slider { let cursor_text = rdom.create_node("|".to_string()); let cursor_text_id = cursor_text.id(); - let mut cursor_span = - rdom.create_node(NodeType::Element(ElementNode { - tag: "div".to_string(), - attributes: [].into_iter().collect(), - ..Default::default() - })); + let mut cursor_span = rdom.create_node(NodeType::Element(ElementNode { + tag: "div".to_string(), + attributes: [].into_iter().collect(), + ..Default::default() + })); cursor_span.add_child(cursor_text_id); let cursor_span_id = cursor_span.id(); diff --git a/packages/router-macro/src/route.rs b/packages/router-macro/src/route.rs index dd2689698..26665e575 100644 --- a/packages/router-macro/src/route.rs +++ b/packages/router-macro/src/route.rs @@ -144,14 +144,13 @@ impl Route { _ => Vec::new(), }; - let (route_segments, query) = - { - parse_route_segments( - variant.ident.span(), - fields.iter().map(|f| (&f.0, &f.1)), - &route, - )? - }; + let (route_segments, query) = { + parse_route_segments( + variant.ident.span(), + fields.iter().map(|f| (&f.0, &f.1)), + &route, + )? + }; Ok(Self { ty, @@ -324,11 +323,10 @@ impl Route { pub fn error_type(&self) -> TokenStream2 { let error_name = self.error_ident(); - let child_type = - match &self.ty { - RouteType::Child(field) => Some(&field.ty), - RouteType::Leaf { .. } => None, - }; + let child_type = match &self.ty { + RouteType::Child(field) => Some(&field.ty), + RouteType::Leaf { .. } => None, + }; create_error_type(error_name, &self.segments, child_type) } diff --git a/packages/router-macro/src/segment.rs b/packages/router-macro/src/segment.rs index 510bc13a2..7e4e40662 100644 --- a/packages/router-macro/src/segment.rs +++ b/packages/router-macro/src/segment.rs @@ -135,11 +135,10 @@ pub fn parse_route_segments<'a>( ) -> syn::Result<(Vec, Option)> { let mut route_segments = Vec::new(); - let (route_string, query) = - match route.rsplit_once('?') { - Some((route, query)) => (route, Some(query)), - None => (route, None), - }; + let (route_string, query) = match route.rsplit_once('?') { + Some((route, query)) => (route, Some(query)), + None => (route, None), + }; let mut iterator = route_string.split('/'); // skip the first empty segment @@ -158,12 +157,11 @@ pub fn parse_route_segments<'a>( if let Some(segment) = segment.strip_prefix(':') { let spread = segment.starts_with(".."); - let ident = - if spread { - segment[2..].to_string() - } else { - segment.to_string() - }; + let ident = if spread { + segment[2..].to_string() + } else { + segment.to_string() + }; let field = fields.find(|(name, _)| **name == ident); @@ -207,15 +205,14 @@ pub fn parse_route_segments<'a>( let query_ident = Ident::new(query, Span::call_site()); let field = fields.find(|(name, _)| *name == &query_ident); - let ty = - if let Some((_, ty)) = field { - ty.clone() - } else { - return Err(syn::Error::new( - route_span, - format!("Could not find a field with the name '{}'", query_ident), - )); - }; + let ty = if let Some((_, ty)) = field { + ty.clone() + } else { + return Err(syn::Error::new( + route_span, + format!("Could not find a field with the name '{}'", query_ident), + )); + }; Some(QuerySegment { ident: query_ident, diff --git a/packages/router/src/history/liveview.rs b/packages/router/src/history/liveview.rs index a7ecc89f6..9ffb09c34 100644 --- a/packages/router/src/history/liveview.rs +++ b/packages/router/src/history/liveview.rs @@ -77,18 +77,17 @@ where self.routes.retain(|&lhs, _| lhs <= last_visited); } }; - let state = - match state { - Some(state) => { - self.current_index = state.index; - state - } - None => { - let index = depth - 1; - self.current_index = index; - State { index } - } - }; + let state = match state { + Some(state) => { + self.current_index = state.index; + state + } + None => { + let index = depth - 1; + self.current_index = index; + State { index } + } + }; self.routes.insert(state.index, route); state } diff --git a/packages/router/src/history/web.rs b/packages/router/src/history/web.rs index 80cde3173..789eed76e 100644 --- a/packages/router/src/history/web.rs +++ b/packages/router/src/history/web.rs @@ -302,16 +302,15 @@ where let s = self.listener_animation_frame.clone(); let d = self.do_scroll_restoration; - self.listener_navigation = - Some(EventListener::new(&self.window, "popstate", move |_| { - (*callback)(); - if d { - let mut s = s.lock().expect("unpoisoned scroll mutex"); - if let Some(current_state) = get_current::>(&h) { - *s = Some(current_state.scroll.scroll_to(w.clone())); - } + self.listener_navigation = Some(EventListener::new(&self.window, "popstate", move |_| { + (*callback)(); + if d { + let mut s = s.lock().expect("unpoisoned scroll mutex"); + if let Some(current_state) = get_current::>(&h) { + *s = Some(current_state.scroll.scroll_to(w.clone())); } - })); + } + })); } } @@ -378,15 +377,14 @@ where let s = self.listener_animation_frame.clone(); let d = self.do_scroll_restoration; - self.listener_navigation = - Some(EventListener::new(&self.window, "popstate", move |_| { - (*callback)(); - if d { - let mut s = s.lock().expect("unpoisoned scroll mutex"); - if let Some([x, y]) = get_current(&h) { - *s = Some(ScrollPosition { x, y }.scroll_to(w.clone())); - } + self.listener_navigation = Some(EventListener::new(&self.window, "popstate", move |_| { + (*callback)(); + if d { + let mut s = s.lock().expect("unpoisoned scroll mutex"); + if let Some([x, y]) = get_current(&h) { + *s = Some(ScrollPosition { x, y }.scroll_to(w.clone())); } - })); + } + })); } } diff --git a/packages/router/src/navigation.rs b/packages/router/src/navigation.rs index e84a8b381..2d7a3f90f 100644 --- a/packages/router/src/navigation.rs +++ b/packages/router/src/navigation.rs @@ -114,9 +114,11 @@ impl FromStr for NavigationTarget { fn from_str(s: &str) -> Result { match Url::parse(s) { Ok(_) => Ok(Self::External(s.to_string())), - Err(ParseError::RelativeUrlWithoutBase) => Ok(Self::Internal( - R::from_str(s).map_err(|e| NavigationTargetParseError::InvalidInternalURL(e))?, - )), + Err(ParseError::RelativeUrlWithoutBase) => { + Ok(Self::Internal(R::from_str(s).map_err(|e| { + NavigationTargetParseError::InvalidInternalURL(e) + })?)) + } Err(e) => Err(NavigationTargetParseError::InvalidUrl(e)), } } diff --git a/packages/router/src/routable.rs b/packages/router/src/routable.rs index 094dcafe1..b1bb6d915 100644 --- a/packages/router/src/routable.rs +++ b/packages/router/src/routable.rs @@ -134,12 +134,11 @@ impl> FromRouteSegments for I { /// A flattened version of [`Routable::SITE_MAP`]. /// This essentially represents a `Vec>`, which you can collect it into. -type SiteMapFlattened<'a> = - FlatMap< - Iter<'a, SiteMapSegment>, - Vec>, - fn(&SiteMapSegment) -> Vec>, - >; +type SiteMapFlattened<'a> = FlatMap< + Iter<'a, SiteMapSegment>, + Vec>, + fn(&SiteMapSegment) -> Vec>, +>; fn seg_strs_to_route(segs_maybe: &Option>) -> Option where diff --git a/packages/router/src/utils/use_router_internal.rs b/packages/router/src/utils/use_router_internal.rs index 32a71d13c..9ac33f5fb 100644 --- a/packages/router/src/utils/use_router_internal.rs +++ b/packages/router/src/utils/use_router_internal.rs @@ -11,15 +11,14 @@ use crate::prelude::*; /// - [`None`], when the current component isn't a descendant of a [`Link`] component. /// - Otherwise [`Some`]. pub(crate) fn use_router_internal(cx: &ScopeState) -> &Option { - let inner = - cx.use_hook(|| { - let router = cx.consume_context::()?; + let inner = cx.use_hook(|| { + let router = cx.consume_context::()?; - let id = cx.scope_id(); - router.subscribe(id); + let id = cx.scope_id(); + router.subscribe(id); - Some(Subscription { router, id }) - }); + Some(Subscription { router, id }) + }); cx.use_hook(|| inner.as_ref().map(|s| s.router.clone())) } diff --git a/packages/rsx-rosetta/tests/simple.rs b/packages/rsx-rosetta/tests/simple.rs index de5e1c6a9..b8fd095e1 100644 --- a/packages/rsx-rosetta/tests/simple.rs +++ b/packages/rsx-rosetta/tests/simple.rs @@ -36,8 +36,7 @@ fn simple_elements() { #[test] fn deeply_nested() { - let html = - r#" + let html = r#"

@@ -49,7 +48,7 @@ fn deeply_nested() {
"# - .trim(); + .trim(); let dom = Dom::parse(html).unwrap(); diff --git a/packages/rsx/src/component.rs b/packages/rsx/src/component.rs index f28859352..6487e5ab7 100644 --- a/packages/rsx/src/component.rs +++ b/packages/rsx/src/component.rs @@ -162,11 +162,10 @@ impl ToTokens for Component { } if !self.children.is_empty() { - let renderer: TemplateRenderer = - TemplateRenderer { - roots: &self.children, - location: None, - }; + let renderer: TemplateRenderer = TemplateRenderer { + roots: &self.children, + location: None, + }; toks.append_all(quote! { .children( @@ -184,11 +183,10 @@ impl ToTokens for Component { let fn_name = self.name.segments.last().unwrap().ident.to_string(); - let gen_name = - match &self.prop_gen_args { - Some(gen) => quote! { #name #gen }, - None => quote! { #name }, - }; + let gen_name = match &self.prop_gen_args { + Some(gen) => quote! { #name #gen }, + None => quote! { #name }, + }; tokens.append_all(quote! { __cx.component( diff --git a/packages/rsx/src/element.rs b/packages/rsx/src/element.rs index 136eeaea2..8f45d91ff 100644 --- a/packages/rsx/src/element.rs +++ b/packages/rsx/src/element.rs @@ -332,60 +332,59 @@ impl ToTokens for ElementAttrNamed { } }; - let attribute = - match attr { - ElementAttr::AttrText { name, value } => { - let ns = ns(name); - let volitile = volitile(name); - let attribute = attribute(name); - quote! { - __cx.attr( - #attribute, - #value, - #ns, - #volitile - ) - } + let attribute = match attr { + ElementAttr::AttrText { name, value } => { + let ns = ns(name); + let volitile = volitile(name); + let attribute = attribute(name); + quote! { + __cx.attr( + #attribute, + #value, + #ns, + #volitile + ) } - ElementAttr::AttrExpression { name, value } => { - let ns = ns(name); - let volitile = volitile(name); - let attribute = attribute(name); - quote! { - __cx.attr( - #attribute, - #value, - #ns, - #volitile - ) - } + } + ElementAttr::AttrExpression { name, value } => { + let ns = ns(name); + let volitile = volitile(name); + let attribute = attribute(name); + quote! { + __cx.attr( + #attribute, + #value, + #ns, + #volitile + ) } - ElementAttr::CustomAttrText { name, value } => { - quote! { - __cx.attr( - #name, - #value, - None, - false - ) - } + } + ElementAttr::CustomAttrText { name, value } => { + quote! { + __cx.attr( + #name, + #value, + None, + false + ) } - ElementAttr::CustomAttrExpression { name, value } => { - quote! { - __cx.attr( - #name, - #value, - None, - false - ) - } + } + ElementAttr::CustomAttrExpression { name, value } => { + quote! { + __cx.attr( + #name, + #value, + None, + false + ) } - ElementAttr::EventTokens { name, tokens } => { - quote! { - dioxus_elements::events::#name(__cx, #tokens) - } + } + ElementAttr::EventTokens { name, tokens } => { + quote! { + dioxus_elements::events::#name(__cx, #tokens) } - }; + } + }; tokens.append_all(attribute); } diff --git a/packages/rsx/src/hot_reload/hot_reloading_file_map.rs b/packages/rsx/src/hot_reload/hot_reloading_file_map.rs index 875323405..0393142b4 100644 --- a/packages/rsx/src/hot_reload/hot_reloading_file_map.rs +++ b/packages/rsx/src/hot_reload/hot_reloading_file_map.rs @@ -77,12 +77,11 @@ impl FileMap { } let FileMapSearchResult { map, errors } = find_rs_files(path, &mut filter)?; - let result = - Self { - map, - in_workspace: HashMap::new(), - phantom: std::marker::PhantomData, - }; + let result = Self { + map, + in_workspace: HashMap::new(), + phantom: std::marker::PhantomData, + }; Ok(FileMapBuildResult { map: result, errors, diff --git a/packages/rsx/src/ifmt.rs b/packages/rsx/src/ifmt.rs index 31d7c6a78..6c72f5025 100644 --- a/packages/rsx/src/ifmt.rs +++ b/packages/rsx/src/ifmt.rs @@ -99,9 +99,10 @@ impl FromStr for IfmtInput { current_literal.push(c); continue; } else { - return Err( - Error::new(Span::call_site(), "unmatched closing '}' in format string") - ); + return Err(Error::new( + Span::call_site(), + "unmatched closing '}' in format string", + )); } } current_literal.push(c); @@ -146,18 +147,17 @@ impl ToTokens for IfmtInput { } } - let positional_args = - self.segments.iter().filter_map(|seg| { - if let Segment::Formatted(FormattedSegment { - segment: FormattedSegmentType::Expr(expr), - .. - }) = seg - { - Some(expr) - } else { - None - } - }); + let positional_args = self.segments.iter().filter_map(|seg| { + if let Segment::Formatted(FormattedSegment { + segment: FormattedSegmentType::Expr(expr), + .. + }) = seg + { + Some(expr) + } else { + None + } + }); // remove duplicate idents let named_args_idents: HashSet<_> = self @@ -228,7 +228,10 @@ impl FormattedSegmentType { if let Ok(expr) = parse_str(input) { Ok(Self::Expr(Box::new(expr))) } else { - Err(Error::new(Span::call_site(), "Expected Ident or Expression")) + Err(Error::new( + Span::call_site(), + "Expected Ident or Expression", + )) } } } diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index 6657ac722..bdf32b272 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -199,11 +199,10 @@ impl<'a> ToTokens for TemplateRenderer<'a> { _ => None, }; - let key_tokens = - match key { - Some(tok) => quote! { Some( __cx.raw_text(#tok) ) }, - None => quote! { None }, - }; + let key_tokens = match key { + Some(tok) => quote! { Some( __cx.raw_text(#tok) ) }, + None => quote! { None }, + }; let spndbg = format!("{:?}", self.roots[0].span()); let root_col = spndbg @@ -519,13 +518,12 @@ impl<'a> DynamicContext<'a> { let attrs = quote! { #(#static_attrs),*}; - let children = - el.children.iter().enumerate().map(|(idx, root)| { - self.current_path.push(idx as u8); - let out = self.render_static_node(root); - self.current_path.pop(); - out - }); + let children = el.children.iter().enumerate().map(|(idx, root)| { + self.current_path.push(idx as u8); + let out = self.render_static_node(root); + self.current_path.pop(); + out + }); let _opt = el.children.len() == 1; let children = quote! { #(#children),* }; diff --git a/packages/server-macro/src/lib.rs b/packages/server-macro/src/lib.rs index 75cf7790c..5ad9a682b 100644 --- a/packages/server-macro/src/lib.rs +++ b/packages/server-macro/src/lib.rs @@ -65,11 +65,10 @@ use syn::{ #[proc_macro_attribute] pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream { // before we pass this off to the server function macro, we apply extractors and middleware - let mut function: syn::ItemFn = - match syn::parse(s).map_err(|e| e.to_compile_error()) { - Ok(f) => f, - Err(e) => return e.into(), - }; + let mut function: syn::ItemFn = match syn::parse(s).map_err(|e| e.to_compile_error()) { + Ok(f) => f, + Err(e) => return e.into(), + }; // extract all #[middleware] attributes let mut middlewares: Vec = vec![]; diff --git a/packages/signals/src/effect.rs b/packages/signals/src/effect.rs index 87755180b..307ee98ab 100644 --- a/packages/signals/src/effect.rs +++ b/packages/signals/src/effect.rs @@ -87,12 +87,11 @@ impl Effect { /// /// The signal will be owned by the current component and will be dropped when the component is dropped. pub fn new(callback: impl FnMut() + 'static) -> Self { - let myself = - Self { - source: current_scope_id().expect("in a virtual dom"), - callback: CopyValue::new(Box::new(callback)), - effect_stack: get_effect_stack(), - }; + let myself = Self { + source: current_scope_id().expect("in a virtual dom"), + callback: CopyValue::new(Box::new(callback)), + effect_stack: get_effect_stack(), + }; myself.try_run(); diff --git a/packages/signals/src/selector.rs b/packages/signals/src/selector.rs index 3dd1c2291..556c8437c 100644 --- a/packages/signals/src/selector.rs +++ b/packages/signals/src/selector.rs @@ -72,10 +72,9 @@ where /// /// Selectors can be used to efficiently compute derived data from signals. pub fn selector(mut f: impl FnMut() -> R + 'static) -> ReadOnlySignal { - let state = - Signal:: { - inner: CopyValue::invalid(), - }; + let state = Signal:: { + inner: CopyValue::invalid(), + }; let effect = Effect { source: current_scope_id().expect("in a virtual dom"), callback: CopyValue::invalid(), diff --git a/packages/signals/tests/create.rs b/packages/signals/tests/create.rs index 0a172617e..ecda2f376 100644 --- a/packages/signals/tests/create.rs +++ b/packages/signals/tests/create.rs @@ -6,14 +6,13 @@ use dioxus_signals::*; #[test] fn create_signals_global() { - let mut dom = - VirtualDom::new(|cx| { - render! { - for _ in 0..10 { - Child {} - } + let mut dom = VirtualDom::new(|cx| { + render! { + for _ in 0..10 { + Child {} } - }); + } + }); fn Child(cx: Scope) -> Element { let signal = create_without_cx(); @@ -32,14 +31,13 @@ fn create_signals_global() { #[test] fn deref_signal() { - let mut dom = - VirtualDom::new(|cx| { - render! { - for _ in 0..10 { - Child {} - } + let mut dom = VirtualDom::new(|cx| { + render! { + for _ in 0..10 { + Child {} } - }); + } + }); fn Child(cx: Scope) -> Element { let signal = Signal::new("hello world".to_string()); @@ -57,17 +55,16 @@ fn deref_signal() { #[test] fn drop_signals() { - let mut dom = - VirtualDom::new(|cx| { - let generation = cx.generation(); + let mut dom = VirtualDom::new(|cx| { + let generation = cx.generation(); - let count = if generation % 2 == 0 { 10 } else { 0 }; - render! { - for _ in 0..count { - Child {} - } + let count = if generation % 2 == 0 { 10 } else { 0 }; + render! { + for _ in 0..count { + Child {} } - }); + } + }); fn Child(cx: Scope) -> Element { let signal = create_without_cx(); diff --git a/packages/signals/tests/selector.rs b/packages/signals/tests/selector.rs index b31e32a89..811871e88 100644 --- a/packages/signals/tests/selector.rs +++ b/packages/signals/tests/selector.rs @@ -100,15 +100,14 @@ fn memos_prevents_component_rerun() { let signal = cx.props.signal; counter.borrow_mut().component += 1; - let memo = - cx.use_hook(move || { - to_owned![counter]; - selector(move || { - counter.borrow_mut().effect += 1; - println!("Signal: {:?}", signal); - signal.value() - }) - }); + let memo = cx.use_hook(move || { + to_owned![counter]; + selector(move || { + counter.borrow_mut().effect += 1; + println!("Signal: {:?}", signal); + signal.value() + }) + }); match cx.generation() { 0 => { assert_eq!(memo.value(), 0); diff --git a/packages/web/src/cache.rs b/packages/web/src/cache.rs index 7648b1c47..e17203a65 100644 --- a/packages/web/src/cache.rs +++ b/packages/web/src/cache.rs @@ -1,301 +1,300 @@ -pub static BUILTIN_INTERNED_STRINGS: &[&str] = - &[ - // Important tags to dioxus - "dioxus-id", - "dioxus", - "dioxus-event-click", // todo: more events - "click", - // All the HTML Tags - "a", - "abbr", - "address", - "area", - "article", - "aside", - "audio", - "b", - "base", - "bdi", - "bdo", - "big", - "blockquote", - "body", - "br", - "button", - "canvas", - "caption", - "cite", - "code", - "col", - "colgroup", - "command", - "data", - "datalist", - "dd", - "del", - "details", - "dfn", - "dialog", - "div", - "dl", - "dt", - "em", - "embed", - "fieldset", - "figcaption", - "figure", - "footer", - "form", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "head", - "header", - "hr", - "html", - "i", - "iframe", - "img", - "input", - "ins", - "kbd", - "keygen", - "label", - "legend", - "li", - "link", - "main", - "map", - "mark", - "menu", - "menuitem", - "meta", - "meter", - "nav", - "noscript", - "object", - "ol", - "optgroup", - "option", - "output", - "p", - "param", - "picture", - "pre", - "progress", - "q", - "rp", - "rt", - "ruby", - "s", - "samp", - "script", - "section", - "select", - "small", - "source", - "span", - "strong", - "style", - "sub", - "summary", - "sup", - "table", - "tbody", - "td", - "textarea", - "tfoot", - "th", - "thead", - "time", - "title", - "tr", - "track", - "u", - "ul", - "var", - "video", - "wbr", - // All the event handlers - "Attribute", - "accept", - "accept-charset", - "accesskey", - "action", - "alt", - "async", - "autocomplete", - "autofocus", - "autoplay", - "charset", - "checked", - "cite", - "class", - "cols", - "colspan", - "content", - "contenteditable", - "controls", - "coords", - "data", - "data-*", - "datetime", - "default", - "defer", - "dir", - "dirname", - "disabled", - "download", - "draggable", - "enctype", - "for", - "form", - "formaction", - "headers", - "height", - "hidden", - "high", - "href", - "hreflang", - "http-equiv", - "id", - "ismap", - "kind", - "label", - "lang", - "list", - "loop", - "low", - "max", - "maxlength", - "media", - "method", - "min", - "multiple", - "muted", - "name", - "novalidate", - "onabort", - "onafterprint", - "onbeforeprint", - "onbeforeunload", - "onblur", - "oncanplay", - "oncanplaythrough", - "onchange", - "onclick", - "oncontextmenu", - "oncopy", - "oncuechange", - "oncut", - "ondblclick", - "ondrag", - "ondragend", - "ondragenter", - "ondragleave", - "ondragover", - "ondragstart", - "ondrop", - "ondurationchange", - "onemptied", - "onended", - "onerror", - "onfocus", - "onfocusout", - "onfocusin", - "onhashchange", - "oninput", - "oninvalid", - "onkeydown", - "onkeypress", - "onkeyup", - "onload", - "onloadeddata", - "onloadedmetadata", - "onloadstart", - "onmousedown", - "onmousemove", - "onmouseout", - "onmouseover", - "onmouseup", - "onmousewheel", - "onoffline", - "ononline", - "onpageshow", - "onpaste", - "onpause", - "onplay", - "onplaying", - "onprogress", - "onratechange", - "onreset", - "onresize", - "onscroll", - "onsearch", - "onseeked", - "onseeking", - "onselect", - "onstalled", - "onsubmit", - "onsuspend", - "ontimeupdate", - "ontoggle", - "onunload", - "onvolumechange", - "onwaiting", - "onwheel", - "open", - "optimum", - "pattern", - "placeholder", - "poster", - "preload", - "readonly", - "rel", - "required", - "reversed", - "rows", - "rowspan", - "sandbox", - "scope", - "selected", - "shape", - "size", - "sizes", - "span", - "spellcheck", - "src", - "srcdoc", - "srclang", - "srcset", - "start", - "step", - "style", - "tabindex", - "target", - "title", - "translate", - "type", - "usemap", - "value", - "width", - "wrap", - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", - ]; +pub static BUILTIN_INTERNED_STRINGS: &[&str] = &[ + // Important tags to dioxus + "dioxus-id", + "dioxus", + "dioxus-event-click", // todo: more events + "click", + // All the HTML Tags + "a", + "abbr", + "address", + "area", + "article", + "aside", + "audio", + "b", + "base", + "bdi", + "bdo", + "big", + "blockquote", + "body", + "br", + "button", + "canvas", + "caption", + "cite", + "code", + "col", + "colgroup", + "command", + "data", + "datalist", + "dd", + "del", + "details", + "dfn", + "dialog", + "div", + "dl", + "dt", + "em", + "embed", + "fieldset", + "figcaption", + "figure", + "footer", + "form", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "head", + "header", + "hr", + "html", + "i", + "iframe", + "img", + "input", + "ins", + "kbd", + "keygen", + "label", + "legend", + "li", + "link", + "main", + "map", + "mark", + "menu", + "menuitem", + "meta", + "meter", + "nav", + "noscript", + "object", + "ol", + "optgroup", + "option", + "output", + "p", + "param", + "picture", + "pre", + "progress", + "q", + "rp", + "rt", + "ruby", + "s", + "samp", + "script", + "section", + "select", + "small", + "source", + "span", + "strong", + "style", + "sub", + "summary", + "sup", + "table", + "tbody", + "td", + "textarea", + "tfoot", + "th", + "thead", + "time", + "title", + "tr", + "track", + "u", + "ul", + "var", + "video", + "wbr", + // All the event handlers + "Attribute", + "accept", + "accept-charset", + "accesskey", + "action", + "alt", + "async", + "autocomplete", + "autofocus", + "autoplay", + "charset", + "checked", + "cite", + "class", + "cols", + "colspan", + "content", + "contenteditable", + "controls", + "coords", + "data", + "data-*", + "datetime", + "default", + "defer", + "dir", + "dirname", + "disabled", + "download", + "draggable", + "enctype", + "for", + "form", + "formaction", + "headers", + "height", + "hidden", + "high", + "href", + "hreflang", + "http-equiv", + "id", + "ismap", + "kind", + "label", + "lang", + "list", + "loop", + "low", + "max", + "maxlength", + "media", + "method", + "min", + "multiple", + "muted", + "name", + "novalidate", + "onabort", + "onafterprint", + "onbeforeprint", + "onbeforeunload", + "onblur", + "oncanplay", + "oncanplaythrough", + "onchange", + "onclick", + "oncontextmenu", + "oncopy", + "oncuechange", + "oncut", + "ondblclick", + "ondrag", + "ondragend", + "ondragenter", + "ondragleave", + "ondragover", + "ondragstart", + "ondrop", + "ondurationchange", + "onemptied", + "onended", + "onerror", + "onfocus", + "onfocusout", + "onfocusin", + "onhashchange", + "oninput", + "oninvalid", + "onkeydown", + "onkeypress", + "onkeyup", + "onload", + "onloadeddata", + "onloadedmetadata", + "onloadstart", + "onmousedown", + "onmousemove", + "onmouseout", + "onmouseover", + "onmouseup", + "onmousewheel", + "onoffline", + "ononline", + "onpageshow", + "onpaste", + "onpause", + "onplay", + "onplaying", + "onprogress", + "onratechange", + "onreset", + "onresize", + "onscroll", + "onsearch", + "onseeked", + "onseeking", + "onselect", + "onstalled", + "onsubmit", + "onsuspend", + "ontimeupdate", + "ontoggle", + "onunload", + "onvolumechange", + "onwaiting", + "onwheel", + "open", + "optimum", + "pattern", + "placeholder", + "poster", + "preload", + "readonly", + "rel", + "required", + "reversed", + "rows", + "rowspan", + "sandbox", + "scope", + "selected", + "shape", + "size", + "sizes", + "span", + "spellcheck", + "src", + "srcdoc", + "srclang", + "srcset", + "start", + "step", + "style", + "tabindex", + "target", + "title", + "translate", + "type", + "usemap", + "value", + "width", + "wrap", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", +]; diff --git a/packages/web/src/dom.rs b/packages/web/src/dom.rs index 135ad8ede..f45d6558a 100644 --- a/packages/web/src/dom.rs +++ b/packages/web/src/dom.rs @@ -80,13 +80,12 @@ impl WebsysDom { } let data = virtual_event_from_websys_event(event.clone(), target); - let _ = - event_channel.unbounded_send(UiEvent { - name, - bubbles, - element, - data, - }); + let _ = event_channel.unbounded_send(UiEvent { + name, + bubbles, + element, + data, + }); } } })); diff --git a/packages/web/src/eval.rs b/packages/web/src/eval.rs index f4da3e69b..eefece50e 100644 --- a/packages/web/src/eval.rs +++ b/packages/web/src/eval.rs @@ -62,18 +62,24 @@ impl WebEvaluator { if let Ok(stringified) = js_sys::JSON::stringify(&result) { if !stringified.is_undefined() && stringified.is_valid_utf16() { let string: String = stringified.into(); - Value::from_str(&string).map_err( - |e| EvalError::Communication(format!("Failed to parse result - {}", e)) - )? + Value::from_str(&string).map_err(|e| { + EvalError::Communication(format!("Failed to parse result - {}", e)) + })? } else { - return Err(EvalError::Communication("Failed to stringify result".into())); + return Err(EvalError::Communication( + "Failed to stringify result".into(), + )); } } else { - return Err(EvalError::Communication("Failed to stringify result".into())); + return Err(EvalError::Communication( + "Failed to stringify result".into(), + )); } } Err(err) => { - return Err(EvalError::InvalidJs(err.as_string().unwrap_or("unknown".to_string()))); + return Err(EvalError::InvalidJs( + err.as_string().unwrap_or("unknown".to_string()), + )); } }; From cbfb80d5c6f4d0b75a4328d4cd221a6f376d34c7 Mon Sep 17 00:00:00 2001 From: Pascal Date: Thu, 7 Dec 2023 17:23:14 +0100 Subject: [PATCH 04/28] fixup: improved documentation and refactored naming to be more self-explanatory Note: This is the actual correct commit. The previous one contained files touched by cargo fmt which are unrelated. Sorry for that. --- packages/desktop/src/cfg.rs | 12 +++++++----- packages/desktop/src/webview.rs | 12 ++++++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/desktop/src/cfg.rs b/packages/desktop/src/cfg.rs index ba42ffa01..3b0409ae8 100644 --- a/packages/desktop/src/cfg.rs +++ b/packages/desktop/src/cfg.rs @@ -36,7 +36,7 @@ pub struct Config { pub(crate) root_name: String, pub(crate) background_color: Option<(u8, u8, u8, u8)>, pub(crate) last_window_close_behaviour: WindowCloseBehaviour, - pub(crate) disable_default_menu_bar: bool, + pub(crate) enable_default_menu_bar: bool, } type DropHandler = Box bool>; @@ -66,13 +66,15 @@ impl Config { root_name: "main".to_string(), background_color: None, last_window_close_behaviour: WindowCloseBehaviour::LastWindowExitsApp, - disable_default_menu_bar: false, + enable_default_menu_bar: true, } } - /// Set whether the default menu bar should be disabled. - pub fn with_disable_default_menu_bar(mut self, disable: bool) -> Self { - self.disable_default_menu_bar = disable; + /// Set whether the default menu bar should be enabled. + /// + /// > Note: `enable` is `true` by default. To disable the default menu bar pass `false`. + pub fn with_default_menu_bar(mut self, enable: bool) -> Self { + self.enable_default_menu_bar = enable; self } diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index 9beae702a..f03878242 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -19,8 +19,8 @@ pub fn build( let index_file = cfg.custom_index.clone(); let root_name = cfg.root_name.clone(); - if !cfg.disable_default_menu_bar { - builder = builder.with_menu(create_default_menu_bar()); + if cfg.enable_default_menu_bar { + builder = builder.with_menu(build_default_menu_bar()); } let window = builder.with_visible(false).build(event_loop).unwrap(); @@ -103,8 +103,12 @@ pub fn build( (webview.build().unwrap(), web_context) } -/// Creates a standard menu bar depending on the platform -fn create_default_menu_bar() -> MenuBar { +/// Builds a standard menu bar depending on the users platform. It may be used as a starting point +/// to further customize the menu bar and pass it to a [`WindowBuilder`](tao::window::WindowBuilder). +/// > Note: The default menu bar enables macOS shortcuts like cut/copy/paste. +/// > The menu bar differs per platform because of constraints introduced +/// > by [`MenuItem`](tao::menu::MenuItem). +pub fn build_default_menu_bar() -> MenuBar { let mut menu_bar = MenuBar::new(); // since it is uncommon on windows to have an "application menu" From 29f9d002e2b9a422c519b934124009ed1d8ffc93 Mon Sep 17 00:00:00 2001 From: Pascal Date: Thu, 7 Dec 2023 19:03:37 +0100 Subject: [PATCH 05/28] expose dioxus_desktop::build_default_menu_bar() --- packages/desktop/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 63a8914f3..4825fa5da 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -45,6 +45,7 @@ use tao::{ event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, }; +pub use webview::build_default_menu_bar; pub use wry; pub use wry::application as tao; use wry::webview::WebView; From d5ec22a26f3148f12712e2ff1a4ea4849ddc12f6 Mon Sep 17 00:00:00 2001 From: Will Crichton Date: Fri, 15 Dec 2023 11:16:25 -0800 Subject: [PATCH 06/28] Add custom asynchronous asset handlers --- packages/desktop/src/desktop_context.rs | 23 ++++ packages/desktop/src/lib.rs | 5 +- packages/desktop/src/protocol.rs | 143 +++++++++++++++++++++++- packages/desktop/src/webview.rs | 42 ++++--- 4 files changed, 194 insertions(+), 19 deletions(-) diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index a48068d84..7f4ef9d1d 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -1,11 +1,18 @@ use std::cell::RefCell; +use std::future::Future; +use std::path::Path; use std::rc::Rc; use std::rc::Weak; use crate::create_new_window; use crate::events::IpcMessage; +use crate::protocol::AssetFuture; +use crate::protocol::AssetHandlerId; +use crate::protocol::AssetHandlerRegistry; +use crate::protocol::AssetResponse; use crate::query::QueryEngine; use crate::shortcut::{HotKey, ShortcutId, ShortcutRegistry, ShortcutRegistryError}; +use crate::AssetHandler; use crate::Config; use crate::WebviewHandler; use dioxus_core::ScopeState; @@ -64,6 +71,8 @@ pub struct DesktopService { pub(crate) shortcut_manager: ShortcutRegistry, + pub(crate) asset_handlers: AssetHandlerRegistry, + #[cfg(target_os = "ios")] pub(crate) views: Rc>>, } @@ -88,6 +97,7 @@ impl DesktopService { webviews: WebviewQueue, event_handlers: WindowEventHandlers, shortcut_manager: ShortcutRegistry, + asset_handlers: AssetHandlerRegistry, ) -> Self { Self { webview: Rc::new(webview), @@ -97,6 +107,7 @@ impl DesktopService { pending_windows: webviews, event_handlers, shortcut_manager, + asset_handlers, #[cfg(target_os = "ios")] views: Default::default(), } @@ -247,6 +258,18 @@ impl DesktopService { self.shortcut_manager.remove_all() } + /// Provide a callback to handle asset loading yourself. + /// + /// See [`use_asset_handle`](crate::use_asset_handle) for a convenient hook. + pub async fn register_asset_handler(&self, f: impl AssetHandler) { + self.asset_handlers.register_handler(f).await; + } + + /// Removes an asset handler by its identifier. + pub async fn remove_asset_handler(&self, id: AssetHandlerId) { + self.asset_handlers.remove_handler(id).await; + } + /// Push an objc view to the window #[cfg(target_os = "ios")] pub fn push_view(&self, view: objc_id::ShareId) { diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index d6d5ef4a5..f8155c333 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -32,6 +32,7 @@ use dioxus_html::{native_bind::NativeFileEngine, FormData, HtmlEvent}; use element::DesktopElement; use eval::init_eval; use futures_util::{pin_mut, FutureExt}; +pub use protocol::{use_asset_handler, AssetFuture, AssetHandler, AssetHandlerId, AssetResponse}; use shortcut::ShortcutRegistry; pub use shortcut::{use_global_shortcut, ShortcutHandle, ShortcutId, ShortcutRegistryError}; use std::cell::Cell; @@ -393,7 +394,8 @@ fn create_new_window( event_handlers: &WindowEventHandlers, shortcut_manager: ShortcutRegistry, ) -> WebviewHandler { - let (webview, web_context) = webview::build(&mut cfg, event_loop, proxy.clone()); + let (webview, web_context, asset_handlers) = + webview::build(&mut cfg, event_loop, proxy.clone()); let desktop_context = Rc::from(DesktopService::new( webview, proxy.clone(), @@ -401,6 +403,7 @@ fn create_new_window( queue.clone(), event_handlers.clone(), shortcut_manager, + asset_handlers, )); let cx = dom.base_scope(); diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index 2f660b7a2..774c0900a 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -1,13 +1,25 @@ +use dioxus_core::ScopeState; use dioxus_interpreter_js::{COMMON_JS, INTERPRETER_JS}; use std::{ borrow::Cow, + collections::HashMap, + future::Future, path::{Path, PathBuf}, + pin::Pin, + rc::Rc, + sync::Arc, +}; +use tokio::{ + runtime::Handle, + sync::{OnceCell, RwLock}, }; use wry::{ http::{status::StatusCode, Request, Response}, Result, }; +use crate::{use_window, DesktopContext}; + fn module_loader(root_name: &str) -> String { let js = INTERPRETER_JS.replace( "/*POST_HANDLE_EDITS*/", @@ -51,12 +63,132 @@ fn module_loader(root_name: &str) -> String { ) } -pub(super) fn desktop_handler( +/// An arbitrary asset is an HTTP response containing a binary body. +pub type AssetResponse = Response>; + +/// A future that returns an [`AssetResponse`]. This future may be spawned in a new thread, +/// so it must be [`Send`], [`Sync`], and `'static`. +pub trait AssetFuture: Future> + Send + Sync + 'static {} +impl> + Send + Sync + 'static> AssetFuture for T {} + +/// A handler that takes an asset [`Path`] and returns a future that loads the path. +/// This handler is stashed indefinitely in a context object, so it must be `'static`. +pub trait AssetHandler: Fn(&Path) -> F + Send + Sync + 'static {} +impl F + Send + Sync + 'static> AssetHandler for T {} + +/// An identifier for a registered asset handler, returned by [`AssetHandlerRegistry::register_handler`]. +#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] +pub struct AssetHandlerId(usize); + +struct AssetHandlerRegistryInner { + handlers: HashMap< + AssetHandlerId, + Box Pin> + Send + Sync + 'static>, + >, + counter: AssetHandlerId, +} + +#[derive(Clone)] +pub struct AssetHandlerRegistry(Arc>); + +impl AssetHandlerRegistry { + pub fn new() -> Self { + AssetHandlerRegistry(Arc::new(RwLock::new(AssetHandlerRegistryInner { + handlers: HashMap::new(), + counter: AssetHandlerId(0), + }))) + } + + pub async fn register_handler( + &self, + f: impl AssetHandler, + ) -> AssetHandlerId { + let mut registry = self.0.write().await; + let id = registry.counter; + registry + .handlers + .insert(id, Box::new(move |path| Box::pin(f(path)))); + registry.counter.0 += 1; + id + } + + pub async fn remove_handler(&self, id: AssetHandlerId) -> Option<()> { + let mut registry = self.0.write().await; + registry.handlers.remove(&id).map(|_| ()) + } + + pub async fn try_handlers(&self, path: &Path) -> Option { + let registry = self.0.read().await; + for handler in registry.handlers.values() { + if let Some(response) = handler(path).await { + return Some(response); + } + } + None + } +} + +/// A handle to a registered asset handler. +pub struct AssetHandlerHandle { + desktop: DesktopContext, + handler_id: Rc>, +} + +impl AssetHandlerHandle { + /// Returns the [`AssetHandlerId`] for this handle. + /// + /// Because registering an ID is asynchronous, this may return `None` if the + /// registration has not completed yet. + pub fn handler_id(&self) -> Option { + self.handler_id.get().copied() + } +} + +impl Drop for AssetHandlerHandle { + fn drop(&mut self) { + let cell = Rc::clone(&self.handler_id); + let desktop = Rc::clone(&self.desktop); + tokio::task::block_in_place(move || { + Handle::current().block_on(async move { + if let Some(id) = cell.get() { + desktop.asset_handlers.remove_handler(*id).await; + } + }) + }); + } +} + +/// Provide a callback to handle asset loading yourself. +/// +/// The callback takes a path as requested by the web view, and it should return `Some(response)` +/// if you want to load the asset, and `None` if you want to fallback on the default behavior. +pub fn use_asset_handler( + cx: &ScopeState, + handler: impl AssetHandler, +) -> &AssetHandlerHandle { + let desktop = Rc::clone(&use_window(cx)); + cx.use_hook(|| { + let handler_id = Rc::new(OnceCell::new()); + let handler_id_ref = Rc::clone(&handler_id); + let desktop_ref = Rc::clone(&desktop); + cx.push_future(async move { + let id = desktop.asset_handlers.register_handler(handler).await; + handler_id.set(id).unwrap(); + }); + AssetHandlerHandle { + desktop: desktop_ref, + handler_id: handler_id_ref, + } + }) +} + +pub(super) async fn desktop_handler( request: &Request>, custom_head: Option, custom_index: Option, root_name: &str, -) -> Result>> { + asset_handlers: &AssetHandlerRegistry, +) -> Result { // If the request is for the root, we'll serve the index.html file. if request.uri().path() == "/" { // If a custom index is provided, just defer to that, expecting the user to know what they're doing. @@ -96,6 +228,13 @@ pub(super) fn desktop_handler( .expect("expected URL to be UTF-8 encoded"); let path = PathBuf::from(&*decoded); + // If the user provided a custom asset handler, then call it and return the response + // if the request was handled. + if let Some(response) = asset_handlers.try_handlers(&path).await { + return Ok(response); + } + + // Else, try to serve a file from the filesystem. // If the path is relative, we'll try to serve it from the assets directory. let mut asset = get_asset_root() .unwrap_or_else(|| Path::new(".").to_path_buf()) diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index cffb6f6b5..e2179352f 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -1,5 +1,7 @@ +use std::sync::Arc; + use crate::desktop_context::EventData; -use crate::protocol; +use crate::protocol::{self, AssetHandlerRegistry}; use crate::{desktop_context::UserWindowEvent, Config}; use tao::event_loop::{EventLoopProxy, EventLoopWindowTarget}; pub use wry; @@ -12,7 +14,7 @@ pub fn build( cfg: &mut Config, event_loop: &EventLoopWindowTarget, proxy: EventLoopProxy, -) -> (WebView, WebContext) { +) -> (WebView, WebContext, AssetHandlerRegistry) { let builder = cfg.window.clone(); let window = builder.with_visible(false).build(event_loop).unwrap(); let file_handler = cfg.file_drop_handler.take(); @@ -33,6 +35,8 @@ pub fn build( } let mut web_context = WebContext::new(cfg.data_dir.clone()); + let asset_handlers = AssetHandlerRegistry::new(); + let asset_handlers_ref = asset_handlers.clone(); let mut webview = WebViewBuilder::new(window) .unwrap() @@ -45,24 +49,30 @@ pub fn build( _ = proxy.send_event(UserWindowEvent(EventData::Ipc(message), window.id())); } }) - .with_custom_protocol( - String::from("dioxus"), - move |r| match protocol::desktop_handler( - &r, - custom_head.clone(), - index_file.clone(), - &root_name, - ) { - Ok(response) => response, - Err(err) => { + .with_asynchronous_custom_protocol(String::from("dioxus"), move |request, responder| { + let custom_head = custom_head.clone(); + let index_file = index_file.clone(); + let root_name = root_name.clone(); + let asset_handlers_ref = asset_handlers_ref.clone(); + tokio::spawn(async move { + let response_res = protocol::desktop_handler( + &request, + custom_head.clone(), + index_file.clone(), + &root_name, + &asset_handlers_ref, + ) + .await; + let response = response_res.unwrap_or_else(|err| { tracing::error!("Error: {}", err); Response::builder() .status(500) .body(err.to_string().into_bytes().into()) .unwrap() - } - }, - ) + }); + responder.respond(response); + }); + }) .with_file_drop_handler(move |window, evet| { file_handler .as_ref() @@ -119,5 +129,5 @@ pub fn build( webview = webview.with_devtools(true); } - (webview.build().unwrap(), web_context) + (webview.build().unwrap(), web_context, asset_handlers) } From 7bede0be59c9e48d55342c9f01978c34f8cc3a53 Mon Sep 17 00:00:00 2001 From: Will Crichton Date: Fri, 15 Dec 2023 11:30:19 -0800 Subject: [PATCH 07/28] Remove unused imports --- packages/desktop/src/desktop_context.rs | 3 --- packages/desktop/src/webview.rs | 2 -- 2 files changed, 5 deletions(-) diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index 7f4ef9d1d..cab3b4589 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -1,6 +1,4 @@ use std::cell::RefCell; -use std::future::Future; -use std::path::Path; use std::rc::Rc; use std::rc::Weak; @@ -9,7 +7,6 @@ use crate::events::IpcMessage; use crate::protocol::AssetFuture; use crate::protocol::AssetHandlerId; use crate::protocol::AssetHandlerRegistry; -use crate::protocol::AssetResponse; use crate::query::QueryEngine; use crate::shortcut::{HotKey, ShortcutId, ShortcutRegistry, ShortcutRegistryError}; use crate::AssetHandler; diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index e2179352f..1b13216c7 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use crate::desktop_context::EventData; use crate::protocol::{self, AssetHandlerRegistry}; use crate::{desktop_context::UserWindowEvent, Config}; From 1002bc955b5f569eb9e74da90b62b16c45d43bc6 Mon Sep 17 00:00:00 2001 From: Will Crichton Date: Sat, 16 Dec 2023 21:44:39 -0800 Subject: [PATCH 08/28] Replace AssetHandlerId with slab and usize --- packages/desktop/src/desktop_context.rs | 11 +++--- packages/desktop/src/lib.rs | 2 +- packages/desktop/src/protocol.rs | 45 +++++++------------------ 3 files changed, 20 insertions(+), 38 deletions(-) diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index cab3b4589..fb0615900 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -5,7 +5,6 @@ use std::rc::Weak; use crate::create_new_window; use crate::events::IpcMessage; use crate::protocol::AssetFuture; -use crate::protocol::AssetHandlerId; use crate::protocol::AssetHandlerRegistry; use crate::query::QueryEngine; use crate::shortcut::{HotKey, ShortcutId, ShortcutRegistry, ShortcutRegistryError}; @@ -258,13 +257,15 @@ impl DesktopService { /// Provide a callback to handle asset loading yourself. /// /// See [`use_asset_handle`](crate::use_asset_handle) for a convenient hook. - pub async fn register_asset_handler(&self, f: impl AssetHandler) { - self.asset_handlers.register_handler(f).await; + pub async fn register_asset_handler(&self, f: impl AssetHandler) -> usize { + self.asset_handlers.register_handler(f).await } /// Removes an asset handler by its identifier. - pub async fn remove_asset_handler(&self, id: AssetHandlerId) { - self.asset_handlers.remove_handler(id).await; + /// + /// Returns `None` if the handler did not exist. + pub async fn remove_asset_handler(&self, id: usize) -> Option<()> { + self.asset_handlers.remove_handler(id).await } /// Push an objc view to the window diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index f8155c333..515c26009 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -32,7 +32,7 @@ use dioxus_html::{native_bind::NativeFileEngine, FormData, HtmlEvent}; use element::DesktopElement; use eval::init_eval; use futures_util::{pin_mut, FutureExt}; -pub use protocol::{use_asset_handler, AssetFuture, AssetHandler, AssetHandlerId, AssetResponse}; +pub use protocol::{use_asset_handler, AssetFuture, AssetHandler, AssetResponse}; use shortcut::ShortcutRegistry; pub use shortcut::{use_global_shortcut, ShortcutHandle, ShortcutId, ShortcutRegistryError}; use std::cell::Cell; diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index 774c0900a..cb21245f8 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -1,5 +1,6 @@ use dioxus_core::ScopeState; use dioxus_interpreter_js::{COMMON_JS, INTERPRETER_JS}; +use slab::Slab; use std::{ borrow::Cow, collections::HashMap, @@ -76,50 +77,30 @@ impl> + Send + Sync + 'static> AssetFut pub trait AssetHandler: Fn(&Path) -> F + Send + Sync + 'static {} impl F + Send + Sync + 'static> AssetHandler for T {} -/// An identifier for a registered asset handler, returned by [`AssetHandlerRegistry::register_handler`]. -#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] -pub struct AssetHandlerId(usize); - -struct AssetHandlerRegistryInner { - handlers: HashMap< - AssetHandlerId, - Box Pin> + Send + Sync + 'static>, - >, - counter: AssetHandlerId, -} +type AssetHandlerRegistryInner = + Slab Pin> + Send + Sync + 'static>>; #[derive(Clone)] pub struct AssetHandlerRegistry(Arc>); impl AssetHandlerRegistry { pub fn new() -> Self { - AssetHandlerRegistry(Arc::new(RwLock::new(AssetHandlerRegistryInner { - handlers: HashMap::new(), - counter: AssetHandlerId(0), - }))) + AssetHandlerRegistry(Arc::new(RwLock::new(Slab::new()))) } - pub async fn register_handler( - &self, - f: impl AssetHandler, - ) -> AssetHandlerId { + pub async fn register_handler(&self, f: impl AssetHandler) -> usize { let mut registry = self.0.write().await; - let id = registry.counter; - registry - .handlers - .insert(id, Box::new(move |path| Box::pin(f(path)))); - registry.counter.0 += 1; - id + registry.insert(Box::new(move |path| Box::pin(f(path)))) } - pub async fn remove_handler(&self, id: AssetHandlerId) -> Option<()> { + pub async fn remove_handler(&self, id: usize) -> Option<()> { let mut registry = self.0.write().await; - registry.handlers.remove(&id).map(|_| ()) + registry.try_remove(id).map(|_| ()) } pub async fn try_handlers(&self, path: &Path) -> Option { let registry = self.0.read().await; - for handler in registry.handlers.values() { + for (_, handler) in registry.iter() { if let Some(response) = handler(path).await { return Some(response); } @@ -131,15 +112,15 @@ impl AssetHandlerRegistry { /// A handle to a registered asset handler. pub struct AssetHandlerHandle { desktop: DesktopContext, - handler_id: Rc>, + handler_id: Rc>, } impl AssetHandlerHandle { - /// Returns the [`AssetHandlerId`] for this handle. + /// Returns the ID for this handle. /// /// Because registering an ID is asynchronous, this may return `None` if the /// registration has not completed yet. - pub fn handler_id(&self) -> Option { + pub fn handler_id(&self) -> Option { self.handler_id.get().copied() } } @@ -166,7 +147,7 @@ pub fn use_asset_handler( cx: &ScopeState, handler: impl AssetHandler, ) -> &AssetHandlerHandle { - let desktop = Rc::clone(&use_window(cx)); + let desktop = Rc::clone(use_window(cx)); cx.use_hook(|| { let handler_id = Rc::new(OnceCell::new()); let handler_id_ref = Rc::clone(&handler_id); From 7649ad84a14aaf920f6ac9facbbdbb5787f41a25 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 17 Dec 2023 17:14:49 -0600 Subject: [PATCH 09/28] allow asset handlers to read the whole request --- packages/desktop/src/lib.rs | 2 +- packages/desktop/src/protocol.rs | 76 +++++++++++++++++++++++++------- packages/desktop/src/webview.rs | 2 +- 3 files changed, 61 insertions(+), 19 deletions(-) diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 515c26009..18739aeda 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -32,7 +32,7 @@ use dioxus_html::{native_bind::NativeFileEngine, FormData, HtmlEvent}; use element::DesktopElement; use eval::init_eval; use futures_util::{pin_mut, FutureExt}; -pub use protocol::{use_asset_handler, AssetFuture, AssetHandler, AssetResponse}; +pub use protocol::{use_asset_handler, AssetFuture, AssetHandler, AssetRequest, AssetResponse}; use shortcut::ShortcutRegistry; pub use shortcut::{use_global_shortcut, ShortcutHandle, ShortcutId, ShortcutRegistryError}; use std::cell::Cell; diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index cb21245f8..31930da50 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -3,8 +3,8 @@ use dioxus_interpreter_js::{COMMON_JS, INTERPRETER_JS}; use slab::Slab; use std::{ borrow::Cow, - collections::HashMap, future::Future, + ops::{Deref, DerefMut}, path::{Path, PathBuf}, pin::Pin, rc::Rc, @@ -72,13 +72,57 @@ pub type AssetResponse = Response>; pub trait AssetFuture: Future> + Send + Sync + 'static {} impl> + Send + Sync + 'static> AssetFuture for T {} -/// A handler that takes an asset [`Path`] and returns a future that loads the path. +/// A request for an asset. This is a wrapper around [`Request>`] that provides methods specific to asset requests. +pub struct AssetRequest { + path: PathBuf, + request: Request>, +} + +impl AssetRequest { + /// Get the path the asset request is for + pub fn path(&self) -> &Path { + &self.path + } +} + +impl From>> for AssetRequest { + fn from(request: Request>) -> Self { + let decoded = urlencoding::decode(request.uri().path().trim_start_matches('/')) + .expect("expected URL to be UTF-8 encoded"); + let path = PathBuf::from(&*decoded); + Self { request, path } + } +} + +impl Deref for AssetRequest { + type Target = Request>; + + fn deref(&self) -> &Self::Target { + &self.request + } +} + +impl DerefMut for AssetRequest { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.request + } +} + +/// A handler that takes an [`AssetRequest`] and returns a future that either loads the asset, or returns `None`. /// This handler is stashed indefinitely in a context object, so it must be `'static`. -pub trait AssetHandler: Fn(&Path) -> F + Send + Sync + 'static {} -impl F + Send + Sync + 'static> AssetHandler for T {} +pub trait AssetHandler: Send + Sync + 'static { + /// Handle an asset request, returning a future that either loads the asset, or returns `None` + fn handle_request(&self, request: &AssetRequest) -> F; +} + +impl F + Send + Sync + 'static> AssetHandler for T { + fn handle_request(&self, request: &AssetRequest) -> F { + self(request) + } +} type AssetHandlerRegistryInner = - Slab Pin> + Send + Sync + 'static>>; + Slab Pin> + Send + Sync + 'static>>; #[derive(Clone)] pub struct AssetHandlerRegistry(Arc>); @@ -90,7 +134,7 @@ impl AssetHandlerRegistry { pub async fn register_handler(&self, f: impl AssetHandler) -> usize { let mut registry = self.0.write().await; - registry.insert(Box::new(move |path| Box::pin(f(path)))) + registry.insert(Box::new(move |req| Box::pin(f.handle_request(req)))) } pub async fn remove_handler(&self, id: usize) -> Option<()> { @@ -98,10 +142,10 @@ impl AssetHandlerRegistry { registry.try_remove(id).map(|_| ()) } - pub async fn try_handlers(&self, path: &Path) -> Option { + pub async fn try_handlers(&self, req: &AssetRequest) -> Option { let registry = self.0.read().await; for (_, handler) in registry.iter() { - if let Some(response) = handler(path).await { + if let Some(response) = handler(req).await { return Some(response); } } @@ -164,12 +208,14 @@ pub fn use_asset_handler( } pub(super) async fn desktop_handler( - request: &Request>, + request: Request>, custom_head: Option, custom_index: Option, root_name: &str, asset_handlers: &AssetHandlerRegistry, ) -> Result { + let request = AssetRequest::from(request); + // If the request is for the root, we'll serve the index.html file. if request.uri().path() == "/" { // If a custom index is provided, just defer to that, expecting the user to know what they're doing. @@ -204,25 +250,21 @@ pub(super) async fn desktop_handler( .map_err(From::from); } - // Else, try to serve a file from the filesystem. - let decoded = urlencoding::decode(request.uri().path().trim_start_matches('/')) - .expect("expected URL to be UTF-8 encoded"); - let path = PathBuf::from(&*decoded); - // If the user provided a custom asset handler, then call it and return the response // if the request was handled. - if let Some(response) = asset_handlers.try_handlers(&path).await { + if let Some(response) = asset_handlers.try_handlers(&request).await { return Ok(response); } // Else, try to serve a file from the filesystem. + // If the path is relative, we'll try to serve it from the assets directory. let mut asset = get_asset_root() .unwrap_or_else(|| Path::new(".").to_path_buf()) - .join(&path); + .join(&request.path); if !asset.exists() { - asset = PathBuf::from("/").join(path); + asset = PathBuf::from("/").join(request.path); } if asset.exists() { diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index 1b13216c7..0294d3460 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -54,7 +54,7 @@ pub fn build( let asset_handlers_ref = asset_handlers_ref.clone(); tokio::spawn(async move { let response_res = protocol::desktop_handler( - &request, + request, custom_head.clone(), index_file.clone(), &root_name, From 9eee4ab8f8ae0c58929adca2c411b84c02d82372 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 17 Dec 2023 17:14:55 -0600 Subject: [PATCH 10/28] add a dynamic asset example --- examples/dynamic_asset.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 examples/dynamic_asset.rs diff --git a/examples/dynamic_asset.rs b/examples/dynamic_asset.rs new file mode 100644 index 000000000..1c004e015 --- /dev/null +++ b/examples/dynamic_asset.rs @@ -0,0 +1,29 @@ +use dioxus::prelude::*; +use dioxus_desktop::wry::http::Response; +use dioxus_desktop::{use_asset_handler, AssetRequest}; +use std::path::Path; + +fn main() { + dioxus_desktop::launch(app); +} + +fn app(cx: Scope) -> Element { + use_asset_handler(cx, |request: &AssetRequest| { + let path = request.path().to_path_buf(); + async move { + if path != Path::new("logo.png") { + return None; + } + let image_data: &[u8] = include_bytes!("./assets/logo.png"); + Some(Response::new(image_data.into())) + } + }); + + cx.render(rsx! { + div { + img { + src: "logo.png" + } + } + }) +} From ec4c1e0a441a6c475632de5244db9b889680471d Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 18 Dec 2023 08:32:50 -0600 Subject: [PATCH 11/28] add video stream example --- Cargo.toml | 1 + examples/video_stream.rs | 178 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 examples/video_stream.rs diff --git a/Cargo.toml b/Cargo.toml index a78f60d3e..41cd7cd83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -133,3 +133,4 @@ fern = { version = "0.6.0", features = ["colored"] } env_logger = "0.10.0" simple_logger = "4.0.0" thiserror = { workspace = true } +http-range = "0.1.5" diff --git a/examples/video_stream.rs b/examples/video_stream.rs new file mode 100644 index 000000000..6338a7d68 --- /dev/null +++ b/examples/video_stream.rs @@ -0,0 +1,178 @@ +use dioxus::prelude::*; +use dioxus_desktop::wry::http; +use dioxus_desktop::wry::http::Response; +use dioxus_desktop::{use_asset_handler, AssetRequest}; +use http::{header::*, response::Builder as ResponseBuilder, status::StatusCode}; +use std::borrow::Cow; +use std::sync::{Arc, Mutex}; +use std::{ + io::{Read, Seek, SeekFrom, Write}, + path::PathBuf, +}; + +fn main() { + dioxus_desktop::launch(app); +} + +fn app(cx: Scope) -> Element { + let id = Arc::new(Mutex::new(0)); + use_asset_handler(cx, move |request: &AssetRequest| { + let response: Option>> = match get_stream_response(request, &id) + { + Ok(response) => Some(response.map(Cow::Owned)), + Err(err) => { + eprintln!("Error: {}", err); + None + } + }; + async move { response } + }); + + cx.render(rsx! { + div { + video { + src: "test_video.mp4", + autoplay: true, + controls: true, + width: 640, + height: 480, + } + } + }) +} + +fn get_stream_response( + request: &AssetRequest, + boundary_id: &Arc>, +) -> Result>, Box> { + let video_file = PathBuf::from("./examples/assets/test_video.mp4"); + + let mut file = std::fs::File::open(&video_file)?; + + // get file length + let len = { + let old_pos = file.stream_position()?; + let len = file.seek(SeekFrom::End(0))?; + file.seek(SeekFrom::Start(old_pos))?; + len + }; + + let mut resp = ResponseBuilder::new().header(CONTENT_TYPE, "video/mp4"); + + // if the webview sent a range header, we need to send a 206 in return + // Actually only macOS and Windows are supported. Linux will ALWAYS return empty headers. + let http_response = if let Some(range_header) = request.headers().get("range") { + let not_satisfiable = || { + ResponseBuilder::new() + .status(StatusCode::RANGE_NOT_SATISFIABLE) + .header(CONTENT_RANGE, format!("bytes */{len}")) + .body(vec![]) + }; + + // parse range header + let ranges = if let Ok(ranges) = http_range::HttpRange::parse(range_header.to_str()?, len) { + ranges + .iter() + // map the output back to spec range , example: 0-499 + .map(|r| (r.start, r.start + r.length - 1)) + .collect::>() + } else { + return Ok(not_satisfiable()?); + }; + + /// The Maximum bytes we send in one range + const MAX_LEN: u64 = 1000 * 1024; + + if ranges.len() == 1 { + let &(start, mut end) = ranges.first().unwrap(); + + // check if a range is not satisfiable + // + // this should be already taken care of by HttpRange::parse + // but checking here again for extra assurance + if start >= len || end >= len || end < start { + return Ok(not_satisfiable()?); + } + + // adjust end byte for MAX_LEN + end = start + (end - start).min(len - start).min(MAX_LEN - 1); + + // calculate number of bytes needed to be read + let bytes_to_read = end + 1 - start; + + // allocate a buf with a suitable capacity + let mut buf = Vec::with_capacity(bytes_to_read as usize); + // seek the file to the starting byte + file.seek(SeekFrom::Start(start))?; + // read the needed bytes + file.take(bytes_to_read).read_to_end(&mut buf)?; + + resp = resp.header(CONTENT_RANGE, format!("bytes {start}-{end}/{len}")); + resp = resp.header(CONTENT_LENGTH, end + 1 - start); + resp = resp.status(StatusCode::PARTIAL_CONTENT); + resp.body(buf) + } else { + let mut buf = Vec::new(); + let ranges = ranges + .iter() + .filter_map(|&(start, mut end)| { + // filter out unsatisfiable ranges + // + // this should be already taken care of by HttpRange::parse + // but checking here again for extra assurance + if start >= len || end >= len || end < start { + None + } else { + // adjust end byte for MAX_LEN + end = start + (end - start).min(len - start).min(MAX_LEN - 1); + Some((start, end)) + } + }) + .collect::>(); + + let mut id = boundary_id.lock().unwrap(); + *id += 1; + let boundary = format!("sadasq2e{id}"); + let boundary_sep = format!("\r\n--{boundary}\r\n"); + let boundary_closer = format!("\r\n--{boundary}\r\n"); + + resp = resp.header( + CONTENT_TYPE, + format!("multipart/byteranges; boundary={boundary}"), + ); + + for (end, start) in ranges { + // a new range is being written, write the range boundary + buf.write_all(boundary_sep.as_bytes())?; + + // write the needed headers `Content-Type` and `Content-Range` + buf.write_all(format!("{CONTENT_TYPE}: video/mp4\r\n").as_bytes())?; + buf.write_all( + format!("{CONTENT_RANGE}: bytes {start}-{end}/{len}\r\n").as_bytes(), + )?; + + // write the separator to indicate the start of the range body + buf.write_all("\r\n".as_bytes())?; + + // calculate number of bytes needed to be read + let bytes_to_read = end + 1 - start; + + let mut local_buf = vec![0_u8; bytes_to_read as usize]; + file.seek(SeekFrom::Start(start))?; + file.read_exact(&mut local_buf)?; + buf.extend_from_slice(&local_buf); + } + // all ranges have been written, write the closing boundary + buf.write_all(boundary_closer.as_bytes())?; + + resp.body(buf) + } + } else { + resp = resp.header(CONTENT_LENGTH, len); + let mut buf = Vec::with_capacity(len as usize); + file.read_to_end(&mut buf)?; + resp.body(buf) + }; + + http_response.map_err(Into::into) +} From dfb118e06ccc97885979da3bd8924de330b2078d Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 18 Dec 2023 09:34:30 -0600 Subject: [PATCH 12/28] make the video streaming async --- .gitignore | 1 + examples/video_stream.rs | 108 ++++++++++++++++--------------- packages/desktop/src/protocol.rs | 16 ++--- 3 files changed, 65 insertions(+), 60 deletions(-) diff --git a/.gitignore b/.gitignore index b8025753e..364e8d0fb 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /dist Cargo.lock .DS_Store +/examples/assets/test_video.mp4 .vscode/* !.vscode/settings.json diff --git a/examples/video_stream.rs b/examples/video_stream.rs index 6338a7d68..f495299f4 100644 --- a/examples/video_stream.rs +++ b/examples/video_stream.rs @@ -4,56 +4,64 @@ use dioxus_desktop::wry::http::Response; use dioxus_desktop::{use_asset_handler, AssetRequest}; use http::{header::*, response::Builder as ResponseBuilder, status::StatusCode}; use std::borrow::Cow; -use std::sync::{Arc, Mutex}; -use std::{ - io::{Read, Seek, SeekFrom, Write}, - path::PathBuf, -}; +use std::{io::SeekFrom, path::PathBuf}; +use tokio::io::AsyncReadExt; +use tokio::io::AsyncSeekExt; +use tokio::io::AsyncWriteExt; + +const VIDEO_PATH: &str = "./examples/assets/test_video.mp4"; fn main() { + let video_file = PathBuf::from(VIDEO_PATH); + if !video_file.exists() { + tokio::runtime::Runtime::new() + .unwrap() + .block_on(async move { + println!("Downloading video file..."); + let video_url = + "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"; + let mut response = reqwest::get(video_url).await.unwrap(); + let mut file = tokio::fs::File::create(&video_file).await.unwrap(); + while let Some(chunk) = response.chunk().await.unwrap() { + file.write_all(&chunk).await.unwrap(); + } + }); + } dioxus_desktop::launch(app); } fn app(cx: Scope) -> Element { - let id = Arc::new(Mutex::new(0)); use_asset_handler(cx, move |request: &AssetRequest| { - let response: Option>> = match get_stream_response(request, &id) - { - Ok(response) => Some(response.map(Cow::Owned)), - Err(err) => { - eprintln!("Error: {}", err); - None - } - }; - async move { response } + let request = request.clone(); + async move { + let video_file = PathBuf::from(VIDEO_PATH); + let mut file = tokio::fs::File::open(&video_file).await.unwrap(); + let response: Option>> = + match get_stream_response(&mut file, &request).await { + Ok(response) => Some(response.map(Cow::Owned)), + Err(err) => { + eprintln!("Error: {}", err); + None + } + }; + response + } }); - cx.render(rsx! { - div { - video { - src: "test_video.mp4", - autoplay: true, - controls: true, - width: 640, - height: 480, - } - } - }) + render! { + div { video { src: "test_video.mp4", autoplay: true, controls: true, width: 640, height: 480 } } + } } -fn get_stream_response( +async fn get_stream_response( + asset: &mut (impl tokio::io::AsyncSeek + tokio::io::AsyncRead + Unpin + Send + Sync), request: &AssetRequest, - boundary_id: &Arc>, ) -> Result>, Box> { - let video_file = PathBuf::from("./examples/assets/test_video.mp4"); - - let mut file = std::fs::File::open(&video_file)?; - - // get file length + // get stream length let len = { - let old_pos = file.stream_position()?; - let len = file.seek(SeekFrom::End(0))?; - file.seek(SeekFrom::Start(old_pos))?; + let old_pos = asset.stream_position().await?; + let len = asset.seek(SeekFrom::End(0)).await?; + asset.seek(SeekFrom::Start(old_pos)).await?; len }; @@ -103,9 +111,9 @@ fn get_stream_response( // allocate a buf with a suitable capacity let mut buf = Vec::with_capacity(bytes_to_read as usize); // seek the file to the starting byte - file.seek(SeekFrom::Start(start))?; + asset.seek(SeekFrom::Start(start)).await?; // read the needed bytes - file.take(bytes_to_read).read_to_end(&mut buf)?; + asset.take(bytes_to_read).read_to_end(&mut buf).await?; resp = resp.header(CONTENT_RANGE, format!("bytes {start}-{end}/{len}")); resp = resp.header(CONTENT_LENGTH, end + 1 - start); @@ -130,9 +138,7 @@ fn get_stream_response( }) .collect::>(); - let mut id = boundary_id.lock().unwrap(); - *id += 1; - let boundary = format!("sadasq2e{id}"); + let boundary = format!("{:x}", rand::random::()); let boundary_sep = format!("\r\n--{boundary}\r\n"); let boundary_closer = format!("\r\n--{boundary}\r\n"); @@ -143,34 +149,34 @@ fn get_stream_response( for (end, start) in ranges { // a new range is being written, write the range boundary - buf.write_all(boundary_sep.as_bytes())?; + buf.write_all(boundary_sep.as_bytes()).await?; // write the needed headers `Content-Type` and `Content-Range` - buf.write_all(format!("{CONTENT_TYPE}: video/mp4\r\n").as_bytes())?; - buf.write_all( - format!("{CONTENT_RANGE}: bytes {start}-{end}/{len}\r\n").as_bytes(), - )?; + buf.write_all(format!("{CONTENT_TYPE}: video/mp4\r\n").as_bytes()) + .await?; + buf.write_all(format!("{CONTENT_RANGE}: bytes {start}-{end}/{len}\r\n").as_bytes()) + .await?; // write the separator to indicate the start of the range body - buf.write_all("\r\n".as_bytes())?; + buf.write_all("\r\n".as_bytes()).await?; // calculate number of bytes needed to be read let bytes_to_read = end + 1 - start; let mut local_buf = vec![0_u8; bytes_to_read as usize]; - file.seek(SeekFrom::Start(start))?; - file.read_exact(&mut local_buf)?; + asset.seek(SeekFrom::Start(start)).await?; + asset.read_exact(&mut local_buf).await?; buf.extend_from_slice(&local_buf); } // all ranges have been written, write the closing boundary - buf.write_all(boundary_closer.as_bytes())?; + buf.write_all(boundary_closer.as_bytes()).await?; resp.body(buf) } } else { resp = resp.header(CONTENT_LENGTH, len); let mut buf = Vec::with_capacity(len as usize); - file.read_to_end(&mut buf)?; + asset.read_to_end(&mut buf).await?; resp.body(buf) }; diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index 31930da50..46be1b942 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -4,7 +4,7 @@ use slab::Slab; use std::{ borrow::Cow, future::Future, - ops::{Deref, DerefMut}, + ops::Deref, path::{Path, PathBuf}, pin::Pin, rc::Rc, @@ -72,10 +72,11 @@ pub type AssetResponse = Response>; pub trait AssetFuture: Future> + Send + Sync + 'static {} impl> + Send + Sync + 'static> AssetFuture for T {} +#[derive(Debug, Clone)] /// A request for an asset. This is a wrapper around [`Request>`] that provides methods specific to asset requests. pub struct AssetRequest { path: PathBuf, - request: Request>, + request: Arc>>, } impl AssetRequest { @@ -90,7 +91,10 @@ impl From>> for AssetRequest { let decoded = urlencoding::decode(request.uri().path().trim_start_matches('/')) .expect("expected URL to be UTF-8 encoded"); let path = PathBuf::from(&*decoded); - Self { request, path } + Self { + request: Arc::new(request), + path, + } } } @@ -102,12 +106,6 @@ impl Deref for AssetRequest { } } -impl DerefMut for AssetRequest { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.request - } -} - /// A handler that takes an [`AssetRequest`] and returns a future that either loads the asset, or returns `None`. /// This handler is stashed indefinitely in a context object, so it must be `'static`. pub trait AssetHandler: Send + Sync + 'static { From 37e9876a703e03b891f795aaf70142f461ba3bd5 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 20 Dec 2023 15:18:20 -0600 Subject: [PATCH 13/28] bump salvo --- packages/fullstack/Cargo.toml | 2 +- packages/fullstack/examples/salvo-hello-world/Cargo.toml | 2 +- packages/liveview/Cargo.toml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/fullstack/Cargo.toml b/packages/fullstack/Cargo.toml index 8de27a9b1..2f3eca420 100644 --- a/packages/fullstack/Cargo.toml +++ b/packages/fullstack/Cargo.toml @@ -26,7 +26,7 @@ tower = { version = "0.4.13", features = ["util"], optional = true } axum-macros = "0.3.7" # salvo -salvo = { version = "0.46.0", optional = true, features = ["serve-static", "websocket", "compression"] } +salvo = { version = "0.63.0", optional = true, features = ["serve-static", "websocket", "compression"] } serde = "1.0.159" # Dioxus + SSR diff --git a/packages/fullstack/examples/salvo-hello-world/Cargo.toml b/packages/fullstack/examples/salvo-hello-world/Cargo.toml index ca0d85ecf..3d4e74c5b 100644 --- a/packages/fullstack/examples/salvo-hello-world/Cargo.toml +++ b/packages/fullstack/examples/salvo-hello-world/Cargo.toml @@ -12,7 +12,7 @@ dioxus = { workspace = true } dioxus-fullstack = { workspace = true } tokio = { workspace = true, features = ["full"], optional = true } serde = "1.0.159" -salvo = { version = "0.37.9", optional = true } +salvo = { version = "0.63.0", optional = true } execute = "0.2.12" reqwest = "0.11.18" simple_logger = "4.2.0" diff --git a/packages/liveview/Cargo.toml b/packages/liveview/Cargo.toml index cbd7b75f5..50d984c7e 100644 --- a/packages/liveview/Cargo.toml +++ b/packages/liveview/Cargo.toml @@ -34,7 +34,7 @@ warp = { version = "0.3.3", optional = true } axum = { version = "0.6.1", optional = true, features = ["ws"] } # salvo -salvo = { version = "0.44.1", optional = true, features = ["ws"] } +salvo = { version = "0.63.0", optional = true, features = ["websocket"] } once_cell = "1.17.1" async-trait = "0.1.71" @@ -49,7 +49,7 @@ tokio = { workspace = true, features = ["full"] } dioxus = { workspace = true } warp = "0.3.3" axum = { version = "0.6.1", features = ["ws"] } -salvo = { version = "0.44.1", features = ["affix", "ws"] } +salvo = { version = "0.63.0", features = ["affix", "websocket"] } tower = "0.4.13" [features] From a0b95a82a0fa16d9101897554444878da7096f74 Mon Sep 17 00:00:00 2001 From: werner291 Date: Mon, 1 Jan 2024 17:22:52 +0100 Subject: [PATCH 14/28] Implemented From> for ReadOnlySignal (#1772) --- packages/signals/src/signal.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/signals/src/signal.rs b/packages/signals/src/signal.rs index 1dc4bd36e..946a6c380 100644 --- a/packages/signals/src/signal.rs +++ b/packages/signals/src/signal.rs @@ -495,3 +495,9 @@ impl Deref for ReadOnlySignal { reference_to_closure as &Self::Target } } + +impl From> for ReadOnlySignal { + fn from(signal: Signal) -> Self { + Self::new(signal) + } +} From 8230566c4d761f6235ce4eba5a990bcb35af194f Mon Sep 17 00:00:00 2001 From: Hampus Lidin Date: Tue, 2 Jan 2024 17:01:53 +0100 Subject: [PATCH 15/28] Add doc comment on generated inline properties struct (#1775) --- .../core-macro/src/component_body_deserializers/component.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/core-macro/src/component_body_deserializers/component.rs b/packages/core-macro/src/component_body_deserializers/component.rs index 36cda850c..994e51709 100644 --- a/packages/core-macro/src/component_body_deserializers/component.rs +++ b/packages/core-macro/src/component_body_deserializers/component.rs @@ -58,8 +58,11 @@ impl ToTokens for ComponentDeserializerOutput { fn to_tokens(&self, tokens: &mut TokenStream2) { let comp_fn = &self.comp_fn; let props_struct = &self.props_struct; + let fn_ident = &comp_fn.sig.ident; + let doc = format!("Properties for the [`{fn_ident}`] component."); tokens.append_all(quote! { + #[doc = #doc] #props_struct #[allow(non_snake_case)] #comp_fn From fd7c9e0359823f767f8b90a0b156be4babdb7a22 Mon Sep 17 00:00:00 2001 From: abhi Date: Tue, 2 Jan 2024 16:02:58 +0000 Subject: [PATCH 16/28] fix empty render causing panic (#1769) (#1774) * fix empty render causing panic (#1769) * use an default root column instead of an empty root column * fix formatting * restore create.rs in core --------- Co-authored-by: Evan Almloff --- packages/core/src/create.rs | 3 +- packages/rsx/src/lib.rs | 17 ++++--- packages/ssr/src/renderer.rs | 88 ++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 7 deletions(-) diff --git a/packages/core/src/create.rs b/packages/core/src/create.rs index a61a8cace..733a796ce 100644 --- a/packages/core/src/create.rs +++ b/packages/core/src/create.rs @@ -205,7 +205,7 @@ impl<'b> VirtualDom { }); } - /// We write all the descndent data for this element + /// We write all the descendent data for this element /// /// Elements can contain other nodes - and those nodes can be dynamic or static /// @@ -405,6 +405,7 @@ impl<'b> VirtualDom { #[allow(unused_mut)] pub(crate) fn register_template(&mut self, mut template: Template<'static>) { let (path, byte_index) = template.name.rsplit_once(':').unwrap(); + let byte_index = byte_index.parse::().unwrap(); // First, check if we've already seen this template if self diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index 5db6baee9..458075b63 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -204,12 +204,17 @@ impl<'a> ToTokens for TemplateRenderer<'a> { None => quote! { None }, }; - let spndbg = format!("{:?}", self.roots[0].span()); - let root_col = spndbg - .rsplit_once("..") - .and_then(|(_, after)| after.split_once(')').map(|(before, _)| before)) - .unwrap_or_default(); - + let root_col = match self.roots.first() { + Some(first_root) => { + let first_root_span = format!("{:?}", first_root.span()); + first_root_span + .rsplit_once("..") + .and_then(|(_, after)| after.split_once(')').map(|(before, _)| before)) + .unwrap_or_default() + .to_string() + } + _ => "0".to_string(), + }; let root_printer = self.roots.iter().enumerate().map(|(idx, root)| { context.current_path.push(idx as u8); let out = context.render_static_node(root); diff --git a/packages/ssr/src/renderer.rs b/packages/ssr/src/renderer.rs index 98afef8b7..c0f9b6c75 100644 --- a/packages/ssr/src/renderer.rs +++ b/packages/ssr/src/renderer.rs @@ -238,6 +238,94 @@ fn to_string_works() { assert_eq!(out, "
Hello world 1 -->123<-- Hello world 2
nest 1
nest 2
</diiiiiiiiv>
finalize 0
finalize 1
finalize 2
finalize 3
finalize 4
"); } +#[test] +fn empty_for_loop_works() { + use dioxus::prelude::*; + + fn app(cx: Scope) -> Element { + render! { + div { class: "asdasdasd", + for _ in (0..5) { + + } + } + } + } + + let mut dom = VirtualDom::new(app); + _ = dom.rebuild(); + + let mut renderer = Renderer::new(); + let out = renderer.render(&dom); + + for item in renderer.template_cache.iter() { + if item.1.segments.len() > 5 { + assert_eq!( + item.1.segments, + vec![ + PreRendered("
".into()), + InnerHtmlMarker, + PreRendered("
".into(),), + ] + ); + } + } + + use Segment::*; + + assert_eq!(out, "
"); +} + +#[test] +fn empty_render_works() { + use dioxus::prelude::*; + + fn app(cx: Scope) -> Element { + render! {} + } + + let mut dom = VirtualDom::new(app); + _ = dom.rebuild(); + + let mut renderer = Renderer::new(); + let out = renderer.render(&dom); + + for item in renderer.template_cache.iter() { + if item.1.segments.len() > 5 { + assert_eq!(item.1.segments, vec![]); + } + } + assert_eq!(out, ""); +} + +#[test] +fn empty_rsx_works() { + use dioxus::prelude::*; + + fn app(_: Scope) -> Element { + rsx! {}; + None + } + + let mut dom = VirtualDom::new(app); + _ = dom.rebuild(); + + let mut renderer = Renderer::new(); + let out = renderer.render(&dom); + + for item in renderer.template_cache.iter() { + if item.1.segments.len() > 5 { + assert_eq!(item.1.segments, vec![]); + } + } + assert_eq!(out, ""); +} + pub(crate) const BOOL_ATTRS: &[&str] = &[ "allowfullscreen", "allowpaymentrequest", From 80a8e1f512bbaeb71695107e64d1d2d3c10477f9 Mon Sep 17 00:00:00 2001 From: Bennett-Petzold <46354948+Bennett-Petzold@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:19:29 -0500 Subject: [PATCH 17/28] Add Cargo Arguments and Cross-Architecture Support (#1777) * Add passthrough to cargo build * Add platform_triple flag * Add handling to bundle and serve commands * Show full stacked error from Tauri in bundling Previously only the top-level error was shown, giving only vague data for debugging the build process * Adjust bundle platform triple when cross compiling * Rename --platform-triple to --target * restore some deleted docs on CLI commands --------- Co-authored-by: Evan Almloff --- packages/cli/src/builder.rs | 17 ++++++++++++++++- packages/cli/src/cli/build.rs | 6 ++++++ packages/cli/src/cli/bundle.rs | 15 +++++++++++++-- packages/cli/src/cli/cfg.rs | 32 ++++++++++++++++++++++++-------- packages/cli/src/cli/serve.rs | 6 ++++++ packages/cli/src/config.rs | 16 ++++++++++++++++ 6 files changed, 81 insertions(+), 11 deletions(-) diff --git a/packages/cli/src/builder.rs b/packages/cli/src/builder.rs index 759be7dec..a5721d7a6 100644 --- a/packages/cli/src/builder.rs +++ b/packages/cli/src/builder.rs @@ -93,6 +93,8 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result { cmd }; + let cmd = cmd.args(&config.cargo_args); + let cmd = match executable { ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), ExecutableType::Lib(name) => cmd.arg("--lib").arg(name), @@ -286,6 +288,14 @@ pub fn build_desktop(config: &CrateConfig, _is_serve: bool) -> Result cmd.arg("--bin").arg(name), crate::ExecutableType::Lib(name) => cmd.arg("--lib").arg(name), @@ -303,12 +313,17 @@ pub fn build_desktop(config: &CrateConfig, _is_serve: bool) -> Result { file_name = name.clone(); - config.target_dir.join(release_type).join(name) + config + .target_dir + .join(target_platform) + .join(release_type) + .join(name) } crate::ExecutableType::Example(name) => { file_name = name.clone(); config .target_dir + .join(target_platform) .join(release_type) .join("examples") .join(name) diff --git a/packages/cli/src/cli/build.rs b/packages/cli/src/cli/build.rs index 63a2969e0..0deeb38ca 100644 --- a/packages/cli/src/cli/build.rs +++ b/packages/cli/src/cli/build.rs @@ -37,6 +37,12 @@ impl Build { .platform .unwrap_or(crate_config.dioxus_config.application.default_platform); + if let Some(target) = self.build.target { + crate_config.set_target(target); + } + + crate_config.set_cargo_args(self.build.cargo_args); + // #[cfg(feature = "plugin")] // let _ = PluginManager::on_build_start(&crate_config, &platform); diff --git a/packages/cli/src/cli/bundle.rs b/packages/cli/src/cli/bundle.rs index 80b52cf2f..fd97930ed 100644 --- a/packages/cli/src/cli/bundle.rs +++ b/packages/cli/src/cli/bundle.rs @@ -76,6 +76,12 @@ impl Bundle { crate_config.set_profile(self.build.profile.unwrap()); } + if let Some(target) = &self.build.target { + crate_config.set_target(target.to_string()); + } + + crate_config.set_cargo_args(self.build.cargo_args); + // build the desktop app build_desktop(&crate_config, false)?; @@ -148,6 +154,11 @@ impl Bundle { .collect(), ); } + + if let Some(target) = &self.build.target { + settings = settings.target(target.to_string()); + } + let settings = settings.build(); // on macos we need to set CI=true (https://github.com/tauri-apps/tauri/issues/2567) @@ -156,9 +167,9 @@ impl Bundle { tauri_bundler::bundle::bundle_project(settings.unwrap()).unwrap_or_else(|err|{ #[cfg(target_os = "macos")] - panic!("Failed to bundle project: {}\nMake sure you have automation enabled in your terminal (https://github.com/tauri-apps/tauri/issues/3055#issuecomment-1624389208) and full disk access enabled for your terminal (https://github.com/tauri-apps/tauri/issues/3055#issuecomment-1624389208)", err); + panic!("Failed to bundle project: {:#?}\nMake sure you have automation enabled in your terminal (https://github.com/tauri-apps/tauri/issues/3055#issuecomment-1624389208) and full disk access enabled for your terminal (https://github.com/tauri-apps/tauri/issues/3055#issuecomment-1624389208)", err); #[cfg(not(target_os = "macos"))] - panic!("Failed to bundle project: {}", err); + panic!("Failed to bundle project: {:#?}", err); }); Ok(()) diff --git a/packages/cli/src/cli/cfg.rs b/packages/cli/src/cli/cfg.rs index 2a441a1c8..0d2a5e212 100644 --- a/packages/cli/src/cli/cfg.rs +++ b/packages/cli/src/cli/cfg.rs @@ -6,10 +6,6 @@ use super::*; /// Config options for the build system. #[derive(Clone, Debug, Default, Deserialize, Parser)] pub struct ConfigOptsBuild { - /// The index HTML file to drive the bundling process [default: index.html] - #[arg(long)] - pub target: Option, - /// Build in release mode [default: false] #[clap(long)] #[serde(default)] @@ -35,14 +31,18 @@ pub struct ConfigOptsBuild { /// Space separated list of features to activate #[clap(long)] pub features: Option>, + + /// Rustc platform triple + #[clap(long)] + pub target: Option, + + /// Extra arguments passed to cargo build + #[clap(last = true)] + pub cargo_args: Vec, } #[derive(Clone, Debug, Default, Deserialize, Parser)] pub struct ConfigOptsServe { - /// The index HTML file to drive the bundling process [default: index.html] - #[arg(short, long)] - pub target: Option, - /// Port of dev server #[clap(long)] #[clap(default_value_t = 8080)] @@ -89,6 +89,14 @@ pub struct ConfigOptsServe { /// Space separated list of features to activate #[clap(long)] pub features: Option>, + + /// Rustc platform triple + #[clap(long)] + pub target: Option, + + /// Extra arguments passed to cargo build + #[clap(last = true)] + pub cargo_args: Vec, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Serialize, Deserialize, Debug)] @@ -129,4 +137,12 @@ pub struct ConfigOptsBundle { /// Space separated list of features to activate #[clap(long)] pub features: Option>, + + /// Rustc platform triple + #[clap(long)] + pub target: Option, + + /// Extra arguments passed to cargo build + #[clap(last = true)] + pub cargo_args: Vec, } diff --git a/packages/cli/src/cli/serve.rs b/packages/cli/src/cli/serve.rs index 433d611b7..e08b02339 100644 --- a/packages/cli/src/cli/serve.rs +++ b/packages/cli/src/cli/serve.rs @@ -34,6 +34,12 @@ impl Serve { // Subdirectories don't work with the server crate_config.dioxus_config.web.app.base_path = None; + if let Some(target) = self.serve.target { + crate_config.set_target(target); + } + + crate_config.set_cargo_args(self.serve.cargo_args); + let platform = self .serve .platform diff --git a/packages/cli/src/config.rs b/packages/cli/src/config.rs index 3abf47f0c..727504e6a 100644 --- a/packages/cli/src/config.rs +++ b/packages/cli/src/config.rs @@ -211,6 +211,8 @@ pub struct CrateConfig { pub verbose: bool, pub custom_profile: Option, pub features: Option>, + pub target: Option, + pub cargo_args: Vec, } #[derive(Debug, Clone)] @@ -278,6 +280,8 @@ impl CrateConfig { let verbose = false; let custom_profile = None; let features = None; + let target = None; + let cargo_args = vec![]; Ok(Self { out_dir, @@ -294,6 +298,8 @@ impl CrateConfig { custom_profile, features, verbose, + target, + cargo_args, }) } @@ -331,6 +337,16 @@ impl CrateConfig { self.features = Some(features); self } + + pub fn set_target(&mut self, target: String) -> &mut Self { + self.target = Some(target); + self + } + + pub fn set_cargo_args(&mut self, cargo_args: Vec) -> &mut Self { + self.cargo_args = cargo_args; + self + } } #[derive(Debug, Clone, Serialize, Deserialize, Default)] From 2f9b6e7dea89f4af422d6c56f315e7ecc8880c37 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 3 Jan 2024 08:26:14 -0600 Subject: [PATCH 18/28] fix non string layout attributes in rink --- packages/rink/src/layout.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rink/src/layout.rs b/packages/rink/src/layout.rs index dbdadac3f..72c8f68b2 100644 --- a/packages/rink/src/layout.rs +++ b/packages/rink/src/layout.rs @@ -92,10 +92,10 @@ impl State for TaffyLayout { attribute, value, .. } in attributes { - if let Some(text) = value.as_text() { + if value.as_custom().is_none() { apply_layout_attributes_cfg( &attribute.name, - text, + &value.to_string(), &mut style, &LayoutConfigeration { border_widths: BorderWidths { From cde5ac5f585c607d6b53f29e8e7ecac88df34306 Mon Sep 17 00:00:00 2001 From: ealmloff Date: Wed, 3 Jan 2024 14:01:50 -0600 Subject: [PATCH 19/28] fix invalid locations never being dropped (#1747) --- packages/generational-box/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/generational-box/src/lib.rs b/packages/generational-box/src/lib.rs index f56904ede..57a02a5d7 100644 --- a/packages/generational-box/src/lib.rs +++ b/packages/generational-box/src/lib.rs @@ -700,14 +700,16 @@ impl Owner { /// Creates an invalid handle. This is useful for creating a handle that will be filled in later. If you use this before the value is filled in, you will get may get a panic or an out of date value. pub fn invalid(&self) -> GenerationalBox { let location = self.store.claim(); - GenerationalBox { + let key = GenerationalBox { raw: location, #[cfg(any(debug_assertions, feature = "check_generation"))] generation: location.0.generation.get(), #[cfg(any(debug_assertions, feature = "debug_ownership"))] created_at: std::panic::Location::caller(), _marker: PhantomData, - } + }; + self.owned.borrow_mut().push(location); + key } } From 937be8b752c48b03f02014130970fa924981cc91 Mon Sep 17 00:00:00 2001 From: ealmloff Date: Wed, 3 Jan 2024 14:02:08 -0600 Subject: [PATCH 20/28] fix the on double click event and depreciate ondblclick (#1743) --- examples/all_events.rs | 11 +- examples/todomvc.rs | 89 ++++++++------- packages/desktop/headless_tests/events.rs | 101 ++++++++++++------ .../examples/all_terminal_events.rs | 20 ++-- packages/fullstack/src/hooks/server_cached.rs | 4 +- packages/html/src/events/mouse.rs | 18 +++- packages/web/src/cache.rs | 2 +- 7 files changed, 143 insertions(+), 102 deletions(-) diff --git a/examples/all_events.rs b/examples/all_events.rs index 594a736d5..3f57ec747 100644 --- a/examples/all_events.rs +++ b/examples/all_events.rs @@ -53,8 +53,7 @@ fn app(cx: Scope) -> Element { }; cx.render(rsx! ( - div { - style: "{CONTAINER_STYLE}", + div { style: "{CONTAINER_STYLE}", div { style: "{RECT_STYLE}", // focusing is necessary to catch keyboard events @@ -62,7 +61,7 @@ fn app(cx: Scope) -> Element { onmousemove: move |event| log_event(Event::MouseMove(event)), onclick: move |event| log_event(Event::MouseClick(event)), - ondblclick: move |event| log_event(Event::MouseDoubleClick(event)), + ondoubleclick: move |event| log_event(Event::MouseDoubleClick(event)), onmousedown: move |event| log_event(Event::MouseDown(event)), onmouseup: move |event| log_event(Event::MouseUp(event)), @@ -77,9 +76,7 @@ fn app(cx: Scope) -> Element { "Hover, click, type or scroll to see the info down below" } - div { - events.read().iter().map(|event| rsx!( div { "{event:?}" } )) - }, - }, + div { events.read().iter().map(|event| rsx!( div { "{event:?}" } )) } + } )) } diff --git a/examples/todomvc.rs b/examples/todomvc.rs index 9ec2dc228..0f3fada71 100644 --- a/examples/todomvc.rs +++ b/examples/todomvc.rs @@ -48,11 +48,8 @@ pub fn app(cx: Scope<()>) -> Element { cx.render(rsx! { section { class: "todoapp", style { include_str!("./assets/todomvc.css") } - TodoHeader { - todos: todos, - } - section { - class: "main", + TodoHeader { todos: todos } + section { class: "main", if !todos.is_empty() { rsx! { input { @@ -103,31 +100,34 @@ pub fn TodoHeader<'a>(cx: Scope<'a, TodoHeaderProps<'a>>) -> Element { cx.render(rsx! { header { class: "header", - h1 {"todos"} - input { - class: "new-todo", - placeholder: "What needs to be done?", - value: "{draft}", - autofocus: "true", - oninput: move |evt| { - draft.set(evt.value.clone()); - }, - onkeydown: move |evt| { - if evt.key() == Key::Enter && !draft.is_empty() { - cx.props.todos.make_mut().insert( - **todo_id, - TodoItem { - id: **todo_id, - checked: false, - contents: draft.to_string(), - }, - ); - *todo_id.make_mut() += 1; - draft.set("".to_string()); + h1 { "todos" } + input { + class: "new-todo", + placeholder: "What needs to be done?", + value: "{draft}", + autofocus: "true", + oninput: move |evt| { + draft.set(evt.value.clone()); + }, + onkeydown: move |evt| { + if evt.key() == Key::Enter && !draft.is_empty() { + cx.props + .todos + .make_mut() + .insert( + **todo_id, + TodoItem { + id: **todo_id, + checked: false, + contents: draft.to_string(), + }, + ); + *todo_id.make_mut() += 1; + draft.set("".to_string()); + } } } } - } }) } @@ -146,8 +146,7 @@ pub fn TodoEntry<'a>(cx: Scope<'a, TodoEntryProps<'a>>) -> Element { let editing = if **is_editing { "editing" } else { "" }; cx.render(rsx!{ - li { - class: "{completed} {editing}", + li { class: "{completed} {editing}", div { class: "view", input { class: "toggle", @@ -160,14 +159,16 @@ pub fn TodoEntry<'a>(cx: Scope<'a, TodoEntryProps<'a>>) -> Element { } label { r#for: "cbg-{todo.id}", - ondblclick: move |_| is_editing.set(true), + ondoubleclick: move |_| is_editing.set(true), prevent_default: "onclick", "{todo.contents}" } button { class: "destroy", - onclick: move |_| { cx.props.todos.make_mut().remove(&todo.id); }, - prevent_default: "onclick", + onclick: move |_| { + cx.props.todos.make_mut().remove(&todo.id); + }, + prevent_default: "onclick" } } is_editing.then(|| rsx!{ @@ -213,15 +214,15 @@ pub fn ListFooter<'a>(cx: Scope<'a, ListFooterProps<'a>>) -> Element { cx.render(rsx! { footer { class: "footer", span { class: "todo-count", - strong {"{active_todo_count} "} - span {"{active_todo_text} left"} + strong { "{active_todo_count} " } + span { "{active_todo_text} left" } } ul { class: "filters", - for (state, state_text, url) in [ - (FilterState::All, "All", "#/"), - (FilterState::Active, "Active", "#/active"), - (FilterState::Completed, "Completed", "#/completed"), - ] { + for (state , state_text , url) in [ + (FilterState::All, "All", "#/"), + (FilterState::Active, "Active", "#/active"), + (FilterState::Completed, "Completed", "#/completed"), +] { li { a { href: url, @@ -250,8 +251,14 @@ pub fn PageFooter(cx: Scope) -> Element { cx.render(rsx! { footer { class: "info", p { "Double-click to edit a todo" } - p { "Created by ", a { href: "http://github.com/jkelleyrtp/", "jkelleyrtp" }} - p { "Part of ", a { href: "http://todomvc.com", "TodoMVC" }} + p { + "Created by " + a { href: "http://github.com/jkelleyrtp/", "jkelleyrtp" } + } + p { + "Part of " + a { href: "http://todomvc.com", "TodoMVC" } + } } }) } diff --git a/packages/desktop/headless_tests/events.rs b/packages/desktop/headless_tests/events.rs index ac62cd37b..6d29b6ffa 100644 --- a/packages/desktop/headless_tests/events.rs +++ b/packages/desktop/headless_tests/events.rs @@ -229,75 +229,111 @@ fn app(cx: Scope) -> Element { println!("{:?}", event.data); assert!(event.data.modifiers().is_empty()); assert!(event.data.held_buttons().is_empty()); - assert_eq!(event.data.trigger_button(), Some(dioxus_html::input_data::MouseButton::Primary)); + assert_eq!( + event.data.trigger_button(), + Some(dioxus_html::input_data::MouseButton::Primary), + ); recieved_events.modify(|x| *x + 1) - }, + } } div { id: "mouse_move_div", onmousemove: move |event| { println!("{:?}", event.data); assert!(event.data.modifiers().is_empty()); - assert!(event.data.held_buttons().contains(dioxus_html::input_data::MouseButton::Secondary)); + assert!( + event + .data + .held_buttons() + .contains(dioxus_html::input_data::MouseButton::Secondary), + ); recieved_events.modify(|x| *x + 1) - }, + } } div { id: "mouse_click_div", onclick: move |event| { println!("{:?}", event.data); assert!(event.data.modifiers().is_empty()); - assert!(event.data.held_buttons().contains(dioxus_html::input_data::MouseButton::Secondary)); - assert_eq!(event.data.trigger_button(), Some(dioxus_html::input_data::MouseButton::Secondary)); - recieved_events.modify(|x| *x + 1) - }, - } - div{ - id: "mouse_dblclick_div", - ondblclick: move |event| { - println!("{:?}", event.data); - assert!(event.data.modifiers().is_empty()); - assert!(event.data.held_buttons().contains(dioxus_html::input_data::MouseButton::Primary)); - assert!(event.data.held_buttons().contains(dioxus_html::input_data::MouseButton::Secondary)); - assert_eq!(event.data.trigger_button(), Some(dioxus_html::input_data::MouseButton::Secondary)); + assert!( + event + .data + .held_buttons() + .contains(dioxus_html::input_data::MouseButton::Secondary), + ); + assert_eq!( + event.data.trigger_button(), + Some(dioxus_html::input_data::MouseButton::Secondary), + ); recieved_events.modify(|x| *x + 1) } } - div{ + div { + id: "mouse_dblclick_div", + ondoubleclick: move |event| { + println!("{:?}", event.data); + assert!(event.data.modifiers().is_empty()); + assert!( + event.data.held_buttons().contains(dioxus_html::input_data::MouseButton::Primary), + ); + assert!( + event + .data + .held_buttons() + .contains(dioxus_html::input_data::MouseButton::Secondary), + ); + assert_eq!( + event.data.trigger_button(), + Some(dioxus_html::input_data::MouseButton::Secondary), + ); + recieved_events.modify(|x| *x + 1) + } + } + div { id: "mouse_down_div", onmousedown: move |event| { println!("{:?}", event.data); assert!(event.data.modifiers().is_empty()); - assert!(event.data.held_buttons().contains(dioxus_html::input_data::MouseButton::Secondary)); - assert_eq!(event.data.trigger_button(), Some(dioxus_html::input_data::MouseButton::Secondary)); + assert!( + event + .data + .held_buttons() + .contains(dioxus_html::input_data::MouseButton::Secondary), + ); + assert_eq!( + event.data.trigger_button(), + Some(dioxus_html::input_data::MouseButton::Secondary), + ); recieved_events.modify(|x| *x + 1) } } - div{ + div { id: "mouse_up_div", onmouseup: move |event| { println!("{:?}", event.data); assert!(event.data.modifiers().is_empty()); assert!(event.data.held_buttons().is_empty()); - assert_eq!(event.data.trigger_button(), Some(dioxus_html::input_data::MouseButton::Primary)); + assert_eq!( + event.data.trigger_button(), + Some(dioxus_html::input_data::MouseButton::Primary), + ); recieved_events.modify(|x| *x + 1) } } - div{ + div { id: "wheel_div", width: "100px", height: "100px", background_color: "red", onwheel: move |event| { println!("{:?}", event.data); - let dioxus_html::geometry::WheelDelta::Pixels(delta)= event.data.delta()else{ - panic!("Expected delta to be in pixels") - }; + let dioxus_html::geometry::WheelDelta::Pixels(delta) = event.data.delta() else { + panic!("Expected delta to be in pixels") }; assert_eq!(delta, Vector3D::new(1.0, 2.0, 3.0)); recieved_events.modify(|x| *x + 1) } } - input{ + input { id: "key_down_div", onkeydown: move |event| { println!("{:?}", event.data); @@ -306,11 +342,10 @@ fn app(cx: Scope) -> Element { assert_eq!(event.data.code().to_string(), "KeyA"); assert_eq!(event.data.location, 0); assert!(event.data.is_auto_repeating()); - recieved_events.modify(|x| *x + 1) } } - input{ + input { id: "key_up_div", onkeyup: move |event| { println!("{:?}", event.data); @@ -319,11 +354,10 @@ fn app(cx: Scope) -> Element { assert_eq!(event.data.code().to_string(), "KeyA"); assert_eq!(event.data.location, 0); assert!(!event.data.is_auto_repeating()); - recieved_events.modify(|x| *x + 1) } } - input{ + input { id: "key_press_div", onkeypress: move |event| { println!("{:?}", event.data); @@ -332,18 +366,17 @@ fn app(cx: Scope) -> Element { assert_eq!(event.data.code().to_string(), "KeyA"); assert_eq!(event.data.location, 0); assert!(!event.data.is_auto_repeating()); - recieved_events.modify(|x| *x + 1) } } - input{ + input { id: "focus_in_div", onfocusin: move |event| { println!("{:?}", event.data); recieved_events.modify(|x| *x + 1) } } - input{ + input { id: "focus_out_div", onfocusout: move |event| { println!("{:?}", event.data); diff --git a/packages/dioxus-tui/examples/all_terminal_events.rs b/packages/dioxus-tui/examples/all_terminal_events.rs index 483e9afdf..004578807 100644 --- a/packages/dioxus-tui/examples/all_terminal_events.rs +++ b/packages/dioxus-tui/examples/all_terminal_events.rs @@ -37,7 +37,7 @@ fn app(cx: Scope) -> Element { // todo: remove let mut trimmed = format!("{event:?}"); trimmed.truncate(200); - rsx!(p { "{trimmed}" }) + rsx!( p { "{trimmed}" } ) }); let log_event = move |event: Event| { @@ -45,10 +45,7 @@ fn app(cx: Scope) -> Element { }; cx.render(rsx! { - div { - width: "100%", - height: "100%", - flex_direction: "column", + div { width: "100%", height: "100%", flex_direction: "column", div { width: "80%", height: "50%", @@ -59,7 +56,7 @@ fn app(cx: Scope) -> Element { onmousemove: move |event| log_event(Event::MouseMove(event.inner().clone())), onclick: move |event| log_event(Event::MouseClick(event.inner().clone())), - ondblclick: move |event| log_event(Event::MouseDoubleClick(event.inner().clone())), + ondoubleclick: move |event| log_event(Event::MouseDoubleClick(event.inner().clone())), onmousedown: move |event| log_event(Event::MouseDown(event.inner().clone())), onmouseup: move |event| log_event(Event::MouseUp(event.inner().clone())), @@ -73,13 +70,8 @@ fn app(cx: Scope) -> Element { onfocusout: move |event| log_event(Event::FocusOut(event.inner().clone())), "Hover, click, type or scroll to see the info down below" - }, - div { - width: "80%", - height: "50%", - flex_direction: "column", - events_rendered, - }, - }, + } + div { width: "80%", height: "50%", flex_direction: "column", events_rendered } + } }) } diff --git a/packages/fullstack/src/hooks/server_cached.rs b/packages/fullstack/src/hooks/server_cached.rs index 519f70dae..572efd2b7 100644 --- a/packages/fullstack/src/hooks/server_cached.rs +++ b/packages/fullstack/src/hooks/server_cached.rs @@ -12,9 +12,11 @@ use serde::{de::DeserializeOwned, Serialize}; /// use dioxus_fullstack::prelude::*; /// /// fn app(cx: Scope) -> Element { -/// let state1 = use_state(cx, || from_server(|| { +/// let state1 = use_state(cx, || server_cached(|| { /// 1234 /// })); +/// +/// todo!() /// } /// ``` pub fn server_cached(server_fn: impl Fn() -> O) -> O { diff --git a/packages/html/src/events/mouse.rs b/packages/html/src/events/mouse.rs index 55d081900..ea5bf29d3 100644 --- a/packages/html/src/events/mouse.rs +++ b/packages/html/src/events/mouse.rs @@ -119,10 +119,7 @@ impl_event! { /// oncontextmenu oncontextmenu - /// ondoubleclick - ondoubleclick - - /// ondoubleclick + #[deprecated(since = "0.5.0", note = "use ondoubleclick instead")] ondblclick /// onmousedown @@ -149,6 +146,19 @@ impl_event! { onmouseup } +/// ondoubleclick +#[inline] +pub fn ondoubleclick<'a, E: crate::EventReturn, T>(_cx: &'a ::dioxus_core::ScopeState, mut _f: impl FnMut(::dioxus_core::Event) -> E + 'a) -> ::dioxus_core::Attribute<'a> { + ::dioxus_core::Attribute::new( + "ondblclick", + _cx.listener(move |e: ::dioxus_core::Event| { + _f(e).spawn(_cx); + }), + None, + false, + ) +} + impl MouseData { /// Construct MouseData with the specified properties /// diff --git a/packages/web/src/cache.rs b/packages/web/src/cache.rs index e17203a65..bfd0fd197 100644 --- a/packages/web/src/cache.rs +++ b/packages/web/src/cache.rs @@ -190,7 +190,7 @@ pub static BUILTIN_INTERNED_STRINGS: &[&str] = &[ "oncopy", "oncuechange", "oncut", - "ondblclick", + "ondoubleclick", "ondrag", "ondragend", "ondragenter", From 43d9fe1ab0c626611d787f1d3052738e810db215 Mon Sep 17 00:00:00 2001 From: ealmloff Date: Wed, 3 Jan 2024 14:02:21 -0600 Subject: [PATCH 21/28] Clear the cache on rebuild in the incremental renderer (#1741) --- packages/ssr/src/incremental_cfg.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/ssr/src/incremental_cfg.rs b/packages/ssr/src/incremental_cfg.rs index 1a4ea3418..15a6ad44e 100644 --- a/packages/ssr/src/incremental_cfg.rs +++ b/packages/ssr/src/incremental_cfg.rs @@ -67,6 +67,7 @@ pub struct IncrementalRendererConfig { memory_cache_limit: usize, invalidate_after: Option, map_path: Option, + clear_cache: bool, } impl Default for IncrementalRendererConfig { @@ -83,9 +84,16 @@ impl IncrementalRendererConfig { memory_cache_limit: 10000, invalidate_after: None, map_path: None, + clear_cache: true, } } + /// Clear the cache on startup (default: true) + pub fn clear_cache(mut self, clear_cache: bool) -> Self { + self.clear_cache = clear_cache; + self + } + /// Set a mapping from the route to the file path. This will override the default mapping configured with `static_dir`. /// The function should return the path to the folder to store the index.html file in. pub fn map_path PathBuf + Send + Sync + 'static>(mut self, map_path: F) -> Self { @@ -114,7 +122,7 @@ impl IncrementalRendererConfig { /// Build the incremental renderer. pub fn build(self) -> IncrementalRenderer { let static_dir = self.static_dir.clone(); - IncrementalRenderer { + let mut renderer = IncrementalRenderer { static_dir: self.static_dir.clone(), memory_cache: NonZeroUsize::new(self.memory_cache_limit) .map(|limit| lru::LruCache::with_hasher(limit, Default::default())), @@ -129,6 +137,12 @@ impl IncrementalRendererConfig { path }) }), + }; + + if self.clear_cache { + renderer.invalidate_all(); } + + renderer } } From 2e424436b362d2c72165d6b51a1683fe7d3e7e66 Mon Sep 17 00:00:00 2001 From: ealmloff Date: Wed, 3 Jan 2024 14:02:36 -0600 Subject: [PATCH 22/28] don't remove futures spawned by spawn_forever when the component is removed (#1708) --- packages/core/src/scope_context.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/core/src/scope_context.rs b/packages/core/src/scope_context.rs index 59bed3b1f..eeede6a81 100644 --- a/packages/core/src/scope_context.rs +++ b/packages/core/src/scope_context.rs @@ -230,17 +230,7 @@ impl ScopeContext { /// This is good for tasks that need to be run after the component has been dropped. pub fn spawn_forever(&self, fut: impl Future + 'static) -> TaskId { // The root scope will never be unmounted so we can just add the task at the top of the app - let id = self.tasks.spawn(ScopeId::ROOT, fut); - - // wake up the scheduler if it is sleeping - self.tasks - .sender - .unbounded_send(SchedulerMsg::TaskNotified(id)) - .expect("Scheduler should exist"); - - self.spawned_tasks.borrow_mut().insert(id); - - id + self.tasks.spawn(ScopeId::ROOT, fut) } /// Informs the scheduler that this task is no longer needed and should be removed. From afb258b658f55a1568b8d7c97b617b34f75c1aea Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 3 Jan 2024 15:18:27 -0600 Subject: [PATCH 23/28] Fix elements and attributes mapping for dx translate --- packages/html/Cargo.toml | 1 + packages/html/src/elements.rs | 48 +++++++++++++++++++-- packages/html/src/global_attributes.rs | 46 ++++++++++++++++++++ packages/html/src/lib.rs | 2 + packages/rsx-rosetta/Cargo.toml | 1 + packages/rsx-rosetta/src/lib.rs | 42 +++++++++++++----- packages/rsx-rosetta/tests/h-tags.rs | 33 ++++++++++++++ packages/rsx-rosetta/tests/raw.rs | 21 +++++++++ packages/rsx-rosetta/tests/simple.rs | 4 -- packages/rsx-rosetta/tests/web-component.rs | 21 +++++++++ 10 files changed, 202 insertions(+), 17 deletions(-) create mode 100644 packages/rsx-rosetta/tests/h-tags.rs create mode 100644 packages/rsx-rosetta/tests/raw.rs create mode 100644 packages/rsx-rosetta/tests/web-component.rs diff --git a/packages/html/Cargo.toml b/packages/html/Cargo.toml index 5644b440c..d12f7cf52 100644 --- a/packages/html/Cargo.toml +++ b/packages/html/Cargo.toml @@ -68,3 +68,4 @@ mounted = [ wasm-bind = ["web-sys", "wasm-bindgen"] native-bind = ["tokio"] hot-reload-context = ["dioxus-rsx"] +html-to-rsx = [] diff --git a/packages/html/src/elements.rs b/packages/html/src/elements.rs index a42c01950..03231c0e9 100644 --- a/packages/html/src/elements.rs +++ b/packages/html/src/elements.rs @@ -79,6 +79,25 @@ macro_rules! impl_attribute_match { }; } +#[cfg(feature = "html-to-rsx")] +macro_rules! impl_html_to_rsx_attribute_match { + ( + $attr:ident $fil:ident $name:literal + ) => { + if $attr == $name { + return Some(stringify!($fil)); + } + }; + + ( + $attr:ident $fil:ident $_:tt + ) => { + if $attr == stringify!($fil) { + return Some(stringify!($fil)); + } + }; +} + macro_rules! impl_element { ( $(#[$attr:meta])* @@ -316,6 +335,30 @@ macro_rules! builder_constructors { } } + #[cfg(feature = "html-to-rsx")] + pub fn map_html_attribute_to_rsx(html: &str) -> Option<&'static str> { + $( + $( + impl_html_to_rsx_attribute_match!( + html $fil $extra + ); + )* + )* + + None + } + + #[cfg(feature = "html-to-rsx")] + pub fn map_html_element_to_rsx(html: &str) -> Option<&'static str> { + $( + if html == stringify!($name) { + return Some(stringify!($name)); + } + )* + + None + } + $( impl_element!( $(#[$attr])* @@ -998,9 +1041,8 @@ builder_constructors! { src: Uri DEFAULT, text: String DEFAULT, - // r#async: Bool, - // r#type: String, // TODO could be an enum - r#type: String "type", + r#async: Bool "async", + r#type: String "type", // TODO could be an enum r#script: String "script", }; diff --git a/packages/html/src/global_attributes.rs b/packages/html/src/global_attributes.rs index 02b0b32ed..639026b33 100644 --- a/packages/html/src/global_attributes.rs +++ b/packages/html/src/global_attributes.rs @@ -33,12 +33,44 @@ macro_rules! trait_method_mapping { }; } +#[cfg(feature = "html-to-rsx")] +macro_rules! html_to_rsx_attribute_mapping { + ( + $matching:ident; + $(#[$attr:meta])* + $name:ident; + ) => { + if $matching == stringify!($name) { + return Some(stringify!($name)); + } + }; + ( + $matching:ident; + $(#[$attr:meta])* + $name:ident: $lit:literal; + ) => { + if $matching == stringify!($lit) { + return Some(stringify!($name)); + } + }; + ( + $matching:ident; + $(#[$attr:meta])* + $name:ident: $lit:literal, $ns:literal; + ) => { + if $matching == stringify!($lit) { + return Some(stringify!($name)); + } + }; +} + macro_rules! trait_methods { ( @base $(#[$trait_attr:meta])* $trait:ident; $fn:ident; + $fn_html_to_rsx:ident; $( $(#[$attr:meta])* $name:ident $(: $($arg:literal),*)*; @@ -62,6 +94,18 @@ macro_rules! trait_methods { )* None } + + #[cfg(feature = "html-to-rsx")] + #[doc = "Converts an HTML attribute to an RSX attribute"] + pub(crate) fn $fn_html_to_rsx(html: &str) -> Option<&'static str> { + $( + html_to_rsx_attribute_mapping! { + html; + $name$(: $($arg),*)*; + } + )* + None + } }; // Rename the incoming ident and apply a custom namespace @@ -79,6 +123,7 @@ trait_methods! { GlobalAttributes; map_global_attributes; + map_html_global_attributes_to_rsx; /// Prevent the default action for this element. /// @@ -1593,6 +1638,7 @@ trait_methods! { @base SvgAttributes; map_svg_attributes; + map_html_svg_attributes_to_rsx; /// Prevent the default action for this element. /// diff --git a/packages/html/src/lib.rs b/packages/html/src/lib.rs index 6dd7c42bd..c44777801 100644 --- a/packages/html/src/lib.rs +++ b/packages/html/src/lib.rs @@ -19,6 +19,8 @@ mod elements; #[cfg(feature = "hot-reload-context")] pub use elements::HtmlCtx; +#[cfg(feature = "html-to-rsx")] +pub use elements::{map_html_attribute_to_rsx, map_html_element_to_rsx}; pub mod events; pub mod geometry; mod global_attributes; diff --git a/packages/rsx-rosetta/Cargo.toml b/packages/rsx-rosetta/Cargo.toml index ab5d4e882..9cd53b02f 100644 --- a/packages/rsx-rosetta/Cargo.toml +++ b/packages/rsx-rosetta/Cargo.toml @@ -15,6 +15,7 @@ keywords = ["dom", "ui", "gui", "react"] [dependencies] dioxus-autofmt = { workspace = true } dioxus-rsx = { workspace = true } +dioxus-html = { workspace = true, features = ["html-to-rsx"]} html_parser.workspace = true proc-macro2 = "1.0.49" quote = "1.0.23" diff --git a/packages/rsx-rosetta/src/lib.rs b/packages/rsx-rosetta/src/lib.rs index 3c11f3a90..e12c6f021 100644 --- a/packages/rsx-rosetta/src/lib.rs +++ b/packages/rsx-rosetta/src/lib.rs @@ -2,6 +2,7 @@ #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] +use dioxus_html::{map_html_element_to_rsx, map_html_attribute_to_rsx}; use convert_case::{Case, Casing}; use dioxus_rsx::{ BodyNode, CallBody, Component, Element, ElementAttr, ElementAttrNamed, ElementName, IfmtInput, @@ -24,26 +25,47 @@ pub fn rsx_node_from_html(node: &Node) -> Option { match node { Node::Text(text) => Some(BodyNode::Text(ifmt_from_text(text))), Node::Element(el) => { - let el_name = el.name.to_case(Case::Snake); - let el_name = ElementName::Ident(Ident::new(el_name.as_str(), Span::call_site())); + let el_name = if let Some(name) = map_html_element_to_rsx(&el.name) { + ElementName::Ident(Ident::new(name, Span::call_site())) + } else { + // if we don't recognize it and it has a dash, we assume it's a web component + if el.name.contains('-') { + ElementName::Custom(LitStr::new(&el.name, Span::call_site())) + } else { + // otherwise, it might be an element that isn't supported yet + ElementName::Ident(Ident::new( + &el.name.to_case(Case::Snake), + Span::call_site(), + )) + } + }; let mut attributes: Vec<_> = el .attributes .iter() .map(|(name, value)| { - let ident = if matches!(name.as_str(), "for" | "async" | "type" | "as") { - Ident::new_raw(name.as_str(), Span::call_site()) + let value = ifmt_from_text(value.as_deref().unwrap_or("false")); + let attr = if let Some(name) = map_html_attribute_to_rsx(name) { + let ident = if let Some(name) = name.strip_prefix("r#") { + Ident::new_raw(name, Span::call_site()) + } else { + Ident::new(name, Span::call_site()) + }; + ElementAttr::AttrText { + value, + name: ident, + } } else { - let new_name = name.to_case(Case::Snake); - Ident::new(new_name.as_str(), Span::call_site()) + // If we don't recognize the attribute, we assume it's a custom attribute + ElementAttr::CustomAttrText { + value, + name: LitStr::new(name, Span::call_site()), + } }; ElementAttrNamed { el_name: el_name.clone(), - attr: ElementAttr::AttrText { - value: ifmt_from_text(value.as_deref().unwrap_or("false")), - name: ident, - }, + attr } }) .collect(); diff --git a/packages/rsx-rosetta/tests/h-tags.rs b/packages/rsx-rosetta/tests/h-tags.rs new file mode 100644 index 000000000..eb179c57f --- /dev/null +++ b/packages/rsx-rosetta/tests/h-tags.rs @@ -0,0 +1,33 @@ +use html_parser::Dom; + +#[test] +fn h_tags_translate() { + let html = r#" +
+

hello world!

+

hello world!

+

hello world!

+

hello world!

+
hello world!
+
hello world!
+
+ "# + .trim(); + + let dom = Dom::parse(html).unwrap(); + + let body = rsx_rosetta::rsx_from_html(&dom); + + let out = dioxus_autofmt::write_block_out(body).unwrap(); + + let expected = r#" + div { + h1 { "hello world!" } + h2 { "hello world!" } + h3 { "hello world!" } + h4 { "hello world!" } + h5 { "hello world!" } + h6 { "hello world!" } + }"#; + pretty_assertions::assert_eq!(&out, &expected); +} diff --git a/packages/rsx-rosetta/tests/raw.rs b/packages/rsx-rosetta/tests/raw.rs new file mode 100644 index 000000000..a3ed1eef8 --- /dev/null +++ b/packages/rsx-rosetta/tests/raw.rs @@ -0,0 +1,21 @@ +use html_parser::Dom; + +#[test] +fn raw_attribute() { + let html = r#" +
+
hello world!
+
+ "# + .trim(); + + let dom = Dom::parse(html).unwrap(); + + let body = rsx_rosetta::rsx_from_html(&dom); + + let out = dioxus_autofmt::write_block_out(body).unwrap(); + + let expected = r#" + div { div { "unrecognizedattribute": "asd", "hello world!" } }"#; + pretty_assertions::assert_eq!(&out, &expected); +} diff --git a/packages/rsx-rosetta/tests/simple.rs b/packages/rsx-rosetta/tests/simple.rs index b8fd095e1..3f3f8230a 100644 --- a/packages/rsx-rosetta/tests/simple.rs +++ b/packages/rsx-rosetta/tests/simple.rs @@ -9,8 +9,6 @@ fn simple_elements() {
hello world!
hello world!
hello world!
-
hello world!
- hello world!
"# .trim(); @@ -28,8 +26,6 @@ fn simple_elements() { div { id: "asd", "hello world!" } div { r#for: "asd", "hello world!" } div { r#async: "asd", "hello world!" } - div { large_thing: "asd", "hello world!" } - ai_is_awesome { "hello world!" } }"#; pretty_assertions::assert_eq!(&out, &expected); } diff --git a/packages/rsx-rosetta/tests/web-component.rs b/packages/rsx-rosetta/tests/web-component.rs new file mode 100644 index 000000000..c7309e1b7 --- /dev/null +++ b/packages/rsx-rosetta/tests/web-component.rs @@ -0,0 +1,21 @@ +use html_parser::Dom; + +#[test] +fn web_components_translate() { + let html = r#" +
+ +
+ "# + .trim(); + + let dom = Dom::parse(html).unwrap(); + + let body = rsx_rosetta::rsx_from_html(&dom); + + let out = dioxus_autofmt::write_block_out(body).unwrap(); + + let expected = r#" + div { my-component {} }"#; + pretty_assertions::assert_eq!(&out, &expected); +} From bc557906fe798e0bd1403fb609d7a5e6eb5b62be Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 3 Jan 2024 15:18:37 -0600 Subject: [PATCH 24/28] fix formatting --- packages/fullstack/src/hooks/server_cached.rs | 2 +- packages/html/src/events/mouse.rs | 5 ++++- packages/rsx-rosetta/src/lib.rs | 14 ++++---------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/packages/fullstack/src/hooks/server_cached.rs b/packages/fullstack/src/hooks/server_cached.rs index 572efd2b7..b3f9113b5 100644 --- a/packages/fullstack/src/hooks/server_cached.rs +++ b/packages/fullstack/src/hooks/server_cached.rs @@ -15,7 +15,7 @@ use serde::{de::DeserializeOwned, Serialize}; /// let state1 = use_state(cx, || server_cached(|| { /// 1234 /// })); -/// +/// /// todo!() /// } /// ``` diff --git a/packages/html/src/events/mouse.rs b/packages/html/src/events/mouse.rs index ea5bf29d3..17128f4e4 100644 --- a/packages/html/src/events/mouse.rs +++ b/packages/html/src/events/mouse.rs @@ -148,7 +148,10 @@ impl_event! { /// ondoubleclick #[inline] -pub fn ondoubleclick<'a, E: crate::EventReturn, T>(_cx: &'a ::dioxus_core::ScopeState, mut _f: impl FnMut(::dioxus_core::Event) -> E + 'a) -> ::dioxus_core::Attribute<'a> { +pub fn ondoubleclick<'a, E: crate::EventReturn, T>( + _cx: &'a ::dioxus_core::ScopeState, + mut _f: impl FnMut(::dioxus_core::Event) -> E + 'a, +) -> ::dioxus_core::Attribute<'a> { ::dioxus_core::Attribute::new( "ondblclick", _cx.listener(move |e: ::dioxus_core::Event| { diff --git a/packages/rsx-rosetta/src/lib.rs b/packages/rsx-rosetta/src/lib.rs index e12c6f021..49b6b6fc7 100644 --- a/packages/rsx-rosetta/src/lib.rs +++ b/packages/rsx-rosetta/src/lib.rs @@ -2,8 +2,8 @@ #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] -use dioxus_html::{map_html_element_to_rsx, map_html_attribute_to_rsx}; use convert_case::{Case, Casing}; +use dioxus_html::{map_html_attribute_to_rsx, map_html_element_to_rsx}; use dioxus_rsx::{ BodyNode, CallBody, Component, Element, ElementAttr, ElementAttrNamed, ElementName, IfmtInput, }; @@ -33,10 +33,7 @@ pub fn rsx_node_from_html(node: &Node) -> Option { ElementName::Custom(LitStr::new(&el.name, Span::call_site())) } else { // otherwise, it might be an element that isn't supported yet - ElementName::Ident(Ident::new( - &el.name.to_case(Case::Snake), - Span::call_site(), - )) + ElementName::Ident(Ident::new(&el.name.to_case(Case::Snake), Span::call_site())) } }; @@ -51,10 +48,7 @@ pub fn rsx_node_from_html(node: &Node) -> Option { } else { Ident::new(name, Span::call_site()) }; - ElementAttr::AttrText { - value, - name: ident, - } + ElementAttr::AttrText { value, name: ident } } else { // If we don't recognize the attribute, we assume it's a custom attribute ElementAttr::CustomAttrText { @@ -65,7 +59,7 @@ pub fn rsx_node_from_html(node: &Node) -> Option { ElementAttrNamed { el_name: el_name.clone(), - attr + attr, } }) .collect(); From 422df68fea099edbf93f3e345dac05552c549801 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 3 Jan 2024 15:35:24 -0600 Subject: [PATCH 25/28] fix formatting --- packages/fullstack/src/hooks/server_cached.rs | 2 +- packages/html/src/events/mouse.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/fullstack/src/hooks/server_cached.rs b/packages/fullstack/src/hooks/server_cached.rs index 572efd2b7..b3f9113b5 100644 --- a/packages/fullstack/src/hooks/server_cached.rs +++ b/packages/fullstack/src/hooks/server_cached.rs @@ -15,7 +15,7 @@ use serde::{de::DeserializeOwned, Serialize}; /// let state1 = use_state(cx, || server_cached(|| { /// 1234 /// })); -/// +/// /// todo!() /// } /// ``` diff --git a/packages/html/src/events/mouse.rs b/packages/html/src/events/mouse.rs index ea5bf29d3..17128f4e4 100644 --- a/packages/html/src/events/mouse.rs +++ b/packages/html/src/events/mouse.rs @@ -148,7 +148,10 @@ impl_event! { /// ondoubleclick #[inline] -pub fn ondoubleclick<'a, E: crate::EventReturn, T>(_cx: &'a ::dioxus_core::ScopeState, mut _f: impl FnMut(::dioxus_core::Event) -> E + 'a) -> ::dioxus_core::Attribute<'a> { +pub fn ondoubleclick<'a, E: crate::EventReturn, T>( + _cx: &'a ::dioxus_core::ScopeState, + mut _f: impl FnMut(::dioxus_core::Event) -> E + 'a, +) -> ::dioxus_core::Attribute<'a> { ::dioxus_core::Attribute::new( "ondblclick", _cx.listener(move |e: ::dioxus_core::Event| { From 682beeccfd87ba1f6e06fd2d5b17bfcff9797253 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 3 Jan 2024 15:45:19 -0600 Subject: [PATCH 26/28] fallback to global attributes when mapping rsx rosetta html attribute names --- packages/html/src/elements.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/html/src/elements.rs b/packages/html/src/elements.rs index 03231c0e9..ca3f4aee7 100644 --- a/packages/html/src/elements.rs +++ b/packages/html/src/elements.rs @@ -345,6 +345,14 @@ macro_rules! builder_constructors { )* )* + if let Some(name) = crate::map_html_global_attributes_to_rsx(html) { + return Some(name); + } + + if let Some(name) = crate::map_html_svg_attributes_to_rsx(html) { + return Some(name); + } + None } From c56d3662e973f60b05ba06e29a38cfe1b34b1ff5 Mon Sep 17 00:00:00 2001 From: ealmloff Date: Thu, 4 Jan 2024 09:06:38 -0600 Subject: [PATCH 27/28] document the type name as optional in the server function docs (#1748) --- packages/server-macro/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server-macro/src/lib.rs b/packages/server-macro/src/lib.rs index 5ad9a682b..871de33bc 100644 --- a/packages/server-macro/src/lib.rs +++ b/packages/server-macro/src/lib.rs @@ -19,7 +19,7 @@ use syn::{ /// are enabled), it will instead make a network request to the server. /// /// You can specify one, two, or three arguments to the server function: -/// 1. **Required**: A type name that will be used to identify and register the server function +/// 1. *Optional*: A type name that will be used to identify and register the server function /// (e.g., `MyServerFn`). /// 2. *Optional*: A URL prefix at which the function will be mounted when it’s registered /// (e.g., `"/api"`). Defaults to `"/"`. From f913b2ce53483b9c352d0ba633e665d7017eb10b Mon Sep 17 00:00:00 2001 From: ealmloff Date: Thu, 4 Jan 2024 09:06:57 -0600 Subject: [PATCH 28/28] don't cache assets in the CLI (#1742) --- packages/cli/src/server/web/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/server/web/mod.rs b/packages/cli/src/server/web/mod.rs index 0e1413597..98ff1e078 100644 --- a/packages/cli/src/server/web/mod.rs +++ b/packages/cli/src/server/web/mod.rs @@ -11,6 +11,7 @@ use axum::{ body::{Full, HttpBody}, extract::{ws::Message, Extension, TypedHeader, WebSocketUpgrade}, http::{ + self, header::{HeaderName, HeaderValue}, Method, Response, StatusCode, }, @@ -262,7 +263,7 @@ async fn setup_router( .override_response_header(HeaderName::from_static("cross-origin-opener-policy"), coop) .and_then( move |response: Response| async move { - let response = if file_service_config + let mut response = if file_service_config .dioxus_config .web .watcher @@ -290,6 +291,13 @@ async fn setup_router( } else { response.map(|body| body.boxed()) }; + let headers = response.headers_mut(); + headers.insert( + http::header::CACHE_CONTROL, + HeaderValue::from_static("no-cache"), + ); + headers.insert(http::header::PRAGMA, HeaderValue::from_static("no-cache")); + headers.insert(http::header::EXPIRES, HeaderValue::from_static("0")); Ok(response) }, )