From 3d8d8a1b6f5b197205293a697a79a64e17b5bd00 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 19 Jul 2023 10:19:23 -0700 Subject: [PATCH 1/7] half-build-times --- packages/autofmt/Cargo.toml | 4 +- packages/autofmt/src/collect_macros.rs | 21 +- packages/autofmt/src/component.rs | 2 +- packages/autofmt/src/lib.rs | 6 +- packages/autofmt/src/writer.rs | 2 +- packages/cli/Cargo.toml | 2 +- packages/core-macro/Cargo.toml | 2 +- packages/core-macro/src/inlineprops.rs | 2 +- packages/core-macro/src/props/mod.rs | 64 ++-- packages/hot-reload/Cargo.toml | 18 +- packages/hot-reload/src/file_watcher.rs | 352 +++++++++++++++++ packages/hot-reload/src/lib.rs | 356 +----------------- packages/html/Cargo.toml | 2 +- packages/native-core-macro/Cargo.toml | 2 +- packages/native-core-macro/src/lib.rs | 2 +- packages/router-macro/Cargo.toml | 2 +- packages/router-macro/src/lib.rs | 14 +- packages/router-macro/src/route.rs | 6 +- packages/rsx-rosetta/Cargo.toml | 2 +- packages/rsx/Cargo.toml | 12 +- packages/rsx/src/error.rs | 13 +- .../rsx/src/hot_reload/hot_reload_diff.rs | 39 +- packages/rsx/src/lib.rs | 18 +- packages/rsx/src/node.rs | 2 +- 24 files changed, 489 insertions(+), 456 deletions(-) create mode 100644 packages/hot-reload/src/file_watcher.rs diff --git a/packages/autofmt/Cargo.toml b/packages/autofmt/Cargo.toml index 254b60093..c658a9f42 100644 --- a/packages/autofmt/Cargo.toml +++ b/packages/autofmt/Cargo.toml @@ -14,9 +14,9 @@ keywords = ["dom", "ui", "gui", "react"] dioxus-rsx = { workspace = true } proc-macro2 = { version = "1.0.6", features = ["span-locations"] } quote = "1.0" -syn = { version = "1.0.11", features = ["full", "extra-traits"] } +syn = { version = "2.0", features = ["full", "extra-traits"] } serde = { version = "1.0.136", features = ["derive"] } -prettyplease = { package = "prettier-please", version = "0.1.16", features = [ +prettyplease = { package = "prettier-please", version = "0.2", features = [ "verbatim", ] } diff --git a/packages/autofmt/src/collect_macros.rs b/packages/autofmt/src/collect_macros.rs index ebb6314e2..9c65fae39 100644 --- a/packages/autofmt/src/collect_macros.rs +++ b/packages/autofmt/src/collect_macros.rs @@ -5,6 +5,8 @@ use proc_macro2::LineColumn; use syn::{Block, Expr, File, Item, Macro, Stmt}; +use crate::expr; + type CollectedMacro<'a> = &'a Macro; pub fn collect_from_file<'a>(file: &'a File, macros: &mut Vec>) { @@ -42,7 +44,7 @@ pub fn collect_from_item<'a>(item: &'a Item, macros: &mut Vec } // None of these we can really do anything with at the item level - Item::Macro2(_) + Item::Macro(_) | Item::Enum(_) | Item::ExternCrate(_) | Item::ForeignMod(_) @@ -61,11 +63,18 @@ pub fn collect_from_block<'a>(block: &'a Block, macros: &mut Vec collect_from_item(item, macros), Stmt::Local(local) => { - if let Some((_eq, init)) = &local.init { - collect_from_expr(init, macros); + if let Some(init) = &local.init { + collect_from_expr(&init.expr, macros); + } + } + Stmt::Expr(expr, _) => collect_from_expr(expr, macros), + Stmt::Macro(mac) => { + if mac.mac.path.segments[0].ident == "rsx" + || mac.mac.path.segments[0].ident == "render" + { + macros.push(&mac.mac); } } - Stmt::Expr(exp) | Stmt::Semi(exp, _) => collect_from_expr(exp, macros), } } } @@ -147,10 +156,9 @@ pub fn collect_from_expr<'a>(expr: &'a Expr, macros: &mut Vec // don't both formatting these for now Expr::Array(_) - | Expr::AssignOp(_) + | Expr::Assign(_) | Expr::Await(_) | Expr::Binary(_) - | Expr::Box(_) | Expr::Break(_) | Expr::Cast(_) | Expr::Continue(_) @@ -167,7 +175,6 @@ pub fn collect_from_expr<'a>(expr: &'a Expr, macros: &mut Vec | Expr::Try(_) | Expr::TryBlock(_) | Expr::Tuple(_) - | Expr::Type(_) | Expr::Unary(_) | Expr::Verbatim(_) => {} diff --git a/packages/autofmt/src/component.rs b/packages/autofmt/src/component.rs index d5d92b79a..7b507e7bd 100644 --- a/packages/autofmt/src/component.rs +++ b/packages/autofmt/src/component.rs @@ -176,7 +176,7 @@ impl Writer<'_> { )?; } ContentField::OnHandlerRaw(exp) => { - let out = prettyplease::unparse_expr(exp); + let out = prettyplease::unparse(exp); let mut lines = out.split('\n').peekable(); let first = lines.next().unwrap(); write!(self.out, "{name}: {first}")?; diff --git a/packages/autofmt/src/lib.rs b/packages/autofmt/src/lib.rs index 0d2426a0b..f878a800a 100644 --- a/packages/autofmt/src/lib.rs +++ b/packages/autofmt/src/lib.rs @@ -88,9 +88,9 @@ pub fn fmt_file(contents: &str) -> Vec { } let span = match item.delimiter { - MacroDelimiter::Paren(b) => b.span, - MacroDelimiter::Brace(b) => b.span, - MacroDelimiter::Bracket(b) => b.span, + MacroDelimiter::Paren(b) => b.span.open(), + MacroDelimiter::Brace(b) => b.span.open(), + MacroDelimiter::Bracket(b) => b.span.open(), }; let mut formatted = String::new(); diff --git a/packages/autofmt/src/writer.rs b/packages/autofmt/src/writer.rs index 59f135592..fae3313a8 100644 --- a/packages/autofmt/src/writer.rs +++ b/packages/autofmt/src/writer.rs @@ -197,7 +197,7 @@ impl<'a> Writer<'a> { self.out, "for {} in {} {{", forloop.pat.clone().into_token_stream(), - prettyplease::unparse_expr(&forloop.expr) + prettyplease::unparse_expr(&*forloop.expr) )?; if forloop.body.is_empty() { diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index 3aa741615..a88b6df18 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -57,7 +57,7 @@ flate2 = "1.0.22" tar = "0.4.38" zip = "0.6.2" tower = "0.4.12" -syn = { version = "1.0", features = ["full", "extra-traits"] } +syn = { version = "2.0", features = ["full", "extra-traits"] } proc-macro2 = { version = "1.0", features = ["span-locations"] } lazy_static = "1.4.0" diff --git a/packages/core-macro/Cargo.toml b/packages/core-macro/Cargo.toml index 92408725a..b99b1c359 100644 --- a/packages/core-macro/Cargo.toml +++ b/packages/core-macro/Cargo.toml @@ -15,7 +15,7 @@ proc-macro = true [dependencies] proc-macro2 = { version = "1.0" } quote = "1.0" -syn = { version = "1.0", features = ["full", "extra-traits"] } +syn = { version = "2.0", features = ["full", "extra-traits"] } dioxus-rsx = { workspace = true } # testing diff --git a/packages/core-macro/src/inlineprops.rs b/packages/core-macro/src/inlineprops.rs index 814724b56..ccc00f4f9 100644 --- a/packages/core-macro/src/inlineprops.rs +++ b/packages/core-macro/src/inlineprops.rs @@ -135,7 +135,7 @@ impl ToTokens for InlinePropsBody { quote! { <#struct_generics> }, ) } else { - let lifetime: LifetimeDef = parse_quote! { 'a }; + let lifetime: LifetimeParam = parse_quote! { 'a }; let mut fn_generics = generics.clone(); fn_generics diff --git a/packages/core-macro/src/props/mod.rs b/packages/core-macro/src/props/mod.rs index 5f3de9dc9..523caf911 100644 --- a/packages/core-macro/src/props/mod.rs +++ b/packages/core-macro/src/props/mod.rs @@ -166,8 +166,9 @@ mod field_info { use crate::props::type_from_inside_option; use proc_macro2::TokenStream; use quote::quote; - use syn::parse::Error; use syn::spanned::Spanned; + use syn::Expr; + use syn::{parse::Error, punctuated::Punctuated}; use super::util::{ expr_to_single_string, ident_to_type, path_to_single_string, strip_raw_ident_prefix, @@ -260,31 +261,32 @@ mod field_info { pub fn with(mut self, attrs: &[syn::Attribute]) -> Result { let mut skip_tokens = None; for attr in attrs { - if path_to_single_string(&attr.path).as_deref() != Some("props") { + if path_to_single_string(attr.path()).as_deref() != Some("props") { continue; } - if attr.tokens.is_empty() { - continue; - } - - let as_expr: syn::Expr = syn::parse2(attr.tokens.clone())?; - match as_expr { - syn::Expr::Paren(body) => { - self.apply_meta(*body.expr)?; - } - syn::Expr::Tuple(body) => { - for expr in body.elems.into_iter() { - self.apply_meta(expr)?; + match &attr.meta { + syn::Meta::List(list) => { + if list.tokens.is_empty() { + continue; } } _ => { - return Err(Error::new_spanned(attr.tokens.clone(), "Expected (<...>)")); + continue; } } + + let as_expr = attr.parse_args_with( + Punctuated::::parse_separated_nonempty, + )?; + + for expr in as_expr.into_iter() { + self.apply_meta(expr)?; + } + // Stash its span for later (we don’t yet know if it’ll be an error) if self.skip && skip_tokens.is_none() { - skip_tokens = Some(attr.tokens.clone()); + skip_tokens = Some(attr.meta.clone()); } } @@ -461,6 +463,8 @@ mod struct_info { use proc_macro2::TokenStream; use quote::quote; use syn::parse::Error; + use syn::punctuated::Punctuated; + use syn::Expr; use super::field_info::{FieldBuilderAttr, FieldInfo}; use super::util::{ @@ -1082,28 +1086,28 @@ Finally, call `.build()` to create the instance of `{name}`. pub fn new(attrs: &[syn::Attribute]) -> Result { let mut result = TypeBuilderAttr::default(); for attr in attrs { - if path_to_single_string(&attr.path).as_deref() != Some("builder") { + if path_to_single_string(&attr.path()).as_deref() != Some("builder") { continue; } - if attr.tokens.is_empty() { - continue; - } - let as_expr: syn::Expr = syn::parse2(attr.tokens.clone())?; - - match as_expr { - syn::Expr::Paren(body) => { - result.apply_meta(*body.expr)?; - } - syn::Expr::Tuple(body) => { - for expr in body.elems.into_iter() { - result.apply_meta(expr)?; + match &attr.meta { + syn::Meta::List(list) => { + if list.tokens.is_empty() { + continue; } } _ => { - return Err(Error::new_spanned(attr.tokens.clone(), "Expected (<...>)")); + continue; } } + + let as_expr = attr.parse_args_with( + Punctuated::::parse_separated_nonempty, + )?; + + for expr in as_expr.into_iter() { + result.apply_meta(expr)?; + } } Ok(result) diff --git a/packages/hot-reload/Cargo.toml b/packages/hot-reload/Cargo.toml index c16dd5468..625fcae8a 100644 --- a/packages/hot-reload/Cargo.toml +++ b/packages/hot-reload/Cargo.toml @@ -5,19 +5,23 @@ edition = "2021" license = "MIT/Apache-2.0" repository = "https://github.com/DioxusLabs/dioxus/" homepage = "https://dioxuslabs.com/docs/0.3/guide/en/getting_started/hot_reload.html" -description = "Hot reloading utilites for Dioxus" +description = "Hot reloading utilities for Dioxus" keywords = ["dom", "ui", "gui", "react", "hot-reloading"] [dependencies] dioxus-rsx = { workspace = true } dioxus-core = { workspace = true, features = ["serialize"] } -dioxus-html = { workspace = true, features = ["hot-reload-context"] } +dioxus-html = { workspace = true } interprocess-docfix = { version = "1.2.2" } -notify = "5.0.0" -chrono = { version = "0.4.24", default-features = false, features = ["clock"] } +notify = { version = "5.0.0", optional = true } +chrono = { version = "0.4.24", default-features = false, features = ["clock"], optional = true } serde_json = "1.0.91" serde = { version = "1", features = ["derive"] } -execute = "0.2.11" -once_cell = "1.17.0" -ignore = "0.4.19" +execute = { version = "0.2.11", optional = true } +once_cell = { version = "1.17.0", optional = true } +ignore = { version = "0.4.19", optional = true } + +[features] +default = [] +file_watcher = ["ignore", "chrono", "notify", "execute", "once_cell", "ignore", "dioxus-html/hot-reload-context"] diff --git a/packages/hot-reload/src/file_watcher.rs b/packages/hot-reload/src/file_watcher.rs new file mode 100644 index 000000000..dd9b22f5f --- /dev/null +++ b/packages/hot-reload/src/file_watcher.rs @@ -0,0 +1,352 @@ +use std::{ + io::{BufRead, BufReader, Write}, + path::PathBuf, + str::FromStr, + sync::{Arc, Mutex}, +}; + +use dioxus_core::Template; +use dioxus_rsx::{ + hot_reload::{FileMap, FileMapBuildResult, UpdateResult}, + HotReloadingContext, +}; +use interprocess_docfix::local_socket::{LocalSocketListener, LocalSocketStream}; +use notify::{RecommendedWatcher, RecursiveMode, Watcher}; + +pub use dioxus_html::HtmlCtx; +use serde::{Deserialize, Serialize}; + +pub struct Config { + root_path: &'static str, + listening_paths: &'static [&'static str], + excluded_paths: &'static [&'static str], + log: bool, + rebuild_with: Option bool + Send + 'static>>, + phantom: std::marker::PhantomData, +} + +impl Default for Config { + fn default() -> Self { + Self { + root_path: "", + listening_paths: &[""], + excluded_paths: &["./target"], + log: true, + rebuild_with: None, + phantom: std::marker::PhantomData, + } + } +} + +impl Config { + pub const fn new() -> Self { + Self { + root_path: "", + listening_paths: &[""], + excluded_paths: &["./target"], + log: true, + rebuild_with: None, + phantom: std::marker::PhantomData, + } + } +} + +impl Config { + /// Set the root path of the project (where the Cargo.toml file is). This is automatically set by the [`hot_reload_init`] macro. + pub fn root(self, path: &'static str) -> Self { + Self { + root_path: path, + ..self + } + } + + /// Set whether to enable logs + pub fn with_logging(self, log: bool) -> Self { + Self { log, ..self } + } + + /// Set the command to run to rebuild the project + /// + /// For example to restart the application after a change is made, you could use `cargo run` + pub fn with_rebuild_command(self, rebuild_command: &'static str) -> Self { + self.with_rebuild_callback(move || { + execute::shell(rebuild_command) + .spawn() + .expect("Failed to spawn the rebuild command"); + true + }) + } + + /// Set a callback to run to when the project needs to be rebuilt and returns if the server should shut down + /// + /// For example a CLI application could rebuild the application when a change is made + pub fn with_rebuild_callback( + self, + rebuild_callback: impl FnMut() -> bool + Send + 'static, + ) -> Self { + Self { + rebuild_with: Some(Box::new(rebuild_callback)), + ..self + } + } + + /// Set the paths to listen for changes in to trigger hot reloading. If this is a directory it will listen for changes in all files in that directory recursively. + pub fn with_paths(self, paths: &'static [&'static str]) -> Self { + Self { + listening_paths: paths, + ..self + } + } + + /// Sets paths to ignore changes on. This will override any paths set in the [`Config::with_paths`] method in the case of conflicts. + pub fn excluded_paths(self, paths: &'static [&'static str]) -> Self { + Self { + excluded_paths: paths, + ..self + } + } +} + +/// Initialize the hot reloading listener +pub fn init(cfg: Config) { + let Config { + root_path, + listening_paths, + log, + mut rebuild_with, + excluded_paths, + phantom: _, + } = cfg; + + if let Ok(crate_dir) = PathBuf::from_str(root_path) { + // try to find the gitingore file + let gitignore_file_path = crate_dir.join(".gitignore"); + let (gitignore, _) = ignore::gitignore::Gitignore::new(gitignore_file_path); + + // convert the excluded paths to absolute paths + let excluded_paths = excluded_paths + .iter() + .map(|path| crate_dir.join(PathBuf::from(path))) + .collect::>(); + + let channels = Arc::new(Mutex::new(Vec::new())); + let FileMapBuildResult { + map: file_map, + errors, + } = FileMap::::create_with_filter(crate_dir.clone(), |path| { + // skip excluded paths + excluded_paths.iter().any(|p| path.starts_with(p)) || + // respect .gitignore + gitignore + .matched_path_or_any_parents(path, path.is_dir()) + .is_ignore() + }) + .unwrap(); + for err in errors { + if log { + println!("hot reloading failed to initialize:\n{err:?}"); + } + } + let file_map = Arc::new(Mutex::new(file_map)); + + #[cfg(target_os = "macos")] + { + // On unix, if you force quit the application, it can leave the file socket open + // This will cause the local socket listener to fail to open + // We check if the file socket is already open from an old session and then delete it + let paths = ["./dioxusin", "./@dioxusin"]; + for path in paths { + let path = PathBuf::from(path); + if path.exists() { + let _ = std::fs::remove_file(path); + } + } + } + + match LocalSocketListener::bind("@dioxusin") { + Ok(local_socket_stream) => { + let aborted = Arc::new(Mutex::new(false)); + + // listen for connections + std::thread::spawn({ + let file_map = file_map.clone(); + let channels = channels.clone(); + let aborted = aborted.clone(); + let _ = local_socket_stream.set_nonblocking(true); + move || { + loop { + if let Ok(mut connection) = local_socket_stream.accept() { + // send any templates than have changed before the socket connected + let templates: Vec<_> = { + file_map + .lock() + .unwrap() + .map + .values() + .filter_map(|(_, template_slot)| *template_slot) + .collect() + }; + for template in templates { + if !send_msg( + HotReloadMsg::UpdateTemplate(template), + &mut connection, + ) { + continue; + } + } + channels.lock().unwrap().push(connection); + if log { + println!("Connected to hot reloading 🚀"); + } + } + if *aborted.lock().unwrap() { + break; + } + } + } + }); + + // watch for changes + std::thread::spawn(move || { + let mut last_update_time = chrono::Local::now().timestamp(); + + let (tx, rx) = std::sync::mpsc::channel(); + + let mut watcher = + RecommendedWatcher::new(tx, notify::Config::default()).unwrap(); + + for path in listening_paths { + let full_path = crate_dir.join(path); + if let Err(err) = watcher.watch(&full_path, RecursiveMode::Recursive) { + if log { + println!( + "hot reloading failed to start watching {full_path:?}:\n{err:?}", + ); + } + } + } + + let mut rebuild = { + let aborted = aborted.clone(); + let channels = channels.clone(); + move || { + if let Some(rebuild_callback) = &mut rebuild_with { + if log { + println!("Rebuilding the application..."); + } + let shutdown = rebuild_callback(); + + if shutdown { + *aborted.lock().unwrap() = true; + } + + for channel in &mut *channels.lock().unwrap() { + send_msg(HotReloadMsg::Shutdown, channel); + } + + return shutdown; + } else if log { + println!( + "Rebuild needed... shutting down hot reloading.\nManually rebuild the application to view futher changes." + ); + } + true + } + }; + + for evt in rx { + if chrono::Local::now().timestamp_millis() >= last_update_time { + if let Ok(evt) = evt { + let real_paths = evt + .paths + .iter() + .filter(|path| { + // skip non rust files + matches!( + path.extension().and_then(|p| p.to_str()), + Some("rs" | "toml" | "css" | "html" | "js") + ) && + // skip excluded paths + !excluded_paths.iter().any(|p| path.starts_with(p)) && + // respect .gitignore + !gitignore + .matched_path_or_any_parents(path, false) + .is_ignore() + }) + .collect::>(); + + // Give time for the change to take effect before reading the file + if !real_paths.is_empty() { + std::thread::sleep(std::time::Duration::from_millis(10)); + } + + let mut channels = channels.lock().unwrap(); + for path in real_paths { + // if this file type cannot be hot reloaded, rebuild the application + if path.extension().and_then(|p| p.to_str()) != Some("rs") + && rebuild() + { + return; + } + // find changes to the rsx in the file + match file_map + .lock() + .unwrap() + .update_rsx(path, crate_dir.as_path()) + { + Ok(UpdateResult::UpdatedRsx(msgs)) => { + for msg in msgs { + let mut i = 0; + while i < channels.len() { + let channel = &mut channels[i]; + if send_msg( + HotReloadMsg::UpdateTemplate(msg), + channel, + ) { + i += 1; + } else { + channels.remove(i); + } + } + } + } + Ok(UpdateResult::NeedsRebuild) => { + drop(channels); + if rebuild() { + return; + } + break; + } + Err(err) => { + if log { + println!( + "hot reloading failed to update rsx:\n{err:?}" + ); + } + } + } + } + } + last_update_time = chrono::Local::now().timestamp_millis(); + } + } + }); + } + Err(error) => println!("failed to connect to hot reloading\n{error}"), + } + } +} + +fn send_msg(msg: HotReloadMsg, channel: &mut impl Write) -> bool { + if let Ok(msg) = serde_json::to_string(&msg) { + if channel.write_all(msg.as_bytes()).is_err() { + return false; + } + if channel.write_all(&[b'\n']).is_err() { + return false; + } + true + } else { + false + } +} diff --git a/packages/hot-reload/src/lib.rs b/packages/hot-reload/src/lib.rs index 48ee50a59..f70f61da9 100644 --- a/packages/hot-reload/src/lib.rs +++ b/packages/hot-reload/src/lib.rs @@ -1,21 +1,16 @@ -use std::{ - io::{BufRead, BufReader, Write}, - path::PathBuf, - str::FromStr, - sync::{Arc, Mutex}, -}; +use std::io::{BufRead, BufReader}; use dioxus_core::Template; -use dioxus_rsx::{ - hot_reload::{FileMap, FileMapBuildResult, UpdateResult}, - HotReloadingContext, -}; -use interprocess_docfix::local_socket::{LocalSocketListener, LocalSocketStream}; -use notify::{RecommendedWatcher, RecursiveMode, Watcher}; - +#[cfg(file_watcher)] pub use dioxus_html::HtmlCtx; +use interprocess_docfix::local_socket::LocalSocketStream; use serde::{Deserialize, Serialize}; +#[cfg(file_watcher)] +mod file_watcher; +#[cfg(file_watcher)] +use file_watcher::*; + /// A message the hot reloading server sends to the client #[derive(Debug, Serialize, Deserialize, Clone, Copy)] pub enum HotReloadMsg { @@ -26,341 +21,6 @@ pub enum HotReloadMsg { Shutdown, } -pub struct Config { - root_path: &'static str, - listening_paths: &'static [&'static str], - excluded_paths: &'static [&'static str], - log: bool, - rebuild_with: Option bool + Send + 'static>>, - phantom: std::marker::PhantomData, -} - -impl Default for Config { - fn default() -> Self { - Self { - root_path: "", - listening_paths: &[""], - excluded_paths: &["./target"], - log: true, - rebuild_with: None, - phantom: std::marker::PhantomData, - } - } -} - -impl Config { - pub const fn new() -> Self { - Self { - root_path: "", - listening_paths: &[""], - excluded_paths: &["./target"], - log: true, - rebuild_with: None, - phantom: std::marker::PhantomData, - } - } -} - -impl Config { - /// Set the root path of the project (where the Cargo.toml file is). This is automatically set by the [`hot_reload_init`] macro. - pub fn root(self, path: &'static str) -> Self { - Self { - root_path: path, - ..self - } - } - - /// Set whether to enable logs - pub fn with_logging(self, log: bool) -> Self { - Self { log, ..self } - } - - /// Set the command to run to rebuild the project - /// - /// For example to restart the application after a change is made, you could use `cargo run` - pub fn with_rebuild_command(self, rebuild_command: &'static str) -> Self { - self.with_rebuild_callback(move || { - execute::shell(rebuild_command) - .spawn() - .expect("Failed to spawn the rebuild command"); - true - }) - } - - /// Set a callback to run to when the project needs to be rebuilt and returns if the server should shut down - /// - /// For example a CLI application could rebuild the application when a change is made - pub fn with_rebuild_callback( - self, - rebuild_callback: impl FnMut() -> bool + Send + 'static, - ) -> Self { - Self { - rebuild_with: Some(Box::new(rebuild_callback)), - ..self - } - } - - /// Set the paths to listen for changes in to trigger hot reloading. If this is a directory it will listen for changes in all files in that directory recursively. - pub fn with_paths(self, paths: &'static [&'static str]) -> Self { - Self { - listening_paths: paths, - ..self - } - } - - /// Sets paths to ignore changes on. This will override any paths set in the [`Config::with_paths`] method in the case of conflicts. - pub fn excluded_paths(self, paths: &'static [&'static str]) -> Self { - Self { - excluded_paths: paths, - ..self - } - } -} - -/// Initialize the hot reloading listener -pub fn init(cfg: Config) { - let Config { - root_path, - listening_paths, - log, - mut rebuild_with, - excluded_paths, - phantom: _, - } = cfg; - - if let Ok(crate_dir) = PathBuf::from_str(root_path) { - // try to find the gitingore file - let gitignore_file_path = crate_dir.join(".gitignore"); - let (gitignore, _) = ignore::gitignore::Gitignore::new(gitignore_file_path); - - // convert the excluded paths to absolute paths - let excluded_paths = excluded_paths - .iter() - .map(|path| crate_dir.join(PathBuf::from(path))) - .collect::>(); - - let channels = Arc::new(Mutex::new(Vec::new())); - let FileMapBuildResult { - map: file_map, - errors, - } = FileMap::::create_with_filter(crate_dir.clone(), |path| { - // skip excluded paths - excluded_paths.iter().any(|p| path.starts_with(p)) || - // respect .gitignore - gitignore - .matched_path_or_any_parents(path, path.is_dir()) - .is_ignore() - }) - .unwrap(); - for err in errors { - if log { - println!("hot reloading failed to initialize:\n{err:?}"); - } - } - let file_map = Arc::new(Mutex::new(file_map)); - - #[cfg(target_os = "macos")] - { - // On unix, if you force quit the application, it can leave the file socket open - // This will cause the local socket listener to fail to open - // We check if the file socket is already open from an old session and then delete it - let paths = ["./dioxusin", "./@dioxusin"]; - for path in paths { - let path = PathBuf::from(path); - if path.exists() { - let _ = std::fs::remove_file(path); - } - } - } - - match LocalSocketListener::bind("@dioxusin") { - Ok(local_socket_stream) => { - let aborted = Arc::new(Mutex::new(false)); - - // listen for connections - std::thread::spawn({ - let file_map = file_map.clone(); - let channels = channels.clone(); - let aborted = aborted.clone(); - let _ = local_socket_stream.set_nonblocking(true); - move || { - loop { - if let Ok(mut connection) = local_socket_stream.accept() { - // send any templates than have changed before the socket connected - let templates: Vec<_> = { - file_map - .lock() - .unwrap() - .map - .values() - .filter_map(|(_, template_slot)| *template_slot) - .collect() - }; - for template in templates { - if !send_msg( - HotReloadMsg::UpdateTemplate(template), - &mut connection, - ) { - continue; - } - } - channels.lock().unwrap().push(connection); - if log { - println!("Connected to hot reloading 🚀"); - } - } - if *aborted.lock().unwrap() { - break; - } - } - } - }); - - // watch for changes - std::thread::spawn(move || { - let mut last_update_time = chrono::Local::now().timestamp(); - - let (tx, rx) = std::sync::mpsc::channel(); - - let mut watcher = - RecommendedWatcher::new(tx, notify::Config::default()).unwrap(); - - for path in listening_paths { - let full_path = crate_dir.join(path); - if let Err(err) = watcher.watch(&full_path, RecursiveMode::Recursive) { - if log { - println!( - "hot reloading failed to start watching {full_path:?}:\n{err:?}", - ); - } - } - } - - let mut rebuild = { - let aborted = aborted.clone(); - let channels = channels.clone(); - move || { - if let Some(rebuild_callback) = &mut rebuild_with { - if log { - println!("Rebuilding the application..."); - } - let shutdown = rebuild_callback(); - - if shutdown { - *aborted.lock().unwrap() = true; - } - - for channel in &mut *channels.lock().unwrap() { - send_msg(HotReloadMsg::Shutdown, channel); - } - - return shutdown; - } else if log { - println!( - "Rebuild needed... shutting down hot reloading.\nManually rebuild the application to view futher changes." - ); - } - true - } - }; - - for evt in rx { - if chrono::Local::now().timestamp_millis() >= last_update_time { - if let Ok(evt) = evt { - let real_paths = evt - .paths - .iter() - .filter(|path| { - // skip non rust files - matches!( - path.extension().and_then(|p| p.to_str()), - Some("rs" | "toml" | "css" | "html" | "js") - ) && - // skip excluded paths - !excluded_paths.iter().any(|p| path.starts_with(p)) && - // respect .gitignore - !gitignore - .matched_path_or_any_parents(path, false) - .is_ignore() - }) - .collect::>(); - - // Give time for the change to take effect before reading the file - if !real_paths.is_empty() { - std::thread::sleep(std::time::Duration::from_millis(10)); - } - - let mut channels = channels.lock().unwrap(); - for path in real_paths { - // if this file type cannot be hot reloaded, rebuild the application - if path.extension().and_then(|p| p.to_str()) != Some("rs") - && rebuild() - { - return; - } - // find changes to the rsx in the file - match file_map - .lock() - .unwrap() - .update_rsx(path, crate_dir.as_path()) - { - Ok(UpdateResult::UpdatedRsx(msgs)) => { - for msg in msgs { - let mut i = 0; - while i < channels.len() { - let channel = &mut channels[i]; - if send_msg( - HotReloadMsg::UpdateTemplate(msg), - channel, - ) { - i += 1; - } else { - channels.remove(i); - } - } - } - } - Ok(UpdateResult::NeedsRebuild) => { - drop(channels); - if rebuild() { - return; - } - break; - } - Err(err) => { - if log { - println!( - "hot reloading failed to update rsx:\n{err:?}" - ); - } - } - } - } - } - last_update_time = chrono::Local::now().timestamp_millis(); - } - } - }); - } - Err(error) => println!("failed to connect to hot reloading\n{error}"), - } - } -} - -fn send_msg(msg: HotReloadMsg, channel: &mut impl Write) -> bool { - if let Ok(msg) = serde_json::to_string(&msg) { - if channel.write_all(msg.as_bytes()).is_err() { - return false; - } - if channel.write_all(&[b'\n']).is_err() { - return false; - } - true - } else { - false - } -} - /// Connect to the hot reloading listener. The callback provided will be called every time a template change is detected pub fn connect(mut f: impl FnMut(HotReloadMsg) + Send + 'static) { std::thread::spawn(move || { diff --git a/packages/html/Cargo.toml b/packages/html/Cargo.toml index a44b22a77..27c4a7cd6 100644 --- a/packages/html/Cargo.toml +++ b/packages/html/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["dom", "ui", "gui", "react"] [dependencies] dioxus-core = { workspace = true } -dioxus-rsx = { workspace = true, optional = true } +dioxus-rsx = { workspace = true, features = ["hot_reload"], optional = true } serde = { version = "1", features = ["derive"], optional = true } serde_repr = { version = "0.1", optional = true } wasm-bindgen = { workspace = true, optional = true } diff --git a/packages/native-core-macro/Cargo.toml b/packages/native-core-macro/Cargo.toml index 82b2dc4a6..ab53c20f2 100644 --- a/packages/native-core-macro/Cargo.toml +++ b/packages/native-core-macro/Cargo.toml @@ -12,7 +12,7 @@ keywords = ["dom", "ui", "gui", "react"] proc-macro = true [dependencies] -syn = { version = "1.0.11", features = ["extra-traits", "full"] } +syn = { version = "2.0", features = ["extra-traits", "full"] } quote = "1.0" [dev-dependencies] diff --git a/packages/native-core-macro/src/lib.rs b/packages/native-core-macro/src/lib.rs index ff0e4629d..d122838bd 100644 --- a/packages/native-core-macro/src/lib.rs +++ b/packages/native-core-macro/src/lib.rs @@ -14,7 +14,7 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream { let has_create_fn = impl_block .items .iter() - .any(|item| matches!(item, syn::ImplItem::Method(method) if method.sig.ident == "create")); + .any(|item| matches!(item, syn::ImplItem::Fn(method) if method.sig.ident == "create")); let parent_dependencies = impl_block .items diff --git a/packages/router-macro/Cargo.toml b/packages/router-macro/Cargo.toml index 3b7a48aeb..9e23fdf86 100644 --- a/packages/router-macro/Cargo.toml +++ b/packages/router-macro/Cargo.toml @@ -15,7 +15,7 @@ keywords = ["dom", "ui", "gui", "react", "router"] proc-macro = true [dependencies] -syn = { version = "1.0.11", features = ["extra-traits", "full"] } +syn = { version = "2.0", features = ["extra-traits", "full"] } quote = "1.0" proc-macro2 = "1.0.56" slab = "0.4" diff --git a/packages/router-macro/src/lib.rs b/packages/router-macro/src/lib.rs index f8c9cff1d..708aa6891 100644 --- a/packages/router-macro/src/lib.rs +++ b/packages/router-macro/src/lib.rs @@ -286,7 +286,7 @@ impl RouteEnum { let mut excluded = Vec::new(); // Apply the any nesting attributes in order for attr in &variant.attrs { - if attr.path.is_ident("nest") { + if attr.path().is_ident("nest") { let mut children_routes = Vec::new(); { // add all of the variants of the enum to the children_routes until we hit an end_nest @@ -294,9 +294,9 @@ impl RouteEnum { 'o: for variant in &data.variants { children_routes.push(variant.fields.clone()); for attr in &variant.attrs { - if attr.path.is_ident("nest") { + if attr.path().is_ident("nest") { level += 1; - } else if attr.path.is_ident("end_nest") { + } else if attr.path().is_ident("end_nest") { level -= 1; if level < 0 { break 'o; @@ -341,7 +341,7 @@ impl RouteEnum { nests.push(nest); nest_stack.push(NestId(nest_index)); - } else if attr.path.is_ident("end_nest") { + } else if attr.path().is_ident("end_nest") { nest_stack.pop(); // pop the current nest segment off the stack and add it to the parent or the site map if let Some(segment) = site_map_stack.pop() { @@ -360,7 +360,7 @@ impl RouteEnum { children.push(current); } - } else if attr.path.is_ident("layout") { + } else if attr.path().is_ident("layout") { let parser = |input: ParseStream| { let bang: Option = input.parse().ok(); let exclude = bang.is_some(); @@ -382,9 +382,9 @@ impl RouteEnum { layouts.push(layout); layout_stack.push(LayoutId(layout_index)); } - } else if attr.path.is_ident("end_layout") { + } else if attr.path().is_ident("end_layout") { layout_stack.pop(); - } else if attr.path.is_ident("redirect") { + } else if attr.path().is_ident("redirect") { let parser = |input: ParseStream| { Redirect::parse(input, nest_stack.clone(), redirects.len()) }; diff --git a/packages/router-macro/src/route.rs b/packages/router-macro/src/route.rs index ad8c74857..af6d7136f 100644 --- a/packages/router-macro/src/route.rs +++ b/packages/router-macro/src/route.rs @@ -75,7 +75,7 @@ impl Route { let route_attr = variant .attrs .iter() - .find(|attr| attr.path.is_ident("route")); + .find(|attr| attr.path().is_ident("route")); let route; let ty; let route_name = variant.ident.clone(); @@ -106,7 +106,7 @@ impl Route { if let Some(route_attr) = variant .attrs .iter() - .find(|attr| attr.path.is_ident("child")) + .find(|attr| attr.path().is_ident("child")) { let args = route_attr.parse_args::()?; route = args.route.value(); @@ -116,7 +116,7 @@ impl Route { let child_field = fields.named.iter().find(|f| { f.attrs .iter() - .any(|attr| attr.path.is_ident("child")) + .any(|attr| attr.path().is_ident("child")) || *f.ident.as_ref().unwrap() == "child" }); match child_field{ diff --git a/packages/rsx-rosetta/Cargo.toml b/packages/rsx-rosetta/Cargo.toml index eef6b2499..4d443d433 100644 --- a/packages/rsx-rosetta/Cargo.toml +++ b/packages/rsx-rosetta/Cargo.toml @@ -18,7 +18,7 @@ dioxus-rsx = { workspace = true } html_parser.workspace = true proc-macro2 = "1.0.49" quote = "1.0.23" -syn = { version = "1.0.107", features = ["full"] } +syn = { version = "2.0", features = ["full"] } convert_case = "0.5.0" # [features] diff --git a/packages/rsx/Cargo.toml b/packages/rsx/Cargo.toml index d4b997187..996262e66 100644 --- a/packages/rsx/Cargo.toml +++ b/packages/rsx/Cargo.toml @@ -14,8 +14,12 @@ keywords = ["dom", "ui", "gui", "react"] [dependencies] proc-macro2 = { version = "1.0", features = ["span-locations"] } dioxus-core = { workspace = true} -syn = { version = "1.0", features = ["full", "extra-traits"] } +syn = { version = "2.0", features = ["full", "extra-traits"] } quote = { version = "1.0" } -serde = { version = "1.0", features = ["derive"] } -internment = "0.7.0" -krates = "0.12.6" \ No newline at end of file +serde = { version = "1.0", features = ["derive"], optional = true } +internment = { version = "0.7.0", optional = true } +krates = { version = "0.12.6", optional = true } + +[features] +hot_reload = ["krates", "internment"] +serde = ["dep:serde"] diff --git a/packages/rsx/src/error.rs b/packages/rsx/src/error.rs index e75331066..16651fe5a 100644 --- a/packages/rsx/src/error.rs +++ b/packages/rsx/src/error.rs @@ -1,15 +1,18 @@ use std::fmt::Display; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; /// An error produced when interperting the rsx -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Error { ParseError(ParseError), RecompileRequiredError(RecompileReason), } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum RecompileReason { Variable(String), Expression(String), @@ -18,14 +21,16 @@ pub enum RecompileReason { Attribute(String), } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct CodeLocation { pub line: u32, pub column: u32, pub file_path: &'static str, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ParseError { pub message: String, pub location: CodeLocation, diff --git a/packages/rsx/src/hot_reload/hot_reload_diff.rs b/packages/rsx/src/hot_reload/hot_reload_diff.rs index ea9918f99..22a01875d 100644 --- a/packages/rsx/src/hot_reload/hot_reload_diff.rs +++ b/packages/rsx/src/hot_reload/hot_reload_diff.rs @@ -85,7 +85,7 @@ fn find_rsx_item( (syn::ImplItem::Const(new_item), syn::ImplItem::Const(old_item)) => { find_rsx_expr(&new_item.expr, &old_item.expr, rsx_calls) } - (syn::ImplItem::Method(new_item), syn::ImplItem::Method(old_item)) => { + (syn::ImplItem::Fn(new_item), syn::ImplItem::Fn(old_item)) => { find_rsx_block(&new_item.block, &old_item.block, rsx_calls) } (syn::ImplItem::Type(new_item), syn::ImplItem::Type(old_item)) => { @@ -114,7 +114,6 @@ fn find_rsx_item( || new_item.semi_token != old_item.semi_token || new_item.ident != old_item.ident } - (syn::Item::Macro2(new_item), syn::Item::Macro2(old_item)) => old_item != new_item, (syn::Item::Mod(new_item), syn::Item::Mod(old_item)) => { match (&new_item.content, &old_item.content) { (Some((_, new_items)), Some((_, old_items))) => { @@ -186,7 +185,7 @@ fn find_rsx_trait( true } } - (syn::TraitItem::Method(new_item), syn::TraitItem::Method(old_item)) => { + (syn::TraitItem::Fn(new_item), syn::TraitItem::Fn(old_item)) => { if let (Some(new_block), Some(old_block)) = (&new_item.default, &old_item.default) { find_rsx_block(new_block, old_block, rsx_calls) } else { @@ -239,8 +238,9 @@ fn find_rsx_stmt( match (new_stmt, old_stmt) { (syn::Stmt::Local(new_local), syn::Stmt::Local(old_local)) => { (match (&new_local.init, &old_local.init) { - (Some((new_eq, new_expr)), Some((old_eq, old_expr))) => { - find_rsx_expr(new_expr, old_expr, rsx_calls) || new_eq != old_eq + (Some(new_local), Some(old_local)) => { + find_rsx_expr(&new_local.expr, &old_local.expr, rsx_calls) + || new_local != old_local } (None, None) => false, _ => true, @@ -252,11 +252,13 @@ fn find_rsx_stmt( (syn::Stmt::Item(new_item), syn::Stmt::Item(old_item)) => { find_rsx_item(new_item, old_item, rsx_calls) } - (syn::Stmt::Expr(new_expr), syn::Stmt::Expr(old_expr)) => { + (syn::Stmt::Expr(new_expr, _), syn::Stmt::Expr(old_expr, _)) => { find_rsx_expr(new_expr, old_expr, rsx_calls) } - (syn::Stmt::Semi(new_expr, new_semi), syn::Stmt::Semi(old_expr, old_semi)) => { - find_rsx_expr(new_expr, old_expr, rsx_calls) || new_semi != old_semi + (syn::Stmt::Macro(new_macro), syn::Stmt::Macro(old_macro)) => { + find_rsx_macro(&new_macro.mac, &old_macro.mac, rsx_calls) + || new_macro.attrs != old_macro.attrs + || new_macro.semi_token != old_macro.semi_token } _ => true, } @@ -285,12 +287,6 @@ fn find_rsx_expr( || new_expr.attrs != old_expr.attrs || new_expr.eq_token != old_expr.eq_token } - (syn::Expr::AssignOp(new_expr), syn::Expr::AssignOp(old_expr)) => { - find_rsx_expr(&new_expr.left, &old_expr.left, rsx_calls) - || find_rsx_expr(&new_expr.right, &old_expr.right, rsx_calls) - || new_expr.attrs != old_expr.attrs - || new_expr.op != old_expr.op - } (syn::Expr::Async(new_expr), syn::Expr::Async(old_expr)) => { find_rsx_block(&new_expr.block, &old_expr.block, rsx_calls) || new_expr.attrs != old_expr.attrs @@ -314,11 +310,6 @@ fn find_rsx_expr( || new_expr.attrs != old_expr.attrs || new_expr.label != old_expr.label } - (syn::Expr::Box(new_expr), syn::Expr::Box(old_expr)) => { - find_rsx_expr(&new_expr.expr, &old_expr.expr, rsx_calls) - || new_expr.attrs != old_expr.attrs - || new_expr.box_token != old_expr.box_token - } (syn::Expr::Break(new_expr), syn::Expr::Break(old_expr)) => { match (&new_expr.expr, &old_expr.expr) { (Some(new_inner), Some(old_inner)) => { @@ -478,7 +469,7 @@ fn find_rsx_expr( } (syn::Expr::Path(new_expr), syn::Expr::Path(old_expr)) => old_expr != new_expr, (syn::Expr::Range(new_expr), syn::Expr::Range(old_expr)) => { - match (&new_expr.from, &old_expr.from) { + match (&new_expr.start, &old_expr.start) { (Some(new_expr), Some(old_expr)) => { if find_rsx_expr(new_expr, old_expr, rsx_calls) { return true; @@ -487,7 +478,7 @@ fn find_rsx_expr( (None, None) => (), _ => return true, } - match (&new_expr.to, &old_expr.to) { + match (&new_expr.end, &old_expr.end) { (Some(new_inner), Some(old_inner)) => { find_rsx_expr(new_inner, old_inner, rsx_calls) || new_expr.attrs != old_expr.attrs @@ -568,12 +559,6 @@ fn find_rsx_expr( } new_expr.attrs != old_expr.attrs || new_expr.paren_token != old_expr.paren_token } - (syn::Expr::Type(new_expr), syn::Expr::Type(old_expr)) => { - find_rsx_expr(&new_expr.expr, &old_expr.expr, rsx_calls) - || new_expr.attrs != old_expr.attrs - || new_expr.colon_token != old_expr.colon_token - || new_expr.ty != old_expr.ty - } (syn::Expr::Unary(new_expr), syn::Expr::Unary(old_expr)) => { find_rsx_expr(&new_expr.expr, &old_expr.expr, rsx_calls) || new_expr.attrs != old_expr.attrs diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index 41156e87e..1f01fcd72 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -15,18 +15,22 @@ mod errors; mod component; mod element; +#[cfg(feature = "hot_reload")] pub mod hot_reload; mod ifmt; mod node; -use std::{collections::HashMap, fmt::Debug, hash::Hash}; +use std::{fmt::Debug, hash::Hash}; // Re-export the namespaces into each other pub use component::*; +#[cfg(feature = "hot_reload")] use dioxus_core::{Template, TemplateAttribute, TemplateNode}; pub use element::*; +#[cfg(feature = "hot_reload")] pub use hot_reload::HotReloadingContext; pub use ifmt::*; +#[cfg(feature = "hot_reload")] use internment::Intern; pub use node::*; @@ -38,6 +42,7 @@ use syn::{ Result, Token, }; +#[cfg(feature = "hot_reload")] // interns a object into a static object, resusing the value if it already exists fn intern(s: impl Into>) -> &'static T { s.into().as_ref() @@ -50,6 +55,7 @@ pub struct CallBody { } impl CallBody { + #[cfg(feature = "hot_reload")] /// This will try to create a new template from the current body and the previous body. This will return None if the rsx has some dynamic part that has changed. /// This function intentionally leaks memory to create a static template. /// Keeping the template static allows us to simplify the core of dioxus and leaking memory in dev mode is less of an issue. @@ -140,6 +146,7 @@ pub struct TemplateRenderer<'a> { } impl<'a> TemplateRenderer<'a> { + #[cfg(feature = "hot_reload")] fn update_template( &mut self, previous_call: Option, @@ -248,14 +255,16 @@ impl<'a> ToTokens for TemplateRenderer<'a> { } } +#[cfg(feature = "hot_reload")] #[derive(Default, Debug)] struct DynamicMapping { - attribute_to_idx: HashMap>, + attribute_to_idx: std::collections::HashMap>, last_attribute_idx: usize, - node_to_idx: HashMap>, + node_to_idx: std::collections::HashMap>, last_element_idx: usize, } +#[cfg(feature = "hot_reload")] impl DynamicMapping { fn from(nodes: Vec) -> Self { let mut new = Self::default(); @@ -349,6 +358,7 @@ pub struct DynamicContext<'a> { } impl<'a> DynamicContext<'a> { + #[cfg(feature = "hot_reload")] fn update_node( &mut self, root: &'a BodyNode, @@ -558,6 +568,7 @@ impl<'a> DynamicContext<'a> { } } +#[cfg(feature = "hot_reload")] #[test] fn create_template() { let input = quote! { @@ -643,6 +654,7 @@ fn create_template() { ) } +#[cfg(feature = "hot_reload")] #[test] fn diff_template() { use dioxus_core::Scope; diff --git a/packages/rsx/src/node.rs b/packages/rsx/src/node.rs index 91651430d..1bda081d9 100644 --- a/packages/rsx/src/node.rs +++ b/packages/rsx/src/node.rs @@ -222,7 +222,7 @@ impl Parse for ForLoop { fn parse(input: ParseStream) -> Result { let for_token: Token![for] = input.parse()?; - let pat = input.parse()?; + let pat = Pat::parse_single(input)?; let in_token: Token![in] = input.parse()?; let expr: Expr = input.call(Expr::parse_without_eager_brace)?; From 0f3606ea53a3ea3bd7dd769a898ac5ab06dc13dc Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 19 Jul 2023 10:21:37 -0700 Subject: [PATCH 2/7] use git prettyplease temporarily --- packages/autofmt/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/autofmt/Cargo.toml b/packages/autofmt/Cargo.toml index c658a9f42..88a500432 100644 --- a/packages/autofmt/Cargo.toml +++ b/packages/autofmt/Cargo.toml @@ -16,7 +16,7 @@ proc-macro2 = { version = "1.0.6", features = ["span-locations"] } quote = "1.0" syn = { version = "2.0", features = ["full", "extra-traits"] } serde = { version = "1.0.136", features = ["derive"] } -prettyplease = { package = "prettier-please", version = "0.2", features = [ +prettyplease = { package = "prettier-please", git = "https://github.com/Demonthos/prettier-please", features = [ "verbatim", ] } From 05a1ea403f174eb2ef31f7a833b866af6f077ee7 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 19 Jul 2023 10:33:23 -0700 Subject: [PATCH 3/7] use published prettier-please --- packages/autofmt/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/autofmt/Cargo.toml b/packages/autofmt/Cargo.toml index 88a500432..c658a9f42 100644 --- a/packages/autofmt/Cargo.toml +++ b/packages/autofmt/Cargo.toml @@ -16,7 +16,7 @@ proc-macro2 = { version = "1.0.6", features = ["span-locations"] } quote = "1.0" syn = { version = "2.0", features = ["full", "extra-traits"] } serde = { version = "1.0.136", features = ["derive"] } -prettyplease = { package = "prettier-please", git = "https://github.com/Demonthos/prettier-please", features = [ +prettyplease = { package = "prettier-please", version = "0.2", features = [ "verbatim", ] } From c9d00908ec14db385c6b380b64ebc0a61ba26739 Mon Sep 17 00:00:00 2001 From: ealmloff Date: Wed, 19 Jul 2023 15:00:10 -0500 Subject: [PATCH 4/7] Update component.rs --- packages/autofmt/src/component.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/autofmt/src/component.rs b/packages/autofmt/src/component.rs index 7b507e7bd..d5d92b79a 100644 --- a/packages/autofmt/src/component.rs +++ b/packages/autofmt/src/component.rs @@ -176,7 +176,7 @@ impl Writer<'_> { )?; } ContentField::OnHandlerRaw(exp) => { - let out = prettyplease::unparse(exp); + let out = prettyplease::unparse_expr(exp); let mut lines = out.split('\n').peekable(); let first = lines.next().unwrap(); write!(self.out, "{name}: {first}")?; From 6639011a3eb15edbe11fa74c4d90668e36920038 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 19 Jul 2023 13:43:04 -0700 Subject: [PATCH 5/7] fix autofmt --- packages/autofmt/src/collect_macros.rs | 6 +----- packages/autofmt/src/lib.rs | 9 +++++---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/autofmt/src/collect_macros.rs b/packages/autofmt/src/collect_macros.rs index 9c65fae39..6494b4bfe 100644 --- a/packages/autofmt/src/collect_macros.rs +++ b/packages/autofmt/src/collect_macros.rs @@ -5,8 +5,6 @@ use proc_macro2::LineColumn; use syn::{Block, Expr, File, Item, Macro, Stmt}; -use crate::expr; - type CollectedMacro<'a> = &'a Macro; pub fn collect_from_file<'a>(file: &'a File, macros: &mut Vec>) { @@ -44,8 +42,7 @@ pub fn collect_from_item<'a>(item: &'a Item, macros: &mut Vec } // None of these we can really do anything with at the item level - Item::Macro(_) - | Item::Enum(_) + Item::Enum(_) | Item::ExternCrate(_) | Item::ForeignMod(_) | Item::TraitAlias(_) @@ -156,7 +153,6 @@ pub fn collect_from_expr<'a>(expr: &'a Expr, macros: &mut Vec // don't both formatting these for now Expr::Array(_) - | Expr::Assign(_) | Expr::Await(_) | Expr::Binary(_) | Expr::Break(_) diff --git a/packages/autofmt/src/lib.rs b/packages/autofmt/src/lib.rs index f878a800a..7d98fb222 100644 --- a/packages/autofmt/src/lib.rs +++ b/packages/autofmt/src/lib.rs @@ -88,10 +88,11 @@ pub fn fmt_file(contents: &str) -> Vec { } let span = match item.delimiter { - MacroDelimiter::Paren(b) => b.span.open(), - MacroDelimiter::Brace(b) => b.span.open(), - MacroDelimiter::Bracket(b) => b.span.open(), - }; + MacroDelimiter::Paren(b) => b.span, + MacroDelimiter::Brace(b) => b.span, + MacroDelimiter::Bracket(b) => b.span, + } + .join(); let mut formatted = String::new(); From 1f19ac9334b0c87720584fed1b7ff9746022693a Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 19 Jul 2023 13:45:47 -0700 Subject: [PATCH 6/7] bump sledgehammer bindgen --- packages/interpreter/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/interpreter/Cargo.toml b/packages/interpreter/Cargo.toml index dd310ce41..7c6796829 100644 --- a/packages/interpreter/Cargo.toml +++ b/packages/interpreter/Cargo.toml @@ -15,7 +15,7 @@ wasm-bindgen = { workspace = true, optional = true } js-sys = { version = "0.3.56", optional = true } web-sys = { version = "0.3.56", optional = true, features = ["Element", "Node"] } sledgehammer_bindgen = { version = "0.2.1", optional = true } -sledgehammer_utils = { version = "0.1.1", optional = true } +sledgehammer_utils = { version = "0.2", optional = true } serde = { version = "1.0", features = ["derive"], optional = true } [features] From 212022d0c24492382c34788ea36060792f96da7a Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 19 Jul 2023 13:54:10 -0700 Subject: [PATCH 7/7] more clippy fixes --- packages/autofmt/src/writer.rs | 2 +- packages/core-macro/src/props/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/autofmt/src/writer.rs b/packages/autofmt/src/writer.rs index fae3313a8..59f135592 100644 --- a/packages/autofmt/src/writer.rs +++ b/packages/autofmt/src/writer.rs @@ -197,7 +197,7 @@ impl<'a> Writer<'a> { self.out, "for {} in {} {{", forloop.pat.clone().into_token_stream(), - prettyplease::unparse_expr(&*forloop.expr) + prettyplease::unparse_expr(&forloop.expr) )?; if forloop.body.is_empty() { diff --git a/packages/core-macro/src/props/mod.rs b/packages/core-macro/src/props/mod.rs index 523caf911..6a0d24a95 100644 --- a/packages/core-macro/src/props/mod.rs +++ b/packages/core-macro/src/props/mod.rs @@ -1086,7 +1086,7 @@ Finally, call `.build()` to create the instance of `{name}`. pub fn new(attrs: &[syn::Attribute]) -> Result { let mut result = TypeBuilderAttr::default(); for attr in attrs { - if path_to_single_string(&attr.path()).as_deref() != Some("builder") { + if path_to_single_string(attr.path()).as_deref() != Some("builder") { continue; }